From d0d0d0cdc4218f1f944481a5116c74d81682deff Mon Sep 17 00:00:00 2001 From: Vidhu Kant Sharma Date: Tue, 15 Aug 2023 13:37:22 +0530 Subject: added validators for read-only endpoints --- anime.go | 32 +++++-- errors.go | 16 ++++ manga.go | 18 +++- mg.go | 70 +++++++++++++++ params.go | 8 +- validators.go | 276 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 407 insertions(+), 13 deletions(-) diff --git a/anime.go b/anime.go index 4246cc5..d73920c 100644 --- a/anime.go +++ b/anime.go @@ -22,7 +22,11 @@ import "encoding/json" const ANIME_BASE_URL string = BASE_URL + "/anime" func (c Client) SearchAnime(animes *[]Anime, params *SearchParams) error { - // TODO: validate params + err := validateAnimeSearchParams(params) + if err != nil { + return err + } + var res struct { Data []struct { Anime Anime `json:"node"` @@ -43,7 +47,11 @@ func (c Client) SearchAnime(animes *[]Anime, params *SearchParams) error { } func (c Client) GetAnimeById(anime *Anime, id int, fields []string) error { - // TODO: validate params + err := validateAnimeFields(&fields) + if err != nil { + return err + } + body, err := c.get(ANIME_BASE_URL + getIdQuery(id, fields)) if err != nil { return err @@ -54,7 +62,11 @@ func (c Client) GetAnimeById(anime *Anime, id int, fields []string) error { } func (c Client) GetAnimeRanking(animes *[]RankedAnime, params *RankingParams) error { - // TODO: validate params + err := validateAnimeRankingParams(params) + if err != nil { + return err + } + body, err := c.get(ANIME_BASE_URL + getRankingQuery(params)) if err != nil { return err @@ -79,7 +91,11 @@ func (c Client) GetAnimeRanking(animes *[]RankedAnime, params *RankingParams) er } func (c Client) GetSeasonalAnime(animes *[]Anime, params *SeasonalParams) error { - // TODO: validate params + err := validateSeasonalParams(params) + if err != nil { + return err + } + body, err := c.get(ANIME_BASE_URL + getSeasonalQuery(params)) if err != nil { return err @@ -100,9 +116,13 @@ func (c Client) GetSeasonalAnime(animes *[]Anime, params *SeasonalParams) error return nil } +// TODO: only allow MainAuth not ClientAuth func (c Client) GetSuggestedAnime(animes *[]Anime, params *SuggestedParams) error { - // TODO: validate params - // TODO: only allow MainAuth not ClientAuth + err := validateSuggestedParams(params) + if err != nil { + return err + } + body, err := c.get(ANIME_BASE_URL + getSuggestedQuery(params)) if err != nil { return err diff --git a/errors.go b/errors.go index 206585b..d2b2828 100644 --- a/errors.go +++ b/errors.go @@ -16,3 +16,19 @@ */ package mg + +import "errors" + +var ( + ErrLimitOutOfRange = errors.New("mg: invalid limit (out of range)") + ErrInvalidField = errors.New("mg: invalid field passed") + ErrInvalidRankingType = errors.New("mg: invalid ranking type") + ErrInvalidSeason = errors.New("mg: invalid season") + ErrInvalidSort = errors.New("mg: invalid sort") + ErrInvalidStatus = errors.New("mg: invalid status") + ErrInvalidScore = errors.New("mg: invalid score") + ErrInvalidPriority = errors.New("mg: invalid priority") + ErrInvalidRewatchValue = errors.New("mg: invalid rewatch value") + ErrInvalidRereadValue = errors.New("mg: invalid reread value") + ErrEmptySearchString = errors.New("mg: invalid search string (empty string)") +) diff --git a/manga.go b/manga.go index 6b5ff3b..626ef94 100644 --- a/manga.go +++ b/manga.go @@ -22,7 +22,11 @@ import "encoding/json" const MANGA_BASE_URL string = BASE_URL + "/manga" func (c Client) SearchManga(mangas *[]Manga, params *SearchParams) error { - // TODO: validate params + err := validateMangaSearchParams(params) + if err != nil { + return err + } + var res struct { Data []struct { Manga Manga `json:"node"` @@ -43,7 +47,11 @@ func (c Client) SearchManga(mangas *[]Manga, params *SearchParams) error { } func (c Client) GetMangaById(manga *Manga, id int, fields []string) error { - // TODO: validate params + err := validateMangaFields(&fields) + if err != nil { + return err + } + body, err := c.get(ANIME_BASE_URL + getIdQuery(id, fields)) if err != nil { return err @@ -54,7 +62,11 @@ func (c Client) GetMangaById(manga *Manga, id int, fields []string) error { } func (c Client) GetMangaRanking(mangas *[]RankedManga, params *RankingParams) error { - // TODO: validate params + err := validateMangaRankingParams(params) + if err != nil { + return err + } + body, err := c.get(MANGA_BASE_URL + getRankingQuery(params)) if err != nil { return err diff --git a/mg.go b/mg.go index 05eb640..7b7cea5 100644 --- a/mg.go +++ b/mg.go @@ -41,3 +41,73 @@ const ( Tags = "tags" Comments = "comments" ) + +// for getting ranking list +const ( + // for anime only + RankingTypeAiring = "airing" + RankingTypeUpcoming = "upcoming" + RankingTypeTV = "tv" + RankingTypeOVA = "ova" + RankingTypeMovie = "movie" + RankingTypeSpecial = "special" + + // for manga only + RankingTypeManga = "manga" + RankingTypeNovel = "novels" + RankingTypeOneShot = "oneshots" + RankingTypeDoujin = "doujin" + RankingTypeManhwa = "manhwa" + RankingTypeManhua = "manhua" + + // for both + RankingTypeAll = "all" + RankingTypeByPopularity = "bypopularity" + RankingTypeFavorite = "favorite" +) + +// for anime/manga list sort +const ( + // for anime only + SortByAnimeTitle = "anime_title" + SortByAnimeStartDate = "anime_start_date" + SortByAnimeId = "anime_id" + + // for manga only + SortByMangaTitle = "manga_title" + SortByMangaStartDate = "manga_start_date" + SortByMangaId = "manga_id" + + // for both + SortByListScore = "list_score" + SortByListUpdatedAt = "list_updated_at" +) + +// for anime/manga list status +const ( + // for anime only + ListStatusWatching = "watching" + ListStatusPTW = "plan_to_watch" + + // for manga only + ListStatusReading = "watching" + ListStatusPTR = "plan_to_read" + + // for both + ListStatusCompleted = "completed" + ListStatusOnHold = "on_hold" + ListStatusDropped = "dropped" +) + +// for anime seasons +const ( + // season names + SeasonWinter = "winter" + SeasonSpring = "spring" + SeasonSummer = "summer" + SeasonFall = "fall" + + // sorting + SeasonSortByAnimeScore = "anime_score" + SeasonSortByNumListUsers = "num_list_users" +) diff --git a/params.go b/params.go index 4fa1406..d29c2f4 100644 --- a/params.go +++ b/params.go @@ -75,7 +75,7 @@ func SearchParamsNew() *SearchParams { func RankingParamsNew() *RankingParams { return &RankingParams { - RankingType: "", + RankingType: RankingTypeAll, Limit: 100, Offset: 0, NSFW: false, @@ -87,7 +87,7 @@ func SeasonalParamsNew() *SeasonalParams { return &SeasonalParams { Year: "", Season: "", - Sort: "", + Sort: SeasonSortByAnimeScore, Limit: 100, Offset: 0, NSFW: false, @@ -106,9 +106,9 @@ func SuggestedParamsNew() *SuggestedParams { func ListParamsNew() *ListParams { return &ListParams { - Username: "", + Username: "@me", Status: "", - Sort: "", + Sort: "list_score", Limit: 100, Offset: 0, NSFW: false, diff --git a/validators.go b/validators.go index 206585b..2dafaad 100644 --- a/validators.go +++ b/validators.go @@ -16,3 +16,279 @@ */ package mg + +import ( + "strings" + "slices" +) + +func validateAnimeFields(fields *[]string) error { + // if no fields given, set all + if cap(*fields) == 0 { + *fields = DefaultAnimeFields + return nil + } + + // check if given fields exist in DefaultAnimeFields + for _, f := range *fields { + if !slices.Contains(DefaultAnimeFields, f) { + return ErrInvalidField + } + } + + return nil +} + +func validateAnimeRankingType(t string) error { + if !slices.Contains([]string{ + RankingTypeAll, + RankingTypeByPopularity, + RankingTypeFavorite, + RankingTypeAiring, + RankingTypeUpcoming, + RankingTypeTV, + RankingTypeOVA, + RankingTypeMovie, + RankingTypeSpecial, + }, t) { + return ErrInvalidRankingType + } + + return nil +} + +func validateAnimeListSort(s string) error { + if !slices.Contains([]string{ + SortByListScore, + SortByListUpdatedAt, + SortByAnimeTitle, + SortByAnimeStartDate, + SortByAnimeId, + }, s) { + return ErrInvalidSort + } + + return nil +} + +func validateAnimeListStatus(s string) error { + if !slices.Contains([]string{ + ListStatusCompleted, + ListStatusOnHold, + ListStatusDropped, + ListStatusWatching, + ListStatusPTW, + }, s) { + return ErrInvalidStatus + } + + return nil +} + +func validateAnimeSeason(s string) error { + if !slices.Contains([]string{ + SeasonWinter, + SeasonSpring, + SeasonSummer, + SeasonFall, + }, s) { + return ErrInvalidSeason + } + + return nil +} + +func validateAnimeSeasonSort(s string) error { + if !slices.Contains([]string{ + SeasonSortByAnimeScore, + SeasonSortByNumListUsers, + }, s) { + return ErrInvalidSort + } + + return nil +} + +func validateMangaFields(fields *[]string) error { + // if no fields given, set all + if cap(*fields) == 0 { + *fields = DefaultMangaFields + return nil + } + + // check if given fields exist in DefaultAnimeFields + for _, f := range *fields { + if !slices.Contains(DefaultMangaFields, f) { + return ErrInvalidField + } + } + + return nil +} + +func validateMangaRankingType(t string) error { + if !slices.Contains([]string{ + RankingTypeAll, + RankingTypeByPopularity, + RankingTypeFavorite, + RankingTypeManga, + RankingTypeNovel, + RankingTypeOneShot, + RankingTypeDoujin, + RankingTypeManhwa, + RankingTypeManhua, + }, t) { + return ErrInvalidRankingType + } + + return nil +} + +func validateMangaListSort(s string) error { + if !slices.Contains([]string{ + SortByListScore, + SortByListUpdatedAt, + SortByMangaTitle, + SortByMangaStartDate, + SortByMangaId, + }, s) { + return ErrInvalidSort + } + + return nil +} + +func validateMangaListStatus(s string) error { + if !slices.Contains([]string{ + ListStatusCompleted, + ListStatusOnHold, + ListStatusDropped, + ListStatusReading, + ListStatusPTR, + }, s) { + return ErrInvalidStatus + } + + return nil +} + +func validateScore(score int) error { + if score >= 0 && score <= 10 { + return nil + } + + return ErrInvalidScore +} + +func validatePriority(priority int) error { + if priority >= 0 && priority <= 2 { + return nil + } + + return ErrInvalidPriority +} + +func validateRewatchValue(val int) error { + if val >= 0 && val <= 5 { + return nil + } + + return ErrInvalidRewatchValue +} + +func validateRereadValue(val int) error { + if val >= 0 && val <= 5 { + return nil + } + + return ErrInvalidRereadValue +} + +func validateAnimeSearchParams(params *SearchParams) error { + if strings.TrimSpace(params.SearchString) == "" { + return ErrEmptySearchString + } + + if params.Limit > 100 || params.Limit < 1 { + return ErrLimitOutOfRange + } + + err := validateAnimeFields(¶ms.Fields) + + return err +} + +func validateAnimeRankingParams(params *RankingParams) error { + err := validateAnimeRankingType(params.RankingType) + if err != nil { + return err + } + + if params.Limit > 500 || params.Limit < 1 { + return ErrLimitOutOfRange + } + + err = validateAnimeFields(¶ms.Fields) + + return err +} + +func validateSeasonalParams(params *SeasonalParams) error { + // check if year is int + + err := validateAnimeSeason(params.Season) + if err != nil { + return err + } + + err = validateAnimeSeasonSort(params.Sort) + if err != nil { + return err + } + + if params.Limit > 500 || params.Limit < 1 { + return ErrLimitOutOfRange + } + + err = validateMangaFields(¶ms.Fields) + + return err +} + +func validateSuggestedParams(params *SuggestedParams) error { + if params.Limit > 100 || params.Limit < 1 { + return ErrLimitOutOfRange + } + + return validateAnimeFields(¶ms.Fields) +} + +func validateMangaSearchParams(params *SearchParams) error { + if strings.TrimSpace(params.SearchString) == "" { + return ErrEmptySearchString + } + + if params.Limit > 100 || params.Limit < 1 { + return ErrLimitOutOfRange + } + + err := validateMangaFields(¶ms.Fields) + + return err +} + + +func validateMangaRankingParams(params *RankingParams) error { + err := validateMangaRankingType(params.RankingType) + if err != nil { + return err + } + + if params.Limit > 500 || params.Limit < 1 { + return ErrLimitOutOfRange + } + + err = validateMangaFields(¶ms.Fields) + + return err +} -- cgit v1.2.3