forked from ebhomengo/niki
Merge pull request 'campaign' (#284) from campaign into develop
Reviewed-on: ebhomengo/niki#284
This commit is contained in:
commit
373ef9512f
|
|
@ -1,8 +1,9 @@
|
||||||
package domain
|
package entity
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/types"
|
||||||
type ID uint64
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type CampaignStatus string
|
type CampaignStatus string
|
||||||
|
|
||||||
|
|
@ -15,7 +16,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Campaign struct {
|
type Campaign struct {
|
||||||
ID ID `json:"id"`
|
ID types.ID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
GoalAmount float64 `json:"goal_amount"`
|
GoalAmount float64 `json:"goal_amount"`
|
||||||
|
|
@ -23,10 +24,10 @@ type Campaign struct {
|
||||||
Status CampaignStatus `json:"status"`
|
Status CampaignStatus `json:"status"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
DeadlineAt *time.Time `json:"deadline_at,omitempty"`
|
DeadlineAt *time.Time `json:"deadline_at,omitempty"`
|
||||||
AdminID ID `json:"creator_id"`
|
AdminID types.ID `json:"creator_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Behavior
|
// Behavior
|
||||||
func (c *Campaign) Activate() {
|
func (c *Campaign) Activate() {
|
||||||
if c.Status == CampaignDraft {
|
if c.Status == CampaignDraft {
|
||||||
c.Status = CampaignActive
|
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 (
|
import (
|
||||||
"context"
|
"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"
|
"time"
|
||||||
|
|
||||||
"your_project/domain"
|
|
||||||
"your_project/pkg/richerror"
|
|
||||||
"your_project/repository"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ID = unit64
|
// CreateCampaign handles creation of a new campaign.
|
||||||
type EntityCampaign = domain.Campaign
|
func (s *CampaignService) CreateCampaign(ctx context.Context, req entity.Campaign) (types.ID, error) {
|
||||||
|
const op = "service.campaign.create_campaign"
|
||||||
|
|
||||||
|
if err := validateCreateCampaignRequest(req); err != nil {
|
||||||
type CampaignServiceImp interface {
|
return 0, richerror.New(op).WithErr(err)
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 validateCreateCampaignRequest(req entity.Campaign) error {
|
||||||
func (s *CampaignService) CreateCampaign(ctx context.Context, req CreateCampaignRequest) (ID, error) {
|
|
||||||
const Op = "service.campaign.create_campaign"
|
|
||||||
|
|
||||||
if req.Title == "" {
|
if req.Title == "" {
|
||||||
return 0, richerror.New(Op).WithMessage("title is required")
|
return errRequired("title")
|
||||||
}
|
}
|
||||||
if req.GoalAmount <= 0 {
|
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 {
|
if req.AdminID == 0 {
|
||||||
return 0, richerror.New(Op).WithMessage("admin_id is required")
|
return errRequired("admin_id")
|
||||||
}
|
}
|
||||||
|
|
||||||
validStatuses := map[string]bool{
|
validStatuses := map[string]bool{
|
||||||
|
|
@ -50,32 +52,20 @@ func (s *CampaignService) CreateCampaign(ctx context.Context, req CreateCampaign
|
||||||
"active": true,
|
"active": true,
|
||||||
"completed": true,
|
"completed": true,
|
||||||
"cancelled": true,
|
"cancelled": true,
|
||||||
"paused": true
|
"paused": true,
|
||||||
}
|
}
|
||||||
if !validStatuses[req.Status] {
|
if !validStatuses[string(req.Status)] {
|
||||||
return 0, richerror.New(Op).WithMessage("invalid status provided")
|
return errInvalid("invalid status provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 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,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 (
|
import (
|
||||||
"context"
|
"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"
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
||||||
"git.gocasts.ir/ebhomengo/niki/types"
|
"git.gocasts.ir/ebhomengo/niki/types"
|
||||||
|
|
@ -16,11 +16,9 @@ func New(db *mysql.DB) *DB {
|
||||||
return &DB{conn: db}
|
return &DB{conn: db}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create adds a new participant to a campaign
|
||||||
|
func (d *DB) CreateCampaignParticipants(ctx context.Context, participant entity.CampaignParticipant) (types.ID, error) {
|
||||||
// CreateCampaign creates a new campaign
|
const Op = "repository.mysql.campaign_participant.create"
|
||||||
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)
|
tx, err := d.conn.Conn().BeginTx(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -28,67 +26,29 @@ func (d *DB) CreateAndSave(ctx context.Context, campaign entity.Campaign) (types
|
||||||
}
|
}
|
||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
|
|
||||||
query := `INSERT INTO campaigns (title, description, goal_amount, raised_amount,
|
query := `INSERT INTO campaign_participants (id,campaign_id, user_id, amount , created_at)
|
||||||
status, deadline_at ,admin_id , created_at )
|
VALUES (?, ?, ? , ? , NOW())`
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ? , NOW() )`
|
|
||||||
|
|
||||||
result, err := tx.ExecContext(ctx, query,
|
result, err := tx.ExecContext(ctx, query,
|
||||||
campaign.Title,
|
participant.ID,
|
||||||
campaign.Description,
|
participant.CampaignID,
|
||||||
campaign.GoalAmount,
|
participant.UserID,
|
||||||
campaign.RaisedAmount,
|
participant.Amount,
|
||||||
campaign.Status,
|
participant.CreatedAt,
|
||||||
campaign.DeadlineAt,
|
|
||||||
campaign.AdminID,
|
|
||||||
campaign.CreatedAt,
|
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, richerror.New(Op).WithErr(err)
|
return 0, richerror.New(Op).WithErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
campaignID, err := result.LastInsertId()
|
id, err := result.LastInsertId()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, richerror.New(Op).WithErr(err)
|
return 0, richerror.New(Op).WithErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tx.Commit(); err != nil {
|
if err := tx.Commit(); err != nil {
|
||||||
return 0, richerror.New(Op).WithErr(err)
|
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 ID uint64
|
||||||
|
|
||||||
|
|
||||||
type CampaignParticipant struct {
|
type CampaignParticipant struct {
|
||||||
ID ID `json:"id"`
|
ID ID `json:"id"`
|
||||||
CampaignID ID `json:"campaign_id"`
|
CampaignID ID `json:"campaign_id"`
|
||||||
UserID ID `json:"user_id"`
|
UserID ID `json:"user_id"`
|
||||||
Amount float64 `json:"amount"`
|
Amount float64 `json:"amount"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1,26 @@
|
||||||
package service
|
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
|
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue