diff --git a/api/app/v1/core/joke_validation.go b/api/app/v1/core/joke_validation.go new file mode 100644 index 0000000..152ec79 --- /dev/null +++ b/api/app/v1/core/joke_validation.go @@ -0,0 +1,30 @@ +package core + +import ( + "errors" + "jokes-bapak2-api/app/v1/utils" + "net/http" + "strings" + + "github.com/gojek/heimdall/v7/httpclient" +) + +var ValidContentType = []string{"image/jpeg", "image/png", "image/webp", "image/gif"} + +// CheckImageValidity calls to the image host to check whether it's a valid image or not. +func CheckImageValidity(client *httpclient.Client, link string) (bool, error) { + if strings.Contains(link, "https://") { + // Perform HTTP call to link + res, err := client.Get(link, http.Header{"User-Agent": []string{"JokesBapak2 API"}}) + if err != nil { + return false, err + } + + if res.StatusCode == 200 && res.ContentLength > 0 && utils.IsIn(ValidContentType, res.Header.Get("content-type")) { + return true, nil + } + + return false, nil + } + return false, errors.New("URL must use HTTPS protocol") +} \ No newline at end of file diff --git a/api/app/v1/handler/joke_add.go b/api/app/v1/handler/joke_add.go index 71a9136..208ef53 100644 --- a/api/app/v1/handler/joke_add.go +++ b/api/app/v1/handler/joke_add.go @@ -16,6 +16,18 @@ func AddNewJoke(c *fiber.Ctx) error { return err } + // Check link validity + valid, err := core.CheckImageValidity(client, body.Link) + if err != nil { + return err + } + + if !valid { + return c.Status(fiber.StatusBadRequest).JSON(models.Error{ + Error: "URL provided is not a valid image", + }) + } + sql, args, err := psql.Insert("jokesbapak2").Columns("link", "creator").Values(body.Link, c.Locals("userID")).ToSql() if err != nil { return err diff --git a/api/app/v1/handler/joke_update.go b/api/app/v1/handler/joke_update.go index 13abf1b..00e3853 100644 --- a/api/app/v1/handler/joke_update.go +++ b/api/app/v1/handler/joke_update.go @@ -31,12 +31,24 @@ func UpdateJoke(c *fiber.Ctx) error { return err } + // Check link validity + valid, err := core.CheckImageValidity(client, body.Link) + if err != nil { + return err + } + + if !valid { + return c.Status(fiber.StatusBadRequest).JSON(models.Error{ + Error: "URL provided is not a valid image", + }) + } + sql, args, err = psql.Update("jokesbapak2").Set("link", body.Link).Set("creator", c.Locals("userID")).ToSql() if err != nil { return err } - _, err := db.Query(context.Background(), sql, args...) + _, err = db.Query(context.Background(), sql, args...) if err != nil { return err } diff --git a/api/app/v1/utils/array.go b/api/app/v1/utils/array.go new file mode 100644 index 0000000..6b70eaa --- /dev/null +++ b/api/app/v1/utils/array.go @@ -0,0 +1,11 @@ +package utils + +// IsIn checks if an array have a value +func IsIn(arr []string, value string) bool { + for _, item := range arr { + if item == value { + return true + } + } + return false +} \ No newline at end of file diff --git a/api/app/v1/utils/array_test.go b/api/app/v1/utils/array_test.go new file mode 100644 index 0000000..3868a40 --- /dev/null +++ b/api/app/v1/utils/array_test.go @@ -0,0 +1,23 @@ +package utils_test + +import ( + "jokes-bapak2-api/app/v1/utils" + "testing" +) + +func TestIsIn(t *testing.T) { + arr := []string{"John", "Matthew", "Thomas", "Adam"} + t.Run("should return true", func(t *testing.T) { + check := utils.IsIn(arr, "Thomas") + if !check { + t.Error("check should be true: ", check) + } + }) + + t.Run("should return false", func(t *testing.T) { + check := utils.IsIn(arr, "James") + if check { + t.Error("check should be false: ", check) + } + }) +} \ No newline at end of file