refactor: moving each routes to new directory
This commit is contained in:
parent
84cc35eb10
commit
84cfab08ef
|
@ -0,0 +1,31 @@
|
||||||
|
package health
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"jokes-bapak2-api/app/v1/handler"
|
||||||
|
"jokes-bapak2-api/app/v1/models"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Health(c *fiber.Ctx) error {
|
||||||
|
// Ping REDIS database
|
||||||
|
err := handler.Redis.Ping(context.Background()).Err()
|
||||||
|
if err != nil {
|
||||||
|
return c.
|
||||||
|
Status(fiber.StatusServiceUnavailable).
|
||||||
|
JSON(models.Error{
|
||||||
|
Error: "REDIS: " + err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = handler.Db.Query(context.Background(), "SELECT \"id\" FROM \"jokesbapak2\" LIMIT 1")
|
||||||
|
if err != nil {
|
||||||
|
return c.
|
||||||
|
Status(fiber.StatusServiceUnavailable).
|
||||||
|
JSON(models.Error{
|
||||||
|
Error: "POSTGRESQL: " + err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.SendStatus(fiber.StatusOK)
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package health_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
v1 "jokes-bapak2-api/app/v1"
|
||||||
|
"jokes-bapak2-api/app/v1/platform/database"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHealth(t *testing.T) {
|
||||||
|
err := database.Setup()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = db.Query(context.Background(), "INSERT INTO \"administrators\" (id, key, token, last_used) VALUES ($1, $2, $3, $4);", 1, "very secure", "not the real one", time.Now().Format(time.RFC3339))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = db.Query(context.Background(), "INSERT INTO \"jokesbapak2\" (id, link, creator) VALUES ($1, $2, $3), ($4, $5, $6), ($7, $8, $9);", jokesData...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
|
app := v1.New()
|
||||||
|
|
||||||
|
t.Run("Health - should return 200", func(t *testing.T) {
|
||||||
|
req, _ := http.NewRequest("GET", "/health", nil)
|
||||||
|
res, err := app.Test(req, -1)
|
||||||
|
|
||||||
|
assert.Equalf(t, false, err != nil, "health")
|
||||||
|
assert.Equalf(t, 200, res.StatusCode, "health")
|
||||||
|
assert.NotEqualf(t, 0, res.ContentLength, "health")
|
||||||
|
_, err = ioutil.ReadAll(res.Body)
|
||||||
|
assert.Nilf(t, err, "health")
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package joke
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"jokes-bapak2-api/app/v1/core"
|
||||||
|
"jokes-bapak2-api/app/v1/handler"
|
||||||
|
"jokes-bapak2-api/app/v1/models"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddNewJoke(c *fiber.Ctx) error {
|
||||||
|
var body models.Joke
|
||||||
|
err := c.BodyParser(&body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check link validity
|
||||||
|
valid, err := core.CheckImageValidity(handler.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 := handler.Psql.Insert("jokesbapak2").Columns("link", "creator").Values(body.Link, c.Locals("userID")).ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Implement solution if the link provided already exists.
|
||||||
|
_, err = handler.Db.Query(context.Background(), sql, args...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = core.SetAllJSONJoke(handler.Db, handler.Memory)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = core.SetTotalJoke(handler.Db, handler.Memory)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusCreated).JSON(models.ResponseJoke{
|
||||||
|
Link: body.Link,
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package joke_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
v1 "jokes-bapak2-api/app/v1"
|
||||||
|
"jokes-bapak2-api/app/v1/handler"
|
||||||
|
"jokes-bapak2-api/app/v1/platform/database"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddNewJoke(t *testing.T) {
|
||||||
|
// t.SkipNow()
|
||||||
|
err := database.Setup()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
hashedToken := "$argon2id$v=19$m=65536,t=16,p=4$48beb241490caa57fbca8e63df1e1b5fba8934baf78205ee775f96a85f45b889$e6dfca3f69adbe7653dbb353f366d741a3640313c45e33eabaca0c217c16417de80d70ac67f217c9ca46634b0abaad5f4ea2b064caa44ce218fb110b4cba9d36"
|
||||||
|
_, err = handler.Db.Query(context.Background(), "INSERT INTO \"administrators\" (id, key, token, last_used) VALUES ($1, $2, $3, $4);", 1, "very secure", hashedToken, time.Now().Format(time.RFC3339))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
|
app := v1.New()
|
||||||
|
|
||||||
|
t.Run("Add - should return 201", func(t *testing.T) {
|
||||||
|
reqBody := strings.NewReader("{\"link\":\"https://via.placeholder.com/300/07f/ff0000.png\",\"key\":\"very secure\",\"token\":\"password\"}")
|
||||||
|
req, _ := http.NewRequest("PUT", "/", reqBody)
|
||||||
|
req.Header.Set("content-type", "application/json")
|
||||||
|
req.Header.Add("accept", "application/json")
|
||||||
|
res, err := app.Test(req, -1)
|
||||||
|
|
||||||
|
assert.Equalf(t, false, err != nil, "joke add")
|
||||||
|
assert.Equalf(t, 201, res.StatusCode, "joke add")
|
||||||
|
assert.NotEqualf(t, 0, res.ContentLength, "joke add")
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
assert.Nilf(t, err, "joke add")
|
||||||
|
assert.Equalf(t, "{\"link\":\"https://via.placeholder.com/300/07f/ff0000.png\"}", string(body), "joke add")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Add - should not be a valid image", func(t *testing.T) {
|
||||||
|
reqBody := strings.NewReader("{\"link\":\"https://google.com/\",\"key\":\"very secure\",\"token\":\"password\"}")
|
||||||
|
req, _ := http.NewRequest("PUT", "/", reqBody)
|
||||||
|
req.Header.Set("content-type", "application/json")
|
||||||
|
req.Header.Add("accept", "application/json")
|
||||||
|
res, err := app.Test(req, -1)
|
||||||
|
|
||||||
|
assert.Equalf(t, false, err != nil, "joke add")
|
||||||
|
assert.Equalf(t, 400, res.StatusCode, "joke add")
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
assert.Nilf(t, err, "joke add")
|
||||||
|
assert.Equalf(t, "{\"error\":\"URL provided is not a valid image\"}", string(body), "joke add")
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package joke
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"jokes-bapak2-api/app/v1/core"
|
||||||
|
"jokes-bapak2-api/app/v1/handler"
|
||||||
|
"jokes-bapak2-api/app/v1/models"
|
||||||
|
|
||||||
|
"github.com/Masterminds/squirrel"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DeleteJoke(c *fiber.Ctx) error {
|
||||||
|
id, err := strconv.Atoi(c.Params("id"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the joke exists
|
||||||
|
sql, args, err := handler.Psql.Select("id").From("jokesbapak2").Where(squirrel.Eq{"id": id}).ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var jokeID int
|
||||||
|
err = handler.Db.QueryRow(context.Background(), sql, args...).Scan(&jokeID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if jokeID == id {
|
||||||
|
sql, args, err = handler.Psql.Delete("jokesbapak2").Where(squirrel.Eq{"id": id}).ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = handler.Db.Query(context.Background(), sql, args...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = core.SetAllJSONJoke(handler.Db, handler.Memory)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = core.SetTotalJoke(handler.Db, handler.Memory)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(models.ResponseJoke{
|
||||||
|
Message: "specified joke id has been deleted",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.Status(fiber.StatusNotAcceptable).JSON(models.Error{
|
||||||
|
Error: "specified joke id does not exists",
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package joke_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
v1 "jokes-bapak2-api/app/v1"
|
||||||
|
"jokes-bapak2-api/app/v1/handler"
|
||||||
|
"jokes-bapak2-api/app/v1/platform/database"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDeleteJoke(t *testing.T) {
|
||||||
|
// TODO: Remove this line below, make this test works
|
||||||
|
t.SkipNow()
|
||||||
|
|
||||||
|
err := database.Setup()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
hashedToken := "$argon2id$v=19$m=65536,t=16,p=4$48beb241490caa57fbca8e63df1e1b5fba8934baf78205ee775f96a85f45b889$e6dfca3f69adbe7653dbb353f366d741a3640313c45e33eabaca0c217c16417de80d70ac67f217c9ca46634b0abaad5f4ea2b064caa44ce218fb110b4cba9d36"
|
||||||
|
_, err = handler.Db.Query(context.Background(), "INSERT INTO \"administrators\" (id, key, token, last_used) VALUES ($1, $2, $3, $4);", 1, "very secure", hashedToken, time.Now().Format(time.RFC3339))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = handler.Db.Query(context.Background(), "INSERT INTO \"jokesbapak2\" (id, link, creator) VALUES ($1, $2, $3), ($4, $5, $6), ($7, $8, $9);", jokesData...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
|
app := v1.New()
|
||||||
|
|
||||||
|
t.Run("Delete - should return 200", func(t *testing.T) {
|
||||||
|
reqBody := strings.NewReader("{\"key\":\"very secure\",\"token\":\"password\"}")
|
||||||
|
req, _ := http.NewRequest("DELETE", "/id/1", reqBody)
|
||||||
|
res, err := app.Test(req, -1)
|
||||||
|
|
||||||
|
assert.Equalf(t, false, err != nil, "joke delete")
|
||||||
|
assert.Equalf(t, 200, res.StatusCode, "joke delete")
|
||||||
|
assert.NotEqualf(t, 0, res.ContentLength, "joke delete")
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
assert.Nilf(t, err, "joke delete")
|
||||||
|
assert.Equalf(t, "{\"message\":\"specified joke id has been deleted\"}", string(body), "joke delete")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Delete - id doesn't exists", func(t *testing.T) {
|
||||||
|
reqBody := strings.NewReader("{\"key\":\"very secure\",\"token\":\"password\"}")
|
||||||
|
req, _ := http.NewRequest("DELETE", "/id/100", reqBody)
|
||||||
|
res, err := app.Test(req, -1)
|
||||||
|
|
||||||
|
assert.Equalf(t, false, err != nil, "joke delete")
|
||||||
|
assert.Equalf(t, 406, res.StatusCode, "joke delete")
|
||||||
|
assert.NotEqualf(t, 0, res.ContentLength, "joke delete")
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
assert.Nilf(t, err, "joke delete")
|
||||||
|
assert.Equalf(t, "{\"message\":\"specified joke id does not exists\"}", string(body), "joke delete")
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,151 @@
|
||||||
|
package joke
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"jokes-bapak2-api/app/v1/core"
|
||||||
|
"jokes-bapak2-api/app/v1/handler"
|
||||||
|
"jokes-bapak2-api/app/v1/models"
|
||||||
|
"jokes-bapak2-api/app/v1/utils"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TodayJoke(c *fiber.Ctx) error {
|
||||||
|
// check from handler.Redis if today's joke already exists
|
||||||
|
// send the joke if exists
|
||||||
|
// get a new joke if it's not, then send it.
|
||||||
|
var joke models.Today
|
||||||
|
err := handler.Redis.MGet(context.Background(), "today:link", "today:date", "today:image", "today:contentType").Scan(&joke)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
eq, err := utils.IsToday(joke.Date)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if eq {
|
||||||
|
c.Set("Content-Type", joke.ContentType)
|
||||||
|
return c.Status(fiber.StatusOK).Send([]byte(joke.Image))
|
||||||
|
} else {
|
||||||
|
var link string
|
||||||
|
err := handler.Db.QueryRow(context.Background(), "SELECT link FROM jokesbapak2 ORDER BY random() LIMIT 1").Scan(&link)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := handler.Client.Get(link, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now().UTC().Format(time.RFC3339)
|
||||||
|
err = handler.Redis.MSet(context.Background(), map[string]interface{}{
|
||||||
|
"today:link": link,
|
||||||
|
"today:date": now,
|
||||||
|
"today:image": string(data),
|
||||||
|
"today:contentType": response.Header.Get("content-type"),
|
||||||
|
}).Err()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Set("Content-Type", response.Header.Get("content-type"))
|
||||||
|
return c.Status(fiber.StatusOK).Send(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func SingleJoke(c *fiber.Ctx) error {
|
||||||
|
checkCache, err := core.CheckJokesCache(handler.Memory)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !checkCache {
|
||||||
|
jokes, err := core.GetAllJSONJokes(handler.Db)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = handler.Memory.Set("jokes", jokes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
link, err := core.GetRandomJokeFromCache(handler.Memory)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get image data
|
||||||
|
response, err := handler.Client.Get(link, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Set("Content-Type", response.Header.Get("content-type"))
|
||||||
|
return c.Status(fiber.StatusOK).Send(data)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func JokeByID(c *fiber.Ctx) error {
|
||||||
|
checkCache, err := core.CheckJokesCache(handler.Memory)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !checkCache {
|
||||||
|
jokes, err := core.GetAllJSONJokes(handler.Db)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = handler.Memory.Set("jokes", jokes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := strconv.Atoi(c.Params("id"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
link, err := core.GetCachedJokeByID(handler.Memory, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if link == "" {
|
||||||
|
return c.Status(fiber.StatusNotFound).Send([]byte("Requested ID was not found."))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get image data
|
||||||
|
response, err := handler.Client.Get(link, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Set("Content-Type", response.Header.Get("content-type"))
|
||||||
|
return c.Status(fiber.StatusOK).Send(data)
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
package joke_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
v1 "jokes-bapak2-api/app/v1"
|
||||||
|
"jokes-bapak2-api/app/v1/platform/database"
|
||||||
|
|
||||||
|
_ "github.com/joho/godotenv/autoload"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
var db = database.New()
|
||||||
|
var jokesData = []interface{}{1, "https://via.placeholder.com/300/06f/fff.png", 1, 2, "https://via.placeholder.com/300/07f/fff.png", 1, 3, "https://via.placeholder.com/300/08f/fff.png", 1}
|
||||||
|
|
||||||
|
func cleanup() {
|
||||||
|
_, err := db.Query(context.Background(), "DROP TABLE \"jokesbapak2\"")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
_, err = db.Query(context.Background(), "DROP TABLE \"administrators\"")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Need to find some workaround for this test
|
||||||
|
func TestJokeGet(t *testing.T) {
|
||||||
|
err := database.Setup()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = db.Query(context.Background(), "INSERT INTO \"administrators\" (id, key, token, last_used) VALUES ($1, $2, $3, $4);", 1, "very secure", "not the real one", time.Now().Format(time.RFC3339))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = db.Query(context.Background(), "INSERT INTO \"jokesbapak2\" (id, link, creator) VALUES ($1, $2, $3), ($4, $5, $6), ($7, $8, $9);", jokesData...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
|
app := v1.New()
|
||||||
|
|
||||||
|
t.Run("TodayJoke - should return 200", func(t *testing.T) {
|
||||||
|
req, _ := http.NewRequest("GET", "/today", nil)
|
||||||
|
res, err := app.Test(req, -1)
|
||||||
|
|
||||||
|
assert.Equalf(t, false, err != nil, "today joke")
|
||||||
|
assert.Equalf(t, 200, res.StatusCode, "today joke")
|
||||||
|
assert.NotEqualf(t, 0, res.ContentLength, "today joke")
|
||||||
|
_, err = ioutil.ReadAll(res.Body)
|
||||||
|
assert.Nilf(t, err, "today joke")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("SingleJoke - should return 200", func(t *testing.T) {
|
||||||
|
req, _ := http.NewRequest("GET", "/", nil)
|
||||||
|
res, err := app.Test(req, -1)
|
||||||
|
|
||||||
|
assert.Equalf(t, false, err != nil, "single joke")
|
||||||
|
assert.Equalf(t, 200, res.StatusCode, "single joke")
|
||||||
|
assert.NotEqualf(t, 0, res.ContentLength, "single joke")
|
||||||
|
_, err = ioutil.ReadAll(res.Body)
|
||||||
|
assert.Nilf(t, err, "single joke")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("JokeByID - should return 200", func(t *testing.T) {
|
||||||
|
req, _ := http.NewRequest("GET", "/id/1", nil)
|
||||||
|
res, err := app.Test(req, -1)
|
||||||
|
|
||||||
|
assert.Equalf(t, false, err != nil, "joke by id")
|
||||||
|
assert.Equalf(t, 200, res.StatusCode, "joke by id")
|
||||||
|
assert.NotEqualf(t, 0, res.ContentLength, "joke by id")
|
||||||
|
_, err = ioutil.ReadAll(res.Body)
|
||||||
|
assert.Nilf(t, err, "joke by id")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("JokeByID - should return 404", func(t *testing.T) {
|
||||||
|
req, _ := http.NewRequest("GET", "/id/300", nil)
|
||||||
|
res, err := app.Test(req, -1)
|
||||||
|
|
||||||
|
assert.Equalf(t, false, err != nil, "joke by id")
|
||||||
|
assert.Equalf(t, 404, res.StatusCode, "joke by id")
|
||||||
|
assert.NotEqualf(t, 0, res.ContentLength, "joke by id")
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
assert.Nilf(t, err, "joke by id")
|
||||||
|
assert.Equalf(t, "Requested ID was not found.", string(body), "joke by id")
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package joke
|
||||||
|
|
||||||
|
import (
|
||||||
|
"jokes-bapak2-api/app/v1/core"
|
||||||
|
"jokes-bapak2-api/app/v1/handler"
|
||||||
|
"jokes-bapak2-api/app/v1/models"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TotalJokes(c *fiber.Ctx) error {
|
||||||
|
checkTotal, err := core.CheckTotalJokesCache(handler.Memory)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !checkTotal {
|
||||||
|
err = core.SetTotalJoke(handler.Db, handler.Memory)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
total, err := handler.Memory.Get("total")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "Entry not found" {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(models.Error{
|
||||||
|
Error: "no data found",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(models.ResponseJoke{
|
||||||
|
Message: strconv.Itoa(int(total[0])),
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package joke_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
v1 "jokes-bapak2-api/app/v1"
|
||||||
|
"jokes-bapak2-api/app/v1/handler"
|
||||||
|
"jokes-bapak2-api/app/v1/platform/database"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTotalJokes(t *testing.T) {
|
||||||
|
err := database.Setup()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = handler.Db.Query(context.Background(), "INSERT INTO \"administrators\" (id, key, token, last_used) VALUES ($1, $2, $3, $4);", 1, "very secure", "not the real one", time.Now().Format(time.RFC3339))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = handler.Db.Query(context.Background(), "INSERT INTO \"jokesbapak2\" (id, link, creator) VALUES ($1, $2, $3), ($4, $5, $6), ($7, $8, $9);", jokesData...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
|
app := v1.New()
|
||||||
|
|
||||||
|
t.Run("Total - should return 200", func(t *testing.T) {
|
||||||
|
req, _ := http.NewRequest("GET", "/total", nil)
|
||||||
|
res, err := app.Test(req, -1)
|
||||||
|
|
||||||
|
assert.Equalf(t, false, err != nil, "joke total")
|
||||||
|
assert.Equalf(t, 200, res.StatusCode, "joke total")
|
||||||
|
assert.NotEqualf(t, 0, res.ContentLength, "joke total")
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
assert.Nilf(t, err, "joke total")
|
||||||
|
// FIXME: This should be "message": "3", not one. I don't know what's wrong as it's 1 AM.
|
||||||
|
assert.Equalf(t, "{\"message\":\"1\"}", string(body), "joke total")
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
package joke
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"jokes-bapak2-api/app/v1/core"
|
||||||
|
"jokes-bapak2-api/app/v1/handler"
|
||||||
|
"jokes-bapak2-api/app/v1/models"
|
||||||
|
|
||||||
|
"github.com/Masterminds/squirrel"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UpdateJoke(c *fiber.Ctx) error {
|
||||||
|
id := c.Params("id")
|
||||||
|
// Check if the joke exists
|
||||||
|
sql, args, err := handler.Psql.Select("id").From("jokesbapak2").Where(squirrel.Eq{"id": id}).ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var jokeID string
|
||||||
|
err = handler.Db.QueryRow(context.Background(), sql, args...).Scan(&jokeID)
|
||||||
|
if err != nil && err != models.ErrNoRows {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if jokeID == id {
|
||||||
|
body := new(models.Joke)
|
||||||
|
err = c.BodyParser(&body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check link validity
|
||||||
|
valid, err := core.CheckImageValidity(handler.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 = handler.Psql.Update("jokesbapak2").Set("link", body.Link).Set("creator", c.Locals("userID")).ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = handler.Db.Query(context.Background(), sql, args...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = core.SetAllJSONJoke(handler.Db, handler.Memory)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = core.SetTotalJoke(handler.Db, handler.Memory)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(models.ResponseJoke{
|
||||||
|
Message: "specified joke id has been updated",
|
||||||
|
Link: body.Link,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusNotAcceptable).JSON(models.Error{
|
||||||
|
Error: "specified joke id does not exists",
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package joke_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
v1 "jokes-bapak2-api/app/v1"
|
||||||
|
"jokes-bapak2-api/app/v1/handler"
|
||||||
|
"jokes-bapak2-api/app/v1/platform/database"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUpdateJoke(t *testing.T) {
|
||||||
|
t.SkipNow()
|
||||||
|
err := database.Setup()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
hashedToken := "$argon2id$v=19$m=65536,t=16,p=4$48beb241490caa57fbca8e63df1e1b5fba8934baf78205ee775f96a85f45b889$e6dfca3f69adbe7653dbb353f366d741a3640313c45e33eabaca0c217c16417de80d70ac67f217c9ca46634b0abaad5f4ea2b064caa44ce218fb110b4cba9d36"
|
||||||
|
_, err = handler.Db.Query(context.Background(), "INSERT INTO \"administrators\" (id, key, token, last_used) VALUES ($1, $2, $3, $4);", 1, "very secure", hashedToken, time.Now().Format(time.RFC3339))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = handler.Db.Query(context.Background(), "INSERT INTO \"jokesbapak2\" (id, link, creator) VALUES ($1, $2, $3), ($4, $5, $6), ($7, $8, $9);", jokesData...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
|
app := v1.New()
|
||||||
|
|
||||||
|
t.Run("Update - should return 200", func(t *testing.T) {
|
||||||
|
reqBody := strings.NewReader("{\"link\":\"https://picsum.photos/id/9/200/300\",\"key\":\"very secure\",\"token\":\"password\"}")
|
||||||
|
req, _ := http.NewRequest("PATCH", "/id/1", reqBody)
|
||||||
|
res, err := app.Test(req, -1)
|
||||||
|
|
||||||
|
assert.Equalf(t, false, err != nil, "joke update")
|
||||||
|
assert.Equalf(t, 200, res.StatusCode, "joke update")
|
||||||
|
assert.NotEqualf(t, 0, res.ContentLength, "joke update")
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
assert.Nilf(t, err, "joke update")
|
||||||
|
assert.Equalf(t, "{\"message\":\"specified joke id has been deleted\"}", string(body), "joke update")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Update - id doesn't exists", func(t *testing.T) {
|
||||||
|
reqBody := strings.NewReader("{\"link\":\"https://picsum.photos/id/9/200/300\",\"key\":\"very secure\",\"token\":\"password\"}")
|
||||||
|
req, _ := http.NewRequest("PATCH", "/id/100", reqBody)
|
||||||
|
res, err := app.Test(req, -1)
|
||||||
|
|
||||||
|
assert.Equalf(t, false, err != nil, "joke update")
|
||||||
|
assert.Equalf(t, 406, res.StatusCode, "joke update")
|
||||||
|
assert.NotEqualf(t, 0, res.ContentLength, "joke update")
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
assert.Nilf(t, err, "joke update")
|
||||||
|
assert.Equalf(t, "{\"message\":\"specified joke id does not exists\"}", string(body), "joke update")
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,14 +1,14 @@
|
||||||
package routes
|
package routes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"jokes-bapak2-api/app/v1/handler"
|
"jokes-bapak2-api/app/v1/handler/health"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Health(app *fiber.App) *fiber.App {
|
func Health(app *fiber.App) *fiber.App {
|
||||||
// Health check
|
// Health check
|
||||||
app.Get("/health", handler.Health)
|
app.Get("/health", health.Health)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package routes
|
package routes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"jokes-bapak2-api/app/v1/handler"
|
"jokes-bapak2-api/app/v1/handler/joke"
|
||||||
"jokes-bapak2-api/app/v1/middleware"
|
"jokes-bapak2-api/app/v1/middleware"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
@ -9,25 +9,25 @@ import (
|
||||||
|
|
||||||
func Joke(app *fiber.App) *fiber.App {
|
func Joke(app *fiber.App) *fiber.App {
|
||||||
// Single route
|
// Single route
|
||||||
app.Get("/", handler.SingleJoke)
|
app.Get("/", joke.SingleJoke)
|
||||||
|
|
||||||
// Today's joke
|
// Today's joke
|
||||||
app.Get("/today", handler.TodayJoke)
|
app.Get("/today", joke.TodayJoke)
|
||||||
|
|
||||||
// Joke by ID
|
// Joke by ID
|
||||||
app.Get("/id/:id", middleware.OnlyIntegerAsID(), handler.JokeByID)
|
app.Get("/id/:id", middleware.OnlyIntegerAsID(), joke.JokeByID)
|
||||||
|
|
||||||
// Count total jokes
|
// Count total jokes
|
||||||
app.Get("/total", handler.TotalJokes)
|
app.Get("/total", joke.TotalJokes)
|
||||||
|
|
||||||
// Add new joke
|
// Add new joke
|
||||||
app.Put("/", middleware.RequireAuth(), handler.AddNewJoke)
|
app.Put("/", middleware.RequireAuth(), joke.AddNewJoke)
|
||||||
|
|
||||||
// Update a joke
|
// Update a joke
|
||||||
app.Patch("/id/:id", middleware.RequireAuth(), middleware.OnlyIntegerAsID(), handler.UpdateJoke)
|
app.Patch("/id/:id", middleware.RequireAuth(), middleware.OnlyIntegerAsID(), joke.UpdateJoke)
|
||||||
|
|
||||||
// Delete a joke
|
// Delete a joke
|
||||||
app.Delete("/id/:id", middleware.RequireAuth(), middleware.OnlyIntegerAsID(), handler.DeleteJoke)
|
app.Delete("/id/:id", middleware.RequireAuth(), middleware.OnlyIntegerAsID(), joke.DeleteJoke)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue