mirror of
https://github.com/elyby/chrly.git
synced 2025-05-31 14:11:51 +05:30
Implemented API endpoint to update skin information
Added tests to jwt package Reworked redis backend implementation Skin repository now have methods to remove skins by user id or username
This commit is contained in:
202
http/api.go
Normal file
202
http/api.go
Normal file
@@ -0,0 +1,202 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"elyby/minecraft-skinsystem/auth"
|
||||
"elyby/minecraft-skinsystem/db"
|
||||
"elyby/minecraft-skinsystem/interfaces"
|
||||
"elyby/minecraft-skinsystem/model"
|
||||
|
||||
"github.com/mono83/slf/wd"
|
||||
"github.com/thedevsaddam/govalidator"
|
||||
)
|
||||
|
||||
func init() {
|
||||
govalidator.AddCustomRule("md5", func(field string, rule string, message string, value interface{}) error {
|
||||
val := []byte(value.(string))
|
||||
if ok, _ := regexp.Match(`^[a-f0-9]{32}$`, val); !ok {
|
||||
if message == "" {
|
||||
message = fmt.Sprintf("The %s field must be a valid md5 hash", field)
|
||||
}
|
||||
|
||||
return errors.New(message)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
govalidator.AddCustomRule("skinUploadingNotAvailable", func(field string, rule string, message string, value interface{}) error {
|
||||
if message == "" {
|
||||
message = "Skin uploading is temporary unavailable"
|
||||
}
|
||||
|
||||
return errors.New(message)
|
||||
})
|
||||
}
|
||||
|
||||
func (cfg *Config) PostSkin(resp http.ResponseWriter, req *http.Request) {
|
||||
validationErrors := validatePostSkinRequest(req)
|
||||
if validationErrors != nil {
|
||||
apiBadRequest(resp, validationErrors)
|
||||
return
|
||||
}
|
||||
|
||||
identityId, _ := strconv.Atoi(req.Form.Get("identityId"))
|
||||
username := req.Form.Get("username")
|
||||
|
||||
record, err := findIdentity(cfg.SkinsRepo, identityId, username)
|
||||
if err != nil {
|
||||
cfg.Logger.Error("Error on requesting a skin from the repository: :err", wd.ErrParam(err))
|
||||
apiServerError(resp)
|
||||
return
|
||||
}
|
||||
|
||||
skinId, _ := strconv.Atoi(req.Form.Get("skinId"))
|
||||
is18, _ := strconv.ParseBool(req.Form.Get("is1_8"))
|
||||
isSlim, _ := strconv.ParseBool(req.Form.Get("isSlim"))
|
||||
|
||||
record.Uuid = req.Form.Get("uuid")
|
||||
record.SkinId = skinId
|
||||
record.Hash = req.Form.Get("hash")
|
||||
record.Is1_8 = is18
|
||||
record.IsSlim = isSlim
|
||||
record.Url = req.Form.Get("url")
|
||||
record.MojangTextures = req.Form.Get("mojangTextures")
|
||||
record.MojangSignature = req.Form.Get("mojangSignature")
|
||||
|
||||
err = cfg.SkinsRepo.Save(record)
|
||||
if err != nil {
|
||||
cfg.Logger.Error("Unable to save record to the repository: :err", wd.ErrParam(err))
|
||||
apiServerError(resp)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteHeader(http.StatusCreated)
|
||||
}
|
||||
|
||||
func (cfg *Config) Authenticate(handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
err := cfg.Auth.Check(req)
|
||||
if err != nil {
|
||||
if _, ok := err.(*auth.Unauthorized); ok {
|
||||
apiForbidden(resp, err.Error())
|
||||
} else {
|
||||
cfg.Logger.Error("Unknown error on validating api request: :err", wd.ErrParam(err))
|
||||
apiServerError(resp)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
handler.ServeHTTP(resp, req)
|
||||
})
|
||||
}
|
||||
|
||||
func validatePostSkinRequest(request *http.Request) map[string][]string {
|
||||
const maxMultipartMemory int64 = 32 << 20
|
||||
const oneOfSkinOrUrlMessage = "One of url or skin should be provided, but not both"
|
||||
|
||||
request.ParseMultipartForm(maxMultipartMemory)
|
||||
|
||||
validationRules := govalidator.MapData{
|
||||
"identityId": {"required", "numeric", "min:1"},
|
||||
"username": {"required"},
|
||||
"uuid": {"required", "uuid"},
|
||||
"skinId": {"required", "numeric", "min:1"},
|
||||
"url": {"url"},
|
||||
"file:skin": {"ext:png", "size:24576", "mime:image/png"},
|
||||
"hash": {"md5"},
|
||||
"is1_8": {"bool"},
|
||||
"isSlim": {"bool"},
|
||||
}
|
||||
|
||||
shouldAppendSkinRequiredError := false
|
||||
url := request.Form.Get("url")
|
||||
_, _, skinErr := request.FormFile("skin")
|
||||
if (url != "" && skinErr == nil) || (url == "" && skinErr != nil) {
|
||||
shouldAppendSkinRequiredError = true
|
||||
} else if skinErr == nil {
|
||||
validationRules["file:skin"] = append(validationRules["file:skin"], "skinUploadingNotAvailable")
|
||||
} else if url != "" {
|
||||
validationRules["hash"] = append(validationRules["hash"], "required")
|
||||
validationRules["is1_8"] = append(validationRules["is1_8"], "required")
|
||||
validationRules["isSlim"] = append(validationRules["isSlim"], "required")
|
||||
}
|
||||
|
||||
mojangTextures := request.Form.Get("mojangTextures")
|
||||
if mojangTextures != "" {
|
||||
validationRules["mojangSignature"] = []string{"required"}
|
||||
}
|
||||
|
||||
validator := govalidator.New(govalidator.Options{
|
||||
Request: request,
|
||||
Rules: validationRules,
|
||||
RequiredDefault: false,
|
||||
FormSize: maxMultipartMemory,
|
||||
})
|
||||
validationResults := validator.Validate()
|
||||
if shouldAppendSkinRequiredError {
|
||||
validationResults["url"] = append(validationResults["url"], oneOfSkinOrUrlMessage)
|
||||
validationResults["skin"] = append(validationResults["skin"], oneOfSkinOrUrlMessage)
|
||||
}
|
||||
|
||||
if len(validationResults) != 0 {
|
||||
return validationResults
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func findIdentity(repo interfaces.SkinsRepository, identityId int, username string) (*model.Skin, error) {
|
||||
var record *model.Skin
|
||||
record, err := repo.FindByUserId(identityId)
|
||||
if err != nil {
|
||||
if _, isSkinNotFound := err.(*db.SkinNotFoundError); !isSkinNotFound {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
record, err = repo.FindByUsername(username)
|
||||
if err == nil {
|
||||
repo.RemoveByUsername(username)
|
||||
record.UserId = identityId
|
||||
} else {
|
||||
record = &model.Skin{
|
||||
UserId: identityId,
|
||||
Username: username,
|
||||
}
|
||||
}
|
||||
} else if record.Username != username {
|
||||
repo.RemoveByUserId(identityId)
|
||||
record.Username = username
|
||||
}
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
||||
func apiBadRequest(resp http.ResponseWriter, errorsPerField map[string][]string) {
|
||||
resp.WriteHeader(http.StatusBadRequest)
|
||||
resp.Header().Set("Content-Type", "application/json")
|
||||
result, _ := json.Marshal(map[string]interface{}{
|
||||
"errors": errorsPerField,
|
||||
})
|
||||
resp.Write(result)
|
||||
}
|
||||
|
||||
func apiForbidden(resp http.ResponseWriter, reason string) {
|
||||
resp.WriteHeader(http.StatusForbidden)
|
||||
resp.Header().Set("Content-Type", "application/json")
|
||||
result, _ := json.Marshal([]interface{}{
|
||||
reason,
|
||||
})
|
||||
resp.Write(result)
|
||||
}
|
||||
|
||||
func apiServerError(resp http.ResponseWriter) {
|
||||
resp.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
337
http/api_test.go
Normal file
337
http/api_test.go
Normal file
@@ -0,0 +1,337 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"elyby/minecraft-skinsystem/auth"
|
||||
"elyby/minecraft-skinsystem/db"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
testify "github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestConfig_PostSkin_Valid(t *testing.T) {
|
||||
assert := testify.New(t)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
config, mocks := setupMocks(ctrl)
|
||||
|
||||
resultModel := createSkinModel("mock_user", false)
|
||||
resultModel.SkinId = 5
|
||||
resultModel.Hash = "94a457d92a61460cb9cb5d6f29732d2a"
|
||||
resultModel.Url = "http://ely.by/minecraft/skins/default.png"
|
||||
resultModel.MojangTextures = ""
|
||||
resultModel.MojangSignature = ""
|
||||
|
||||
mocks.Auth.EXPECT().Check(gomock.Any()).Return(nil)
|
||||
mocks.Skins.EXPECT().FindByUserId(1).Return(createSkinModel("mock_user", false), nil)
|
||||
mocks.Skins.EXPECT().Save(resultModel).Return(nil)
|
||||
|
||||
form := url.Values{
|
||||
"identityId": {"1"},
|
||||
"username": {"mock_user"},
|
||||
"uuid": {"0f657aa8-bfbe-415d-b700-5750090d3af3"},
|
||||
"skinId": {"5"},
|
||||
"hash": {"94a457d92a61460cb9cb5d6f29732d2a"},
|
||||
"is1_8": {"0"},
|
||||
"isSlim": {"0"},
|
||||
"url": {"http://ely.by/minecraft/skins/default.png"},
|
||||
}
|
||||
|
||||
req := httptest.NewRequest("POST", "http://skinsystem.ely.by/api/skins", bytes.NewBufferString(form.Encode()))
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
config.CreateHandler().ServeHTTP(w, req)
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
assert.Equal(201, resp.StatusCode)
|
||||
response, _ := ioutil.ReadAll(resp.Body)
|
||||
assert.Empty(string(response))
|
||||
}
|
||||
|
||||
func TestConfig_PostSkin_ChangedIdentityId(t *testing.T) {
|
||||
assert := testify.New(t)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
config, mocks := setupMocks(ctrl)
|
||||
|
||||
resultModel := createSkinModel("mock_user", false)
|
||||
resultModel.UserId = 2
|
||||
resultModel.SkinId = 5
|
||||
resultModel.Hash = "94a457d92a61460cb9cb5d6f29732d2a"
|
||||
resultModel.Url = "http://ely.by/minecraft/skins/default.png"
|
||||
resultModel.MojangTextures = ""
|
||||
resultModel.MojangSignature = ""
|
||||
|
||||
form := url.Values{
|
||||
"identityId": {"2"},
|
||||
"username": {"mock_user"},
|
||||
"uuid": {"0f657aa8-bfbe-415d-b700-5750090d3af3"},
|
||||
"skinId": {"5"},
|
||||
"hash": {"94a457d92a61460cb9cb5d6f29732d2a"},
|
||||
"is1_8": {"0"},
|
||||
"isSlim": {"0"},
|
||||
"url": {"http://ely.by/minecraft/skins/default.png"},
|
||||
}
|
||||
|
||||
req := httptest.NewRequest("POST", "http://skinsystem.ely.by/api/skins", bytes.NewBufferString(form.Encode()))
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
mocks.Auth.EXPECT().Check(gomock.Any()).Return(nil)
|
||||
mocks.Skins.EXPECT().FindByUserId(2).Return(nil, &db.SkinNotFoundError{"unknown"})
|
||||
mocks.Skins.EXPECT().FindByUsername("mock_user").Return(createSkinModel("mock_user", false), nil)
|
||||
mocks.Skins.EXPECT().RemoveByUsername("mock_user").Return(nil)
|
||||
mocks.Skins.EXPECT().Save(resultModel).Return(nil)
|
||||
|
||||
config.CreateHandler().ServeHTTP(w, req)
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
assert.Equal(201, resp.StatusCode)
|
||||
response, _ := ioutil.ReadAll(resp.Body)
|
||||
assert.Empty(string(response))
|
||||
}
|
||||
|
||||
func TestConfig_PostSkin_ChangedUsername(t *testing.T) {
|
||||
assert := testify.New(t)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
config, mocks := setupMocks(ctrl)
|
||||
|
||||
resultModel := createSkinModel("changed_username", false)
|
||||
resultModel.SkinId = 5
|
||||
resultModel.Hash = "94a457d92a61460cb9cb5d6f29732d2a"
|
||||
resultModel.Url = "http://ely.by/minecraft/skins/default.png"
|
||||
resultModel.MojangTextures = ""
|
||||
resultModel.MojangSignature = ""
|
||||
|
||||
form := url.Values{
|
||||
"identityId": {"1"},
|
||||
"username": {"changed_username"},
|
||||
"uuid": {"0f657aa8-bfbe-415d-b700-5750090d3af3"},
|
||||
"skinId": {"5"},
|
||||
"hash": {"94a457d92a61460cb9cb5d6f29732d2a"},
|
||||
"is1_8": {"0"},
|
||||
"isSlim": {"0"},
|
||||
"url": {"http://ely.by/minecraft/skins/default.png"},
|
||||
}
|
||||
|
||||
req := httptest.NewRequest("POST", "http://skinsystem.ely.by/api/skins", bytes.NewBufferString(form.Encode()))
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
mocks.Auth.EXPECT().Check(gomock.Any()).Return(nil)
|
||||
mocks.Skins.EXPECT().FindByUserId(1).Return(createSkinModel("mock_user", false), nil)
|
||||
mocks.Skins.EXPECT().RemoveByUserId(1).Return(nil)
|
||||
mocks.Skins.EXPECT().Save(resultModel).Return(nil)
|
||||
|
||||
config.CreateHandler().ServeHTTP(w, req)
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
assert.Equal(201, resp.StatusCode)
|
||||
response, _ := ioutil.ReadAll(resp.Body)
|
||||
assert.Empty(string(response))
|
||||
}
|
||||
|
||||
func TestConfig_PostSkin_CompletelyNewIdentity(t *testing.T) {
|
||||
assert := testify.New(t)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
config, mocks := setupMocks(ctrl)
|
||||
|
||||
resultModel := createSkinModel("mock_user", false)
|
||||
resultModel.SkinId = 5
|
||||
resultModel.Hash = "94a457d92a61460cb9cb5d6f29732d2a"
|
||||
resultModel.Url = "http://ely.by/minecraft/skins/default.png"
|
||||
resultModel.MojangTextures = ""
|
||||
resultModel.MojangSignature = ""
|
||||
|
||||
form := url.Values{
|
||||
"identityId": {"1"},
|
||||
"username": {"mock_user"},
|
||||
"uuid": {"0f657aa8-bfbe-415d-b700-5750090d3af3"},
|
||||
"skinId": {"5"},
|
||||
"hash": {"94a457d92a61460cb9cb5d6f29732d2a"},
|
||||
"is1_8": {"0"},
|
||||
"isSlim": {"0"},
|
||||
"url": {"http://ely.by/minecraft/skins/default.png"},
|
||||
}
|
||||
|
||||
req := httptest.NewRequest("POST", "http://skinsystem.ely.by/api/skins", bytes.NewBufferString(form.Encode()))
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
mocks.Auth.EXPECT().Check(gomock.Any()).Return(nil)
|
||||
mocks.Skins.EXPECT().FindByUserId(1).Return(nil, &db.SkinNotFoundError{"unknown"})
|
||||
mocks.Skins.EXPECT().FindByUsername("mock_user").Return(nil, &db.SkinNotFoundError{"mock_user"})
|
||||
mocks.Skins.EXPECT().Save(resultModel).Return(nil)
|
||||
|
||||
config.CreateHandler().ServeHTTP(w, req)
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
assert.Equal(201, resp.StatusCode)
|
||||
response, _ := ioutil.ReadAll(resp.Body)
|
||||
assert.Empty(string(response))
|
||||
}
|
||||
|
||||
func TestConfig_PostSkin_UploadSkin(t *testing.T) {
|
||||
assert := testify.New(t)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
config, mocks := setupMocks(ctrl)
|
||||
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
|
||||
part, _ := writer.CreateFormFile("skin", "char.png")
|
||||
part.Write(loadSkinFile())
|
||||
|
||||
_ = writer.WriteField("identityId", "1")
|
||||
_ = writer.WriteField("username", "mock_user")
|
||||
_ = writer.WriteField("uuid", "0f657aa8-bfbe-415d-b700-5750090d3af3")
|
||||
_ = writer.WriteField("skinId", "5")
|
||||
|
||||
err := writer.Close()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
req := httptest.NewRequest("POST", "http://skinsystem.ely.by/api/skins", body)
|
||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
mocks.Auth.EXPECT().Check(gomock.Any()).Return(nil)
|
||||
|
||||
config.CreateHandler().ServeHTTP(w, req)
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
assert.Equal(400, resp.StatusCode)
|
||||
response, _ := ioutil.ReadAll(resp.Body)
|
||||
assert.JSONEq(`{
|
||||
"errors": {
|
||||
"skin": [
|
||||
"Skin uploading is temporary unavailable"
|
||||
]
|
||||
}
|
||||
}`, string(response))
|
||||
}
|
||||
|
||||
func TestConfig_PostSkin_RequiredFields(t *testing.T) {
|
||||
assert := testify.New(t)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
config, mocks := setupMocks(ctrl)
|
||||
|
||||
form := url.Values{
|
||||
"hash": {"this is not md5"},
|
||||
"mojangTextures": {"someBase64EncodedString"},
|
||||
}
|
||||
|
||||
req := httptest.NewRequest("POST", "http://skinsystem.ely.by/api/skins", bytes.NewBufferString(form.Encode()))
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
mocks.Auth.EXPECT().Check(gomock.Any()).Return(nil)
|
||||
|
||||
config.CreateHandler().ServeHTTP(w, req)
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
assert.Equal(400, resp.StatusCode)
|
||||
response, _ := ioutil.ReadAll(resp.Body)
|
||||
assert.JSONEq(`{
|
||||
"errors": {
|
||||
"identityId": [
|
||||
"The identityId field is required",
|
||||
"The identityId field must be numeric",
|
||||
"The identityId field must be minimum 1 char"
|
||||
],
|
||||
"skinId": [
|
||||
"The skinId field is required",
|
||||
"The skinId field must be numeric",
|
||||
"The skinId field must be minimum 1 char"
|
||||
],
|
||||
"username": [
|
||||
"The username field is required"
|
||||
],
|
||||
"uuid": [
|
||||
"The uuid field is required",
|
||||
"The uuid field must contain valid UUID"
|
||||
],
|
||||
"hash": [
|
||||
"The hash field must be a valid md5 hash"
|
||||
],
|
||||
"url": [
|
||||
"One of url or skin should be provided, but not both"
|
||||
],
|
||||
"skin": [
|
||||
"One of url or skin should be provided, but not both"
|
||||
],
|
||||
"mojangSignature": [
|
||||
"The mojangSignature field is required"
|
||||
]
|
||||
}
|
||||
}`, string(response))
|
||||
}
|
||||
|
||||
func TestConfig_PostSkin_Unauthorized(t *testing.T) {
|
||||
assert := testify.New(t)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
config, mocks := setupMocks(ctrl)
|
||||
|
||||
req := httptest.NewRequest("POST", "http://skinsystem.ely.by/api/skins", nil)
|
||||
req.Header.Add("Authorization", "Bearer invalid.jwt.token")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
mocks.Auth.EXPECT().Check(gomock.Any()).Return(&auth.Unauthorized{"Cannot parse passed JWT token"})
|
||||
|
||||
config.CreateHandler().ServeHTTP(w, req)
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
assert.Equal(403, resp.StatusCode)
|
||||
response, _ := ioutil.ReadAll(resp.Body)
|
||||
assert.JSONEq(`[
|
||||
"Cannot parse passed JWT token"
|
||||
]`, string(response))
|
||||
}
|
||||
|
||||
// base64 https://github.com/mathiasbynens/small/blob/0ca3c51/png-transparent.png
|
||||
var OnePxPng = []byte("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==")
|
||||
|
||||
func loadSkinFile() []byte {
|
||||
result := make([]byte, 92)
|
||||
_, err := base64.StdEncoding.Decode(result, OnePxPng)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
@@ -22,6 +22,7 @@ type Config struct {
|
||||
SkinsRepo interfaces.SkinsRepository
|
||||
CapesRepo interfaces.CapesRepository
|
||||
Logger wd.Watchdog
|
||||
Auth interfaces.AuthChecker
|
||||
}
|
||||
|
||||
func (cfg *Config) Run() error {
|
||||
@@ -59,6 +60,8 @@ func (cfg *Config) CreateHandler() http.Handler {
|
||||
// Legacy
|
||||
router.HandleFunc("/skins", cfg.SkinGET).Methods("GET")
|
||||
router.HandleFunc("/cloaks", cfg.CapeGET).Methods("GET")
|
||||
// API
|
||||
router.Handle("/api/skins", cfg.Authenticate(http.HandlerFunc(cfg.PostSkin))).Methods("POST")
|
||||
// 404
|
||||
router.NotFoundHandler = http.HandlerFunc(cfg.NotFound)
|
||||
|
||||
|
@@ -25,6 +25,7 @@ func TestBuildElyUrl(t *testing.T) {
|
||||
type mocks struct {
|
||||
Skins *mock_interfaces.MockSkinsRepository
|
||||
Capes *mock_interfaces.MockCapesRepository
|
||||
Auth *mock_interfaces.MockAuthChecker
|
||||
Log *mock_wd.MockWatchdog
|
||||
}
|
||||
|
||||
@@ -34,15 +35,18 @@ func setupMocks(ctrl *gomock.Controller) (
|
||||
) {
|
||||
skinsRepo := mock_interfaces.NewMockSkinsRepository(ctrl)
|
||||
capesRepo := mock_interfaces.NewMockCapesRepository(ctrl)
|
||||
authChecker := mock_interfaces.NewMockAuthChecker(ctrl)
|
||||
wd := mock_wd.NewMockWatchdog(ctrl)
|
||||
|
||||
return &Config{
|
||||
SkinsRepo: skinsRepo,
|
||||
CapesRepo: capesRepo,
|
||||
Auth: authChecker,
|
||||
Logger: wd,
|
||||
}, &mocks{
|
||||
Skins: skinsRepo,
|
||||
Capes: capesRepo,
|
||||
Auth: authChecker,
|
||||
Log: wd,
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user