diff --git a/.gitignore b/.gitignore index adf8f72..d1ce888 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ *.dll *.so *.dylib +go-cook # Test binary, built with `go test -c` *.test diff --git a/README.md b/README.md index 9c6a01b..f273be5 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,4 @@ Golang project to create a self hosted cookbook. -We would like to templ for the frontend with htmx. \ No newline at end of file +We would like to use templ for the frontend with htmx. diff --git a/api/handlers/v1/demo.go b/api/handlers/v1/demo.go new file mode 100644 index 0000000..ab0b1a5 --- /dev/null +++ b/api/handlers/v1/demo.go @@ -0,0 +1,17 @@ +package v1 + +import ( + "fmt" + "net/http" + + "github.com/labstack/echo/v4" +) + +func (h *Handler) DemoHello(c echo.Context) error { + return c.String(http.StatusOK, "Hello, World!") +} + +func (h *Handler) HelloWho(c echo.Context) error { + who := c.Param("who") + return c.String(http.StatusOK, fmt.Sprintf("Hello, %s!", who)) +} diff --git a/api/handlers/v1/handler.go b/api/handlers/v1/handler.go new file mode 100644 index 0000000..fbaf6cc --- /dev/null +++ b/api/handlers/v1/handler.go @@ -0,0 +1,27 @@ +package v1 + +import ( + "database/sql" + "go-cook/api/repositories" + + "github.com/labstack/echo/v4" +) + +type Handler struct { + userRepo repositories.UserRepository +} + +func NewHandler(conn *sql.DB) *Handler { + return &Handler{ + userRepo: repositories.NewUserRepository(conn), + } +} + +func (h *Handler) Register(v1 *echo.Group) { + demo := v1.Group("/demo") + demo.GET("/hello", h.DemoHello) + demo.GET("/hello/:who", h.HelloWho) + + users := v1.Group("/users") + users.POST("/new", h.NewUser) +} diff --git a/api/handlers/v1/users.go b/api/handlers/v1/users.go new file mode 100644 index 0000000..3f3ed84 --- /dev/null +++ b/api/handlers/v1/users.go @@ -0,0 +1,11 @@ +package v1 + +import ( + "net/http" + + "github.com/labstack/echo/v4" +) + +func (h *Handler) NewUser(c echo.Context) error { + return c.JSON(http.StatusOK, "not implemented yet") +} diff --git a/api/models/users.go b/api/models/users.go new file mode 100644 index 0000000..730153c --- /dev/null +++ b/api/models/users.go @@ -0,0 +1,6 @@ +package models + +type UserModel struct { + Name string + Hash string +} \ No newline at end of file diff --git a/api/repositories/users.go b/api/repositories/users.go new file mode 100644 index 0000000..c629fcc --- /dev/null +++ b/api/repositories/users.go @@ -0,0 +1,49 @@ +package repositories + +import ( + "database/sql" + "go-cook/api/models" + "errors" + "fmt" + + "github.com/huandu/go-sqlbuilder" + "golang.org/x/crypto/bcrypt" +) + +// Creates a new instance of UserRepository with the bound sql +func NewUserRepository(conn *sql.DB) UserRepository { + return UserRepository{ + connection: conn, + } +} + +type UserRepository struct { + connection *sql.DB +} + +func (ur UserRepository) GetByName(name string) (models.UserModel, error) { + builder := sqlbuilder.NewSelectBuilder() + builder.Select("*").From("users").Where( + builder.E("Name", name), + ); + + + return models.UserModel{}, errors.New("user was not found") +} + +func (ur UserRepository) NewUser(name string, password string) (int, error) { + passwordBytes := []byte(password) + hash, err := bcrypt.GenerateFromPassword(passwordBytes, bcrypt.DefaultCost) + if err != nil { + return 0, err + } + fmt.Println(hash) + + query := sqlbuilder.NewInsertBuilder() + query.InsertInto("users") + query.Cols("name", "hash") + query.Values(name, string(hash)) + ur.connection.Query(query.Build()) + + return 1, nil +} diff --git a/api/repositories/users_test.go b/api/repositories/users_test.go new file mode 100644 index 0000000..f72d491 --- /dev/null +++ b/api/repositories/users_test.go @@ -0,0 +1,7 @@ +package repositories_test + +import "testing" + +func TestNewUser(t *testing.T) { + +} \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..61eaf10 --- /dev/null +++ b/go.mod @@ -0,0 +1,31 @@ +module go-cook + +go 1.22.1 + +require github.com/labstack/echo v3.3.10+incompatible + +require ( + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/glebarez/go-sqlite v1.22.0 // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect + github.com/google/uuid v1.5.0 // indirect + github.com/huandu/go-sqlbuilder v1.25.0 // indirect + github.com/huandu/xstrings v1.3.2 // indirect + github.com/labstack/echo/v4 v4.11.4 // indirect + github.com/labstack/gommon v0.4.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.5.0 // indirect + modernc.org/libc v1.37.6 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.7.2 // indirect + modernc.org/sqlite v1.28.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..0728599 --- /dev/null +++ b/go.sum @@ -0,0 +1,65 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= +github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= +github.com/huandu/go-sqlbuilder v1.25.0 h1:h1l+6CqeCviPJCnkEZoRGNdfZ5RO9BKMvG3A+1VuKNM= +github.com/huandu/go-sqlbuilder v1.25.0/go.mod h1:nUVmMitjOmn/zacMLXT0d3Yd3RHoO2K+vy906JzqxMI= +github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= +github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg= +github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s= +github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8= +github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +modernc.org/libc v1.37.6 h1:orZH3c5wmhIQFTXF+Nt+eeauyd+ZIt2BX6ARe+kD+aw= +modernc.org/libc v1.37.6/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= +modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ= +modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= diff --git a/main.go b/main.go new file mode 100644 index 0000000..55c9a4e --- /dev/null +++ b/main.go @@ -0,0 +1,28 @@ +package main + +import ( + "database/sql" + v1 "go-cook/api/handlers/v1" + "log" + + _ "github.com/glebarez/go-sqlite" + "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" +) + +func main() { + db, err := sql.Open("sqlite", "gocook.db") + if err != nil { + log.Fatal(err) + } + + e := echo.New() + e.Pre(middleware.RemoveTrailingSlash()) + e.Pre(middleware.Logger()) + + v1Group := e.Group("/api/v1") + v1Api := v1.NewHandler(db) + v1Api.Register(v1Group) + + e.Logger.Fatal(e.Start(":1323")) +} diff --git a/portal/.gitkeep b/portal/.gitkeep new file mode 100644 index 0000000..e69de29