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,16 +5,6 @@ import (
"time"
)
type CampaignStatus string
const (
CampaignDraft CampaignStatus = "draft"
CampaignActive CampaignStatus = "active"
CampaignFinished CampaignStatus = "completed"
CampaignPaused CampaignStatus = "paused"
CampaignCanceled CampaignStatus = "cancelled"
)
type Campaign struct {
ID types.ID `json:"id"`
Title string `json:"title"`
@ -23,7 +13,7 @@ type Campaign struct {
Slogan string `json:"slogan"` //
GoalAmount float64 `json:"goal_amount"`
RaisedAmount float64 `json:"raised_amount"`
Status CampaignStatus `json:"status"`
Status types.CampaignStatus `json:"status"`
CreatedAt time.Time `json:"created_at"`
DeadlineAt *time.Time `json:"deadline_at,omitempty"`
AdminID types.ID `json:"creator_id"`
@ -31,15 +21,15 @@ type Campaign struct {
// Behavior
func (c *Campaign) Activate() {
if c.Status == CampaignDraft {
c.Status = CampaignActive
if c.Status == types.CampaignDraft {
c.Status = types.CampaignActive
}
}
func (c *Campaign) AddFunds(amount float64) {
c.RaisedAmount += amount
if c.RaisedAmount >= c.GoalAmount {
c.Status = CampaignFinished
c.Status = types.CampaignFinished
}
}

View File

@ -3,11 +3,27 @@ package service
import (
"context"
"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"
"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.
func (s *CampaignService) CreateCampaign(ctx context.Context, req CreateCampaignRequest) (types.ID, error) {
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)
}
campaign := mapper.ToCampaignEntity(req)
campaign := ToCampaignEntity(req)
id, err := s.repo.Create(ctx, campaign)
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
}
type CampaignStatus interface {
FindActiveCampaigns(ctx context.Context) ([]entity.Campaign, error)
UpdateStatus(ctx context.Context, id types.ID, status types.CampaignStatus) error
}
type CampaignStorage interface {
Create(ctx context.Context, c entity.Campaign) (types.ID, error)
Update(ctx context.Context, c entity.Campaign) error
@ -25,9 +30,9 @@ type CampaignStorage interface {
type CampaignService struct {
repo CampaignStorage
repoStatus CampaignStatus
}
// NewCampaignService constructs a new CampaignService.
func NewCampaignService(storage CampaignStorage) *CampaignService {
return &CampaignService{
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"
)