adding status interface

This commit is contained in:
matina 2026-05-05 11:12:03 -07:00
parent 233df829fe
commit 11c73efd66
6 changed files with 113 additions and 50 deletions

View File

@ -5,41 +5,31 @@ import (
"time" "time"
) )
type CampaignStatus string
const (
CampaignDraft CampaignStatus = "draft"
CampaignActive CampaignStatus = "active"
CampaignFinished CampaignStatus = "completed"
CampaignPaused CampaignStatus = "paused"
CampaignCanceled CampaignStatus = "cancelled"
)
type Campaign struct { type Campaign struct {
ID types.ID `json:"id"` ID types.ID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Link string `json:"link"` Link string `json:"link"`
Slogan string `json:"slogan"` // Slogan string `json:"slogan"` //
GoalAmount float64 `json:"goal_amount"` GoalAmount float64 `json:"goal_amount"`
RaisedAmount float64 `json:"raised_amount"` RaisedAmount float64 `json:"raised_amount"`
Status CampaignStatus `json:"status"` Status types.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 types.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 == types.CampaignDraft {
c.Status = CampaignActive c.Status = types.CampaignActive
} }
} }
func (c *Campaign) AddFunds(amount float64) { func (c *Campaign) AddFunds(amount float64) {
c.RaisedAmount += amount c.RaisedAmount += amount
if c.RaisedAmount >= c.GoalAmount { if c.RaisedAmount >= c.GoalAmount {
c.Status = CampaignFinished c.Status = types.CampaignFinished
} }
} }

View File

@ -3,11 +3,27 @@ package service
import ( import (
"context" "context"
"fmt" "fmt"
"git.gocasts.ir/ebhomengo/niki/domain/campaign/service/mapper" "git.gocasts.ir/ebhomengo/niki/domain/campaign/entity"
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error" richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
"git.gocasts.ir/ebhomengo/niki/types" "git.gocasts.ir/ebhomengo/niki/types"
"time"
) )
func ToCampaignEntity(req CreateCampaignRequest) entity.Campaign {
return entity.Campaign{
Title: req.Title,
Description: req.Description,
Link: req.Link,
Slogan: req.Slogan,
GoalAmount: req.GoalAmount,
RaisedAmount: 0,
Status: types.CampaignStatus(req.Status),
DeadlineAt: req.DeadlineAt,
AdminID: req.AdminID,
CreatedAt: time.Now(),
}
}
// CreateCampaign handles creation of a new campaign. // CreateCampaign handles creation of a new campaign.
func (s *CampaignService) CreateCampaign(ctx context.Context, req CreateCampaignRequest) (types.ID, error) { func (s *CampaignService) CreateCampaign(ctx context.Context, req CreateCampaignRequest) (types.ID, error) {
const op = "service.campaign.create_campaign" const op = "service.campaign.create_campaign"
@ -16,7 +32,7 @@ func (s *CampaignService) CreateCampaign(ctx context.Context, req CreateCampaign
return 0, richerror.New(op).WithErr(err) return 0, richerror.New(op).WithErr(err)
} }
campaign := mapper.ToCampaignEntity(req) campaign := ToCampaignEntity(req)
id, err := s.repo.Create(ctx, campaign) id, err := s.repo.Create(ctx, campaign)
if err != nil { if err != nil {

View File

@ -1,22 +0,0 @@
package mapper
import (
"git.gocasts.ir/ebhomengo/niki/domain/campaign/entity"
param "git.gocasts.ir/ebhomengo/niki/domain/campaign/service"
"time"
)
func ToCampaignEntity(req param.CreateCampaignRequest) entity.Campaign {
return entity.Campaign{
Title: req.Title,
Description: req.Description,
Link: req.Link,
Slogan: req.Slogan,
GoalAmount: req.GoalAmount,
RaisedAmount: 0,
Status: entity.CampaignStatus(req.Status),
DeadlineAt: req.DeadlineAt,
AdminID: req.AdminID,
CreatedAt: time.Now(),
}
}

View File

@ -14,6 +14,11 @@ type CampaignFilterParam struct {
IsArchived *bool IsArchived *bool
} }
type CampaignStatus interface {
FindActiveCampaigns(ctx context.Context) ([]entity.Campaign, error)
UpdateStatus(ctx context.Context, id types.ID, status types.CampaignStatus) error
}
type CampaignStorage interface { type CampaignStorage interface {
Create(ctx context.Context, c entity.Campaign) (types.ID, error) Create(ctx context.Context, c entity.Campaign) (types.ID, error)
Update(ctx context.Context, c entity.Campaign) error Update(ctx context.Context, c entity.Campaign) error
@ -24,10 +29,10 @@ type CampaignStorage interface {
} }
type CampaignService struct { type CampaignService struct {
repo CampaignStorage repo CampaignStorage
repoStatus CampaignStatus
} }
// NewCampaignService constructs a new CampaignService.
func NewCampaignService(storage CampaignStorage) *CampaignService { func NewCampaignService(storage CampaignStorage) *CampaignService {
return &CampaignService{ return &CampaignService{
repo: storage, repo: storage,

View File

@ -0,0 +1,63 @@
package service
import (
"context"
"git.gocasts.ir/ebhomengo/niki/types"
"time"
)
func (s *CampaignService) MonitorCampaignProgress(ctx context.Context) {
//c := cron.New()
//
//c.AddFunc("@hourly", func() {
// s.checkAndCompleteCampaigns(context.Background())
//})
//
//c.Start()
//ticker := time.NewTicker(1 * time.Hour) // Check every hour
//defer ticker.Stop()
//
//for {
// select {
// case <-ticker.C:
// s.checkAndCompleteCampaigns(ctx)
// case <-ctx.Done():
// return
// }
//}
}
func (s *CampaignService) checkAndCompleteCampaigns(ctx context.Context) {
activeCampaigns, err := s.repoStatus.FindActiveCampaigns(ctx) // Method to fetch active campaigns
if err != nil {
// Log the error, but don't stop the monitor
return
}
for _, campaign := range activeCampaigns {
// Check if deadline has passed
if campaign.DeadlineAt != nil && campaign.DeadlineAt.Before(time.Now()) {
if campaign.Status != types.CampaignFinished {
campaign.Status = types.CampaignFinished
err := s.repoStatus.UpdateStatus(ctx, campaign.ID, types.CampaignFinished) // Method to update status
if err != nil {
// Log error for this specific campaign
}
}
continue // Move to next campaign
}
// Check if goal is met
if campaign.RaisedAmount >= campaign.GoalAmount {
if campaign.Status != types.CampaignFinished {
campaign.Status = types.CampaignFinished
err := s.repoStatus.UpdateStatus(ctx, campaign.ID, types.CampaignFinished) // Method to update status
if err != nil {
// Log error for this specific campaign
}
}
}
}
}

11
types/status.go Normal file
View File

@ -0,0 +1,11 @@
package types
type CampaignStatus string
const (
CampaignDraft CampaignStatus = "draft"
CampaignActive CampaignStatus = "active"
CampaignFinished CampaignStatus = "completed"
CampaignPaused CampaignStatus = "paused"
CampaignCanceled CampaignStatus = "cancelled"
)