From 2d96a1a1357c698b6f6965a0cae3907b32e7a622 Mon Sep 17 00:00:00 2001 From: anxi0uz Date: Sun, 12 Apr 2026 21:02:14 +0500 Subject: [PATCH] manager.go handler + some pieces of order.go service --- internal/handler/manager.go | 130 ++++++++++++++++++++++++++++++++++-- internal/handler/order.go | 14 +++- internal/services/order.go | 54 ++++++++++++++- 3 files changed, 190 insertions(+), 8 deletions(-) diff --git a/internal/handler/manager.go b/internal/handler/manager.go index 1cb2c2b..5e7f8b5 100644 --- a/internal/handler/manager.go +++ b/internal/handler/manager.go @@ -1,11 +1,131 @@ package handler -import "net/http" +import ( + "encoding/json" + "errors" + "log/slog" + "net/http" + "time" -func (s *Server) ListManagers(w http.ResponseWriter, r *http.Request) {} + "github.com/anxi0uz/logiflow/internal/api" + "github.com/anxi0uz/logiflow/internal/models" + storage "github.com/anxi0uz/logiflow/pkg" + "github.com/google/uuid" + "github.com/huandu/go-sqlbuilder" + "golang.org/x/crypto/bcrypt" +) -func (s *Server) CreateManager(w http.ResponseWriter, r *http.Request) {} +func (s *Server) ListManagers(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() -func (s *Server) GetManager(w http.ResponseWriter, r *http.Request, slug string) {} + managers, err := storage.GetAll[models.Manager](ctx, "managers", s.DB) + if err != nil { + slog.ErrorContext(ctx, "Error while getting managers", slog.String("error", err.Error())) + s.JSON(w, r, http.StatusInternalServerError, MsgInternalError, RespError) + return + } + s.JSON(w, r, http.StatusOK, managers, RespSuccess) +} -func (s *Server) DeleteManager(w http.ResponseWriter, r *http.Request, slug string) {} +func (s *Server) CreateManager(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + var req api.ManagerCreate + + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + slog.ErrorContext(ctx, "Error while decoding body", slog.Any("request", req), slog.String("Error", err.Error())) + s.JSON(w, r, http.StatusBadRequest, MsgInvalidBody, RespError) + return + } + + passwordHash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost) + if err != nil { + slog.ErrorContext(ctx, "error while generating passwordhash", slog.String("error", err.Error())) + s.JSON(w, r, http.StatusInternalServerError, MsgInternalError, RespError) + return + } + + userid := uuid.New() + now := time.Now() + + userModel := models.User{ + ID: userid, + Slug: s.GenerateUserSlug(req.FullName, userid), + CreatedAt: now, + UpdatedAt: now, + Role: "manager", + Email: string(req.Email), + PasswordHash: string(passwordHash), + FullName: req.FullName, + } + + tx, err := s.DB.Begin(ctx) + if err != nil { + slog.ErrorContext(ctx, "Error while opening transaction", slog.String("error", err.Error())) + s.JSON(w, r, http.StatusInternalServerError, MsgInternalError, RespError) + return + } + defer tx.Rollback(ctx) + + if err := storage.Create(ctx, "users", userModel, tx); err != nil { + slog.ErrorContext(ctx, "Error while creating user", slog.String("error", err.Error())) + s.JSON(w, r, http.StatusInternalServerError, MsgInternalError, RespError) + return + } + + managerid := uuid.New() + managerModel := models.Manager{ + ID: managerid, + WarehouseID: req.WarehouseId, + UserID: userid, + Slug: s.GenerateUserSlug(req.FullName, managerid), + } + if err := storage.Create(ctx, "managers", managerModel, tx); err != nil { + slog.ErrorContext(ctx, "Error while creating manager", slog.String("error", err.Error())) + s.JSON(w, r, http.StatusInternalServerError, MsgInternalError, RespError) + return + } + + if err := tx.Commit(ctx); err != nil { + slog.ErrorContext(ctx, "Error while commiting transaction", slog.String("error", err.Error())) + s.JSON(w, r, http.StatusInternalServerError, MsgInternalError, RespError) + return + } + s.JSON(w, r, http.StatusCreated, map[string]any{ + "user": userModel, + "manager": managerModel, + }, RespSuccess) +} + +func (s *Server) GetManager(w http.ResponseWriter, r *http.Request, slug string) { + ctx := r.Context() + + manager, err := storage.GetOne[models.Manager](ctx, s.DB, "managers", func(sb *sqlbuilder.SelectBuilder) { + sb.Where(sb.EQ("slug", slug)) + }) + if err != nil { + if errors.Is(err, storage.ErrNotFound) { + slog.ErrorContext(ctx, "No manager was found with that slug", slog.String("slug", slug)) + s.JSON(w, r, http.StatusNotFound, MsgNotFound, RespNotFound) + return + } + slog.ErrorContext(ctx, "Error while getting manager with that slug", slog.String("slug", slug), slog.String("error", err.Error())) + s.JSON(w, r, http.StatusInternalServerError, MsgInternalError, RespError) + return + } + s.JSON(w, r, http.StatusOK, manager, RespSuccess) +} + +func (s *Server) DeleteManager(w http.ResponseWriter, r *http.Request, slug string) { + ctx := r.Context() + + err := storage.Delete[models.Manager](ctx, "managers", s.DB, func(db *sqlbuilder.DeleteBuilder) { + db.Where(db.EQ("slug", slug)) + }) + if err != nil { + slog.ErrorContext(ctx, "Error while deleting manager with that slug", slog.String("slug", slug), slog.String("error", err.Error())) + s.JSON(w, r, http.StatusInternalServerError, MsgInternalError, RespError) + return + } + s.JSON(w, r, http.StatusOK, "Deleted", RespSuccess) +} diff --git a/internal/handler/order.go b/internal/handler/order.go index c1ace3c..c9ac7a1 100644 --- a/internal/handler/order.go +++ b/internal/handler/order.go @@ -9,7 +9,19 @@ import ( openapi_types "github.com/oapi-codegen/runtime/types" ) -func (s *Server) ListOrders(w http.ResponseWriter, r *http.Request, params api.ListOrdersParams) {} +func (s *Server) ListOrders(w http.ResponseWriter, r *http.Request, params api.ListOrdersParams) { + ctx := r.Context() + claims, ok := ctx.Value("user").(*Claims) + if !ok { + slog.ErrorContext(ctx, "Error while casting claims") + s.JSON(w, r, http.StatusInternalServerError, MsgInternalError, RespError) + return + } + switch claims.Role { + case "client": + break + } +} func (s *Server) CreateOrder(w http.ResponseWriter, r *http.Request) { ctx := r.Context() diff --git a/internal/services/order.go b/internal/services/order.go index caa3f4e..66d5006 100644 --- a/internal/services/order.go +++ b/internal/services/order.go @@ -3,12 +3,13 @@ package services import ( "context" "encoding/json" + "errors" "fmt" "log/slog" "net/http" "time" - "github.com/anxi0uz/logiflow/internal/api" + api "github.com/anxi0uz/logiflow/internal/api" "github.com/anxi0uz/logiflow/internal/config" "github.com/anxi0uz/logiflow/internal/models" storage "github.com/anxi0uz/logiflow/pkg" @@ -24,6 +25,8 @@ type OrderService struct { config config.Config } +var ErrForbidden = errors.New("forbidden") + type CreateOrderResult struct { Order models.Order Route models.Route @@ -70,7 +73,7 @@ func (s *OrderService) CreateOrder(ctx context.Context, req api.OrderCreate, use return nil } var err error - destLat, originLon, err = geocode.Geocode(ctx, req.DestinationAddress) + destLat, destLon, err = geocode.Geocode(ctx, req.DestinationAddress) return err }) @@ -162,3 +165,50 @@ func (s *OrderService) CreateOrder(ctx context.Context, req api.OrderCreate, use return &CreateOrderResult{Order: order, Route: routeModel}, nil } + +func (s *OrderService) ListOrders(ctx context.Context, userID uuid.UUID, role string, params api.ListOrdersParams) ([]models.Order, error) { + var driverID *uuid.UUID + if role == "driver" { + driver, err := storage.GetOne[models.Driver](ctx, s.db, "driver", func(sb *sqlbuilder.SelectBuilder) { + sb.Where(sb.EQ("user_id", userID)) + }) + if err != nil { + return nil, fmt.Errorf("get driver: %w", err) + } + driverID = &driver.ID + } + orders, err := storage.GetAll[models.Order](ctx, "orders", s.db, func(sb *sqlbuilder.SelectBuilder) { + switch role { + case "client": + sb.Where(sb.EQ("created_by_id", userID)) + case "driver": + sb.Where(sb.EQ("driver_id", driverID)) + default: + if params.Status != nil { + sb.Where(sb.EQ("status", params.Status)) + } + if params.DriverId != nil { + sb.Where(sb.EQ("driver_id", params.DriverId)) + } + } + }) + if err != nil { + return nil, fmt.Errorf("list orders: %w", err) + } + return orders, nil +} +func (s *OrderService) GetOrder(ctx context.Context, id uuid.UUID, userID uuid.UUID, role string) (*models.Order, error) { + order, err := storage.GetOne[models.Order](ctx, s.db, "orders", func(sb *sqlbuilder.SelectBuilder) { + sb.Where(sb.EQ("id", id)) + }) + if err != nil { + return nil, err + } + if role == "client" && (order.CreatedByID == nil || *order.CreatedByID != userID) { + return nil, ErrForbidden + } + return order, nil +} +func (s *OrderService) CancelOrder(ctx context.Context, id uuid.UUID, userID uuid.UUID, role string) error +func (s *OrderService) UpdateOrderStatus(ctx context.Context, id uuid.UUID, userID uuid.UUID, role string, req api.OrderStatusUpdate) (*models.Order, error) +func (s *OrderService) GetOrdersReport(ctx context.Context, role string, params api.GetOrdersReportParams) ([]models.Order, error)