forked from ebhomengo/niki
Merge branch 'develop' into mahsaaghagolzadeh/issue252-create-Payment
This commit is contained in:
commit
0556f3c345
|
|
@ -1,8 +1,9 @@
|
|||
package domain
|
||||
package entity
|
||||
|
||||
import "time"
|
||||
|
||||
type ID uint64
|
||||
import (
|
||||
"git.gocasts.ir/ebhomengo/niki/types"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CampaignStatus string
|
||||
|
||||
|
|
@ -15,7 +16,7 @@ const (
|
|||
)
|
||||
|
||||
type Campaign struct {
|
||||
ID ID `json:"id"`
|
||||
ID types.ID `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
GoalAmount float64 `json:"goal_amount"`
|
||||
|
|
@ -23,10 +24,10 @@ type Campaign struct {
|
|||
Status CampaignStatus `json:"status"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
DeadlineAt *time.Time `json:"deadline_at,omitempty"`
|
||||
AdminID ID `json:"creator_id"`
|
||||
AdminID types.ID `json:"creator_id"`
|
||||
}
|
||||
|
||||
// Behavior
|
||||
// Behavior
|
||||
func (c *Campaign) Activate() {
|
||||
if c.Status == CampaignDraft {
|
||||
c.Status = CampaignActive
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.gocasts.ir/ebhomengo/niki/domain/campaign/entity"
|
||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
||||
"git.gocasts.ir/ebhomengo/niki/types"
|
||||
)
|
||||
|
||||
type DB struct {
|
||||
conn *mysql.DB
|
||||
}
|
||||
|
||||
func New(db *mysql.DB) *DB {
|
||||
return &DB{conn: db}
|
||||
}
|
||||
|
||||
// CreateCampaign creates a new campaign
|
||||
func (d *DB) CreateAndSave(ctx context.Context, campaign entity.Campaign) (types.ID, error) {
|
||||
const Op = "repository.mysql.campaign.create"
|
||||
|
||||
tx, err := d.conn.Conn().BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return 0, richerror.New(Op).WithErr(err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
query := `INSERT INTO campaigns (title, description, goal_amount, raised_amount,
|
||||
status, deadline_at ,admin_id , created_at )
|
||||
VALUES (?, ?, ?, ?, ?, ?, ? , NOW() )`
|
||||
|
||||
result, err := tx.ExecContext(ctx, query,
|
||||
campaign.Title,
|
||||
campaign.Description,
|
||||
campaign.GoalAmount,
|
||||
campaign.RaisedAmount,
|
||||
campaign.Status,
|
||||
campaign.DeadlineAt,
|
||||
campaign.AdminID,
|
||||
campaign.CreatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, richerror.New(Op).WithErr(err)
|
||||
}
|
||||
|
||||
campaignID, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return 0, richerror.New(Op).WithErr(err)
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return 0, richerror.New(Op).WithErr(err)
|
||||
}
|
||||
|
||||
return types.ID(campaignID), nil
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.gocasts.ir/ebhomengo/niki/campaign/entity"
|
||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
||||
"git.gocasts.ir/ebhomengo/niki/types"
|
||||
)
|
||||
|
||||
|
||||
|
||||
type CampaignRepository interface {
|
||||
CreateAndSave(ctx context.Context, campaign *Campaign) error
|
||||
FindByID(ctx context.Context, id ID) (*Campaign, error)
|
||||
List(ctx context.Context, status CampaignStatus, limit, offset int) ([]*Campaign, error)
|
||||
Delete(ctx context.Context, id ID) error
|
||||
Update(ctx context.Context, campaign *Campaign) error
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
|
@ -1,48 +1,50 @@
|
|||
package campaign
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors" // For standard errors
|
||||
"fmt"
|
||||
"git.gocasts.ir/ebhomengo/niki/domain/campaign/entity"
|
||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||
"git.gocasts.ir/ebhomengo/niki/types"
|
||||
"time"
|
||||
|
||||
"your_project/domain"
|
||||
"your_project/pkg/richerror"
|
||||
"your_project/repository"
|
||||
)
|
||||
|
||||
type ID = unit64
|
||||
type EntityCampaign = domain.Campaign
|
||||
// CreateCampaign handles creation of a new campaign.
|
||||
func (s *CampaignService) CreateCampaign(ctx context.Context, req entity.Campaign) (types.ID, error) {
|
||||
const op = "service.campaign.create_campaign"
|
||||
|
||||
|
||||
type CampaignServiceImp interface {
|
||||
CreateCampaign(ctx context.Context, req CampaignRepository) (types.ID, error)
|
||||
}
|
||||
|
||||
|
||||
type CampaignService struct {
|
||||
repo repository.CampaignRepository
|
||||
}
|
||||
|
||||
func NewCampaignService(
|
||||
campaignRepo repository.CampaignRepository,
|
||||
) *CampaignService {
|
||||
return &CampaignService{
|
||||
repo: campaignRepo,
|
||||
if err := validateCreateCampaignRequest(req); err != nil {
|
||||
return 0, richerror.New(op).WithErr(err)
|
||||
}
|
||||
|
||||
campaign := entity.Campaign{
|
||||
Title: req.Title,
|
||||
Description: req.Description,
|
||||
GoalAmount: req.GoalAmount,
|
||||
RaisedAmount: 0,
|
||||
Status: req.Status,
|
||||
DeadlineAt: req.DeadlineAt,
|
||||
AdminID: req.AdminID,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
id, err := s.repo.Create(ctx, campaign)
|
||||
if err != nil {
|
||||
return 0, richerror.New(op).WithErr(err)
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
|
||||
func (s *CampaignService) CreateCampaign(ctx context.Context, req CreateCampaignRequest) (ID, error) {
|
||||
const Op = "service.campaign.create_campaign"
|
||||
|
||||
func validateCreateCampaignRequest(req entity.Campaign) error {
|
||||
if req.Title == "" {
|
||||
return 0, richerror.New(Op).WithMessage("title is required")
|
||||
return errRequired("title")
|
||||
}
|
||||
if req.GoalAmount <= 0 {
|
||||
return 0, richerror.New(Op).WithMessage("goal_amount must be greater than 0")
|
||||
return errInvalid("goal_amount must be greater than 0")
|
||||
}
|
||||
if req.AdminID == 0 {
|
||||
return 0, richerror.New(Op).WithMessage("admin_id is required")
|
||||
if req.AdminID == 0 {
|
||||
return errRequired("admin_id")
|
||||
}
|
||||
|
||||
validStatuses := map[string]bool{
|
||||
|
|
@ -50,32 +52,20 @@ func (s *CampaignService) CreateCampaign(ctx context.Context, req CreateCampaign
|
|||
"active": true,
|
||||
"completed": true,
|
||||
"cancelled": true,
|
||||
"paused": true
|
||||
"paused": true,
|
||||
}
|
||||
if !validStatuses[req.Status] {
|
||||
return 0, richerror.New(Op).WithMessage("invalid status provided")
|
||||
if !validStatuses[string(req.Status)] {
|
||||
return errInvalid("invalid status provided")
|
||||
}
|
||||
|
||||
|
||||
newCampaign := &EntityCampaign{
|
||||
Title: req.Title,
|
||||
Description: req.Description,
|
||||
GoalAmount: req.GoalAmount,
|
||||
RaisedAmount: 0, // Initially 0
|
||||
Status: EntityCampaign.Status(req.Status),
|
||||
DeadlineAt: req.DeadlineAt,
|
||||
AdminID: req.AdminID,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
createdCampaignID, err := s.repo.CreateAndSave(ctx, newCampaign)
|
||||
if err != nil {
|
||||
return 0, richerror.New(Op).WithErr(err)
|
||||
}
|
||||
|
||||
return createdCampaignID, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// --- Helpers ---
|
||||
func errRequired(field string) error {
|
||||
return fmt.Errorf("%s is required", field)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func errInvalid(msg string) error {
|
||||
return fmt.Errorf(msg)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"git.gocasts.ir/ebhomengo/niki/types"
|
||||
"time"
|
||||
)
|
||||
|
||||
type GetCampaignResponse struct {
|
||||
ID types.ID `json:"user_id"`
|
||||
}
|
||||
|
||||
type AddCampaignRequest struct {
|
||||
ID uint64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
GoalAmount float64 `json:"goal_amount"`
|
||||
DeadlineAt *time.Time `json:"deadline_at,omitempty"`
|
||||
AdminID types.ID `json:"admin_id"`
|
||||
}
|
||||
|
||||
type UpdateCampaignRequest struct {
|
||||
Title *string `json:"title,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
GoalAmount *float64 `json:"goal_amount,omitempty"`
|
||||
DeadlineAt *time.Time `json:"deadline_at,omitempty"`
|
||||
Status *string `json:"status,omitempty"` // draft/active/completed/paused/cancelled
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "fmt"
|
||||
"git.gocasts.ir/ebhomengo/niki/domain/campaign/entity"
|
||||
"git.gocasts.ir/ebhomengo/niki/types"
|
||||
)
|
||||
|
||||
type CampaignFilterParam struct {
|
||||
AdminID types.ID
|
||||
Status string
|
||||
//nil true false
|
||||
IsArchived *bool
|
||||
}
|
||||
|
||||
type CampaignStorage interface {
|
||||
Create(ctx context.Context, c entity.Campaign) (types.ID, error) // باید ID برگرداند
|
||||
Update(ctx context.Context, c entity.Campaign) error
|
||||
FindByID(ctx context.Context, id types.ID) (entity.Campaign, error)
|
||||
FindAll(ctx context.Context, filter CampaignFilterParam) ([]entity.Campaign, error)
|
||||
Archive(ctx context.Context, id types.ID) error // instead Delete
|
||||
TotalDonations(ctx context.Context, campaignID types.ID) (int64, error)
|
||||
}
|
||||
|
||||
type CampaignService struct {
|
||||
repo CampaignStorage
|
||||
}
|
||||
|
||||
// NewCampaignService constructs a new CampaignService.
|
||||
func NewCampaignService(storage CampaignStorage) *CampaignService {
|
||||
return &CampaignService{
|
||||
repo: storage,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package cart
|
||||
package entity
|
||||
|
||||
import (
|
||||
"git.gocasts.ir/ebhomengo/niki/types"
|
||||
|
|
@ -4,8 +4,8 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.gocasts.ir/ebhomengo/niki/domain/shoppingbasket/entity"
|
||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||
"git.gocasts.ir/ebhomengo/niki/shoppingbasketapp/service/cart"
|
||||
"git.gocasts.ir/ebhomengo/niki/types"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"strconv"
|
||||
|
|
@ -43,7 +43,7 @@ func (r Repo) itemKey(productID types.ID) string {
|
|||
return fmt.Sprintf("item:%d", productID)
|
||||
}
|
||||
|
||||
func (r Repo) AddItem(ctx context.Context, userID types.ID, item cart.Item) error {
|
||||
func (r Repo) AddItem(ctx context.Context, userID types.ID, item entity.Item) error {
|
||||
const op = "shoppingbasketapp.repository.AddItem"
|
||||
|
||||
cartKey := r.cartKey(userID)
|
||||
|
|
@ -65,7 +65,7 @@ func (r Repo) AddItem(ctx context.Context, userID types.ID, item cart.Item) erro
|
|||
} else {
|
||||
existsItem, _ := r.client.HGet(ctx, cartKey, itemKey).Result()
|
||||
if existsItem != "" {
|
||||
var i cart.Item
|
||||
var i entity.Item
|
||||
if err := json.Unmarshal([]byte(existsItem), &i); err != nil {
|
||||
return richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
||||
}
|
||||
|
|
@ -91,31 +91,31 @@ func parsInt(s string) int64 {
|
|||
return i
|
||||
}
|
||||
|
||||
func (r Repo) GetCart(ctx context.Context, userID types.ID) (cart.Cart, error) {
|
||||
func (r Repo) GetCart(ctx context.Context, userID types.ID) (entity.Cart, error) {
|
||||
const op = "shoppingbasketapp.repository.GetCart"
|
||||
cartKey := r.cartKey(userID)
|
||||
|
||||
exists, err := r.client.Exists(ctx, cartKey).Result()
|
||||
if err != nil {
|
||||
return cart.Cart{}, richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
||||
return entity.Cart{}, richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
||||
}
|
||||
|
||||
if exists == 0 {
|
||||
return cart.Cart{}, richerror.New(op).WithKind(richerror.KindNotFound).WithMessage("not found shopping basket")
|
||||
return entity.Cart{}, richerror.New(op).WithKind(richerror.KindNotFound).WithMessage("not found shopping basket")
|
||||
}
|
||||
|
||||
allCart, err := r.client.HGetAll(ctx, cartKey).Result()
|
||||
if err != nil {
|
||||
return cart.Cart{}, richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
||||
return entity.Cart{}, richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
||||
}
|
||||
|
||||
c := cart.Cart{Items: []cart.Item{}}
|
||||
c := entity.Cart{Items: []entity.Item{}}
|
||||
|
||||
for field, value := range allCart {
|
||||
if strings.HasPrefix(field, "item:") {
|
||||
var i cart.Item
|
||||
var i entity.Item
|
||||
if err := json.Unmarshal([]byte(value), &i); err != nil {
|
||||
return cart.Cart{}, richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
||||
return entity.Cart{}, richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
||||
}
|
||||
|
||||
c.Items = append(c.Items, i)
|
||||
|
|
@ -185,7 +185,7 @@ func (r Repo) UpdateQuantity(ctx context.Context, userID, productID types.ID, qu
|
|||
return richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
||||
}
|
||||
|
||||
var item cart.Item
|
||||
var item entity.Item
|
||||
if err := json.Unmarshal([]byte(data), &item); err != nil {
|
||||
return richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
||||
}
|
||||
|
|
@ -228,7 +228,7 @@ func (r Repo) updateTotalPrice(ctx context.Context, cartKey string) error {
|
|||
|
||||
for field, value := range allFields {
|
||||
if strings.HasPrefix(field, "item:") {
|
||||
var item cart.Item
|
||||
var item entity.Item
|
||||
|
||||
if err := json.Unmarshal([]byte(value), &item); err != nil {
|
||||
return richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
package cart
|
||||
package service
|
||||
|
||||
import "git.gocasts.ir/ebhomengo/niki/types"
|
||||
import (
|
||||
"git.gocasts.ir/ebhomengo/niki/domain/shoppingbasket/entity"
|
||||
"git.gocasts.ir/ebhomengo/niki/types"
|
||||
)
|
||||
|
||||
type AddToCartRequest struct {
|
||||
UserID types.ID `json:"user_id"`
|
||||
|
|
@ -11,11 +14,11 @@ type AddToCartRequest struct {
|
|||
}
|
||||
|
||||
type GetCartResponse struct {
|
||||
UserID types.ID `json:"user_id"`
|
||||
Items []Item `json:"items"`
|
||||
TotalPrice types.Price `json:"total_price"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
ExpireAt int64 `json:"expire_at"`
|
||||
UserID types.ID `json:"user_id"`
|
||||
Items []entity.Item `json:"items"`
|
||||
TotalPrice types.Price `json:"total_price"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
ExpireAt int64 `json:"expire_at"`
|
||||
}
|
||||
|
||||
type RemoveFromCartRequest struct {
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
package cart
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.gocasts.ir/ebhomengo/niki/domain/shoppingbasket/entity"
|
||||
"git.gocasts.ir/ebhomengo/niki/pkg/logger"
|
||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||
"git.gocasts.ir/ebhomengo/niki/types"
|
||||
|
|
@ -9,8 +10,8 @@ import (
|
|||
)
|
||||
|
||||
type Repository interface {
|
||||
AddItem(ctx context.Context, userID types.ID, item Item) error
|
||||
GetCart(ctx context.Context, userID types.ID) (Cart, error)
|
||||
AddItem(ctx context.Context, userID types.ID, item entity.Item) error
|
||||
GetCart(ctx context.Context, userID types.ID) (entity.Cart, error)
|
||||
DeleteItem(ctx context.Context, userID, productID types.ID) error
|
||||
UpdateQuantity(ctx context.Context, userID, productID types.ID, quantity int) error
|
||||
DeleteCart(ctx context.Context, userID types.ID) error
|
||||
|
|
@ -33,7 +34,7 @@ func (s Service) AddToBasket(ctx context.Context, req AddToCartRequest) error {
|
|||
return err
|
||||
}
|
||||
|
||||
return s.repo.AddItem(ctx, req.UserID, Item{
|
||||
return s.repo.AddItem(ctx, req.UserID, entity.Item{
|
||||
ProductID: req.ProductID,
|
||||
Quantity: req.Quantity,
|
||||
Price: req.Price,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package cart
|
||||
package service
|
||||
|
||||
import (
|
||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
package donate_server
|
||||
|
||||
type Handler struct{}
|
||||
|
||||
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package donate_server
|
||||
|
||||
import "github.com/labstack/echo/v4"
|
||||
|
||||
func (h Handler) RegisterRoutes(e *echo.Echo) {
|
||||
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package donate_server
|
||||
|
||||
import (
|
||||
httpserver "git.gocasts.ir/ebhomengo/niki/delivery/http_server"
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
Server httpserver.Server
|
||||
Handler Handler
|
||||
Router *echo.Echo
|
||||
}
|
||||
|
||||
func (s Server) Start() {
|
||||
s.Handler.RegisterRoutes(s.Router)
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"git.gocasts.ir/ebhomengo/niki/domain/campaign/entity"
|
||||
"git.gocasts.ir/ebhomengo/niki/domain/campaign/service"
|
||||
httpmsg "git.gocasts.ir/ebhomengo/niki/pkg/http_msg"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
svc service.CampaignService
|
||||
}
|
||||
|
||||
func NewHandler(svc service.CampaignService) Handler {
|
||||
return Handler{svc: svc}
|
||||
}
|
||||
|
||||
func (h Handler) createCampaign(c echo.Context) error {
|
||||
|
||||
var req entity.Campaign
|
||||
if err := c.Bind(&req); err != nil {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{
|
||||
"error": "invalid request body",
|
||||
})
|
||||
}
|
||||
req.CreatedAt = time.Now()
|
||||
req.RaisedAmount = 0
|
||||
|
||||
createdID, err := h.svc.CreateCampaign(c.Request().Context(), req)
|
||||
if err != nil {
|
||||
msg, code := httpmsg.Error(err)
|
||||
c.Logger().Errorf("Service error creating campaign: %v (Code: %d)", err, code)
|
||||
return c.JSON(code, msg)
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusCreated, map[string]interface{}{
|
||||
"message": "campaign created successfully",
|
||||
"id": createdID,
|
||||
})
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (s Server) healthCheck(c echo.Context) error {
|
||||
return c.JSON(http.StatusOK, echo.Map{
|
||||
"message": "everything is good!",
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.gocasts.ir/ebhomengo/niki/pkg/httpserver"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
handler Handler
|
||||
HTTPServer *httpserver.Server
|
||||
}
|
||||
|
||||
func NewServer(handler Handler, hS *httpserver.Server) Server {
|
||||
return Server{handler: handler, HTTPServer: hS}
|
||||
}
|
||||
|
||||
func (s Server) Serve() error {
|
||||
s.registerRoutes()
|
||||
if err := s.HTTPServer.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Server) Stop(ctx context.Context) error {
|
||||
return s.HTTPServer.Stop(ctx)
|
||||
}
|
||||
|
||||
func (s Server) registerRoutes() {
|
||||
router := s.HTTPServer.GetRouter()
|
||||
|
||||
router.GET("campaign/health-check", s.healthCheck)
|
||||
|
||||
r := router.Group("campaign")
|
||||
|
||||
r.POST("/", s.handler.createCampaign)
|
||||
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ package mysql
|
|||
|
||||
import (
|
||||
"context"
|
||||
"git.gocasts.ir/ebhomengo/niki/campaign/entity"
|
||||
"git.gocasts.ir/ebhomengo/niki/donate_app/service/entity"
|
||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
||||
"git.gocasts.ir/ebhomengo/niki/types"
|
||||
|
|
@ -16,11 +16,9 @@ func New(db *mysql.DB) *DB {
|
|||
return &DB{conn: db}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// CreateCampaign creates a new campaign
|
||||
func (d *DB) CreateAndSave(ctx context.Context, campaign entity.Campaign) (types.ID, error) {
|
||||
const Op = "repository.mysql.campaign.create"
|
||||
// Create adds a new participant to a campaign
|
||||
func (d *DB) CreateCampaignParticipants(ctx context.Context, participant entity.CampaignParticipant) (types.ID, error) {
|
||||
const Op = "repository.mysql.campaign_participant.create"
|
||||
|
||||
tx, err := d.conn.Conn().BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
|
|
@ -28,67 +26,29 @@ func (d *DB) CreateAndSave(ctx context.Context, campaign entity.Campaign) (types
|
|||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
query := `INSERT INTO campaigns (title, description, goal_amount, raised_amount,
|
||||
status, deadline_at ,admin_id , created_at )
|
||||
VALUES (?, ?, ?, ?, ?, ?, ? , NOW() )`
|
||||
query := `INSERT INTO campaign_participants (id,campaign_id, user_id, amount , created_at)
|
||||
VALUES (?, ?, ? , ? , NOW())`
|
||||
|
||||
result, err := tx.ExecContext(ctx, query,
|
||||
campaign.Title,
|
||||
campaign.Description,
|
||||
campaign.GoalAmount,
|
||||
campaign.RaisedAmount,
|
||||
campaign.Status,
|
||||
campaign.DeadlineAt,
|
||||
campaign.AdminID,
|
||||
campaign.CreatedAt,
|
||||
|
||||
|
||||
participant.ID,
|
||||
participant.CampaignID,
|
||||
participant.UserID,
|
||||
participant.Amount,
|
||||
participant.CreatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return 0, richerror.New(Op).WithErr(err)
|
||||
}
|
||||
|
||||
campaignID, err := result.LastInsertId()
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return 0, richerror.New(Op).WithErr(err)
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return 0, richerror.New(Op).WithErr(err)
|
||||
}
|
||||
|
||||
return types.ID(campaignID), nil
|
||||
return types.ID(id), nil
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Create adds a new participant to a campaign
|
||||
func (d *DB) CreateCampaignParticipants(ctx context.Context, participant entity.CampaignParticipant) (types.ID, error) {
|
||||
const Op = "repository.mysql.campaign_participant.create"
|
||||
|
||||
query := `INSERT INTO campaign_participants (id,campaign_id, user_id, amount , created_at)
|
||||
VALUES (?, ?, ? , ? , NOW())`
|
||||
|
||||
result, err := d.conn.ExecContext(ctx, query,
|
||||
participant.ID,
|
||||
participant.CampaignID,
|
||||
participant.UserID,
|
||||
participant.Amount,
|
||||
participant.CreatedAt
|
||||
)
|
||||
if err != nil {
|
||||
return 0, richerror.New(Op).WithErr(err)
|
||||
}
|
||||
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return 0, richerror.New(Op).WithErr(err)
|
||||
}
|
||||
|
||||
return types.ID(id), nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
package service
|
||||
package entity
|
||||
|
||||
import "time"
|
||||
|
||||
type ID uint64
|
||||
|
||||
|
||||
type CampaignParticipant struct {
|
||||
ID ID `json:"id"`
|
||||
CampaignID ID `json:"campaign_id"`
|
||||
UserID ID `json:"user_id"`
|
||||
Amount float64 `json:"amount"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
|
||||
}
|
||||
ID ID `json:"id"`
|
||||
CampaignID ID `json:"campaign_id"`
|
||||
UserID ID `json:"user_id"`
|
||||
Amount float64 `json:"amount"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1,26 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"git.gocasts.ir/ebhomengo/niki/types"
|
||||
"time"
|
||||
)
|
||||
|
||||
type GetCampaignResponse struct {
|
||||
ID types.ID `json:"user_id"`
|
||||
}
|
||||
|
||||
type AddCampaignRequest struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
GoalAmount float64 `json:"goal_amount"`
|
||||
DeadlineAt *time.Time `json:"deadline_at,omitempty"`
|
||||
AdminID types.ID `json:"admin_id"`
|
||||
}
|
||||
|
||||
type UpdateCampaignRequest struct {
|
||||
Title *string `json:"title,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
GoalAmount *float64 `json:"goal_amount,omitempty"`
|
||||
DeadlineAt *time.Time `json:"deadline_at,omitempty"`
|
||||
Status *string `json:"status,omitempty"` // draft/active/completed/paused/cancelled
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,38 +1 @@
|
|||
package service
|
||||
|
||||
|
||||
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"git.gocasts.ir/ebhomengo/niki/campaign/entity"
|
||||
"git.gocasts.ir/ebhomengo/niki/repository"
|
||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||
"git.gocasts.ir/ebhomengo/niki/types"
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
type CampaignService struct {
|
||||
repo repository.repo
|
||||
}
|
||||
|
||||
|
||||
// type CampaignServiceInterface interface {
|
||||
// CreateCampaign(ctx context.Context, req CampaignRepository) (types.ID, error)
|
||||
// }
|
||||
|
||||
func NewCampaignService(
|
||||
repo repository.CampaignRepository,
|
||||
participantRepo repository.CampaignParticipantRepository,
|
||||
) *CampaignService {
|
||||
return &CampaignService{
|
||||
repo: repo,
|
||||
participantRepo: participantRepo,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ package purchaseapp
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
purchaseMysql "git.gocasts.ir/ebhomengo/niki/domain/purchase/repository/mysql"
|
||||
purchaseMysql "git.gocasts.ir/ebhomengo/niki/domain/order/repository/mysql"
|
||||
purchaseService "git.gocasts.ir/ebhomengo/niki/domain/order/service"
|
||||
purchaseHTTP "git.gocasts.ir/ebhomengo/niki/purchaseapp/delivery/http"
|
||||
purchaseHandler "git.gocasts.ir/ebhomengo/niki/purchaseapp/delivery/http/order"
|
||||
purchaseService "git.gocasts.ir/ebhomengo/niki/purchaseapp/service/order"
|
||||
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"git.gocasts.ir/ebhomengo/niki/adapter/redis"
|
||||
"git.gocasts.ir/ebhomengo/niki/domain/shoppingbasket/repository"
|
||||
"git.gocasts.ir/ebhomengo/niki/domain/shoppingbasket/service"
|
||||
"git.gocasts.ir/ebhomengo/niki/pkg/httpserver"
|
||||
"git.gocasts.ir/ebhomengo/niki/pkg/logger"
|
||||
"git.gocasts.ir/ebhomengo/niki/shoppingbasketapp/delivery/http"
|
||||
"git.gocasts.ir/ebhomengo/niki/shoppingbasketapp/repository"
|
||||
"git.gocasts.ir/ebhomengo/niki/shoppingbasketapp/service/cart"
|
||||
"git.gocasts.ir/ebhomengo/niki/shoppingbasketapp/delivery/http/cart"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
|
|
@ -17,8 +18,8 @@ import (
|
|||
|
||||
type Application struct {
|
||||
Repo repository.Repo
|
||||
Service cart.Service
|
||||
Handler http.Handler
|
||||
Service service.Service
|
||||
Handler cart.Handler
|
||||
Server http.Server
|
||||
Config Config
|
||||
}
|
||||
|
|
@ -28,10 +29,10 @@ func Setup(ctx context.Context, cfg Config) (Application, error) {
|
|||
adapter := redis.New(cfg.Redis)
|
||||
repo := repository.New(adapter.Client(), cfg.Repo)
|
||||
|
||||
validator := cart.NewValidate()
|
||||
svc := cart.New(validator, repo)
|
||||
validator := service.NewValidate()
|
||||
svc := service.New(validator, repo)
|
||||
|
||||
handler := http.NewHandler(svc)
|
||||
handler := cart.NewHandler(svc)
|
||||
|
||||
httpServer, err := httpserver.New(cfg.HTTPServer)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ package shoppingbasketapp
|
|||
|
||||
import (
|
||||
"git.gocasts.ir/ebhomengo/niki/adapter/redis"
|
||||
"git.gocasts.ir/ebhomengo/niki/domain/shoppingbasket/repository"
|
||||
"git.gocasts.ir/ebhomengo/niki/pkg/httpserver"
|
||||
logger "git.gocasts.ir/ebhomengo/niki/pkg/logger"
|
||||
"git.gocasts.ir/ebhomengo/niki/shoppingbasketapp/repository"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
package http
|
||||
package cart
|
||||
|
||||
import (
|
||||
"git.gocasts.ir/ebhomengo/niki/domain/shoppingbasket/service"
|
||||
"git.gocasts.ir/ebhomengo/niki/pkg/claim"
|
||||
httpmsg "git.gocasts.ir/ebhomengo/niki/pkg/http_msg"
|
||||
"git.gocasts.ir/ebhomengo/niki/shoppingbasketapp/service/cart"
|
||||
"git.gocasts.ir/ebhomengo/niki/types"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
|
|
@ -11,17 +11,17 @@ import (
|
|||
)
|
||||
|
||||
type Handler struct {
|
||||
svc cart.Service
|
||||
svc service.Service
|
||||
}
|
||||
|
||||
func NewHandler(svc cart.Service) Handler {
|
||||
func NewHandler(svc service.Service) Handler {
|
||||
return Handler{svc: svc}
|
||||
}
|
||||
|
||||
func (h Handler) addToBasket(c echo.Context) error {
|
||||
func (h Handler) AddToBasket(c echo.Context) error {
|
||||
claims := claim.GetClaimsFromEchoContext(c)
|
||||
|
||||
var req cart.AddToCartRequest
|
||||
var req service.AddToCartRequest
|
||||
if err := c.Bind(&req); err != nil {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{
|
||||
"error": "invalid request body",
|
||||
|
|
@ -37,7 +37,7 @@ func (h Handler) addToBasket(c echo.Context) error {
|
|||
return c.NoContent(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (h Handler) getCart(c echo.Context) error {
|
||||
func (h Handler) GetCart(c echo.Context) error {
|
||||
claims := claim.GetClaimsFromEchoContext(c)
|
||||
|
||||
res, err := h.svc.GetCart(c.Request().Context(), types.ID(claims.UserID))
|
||||
|
|
@ -49,7 +49,7 @@ func (h Handler) getCart(c echo.Context) error {
|
|||
return c.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
func (h Handler) removeCart(c echo.Context) error {
|
||||
func (h Handler) RemoveCart(c echo.Context) error {
|
||||
claims := claim.GetClaimsFromEchoContext(c)
|
||||
|
||||
if err := h.svc.ClearCart(c.Request().Context(), types.ID(claims.UserID)); err != nil {
|
||||
|
|
@ -60,7 +60,7 @@ func (h Handler) removeCart(c echo.Context) error {
|
|||
return c.NoContent(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (h Handler) removeItem(c echo.Context) error {
|
||||
func (h Handler) RemoveItem(c echo.Context) error {
|
||||
claims := claim.GetClaimsFromEchoContext(c)
|
||||
p := c.Param("productID")
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ func (h Handler) removeItem(c echo.Context) error {
|
|||
})
|
||||
}
|
||||
|
||||
var req cart.RemoveFromCartRequest
|
||||
var req service.RemoveFromCartRequest
|
||||
|
||||
req.UserID = types.ID(claims.UserID)
|
||||
req.ProductID = types.ID(pID)
|
||||
|
|
@ -84,7 +84,7 @@ func (h Handler) removeItem(c echo.Context) error {
|
|||
return c.NoContent(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (h Handler) updateQuantity(c echo.Context) error {
|
||||
func (h Handler) UpdateQuantity(c echo.Context) error {
|
||||
claims := claim.GetClaimsFromEchoContext(c)
|
||||
p := c.Param("productID")
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ func (h Handler) updateQuantity(c echo.Context) error {
|
|||
})
|
||||
}
|
||||
|
||||
var req cart.UpdateQuantityRequest
|
||||
var req service.UpdateQuantityRequest
|
||||
req.UserID = types.ID(claims.UserID)
|
||||
req.ProductID = types.ID(pID)
|
||||
req.Quantity = q
|
||||
|
|
@ -3,14 +3,15 @@ package http
|
|||
import (
|
||||
"context"
|
||||
"git.gocasts.ir/ebhomengo/niki/pkg/httpserver"
|
||||
"git.gocasts.ir/ebhomengo/niki/shoppingbasketapp/delivery/http/cart"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
handler Handler
|
||||
handler cart.Handler
|
||||
HTTPServer *httpserver.Server
|
||||
}
|
||||
|
||||
func NewServer(handler Handler, hS *httpserver.Server) Server {
|
||||
func NewServer(handler cart.Handler, hS *httpserver.Server) Server {
|
||||
return Server{handler: handler, HTTPServer: hS}
|
||||
}
|
||||
|
||||
|
|
@ -34,10 +35,10 @@ func (s Server) registerRoutes() {
|
|||
|
||||
r := router.Group("shoppingbasket/cart") // Authentication is required
|
||||
|
||||
r.GET("/", s.handler.getCart)
|
||||
r.DELETE("/", s.handler.removeCart)
|
||||
r.GET("/", s.handler.GetCart)
|
||||
r.DELETE("/", s.handler.RemoveCart)
|
||||
|
||||
r.POST("/items", s.handler.addToBasket)
|
||||
r.DELETE("/items/:productID", s.handler.removeItem)
|
||||
r.PUT("/items/:productID/:quantity", s.handler.updateQuantity)
|
||||
r.POST("/items", s.handler.AddToBasket)
|
||||
r.DELETE("/items/:productID", s.handler.RemoveItem)
|
||||
r.PUT("/items/:productID/:quantity", s.handler.UpdateQuantity)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue