summaryrefslogtreecommitdiff
path: root/pkg/handler
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/handler')
-rw-r--r--pkg/handler/location.go141
-rw-r--r--pkg/handler/user.go155
2 files changed, 296 insertions, 0 deletions
diff --git a/pkg/handler/location.go b/pkg/handler/location.go
new file mode 100644
index 0000000..9f4a2c1
--- /dev/null
+++ b/pkg/handler/location.go
@@ -0,0 +1,141 @@
+package handler
+
+import (
+ "encoding/json"
+ "time"
+
+ "github.com/alexedwards/scs/v2"
+ "github.com/labstack/echo/v4"
+ "gitrepo.ru/neonxp/track/pkg/models"
+ "go.etcd.io/bbolt"
+ "go.neonxp.ru/objectid"
+)
+
+type Location struct {
+ db *bbolt.DB
+ sessions *scs.SessionManager
+}
+
+func NewLocation(db *bbolt.DB, sessions *scs.SessionManager) *Location {
+ return &Location{
+ db: db,
+ sessions: sessions,
+ }
+}
+
+func (l *Location) AddPoint(c echo.Context) error {
+ uu := l.sessions.Get(c.Request().Context(), "user")
+ if uu == nil {
+ return echo.ErrForbidden
+ }
+ user, ok := uu.(*models.User)
+ if !ok {
+ return echo.ErrForbidden
+ }
+
+ req := new(PointArgs)
+ if err := c.Bind(req); err != nil {
+ return err
+ }
+
+ point := &models.Point{
+ ID: objectid.FromTime(req.Time),
+ UserID: user.ID,
+ Lat: req.Lat,
+ Lon: req.Lon,
+ Time: req.Time,
+ Speed: req.Speed,
+ Direction: req.Direction,
+ Accuracy: req.Accuracy,
+ }
+
+ err := l.db.Update(func(tx *bbolt.Tx) error {
+ points, err := tx.CreateBucketIfNotExists([]byte("points"))
+ if err != nil {
+ return err
+ }
+ jp, err := json.Marshal(point)
+ if err != nil {
+ return err
+ }
+
+ return points.Put(point.ID, jp)
+ })
+ if err != nil {
+ return err
+ }
+
+ return c.NoContent(201)
+}
+
+func (l *Location) GetPoints(c echo.Context) error {
+ // uu := l.sessions.Get(c.Request().Context(), "user")
+ // if uu == nil {
+ // return echo.ErrForbidden
+ // }
+ // user, ok := uu.(*models.User)
+ // if !ok {
+ // return echo.ErrForbidden
+ // }
+
+ pointsResp := []models.Point{}
+ err := l.db.View(func(tx *bbolt.Tx) error {
+ points := tx.Bucket([]byte("points"))
+ point := new(models.Point)
+ return points.ForEach(func(k, v []byte) error {
+ if err := json.Unmarshal(v, point); err != nil {
+ return err
+ }
+ // if slices.Equal(point.UserID, user.ID) {
+ pointsResp = append(pointsResp, *point)
+ // }
+ return nil
+ })
+ })
+ if err != nil {
+ return err
+ }
+
+ return c.JSON(200, pointsResp)
+}
+
+func (l *Location) GetLast(c echo.Context) error {
+ // uu := l.sessions.Get(c.Request().Context(), "user")
+ // if uu == nil {
+ // return echo.ErrForbidden
+ // }
+ // user, ok := uu.(*models.User)
+ // if !ok {
+ // return echo.ErrForbidden
+ // }
+
+ lastPoint := new(models.Point)
+ err := l.db.View(func(tx *bbolt.Tx) error {
+ points := tx.Bucket([]byte("points"))
+ point := new(models.Point)
+ return points.ForEach(func(k, v []byte) error {
+ if err := json.Unmarshal(v, point); err != nil {
+ return err
+ }
+ // if slices.Equal(point.UserID, user.ID) && lastPoint.Time.Before(point.Time) {
+ if lastPoint.Time.Before(point.Time) {
+ lastPoint = point
+ }
+ return nil
+ })
+ })
+ if err != nil {
+ return err
+ }
+
+ return c.JSON(200, lastPoint)
+}
+
+type PointArgs struct {
+ Lat float64 `query:"lat"`
+ Lon float64 `query:"lon"`
+ Time time.Time `query:"time"`
+ Speed float64 `query:"spd"`
+ Direction float64 `query:"dir"`
+ Accuracy float64 `query:"acc"`
+}
diff --git a/pkg/handler/user.go b/pkg/handler/user.go
new file mode 100644
index 0000000..9506c85
--- /dev/null
+++ b/pkg/handler/user.go
@@ -0,0 +1,155 @@
+package handler
+
+import (
+ "encoding/json"
+ "net/mail"
+ "strings"
+
+ "github.com/alexedwards/scs/v2"
+ "github.com/labstack/echo/v4"
+ "gitrepo.ru/neonxp/track/pkg/models"
+ "go.etcd.io/bbolt"
+ "go.neonxp.ru/objectid"
+ "golang.org/x/crypto/bcrypt"
+)
+
+var (
+ ErrInvalidPasswordLen = echo.NewHTTPError(400, "Неверная длина пароля (должно быть от 8 до 32 символов)")
+ ErrPasswordsNotSame = echo.NewHTTPError(400, "Пароли не совпадают")
+ ErrInvalidEmailOrPassword = echo.NewHTTPError(400, "Неверный email или пароль")
+)
+
+type User struct {
+ db *bbolt.DB
+ sessions *scs.SessionManager
+}
+
+func NewUser(db *bbolt.DB, sessions *scs.SessionManager) *User {
+ return &User{
+ db: db,
+ sessions: sessions,
+ }
+}
+
+func (u *User) Register(c echo.Context) error {
+ req := new(RegisterRequest)
+ if err := c.Bind(req); err != nil {
+ return err
+ }
+
+ if _, err := mail.ParseAddress(req.Email); err != nil {
+ return echo.NewHTTPError(400, err.Error())
+ }
+
+ if len(req.Password) < 8 || len(req.Password) > 32 {
+ return ErrInvalidPasswordLen
+ }
+
+ if req.Password != req.Password2 {
+ return ErrPasswordsNotSame
+ }
+
+ password, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
+ if err != nil {
+ return err
+ }
+
+ user := &models.User{
+ ID: objectid.New(),
+ Email: req.Email,
+ Password: password,
+ }
+
+ err = u.db.Update(func(tx *bbolt.Tx) error {
+ users, err := tx.CreateBucketIfNotExists([]byte("users"))
+ if err != nil {
+ return err
+ }
+
+ jb, err := json.Marshal(user)
+ if err != nil {
+ return err
+ }
+
+ if err := users.Put([]byte(strings.ToLower(user.Email)), jb); err != nil {
+ return err
+ }
+
+ return nil
+ })
+ if err != nil {
+ return err
+ }
+
+ return c.JSON(201, UserResponse{
+ ID: user.ID,
+ Email: user.Email,
+ })
+}
+
+func (u *User) Login(c echo.Context) error {
+ req := new(LoginRequest)
+ if err := c.Bind(req); err != nil {
+ return err
+ }
+
+ user := new(models.User)
+
+ err := u.db.View(func(tx *bbolt.Tx) error {
+ users := tx.Bucket([]byte("users"))
+ jb := users.Get([]byte(strings.ToLower(req.Email)))
+ if jb == nil {
+ return ErrInvalidEmailOrPassword
+ }
+ if err := json.Unmarshal(jb, user); err != nil {
+ return err
+ }
+ if err := bcrypt.CompareHashAndPassword(user.Password, []byte(req.Password)); err != nil {
+ return ErrInvalidEmailOrPassword
+ }
+
+ return nil
+ })
+ if err != nil {
+ return err
+ }
+
+ u.sessions.Put(c.Request().Context(), "user", user)
+
+ return c.JSON(200, UserResponse{
+ ID: user.ID,
+ Email: user.Email,
+ })
+}
+
+func (u *User) User(c echo.Context) error {
+ uu := u.sessions.Get(c.Request().Context(), "user")
+ if uu == nil {
+ return echo.ErrForbidden
+ }
+ user, ok := uu.(*models.User)
+ if !ok {
+ return echo.ErrForbidden
+ }
+
+ return c.JSON(200, UserResponse{
+ ID: user.ID,
+ Email: user.Email,
+ })
+}
+
+type RegisterRequest struct {
+ Email string `json:"email"`
+ Password string `json:"password"`
+ Password2 string `json:"password2"`
+}
+
+type LoginRequest struct {
+ Email string `json:"email"`
+ Password string `json:"password"`
+}
+
+type UserResponse struct {
+ ID objectid.ID `json:"id"`
+ Email string `json:"email"`
+}