Compare commits

...

2 Commits

Author SHA1 Message Date
417a7cf982 Decouples routers and adds auth for plans and actions call
All checks were successful
gitea-deepak/gogmagog/pipeline/head This commit looks good
2021-01-12 16:15:28 -06:00
ab1dab6619 jwt auth token return 2021-01-12 15:52:46 -06:00
16 changed files with 204 additions and 104 deletions

1
go.mod
View File

@@ -5,6 +5,7 @@ go 1.15
require (
github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/go-chi/chi v4.1.2+incompatible
github.com/go-chi/jwtauth v1.1.1
github.com/golang-migrate/migrate/v4 v4.14.1
github.com/jackc/pgx/v4 v4.10.1
github.com/jmoiron/sqlx v1.2.0

9
go.sum
View File

@@ -108,8 +108,11 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi v1.5.1/go.mod h1:REp24E+25iKvxgeTfHmdUoL5x15kBiDBlnIl5bCwe2k=
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/jwtauth v1.1.1 h1:CtUHwzvXUfZeZSbASLgzaTZQ8mL7p+vitX59NBTL1vY=
github.com/go-chi/jwtauth v1.1.1/go.mod h1:znOWz9e5/GfBOKiZlOUoEfjSjUF+cLZO3GcpkoGXvFI=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -307,6 +310,11 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/ktrysmt/go-bitbucket v0.6.4/go.mod h1:9u0v3hsd2rqCHRIpbir1oP7F58uo5dq19sBYvuMoyQ4=
github.com/lestrrat-go/iter v0.0.0-20200422075355-fc1769541911 h1:FvnrqecqX4zT0wOIbYK1gNgTm0677INEWiFY8UEYggY=
github.com/lestrrat-go/iter v0.0.0-20200422075355-fc1769541911/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc=
github.com/lestrrat-go/jwx v1.0.6-0.20201127121120-26218808f029 h1:+HTAqhgKkKqizghOYb4uEpZ7wK8tl3Y48ZbUTHF521c=
github.com/lestrrat-go/jwx v1.0.6-0.20201127121120-26218808f029/go.mod h1:TPF17WiSFegZo+c20fdpw49QD+/7n4/IsGvEmCSWwT0=
github.com/lestrrat-go/pdebug v0.0.0-20200204225717-4d6bd78da58d/go.mod h1:B06CSso/AWxiPejj+fheUINGeBKeeEZNt8w+EoU7+L8=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -651,6 +659,7 @@ golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200417140056-c07e33ef3290/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=

View File

@@ -5,6 +5,7 @@ import (
"gitea.deepak.science/deepak/gogmagog/models"
"gitea.deepak.science/deepak/gogmagog/routes"
"gitea.deepak.science/deepak/gogmagog/store"
"gitea.deepak.science/deepak/gogmagog/tokens"
"log"
"net/http"
"os"
@@ -38,7 +39,7 @@ func main() {
log.Println("created model")
}
router := routes.NewRouter(m)
router := routes.NewRouter(m, tokens.New("my secret"))
log.Println("Running server on " + port)

View File

@@ -9,7 +9,8 @@ import (
"strconv"
)
func newActionRouter(m *models.Model) http.Handler {
// NewActionRouter returns a new action router
func NewActionRouter(m *models.Model) http.Handler {
router := chi.NewRouter()
router.Get("/", getActionsFunc(m))
router.Post("/", postActionFunc(m))

View File

@@ -15,8 +15,8 @@ func TestEmptyActions(t *testing.T) {
// set up
assert := assert.New(t)
m := getEmptyModel()
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions", nil)
router := routes.NewActionRouter(m)
req, _ := http.NewRequest("GET", "/", nil)
rr := httptest.NewRecorder()
@@ -41,8 +41,8 @@ func TestOneAction(t *testing.T) {
completedDate, _ := time.Parse("2006-01-02", "2021-01-03")
a1 := &models.Action{ActionID: 3, ActionDescription: "testing", CompletedChunks: 1, CompletedOn: &completedDate, CreatedAt: &createdDate, UpdatedAt: &updatedDate, EstimatedChunks: 3, PlanID: 0}
m := getModel([]*models.Plan{}, []*models.Action{a1})
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions", nil)
router := routes.NewActionRouter(m)
req, _ := http.NewRequest("GET", "/", nil)
rr := httptest.NewRecorder()
@@ -76,8 +76,8 @@ func TestErrorAction(t *testing.T) {
m := getErrorModel("Model always errors")
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions", nil)
router := routes.NewActionRouter(m)
req, _ := http.NewRequest("GET", "/", nil)
rr := httptest.NewRecorder()
@@ -98,8 +98,8 @@ func TestEmptyActionErrorWriter(t *testing.T) {
m := getEmptyModel()
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions", nil)
router := routes.NewActionRouter(m)
req, _ := http.NewRequest("GET", "/", nil)
rr := NewBadWriter()
@@ -119,8 +119,8 @@ func TestOneActionByID(t *testing.T) {
updatedDate, _ := time.Parse("2006-01-02", "2021-01-02")
a := &models.Action{ActionID: 6, ActionDescription: "howdy", CompletedOn: nil, CreatedAt: &createdDate, UpdatedAt: &updatedDate, CompletedChunks: 0, EstimatedChunks: 54, PlanID: 3}
m := getModel([]*models.Plan{}, []*models.Action{a})
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions/6", nil)
router := routes.NewActionRouter(m)
req, _ := http.NewRequest("GET", "/6", nil)
rr := httptest.NewRecorder()
@@ -151,8 +151,8 @@ func TestErrorActionByID(t *testing.T) {
m := getErrorModel("Model always errors")
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions/5", nil)
router := routes.NewActionRouter(m)
req, _ := http.NewRequest("GET", "/5", nil)
rr := httptest.NewRecorder()
@@ -174,8 +174,8 @@ func TestEmptyActionErrorWriterByID(t *testing.T) {
a := &models.Action{ActionID: 6}
m := getModel([]*models.Plan{}, []*models.Action{a})
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions/6", nil)
router := routes.NewActionRouter(m)
req, _ := http.NewRequest("GET", "/6", nil)
rr := NewBadWriter()
@@ -194,8 +194,8 @@ func TestNotFoundActionByIDText(t *testing.T) {
m := getEmptyModel()
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions/wo", nil)
router := routes.NewActionRouter(m)
req, _ := http.NewRequest("GET", "/wo", nil)
rr := httptest.NewRecorder()
@@ -213,8 +213,8 @@ func TestNotFoundActionByIDEmpty(t *testing.T) {
m := getEmptyModel()
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions/1", nil)
router := routes.NewActionRouter(m)
req, _ := http.NewRequest("GET", "/1", nil)
rr := httptest.NewRecorder()
@@ -234,8 +234,8 @@ func TestActionsByPlanID(t *testing.T) {
updatedDate, _ := time.Parse("2006-01-02", "2021-01-02")
a := &models.Action{ActionID: 6, ActionDescription: "howdy", CompletedOn: nil, CreatedAt: &createdDate, UpdatedAt: &updatedDate, CompletedChunks: 0, EstimatedChunks: 54, PlanID: 3}
m := getModel([]*models.Plan{}, []*models.Action{a})
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions?plan_id=6", nil)
router := routes.NewActionRouter(m)
req, _ := http.NewRequest("GET", "/?plan_id=6", nil)
rr := httptest.NewRecorder()
@@ -269,8 +269,8 @@ func TestActionsByPlanIDInvalidID(t *testing.T) {
updatedDate, _ := time.Parse("2006-01-02", "2021-01-02")
a := &models.Action{ActionID: 6, ActionDescription: "howdy", CompletedOn: nil, CreatedAt: &createdDate, UpdatedAt: &updatedDate, CompletedChunks: 0, EstimatedChunks: 54, PlanID: 3}
m := getModel([]*models.Plan{}, []*models.Action{a})
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions?plan_id=aoeu", nil)
router := routes.NewActionRouter(m)
req, _ := http.NewRequest("GET", "/?plan_id=aoeu", nil)
rr := httptest.NewRecorder()

View File

@@ -3,15 +3,16 @@ package routes
import (
"encoding/json"
"gitea.deepak.science/deepak/gogmagog/models"
"gitea.deepak.science/deepak/gogmagog/tokens"
"github.com/go-chi/chi"
"io"
"net/http"
)
func newAuthRouter(m *models.Model) http.Handler {
func newAuthRouter(m *models.Model, tok tokens.Toker) http.Handler {
router := chi.NewRouter()
router.Post("/register", postUserFunc(m))
router.Post("/tokens", createTokenFunc(m))
router.Post("/tokens", createTokenFunc(m, tok))
return router
}
@@ -59,8 +60,11 @@ type loginCreds struct {
Username string `json:"username"`
Password string `json:"password"`
}
type createdToken struct {
Token string `json:"token"`
}
func createTokenFunc(m *models.Model) http.HandlerFunc {
func createTokenFunc(m *models.Model, tok tokens.Toker) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, 1024)
@@ -89,8 +93,10 @@ func createTokenFunc(m *models.Model) http.HandlerFunc {
}
w.Header().Add("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(user); err != nil {
response := &createdToken{Token: tok.EncodeUser(user)}
if err := json.NewEncoder(w).Encode(response); err != nil {
serverError(w, err)
return
}
}
}

View File

@@ -3,6 +3,7 @@ package routes_test
import (
"fmt"
"gitea.deepak.science/deepak/gogmagog/routes"
"gitea.deepak.science/deepak/gogmagog/tokens"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
@@ -15,7 +16,7 @@ func TestEmptyHeatlhErrorWriter(t *testing.T) {
m := getEmptyModel()
router := routes.NewRouter(m)
router := routes.NewRouter(m, tokens.New("whatever"))
req, _ := http.NewRequest("GET", "/health", nil)
rr := NewBadWriter()
@@ -33,7 +34,7 @@ func TestEmptyHealth(t *testing.T) {
// set up
assert := assert.New(t)
m := getEmptyModel()
router := routes.NewRouter(m)
router := routes.NewRouter(m, tokens.New("whatever"))
req, _ := http.NewRequest("GET", "/health", nil)
rr := httptest.NewRecorder()
@@ -62,7 +63,7 @@ func TestUnhealthyDB(t *testing.T) {
assert := assert.New(t)
errorMsg := "error"
m := getErrorModel(errorMsg)
router := routes.NewRouter(m)
router := routes.NewRouter(m, tokens.New("whatever"))
req, _ := http.NewRequest("GET", "/health", nil)
rr := httptest.NewRecorder()

View File

@@ -9,7 +9,8 @@ import (
"strconv"
)
func newPlanRouter(m *models.Model) http.Handler {
// NewPlanRouter returns the http.Handler for the passed in model to route plan methods.
func NewPlanRouter(m *models.Model) http.Handler {
router := chi.NewRouter()
router.Get("/", getAllPlansFunc(m))
router.Post("/", postPlanFunc(m))

View File

@@ -15,8 +15,8 @@ func TestEmptyPlans(t *testing.T) {
// set up
assert := assert.New(t)
m := getEmptyModel()
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/plans", nil)
router := routes.NewPlanRouter(m)
req, _ := http.NewRequest("GET", "/", nil)
rr := httptest.NewRecorder()
@@ -39,8 +39,8 @@ func TestOnePlan(t *testing.T) {
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/plans", nil)
router := routes.NewPlanRouter(m)
req, _ := http.NewRequest("GET", "/", nil)
rr := httptest.NewRecorder()
@@ -68,8 +68,8 @@ func TestErrorPlan(t *testing.T) {
m := getErrorModel("Model always errors")
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/plans", nil)
router := routes.NewPlanRouter(m)
req, _ := http.NewRequest("GET", "/", nil)
rr := httptest.NewRecorder()
@@ -90,8 +90,8 @@ func TestEmptyPlanErrorWriter(t *testing.T) {
m := getEmptyModel()
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/plans", nil)
router := routes.NewPlanRouter(m)
req, _ := http.NewRequest("GET", "/", nil)
rr := NewBadWriter()
@@ -110,8 +110,8 @@ func TestOnePlanByID(t *testing.T) {
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/plans/6", nil)
router := routes.NewPlanRouter(m)
req, _ := http.NewRequest("GET", "/6", nil)
rr := httptest.NewRecorder()
@@ -137,8 +137,8 @@ func TestErrorPlanByID(t *testing.T) {
m := getErrorModel("Model always errors")
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/plans/5", nil)
router := routes.NewPlanRouter(m)
req, _ := http.NewRequest("GET", "/5", nil)
rr := httptest.NewRecorder()
@@ -161,8 +161,8 @@ func TestEmptyPlanErrorWriterByID(t *testing.T) {
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/plans/6", nil)
router := routes.NewPlanRouter(m)
req, _ := http.NewRequest("GET", "/6", nil)
rr := NewBadWriter()
@@ -181,8 +181,8 @@ func TestNotFoundPlanByIDText(t *testing.T) {
m := getEmptyModel()
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/plans/wo", nil)
router := routes.NewPlanRouter(m)
req, _ := http.NewRequest("GET", "/wo", nil)
rr := httptest.NewRecorder()
@@ -200,8 +200,8 @@ func TestNotFoundPlanByIDEmpty(t *testing.T) {
m := getEmptyModel()
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/plans/1", nil)
router := routes.NewPlanRouter(m)
req, _ := http.NewRequest("GET", "/1", nil)
rr := httptest.NewRecorder()

View File

@@ -25,7 +25,7 @@ func TestPureJSONPostAction(t *testing.T) {
ActionDescription: "here's an action",
}
m := getModel([]*models.Plan{}, []*models.Action{a})
router := routes.NewRouter(m)
router := routes.NewActionRouter(m)
data := []byte(`{
"action_description": "here's an action",
"estimated_chunks": 3,
@@ -33,7 +33,7 @@ func TestPureJSONPostAction(t *testing.T) {
"completed_on": "2021-01-01T00:00:00Z",
"plan_id": 5
}`)
req, _ := http.NewRequest("POST", "/actions", bytes.NewBuffer(data))
req, _ := http.NewRequest("POST", "/", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -66,13 +66,13 @@ func TestExtraFieldActionPostJSON(t *testing.T) {
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
router := routes.NewActionRouter(m)
data := []byte(`{
"completed_on": "2021-01-01T00:00:00Z",
"plan_id": 5,
"sabotage": "omg"
}`)
req, _ := http.NewRequest("POST", "/actions", bytes.NewBuffer(data))
req, _ := http.NewRequest("POST", "/", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -92,9 +92,9 @@ func TestEmptyBodyActionPost(t *testing.T) {
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
router := routes.NewActionRouter(m)
data := []byte(``)
req, _ := http.NewRequest("POST", "/actions", bytes.NewBuffer(data))
req, _ := http.NewRequest("POST", "/", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -115,13 +115,13 @@ func TestTwoBodyActionPost(t *testing.T) {
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
router := routes.NewActionRouter(m)
data := []byte(`{
"plan_id": 5
}, {
"plan_id": 6
}`)
req, _ := http.NewRequest("POST", "/actions", bytes.NewBuffer(data))
req, _ := http.NewRequest("POST", "/", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -142,10 +142,10 @@ func TestErrorCreateAction(t *testing.T) {
m := getErrorModel("Model always errors")
router := routes.NewRouter(m)
router := routes.NewActionRouter(m)
a := &models.Action{PlanID: 6}
data, _ := json.Marshal(a)
req, _ := http.NewRequest("POST", "/actions", bytes.NewBuffer(data))
req, _ := http.NewRequest("POST", "/", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -167,10 +167,10 @@ func TestErrorOnRetrieveCreateAction(t *testing.T) {
m := getErrorOnGetModel("Model always errors")
router := routes.NewRouter(m)
router := routes.NewActionRouter(m)
a := &models.Action{PlanID: 6}
data, _ := json.Marshal(a)
req, _ := http.NewRequest("POST", "/actions", bytes.NewBuffer(data))
req, _ := http.NewRequest("POST", "/", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -192,9 +192,9 @@ func TestErrorWriterCreateAction(t *testing.T) {
a := &models.Action{PlanID: 6}
m := getModel([]*models.Plan{}, []*models.Action{a})
router := routes.NewRouter(m)
router := routes.NewActionRouter(m)
data, _ := json.Marshal(a)
req, _ := http.NewRequest("POST", "/actions", bytes.NewBuffer(data))
req, _ := http.NewRequest("POST", "/", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := NewBadWriter()

View File

@@ -19,9 +19,9 @@ func TestCreatePlanRoute(t *testing.T) {
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
router := routes.NewPlanRouter(m)
data, _ := json.Marshal(p)
req, _ := http.NewRequest("POST", "/plans", bytes.NewBuffer(data))
req, _ := http.NewRequest("POST", "/", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -50,12 +50,12 @@ func TestPureJSON(t *testing.T) {
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
router := routes.NewPlanRouter(m)
data := []byte(`{
"plan_date": "2021-01-01T00:00:00Z",
"plan_id": 5
}`)
req, _ := http.NewRequest("POST", "/plans", bytes.NewBuffer(data))
req, _ := http.NewRequest("POST", "/", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -84,13 +84,13 @@ func TestExtraFieldJSON(t *testing.T) {
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
router := routes.NewPlanRouter(m)
data := []byte(`{
"plan_date": "2021-01-01T00:00:00Z",
"plan_id": 5,
"plan_sabotage": "omg"
}`)
req, _ := http.NewRequest("POST", "/plans", bytes.NewBuffer(data))
req, _ := http.NewRequest("POST", "/", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -110,9 +110,9 @@ func TestEmptyBody(t *testing.T) {
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
router := routes.NewPlanRouter(m)
data := []byte(``)
req, _ := http.NewRequest("POST", "/plans", bytes.NewBuffer(data))
req, _ := http.NewRequest("POST", "/", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -133,7 +133,7 @@ func TestTwoBody(t *testing.T) {
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
router := routes.NewPlanRouter(m)
data := []byte(`{
"plan_date": "2021-01-01T00:00:00Z",
"plan_id": 5
@@ -141,7 +141,7 @@ func TestTwoBody(t *testing.T) {
"plan_date": "2021-01-01T00:00:00Z",
"plan_id": 6
}`)
req, _ := http.NewRequest("POST", "/plans", bytes.NewBuffer(data))
req, _ := http.NewRequest("POST", "/", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -162,11 +162,11 @@ func TestErrorCreatePlan(t *testing.T) {
m := getErrorModel("Model always errors")
router := routes.NewRouter(m)
router := routes.NewPlanRouter(m)
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
data, _ := json.Marshal(p)
req, _ := http.NewRequest("POST", "/plans", bytes.NewBuffer(data))
req, _ := http.NewRequest("POST", "/", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -188,11 +188,11 @@ func TestErrorOnRetrieveCreatePlan(t *testing.T) {
m := getErrorOnGetModel("Model always errors")
router := routes.NewRouter(m)
router := routes.NewPlanRouter(m)
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
data, _ := json.Marshal(p)
req, _ := http.NewRequest("POST", "/plans", bytes.NewBuffer(data))
req, _ := http.NewRequest("POST", "/", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -215,9 +215,9 @@ func TestErrorWriterCreatePlan(t *testing.T) {
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
router := routes.NewPlanRouter(m)
data, _ := json.Marshal(p)
req, _ := http.NewRequest("POST", "/plans", bytes.NewBuffer(data))
req, _ := http.NewRequest("POST", "/", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := NewBadWriter()

View File

@@ -25,7 +25,7 @@ func TestPureJSONPutAction(t *testing.T) {
ActionDescription: "here's an action",
}
m := getModel([]*models.Plan{}, []*models.Action{a})
router := routes.NewRouter(m)
router := routes.NewActionRouter(m)
data := []byte(`{
"action_description": "here's an action",
"estimated_chunks": 3,
@@ -33,7 +33,7 @@ func TestPureJSONPutAction(t *testing.T) {
"completed_on": "2021-01-01T00:00:00Z",
"plan_id": 5
}`)
req, _ := http.NewRequest("PUT", "/actions/0", bytes.NewBuffer(data))
req, _ := http.NewRequest("PUT", "/0", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -66,13 +66,13 @@ func TestExtraFieldActionPutJSON(t *testing.T) {
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
router := routes.NewActionRouter(m)
data := []byte(`{
"completed_on": "2021-01-01T00:00:00Z",
"plan_id": 5,
"sabotage": "omg"
}`)
req, _ := http.NewRequest("PUT", "/actions/1", bytes.NewBuffer(data))
req, _ := http.NewRequest("PUT", "/1", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -92,9 +92,9 @@ func TestEmptyBodyActionPut(t *testing.T) {
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
router := routes.NewActionRouter(m)
data := []byte(``)
req, _ := http.NewRequest("PUT", "/actions/1", bytes.NewBuffer(data))
req, _ := http.NewRequest("PUT", "/1", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -115,13 +115,13 @@ func TestTwoBodyActionPut(t *testing.T) {
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
router := routes.NewActionRouter(m)
data := []byte(`{
"plan_id": 5
}, {
"plan_id": 6
}`)
req, _ := http.NewRequest("PUT", "/actions/1", bytes.NewBuffer(data))
req, _ := http.NewRequest("PUT", "/1", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -142,13 +142,13 @@ func TestBadActionIDPut(t *testing.T) {
planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m)
router := routes.NewActionRouter(m)
data := []byte(`{
"plan_id": 5
}, {
"plan_id": 6
}`)
req, _ := http.NewRequest("PUT", "/actions/text", bytes.NewBuffer(data))
req, _ := http.NewRequest("PUT", "/text", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -169,10 +169,10 @@ func TestErrorUpdateAction(t *testing.T) {
m := getErrorModel("Model always errors")
router := routes.NewRouter(m)
router := routes.NewActionRouter(m)
a := &models.Action{PlanID: 6}
data, _ := json.Marshal(a)
req, _ := http.NewRequest("PUT", "/actions/1", bytes.NewBuffer(data))
req, _ := http.NewRequest("PUT", "/1", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -194,10 +194,10 @@ func TestErrorOnRetrieveUpdateAction(t *testing.T) {
m := getErrorOnGetModel("Model always errors")
router := routes.NewRouter(m)
router := routes.NewActionRouter(m)
a := &models.Action{PlanID: 6}
data, _ := json.Marshal(a)
req, _ := http.NewRequest("PUT", "/actions/1", bytes.NewBuffer(data))
req, _ := http.NewRequest("PUT", "/1", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
@@ -219,9 +219,9 @@ func TestErrorWriterUpdateAction(t *testing.T) {
a := &models.Action{PlanID: 6}
m := getModel([]*models.Plan{}, []*models.Action{a})
router := routes.NewRouter(m)
router := routes.NewActionRouter(m)
data, _ := json.Marshal(a)
req, _ := http.NewRequest("PUT", "/actions/1", bytes.NewBuffer(data))
req, _ := http.NewRequest("PUT", "/1", bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
rr := NewBadWriter()

View File

@@ -3,18 +3,28 @@ package routes
import (
"encoding/json"
"gitea.deepak.science/deepak/gogmagog/models"
"gitea.deepak.science/deepak/gogmagog/tokens"
"github.com/go-chi/chi"
"github.com/go-chi/jwtauth"
"net/http"
)
// NewRouter returns a router powered by the provided model.
func NewRouter(m *models.Model) http.Handler {
func NewRouter(m *models.Model, tok tokens.Toker) http.Handler {
router := chi.NewRouter()
router.MethodNotAllowed(methodNotAllowedHandler)
router.NotFound(notFoundHandler)
router.Mount("/plans", newPlanRouter(m))
router.Mount("/actions", newActionRouter(m))
router.Mount("/auth", newAuthRouter(m))
router.Group(func(r chi.Router) {
r.Use(tok.Verifier())
// Handle valid / invalid tokens. In this example, we use
// the provided authenticator middleware, but you can write your
// own very easily, look at the Authenticator method in jwtauth.go
// and tweak it, its not scary.
r.Use(jwtauth.Authenticator)
r.Mount("/actions", NewActionRouter(m))
r.Mount("/plans", NewPlanRouter(m))
})
router.Mount("/auth", newAuthRouter(m, tok))
router.Mount("/health", newHealthRouter(m))
router.Get("/ping", ping)
return router

View File

@@ -2,6 +2,7 @@ package routes_test
import (
"gitea.deepak.science/deepak/gogmagog/routes"
"gitea.deepak.science/deepak/gogmagog/tokens"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
@@ -13,7 +14,7 @@ func TestPingHandler(t *testing.T) {
// set up
assert := assert.New(t)
m := getEmptyModel()
router := routes.NewRouter(m)
router := routes.NewRouter(m, tokens.New("whatever"))
req, _ := http.NewRequest("GET", "/ping", nil)
rr := httptest.NewRecorder()
@@ -34,7 +35,7 @@ func TestPingPostHandler(t *testing.T) {
// set up
assert := assert.New(t)
m := getEmptyModel()
router := routes.NewRouter(m)
router := routes.NewRouter(m, tokens.New("whatever"))
req, _ := http.NewRequest("POST", "/ping", nil)
rr := httptest.NewRecorder()
@@ -53,7 +54,7 @@ func TestNotFoundHandler(t *testing.T) {
// set up
assert := assert.New(t)
m := getEmptyModel()
router := routes.NewRouter(m)
router := routes.NewRouter(m, tokens.New("whatever"))
req, _ := http.NewRequest("POST", "/null", nil)
rr := httptest.NewRecorder()
@@ -72,7 +73,7 @@ func TestPingError(t *testing.T) {
// set up
assert := assert.New(t)
m := getEmptyModel()
router := routes.NewRouter(m)
router := routes.NewRouter(m, tokens.New("whatever"))
req, _ := http.NewRequest("GET", "/ping", nil)
rr := NewBadWriter()

47
tokens/tokens.go Normal file
View File

@@ -0,0 +1,47 @@
package tokens
import (
"gitea.deepak.science/deepak/gogmagog/models"
"github.com/go-chi/jwtauth"
"net/http"
"time"
)
// Toker represents a tokenizer, capable of encoding and verifying tokens.
type Toker interface {
EncodeUser(user *models.UserNoPassword) string
VerifyTokenString(tokenString string) error
Verifier() func(http.Handler) http.Handler
}
type jwtToker struct {
tokenAuth *jwtauth.JWTAuth
}
// New returns a default Toker for a given secret key.
func New(key string) Toker {
return &jwtToker{tokenAuth: jwtauth.New("HS256", []byte(key), nil)}
}
func (tok *jwtToker) EncodeUser(user *models.UserNoPassword) string {
claims := map[string]interface{}{
"user_id": user.UserID,
"username": user.Username,
"display_name": user.DisplayName,
"iss": "gogmagog.deepak.science",
"aud": "gogmagog.deepak.science",
}
jwtauth.SetIssuedNow(claims)
jwtauth.SetExpiryIn(claims, 2*time.Hour)
_, tokenString, _ := tok.tokenAuth.Encode(claims)
return tokenString
}
func (tok *jwtToker) VerifyTokenString(tokenString string) error {
_, err := jwtauth.VerifyToken(tok.tokenAuth, tokenString)
return err
}
func (tok *jwtToker) Verifier() func(http.Handler) http.Handler {
return jwtauth.Verifier(tok.tokenAuth)
}

22
tokens/tokens_test.go Normal file
View File

@@ -0,0 +1,22 @@
package tokens_test
import (
"gitea.deepak.science/deepak/gogmagog/models"
"gitea.deepak.science/deepak/gogmagog/tokens"
"github.com/stretchr/testify/assert"
"testing"
)
func TestBasic(t *testing.T) {
assert := assert.New(t)
toker := tokens.New("secret")
usr := &models.UserNoPassword{
UserID: 3,
Username: "test",
DisplayName: "Ted Est III",
}
token := toker.EncodeUser(usr)
assert.Nil(toker.VerifyTokenString(token))
assert.NotNil(tokens.New("bad secret").VerifyTokenString(token))
}