Files
cms-server/data/event.go
Asai Neko c540235c6d
All checks were successful
Server Check Build (NixCN CMS) TeamCity build finished
Full restruct data layer without alibaba style SetXxx to Functional
Options

Signed-off-by: Asai Neko <sugar@sne.moe>
2026-03-26 16:32:51 +08:00

332 lines
9.2 KiB
Go

package data
import (
"context"
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type Event struct {
Id uint `json:"id" gorm:"primarykey;autoincrement"`
UUID uuid.UUID `json:"uuid" gorm:"type:uuid;uniqueIndex;not null"`
EventId uuid.UUID `json:"event_id" gorm:"type:uuid;uniqueIndex;not null"`
Name string `json:"name" gorm:"type:varchar(255);index;not null"`
Type string `json:"type" gorm:"type:varchar(255);index;not null"` // official | party
Subtitle string `json:"subtitle" gorm:"type:text;not null;default:an amazing event"`
Description string `json:"description" gorm:"type:text"` // base64 markdown
AttendanceGuide string `json:"attendance_guide" gorm:"type:text"` // base64 markdown
StartTime time.Time `json:"start_time" gorm:"index;not null"`
EndTime time.Time `json:"end_time" gorm:"index;not null"`
Thumbnail string `json:"thumbnail" gorm:"type:varchar(255)"`
Owner uuid.UUID `json:"owner" gorm:"type:uuid;index;not null"`
EnableKYC bool `json:"enable_kyc" gorm:"not null"`
IsAgendaPublished bool `json:"is_agenda_published" gorm:"not null;default:false"`
Quota int64 `json:"quota" gorm:"not null"`
Limit int64 `json:"limit" gorm:"not null"`
}
type EventIndexDoc struct {
EventId string `json:"event_id" validate:"required"`
Name string `json:"name" validate:"required"`
Type string `json:"type" validate:"required"`
Subtitle string `json:"subtitle" validate:"required"`
Description string `json:"description"`
StartTime time.Time `json:"start_time" validate:"required"`
EndTime time.Time `json:"end_time" validate:"required"`
Thumbnail string `json:"thumbnail"`
EnableKYC bool `json:"enable_kyc" validate:"required"`
IsAgendaPublished bool `json:"is_agenda_published"`
Owner string `json:"owner"`
}
type EventListOptions struct {
TypeFilter string
OwnerId *uuid.UUID
SortBy string
SortOrder string
Limit int64
Offset int64
}
type eventOpts struct {
Name *string
Type *string
Subtitle *string
Description *string
AttendanceGuide *string
StartTime *time.Time
EndTime *time.Time
Thumbnail *string
Owner *uuid.UUID
EnableKYC *bool
IsAgendaPublished *bool
Quota *int64
Limit *int64
}
type EventOption func(*eventOpts)
func WithEventName(v string) EventOption { return func(o *eventOpts) { o.Name = &v } }
func WithEventType(v string) EventOption { return func(o *eventOpts) { o.Type = &v } }
func WithEventSubtitle(v string) EventOption { return func(o *eventOpts) { o.Subtitle = &v } }
func WithEventDescription(v string) EventOption { return func(o *eventOpts) { o.Description = &v } }
func WithAttendanceGuide(v string) EventOption { return func(o *eventOpts) { o.AttendanceGuide = &v } }
func WithEventStartTime(v time.Time) EventOption { return func(o *eventOpts) { o.StartTime = &v } }
func WithEventEndTime(v time.Time) EventOption { return func(o *eventOpts) { o.EndTime = &v } }
func WithThumbnail(v string) EventOption { return func(o *eventOpts) { o.Thumbnail = &v } }
func WithOwner(v uuid.UUID) EventOption { return func(o *eventOpts) { o.Owner = &v } }
func WithEnableKYC(v bool) EventOption { return func(o *eventOpts) { o.EnableKYC = &v } }
func WithIsAgendaPublished(v bool) EventOption {
return func(o *eventOpts) { o.IsAgendaPublished = &v }
}
func WithQuota(v int64) EventOption { return func(o *eventOpts) { o.Quota = &v } }
func WithLimit(v int64) EventOption { return func(o *eventOpts) { o.Limit = &v } }
func applyEventOpts(opts []EventOption) *eventOpts {
o := &eventOpts{}
for _, opt := range opts {
opt(o)
}
return o
}
func NewEvent(opts ...EventOption) *Event {
o := applyEventOpts(opts)
e := &Event{}
if o.Name != nil {
e.Name = *o.Name
}
if o.Type != nil {
e.Type = *o.Type
}
if o.Subtitle != nil {
e.Subtitle = *o.Subtitle
}
if o.Description != nil {
e.Description = *o.Description
}
if o.AttendanceGuide != nil {
e.AttendanceGuide = *o.AttendanceGuide
}
if o.StartTime != nil {
e.StartTime = *o.StartTime
}
if o.EndTime != nil {
e.EndTime = *o.EndTime
}
if o.Thumbnail != nil {
e.Thumbnail = *o.Thumbnail
}
if o.Owner != nil {
e.Owner = *o.Owner
}
if o.EnableKYC != nil {
e.EnableKYC = *o.EnableKYC
}
if o.IsAgendaPublished != nil {
e.IsAgendaPublished = *o.IsAgendaPublished
}
if o.Quota != nil {
e.Quota = *o.Quota
}
if o.Limit != nil {
e.Limit = *o.Limit
}
return e
}
func (self *Event) GetEventById(ctx context.Context, eventId uuid.UUID) (*Event, error) {
var event Event
err := Database.WithContext(ctx).
Where("event_id = ?", eventId).
First(&event).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
return nil, err
}
return &event, nil
}
func (self *Event) Create(ctx context.Context) error {
self.UUID = uuid.New()
self.EventId = uuid.New()
if err := Database.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
return tx.Create(self).Error
}); err != nil {
return err
}
return nil
}
func (self *Event) PatchByEventId(ctx context.Context, eventId uuid.UUID, opts ...EventOption) error {
o := applyEventOpts(opts)
updates := make(map[string]any)
if o.Name != nil {
updates["name"] = *o.Name
}
if o.Type != nil {
updates["type"] = *o.Type
}
if o.Subtitle != nil {
updates["subtitle"] = *o.Subtitle
}
if o.Description != nil {
updates["description"] = *o.Description
}
if o.AttendanceGuide != nil {
updates["attendance_guide"] = *o.AttendanceGuide
}
if o.StartTime != nil {
updates["start_time"] = *o.StartTime
}
if o.EndTime != nil {
updates["end_time"] = *o.EndTime
}
if o.Thumbnail != nil {
updates["thumbnail"] = *o.Thumbnail
}
if o.Owner != nil {
updates["owner"] = *o.Owner
}
if o.EnableKYC != nil {
updates["enable_kyc"] = *o.EnableKYC
}
if o.IsAgendaPublished != nil {
updates["is_agenda_published"] = *o.IsAgendaPublished
}
if o.Quota != nil {
updates["quota"] = *o.Quota
}
if o.Limit != nil {
updates["limit"] = *o.Limit
}
if len(updates) == 0 {
return nil
}
return Database.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
if err := tx.Model(&Event{}).
Where("event_id = ?", eventId).
Updates(updates).Error; err != nil {
return err
}
return tx.Where("event_id = ?", eventId).First(self).Error
})
}
func (self *Event) DeleteEventById(ctx context.Context, eventId uuid.UUID) error {
return Database.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
result := tx.Where("event_id = ?", eventId).Delete(&Event{})
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return gorm.ErrRecordNotFound
}
return nil
})
}
func (self *Event) FastListEvents(ctx context.Context, limit, offset int64) (*[]EventIndexDoc, error) {
var results []EventIndexDoc
err := Database.WithContext(ctx).
Model(&Event{}).
Select("event_id", "name", "type", "subtitle", "description", "start_time", "end_time", "thumbnail", "enable_kyc", "is_agenda_published", "owner").
Limit(int(limit)).
Offset(int(offset)).
Scan(&results).Error
if err != nil {
return nil, err
}
return &results, nil
}
func (self *Event) ListEventsWithOptions(ctx context.Context, opts EventListOptions) (*[]EventIndexDoc, int64, error) {
var results []EventIndexDoc
var total int64
selectCols := "event_id, name, type, subtitle, description, start_time, end_time, thumbnail, enable_kyc, is_agenda_published, owner"
baseQuery := Database.WithContext(ctx).Model(&Event{})
if opts.TypeFilter != "" {
baseQuery = baseQuery.Where("type = ?", opts.TypeFilter)
}
if opts.OwnerId != nil {
baseQuery = baseQuery.Where("owner = ?", opts.OwnerId)
}
if err := baseQuery.Count(&total).Error; err != nil {
return nil, 0, err
}
sortField := "start_time"
switch opts.SortBy {
case "end_time", "name":
sortField = opts.SortBy
}
sortOrder := "DESC"
if opts.SortOrder == "asc" {
sortOrder = "ASC"
}
err := baseQuery.
Select(selectCols).
Order(sortField + " " + sortOrder).
Limit(int(opts.Limit)).
Offset(int(opts.Offset)).
Scan(&results).Error
if err != nil {
return nil, 0, err
}
return &results, total, nil
}
func (self *Event) GetEventsByUserId(ctx context.Context, userId uuid.UUID, limit, offset int64) (*[]EventIndexDoc, error) {
var results []EventIndexDoc
err := Database.WithContext(ctx).
Table("events").
Select(`
events.event_id,
events.name,
events.type,
events.subtitle,
events.description,
events.start_time,
events.end_time,
events.thumbnail,
events.enable_kyc,
(SELECT COUNT(*) FROM attendances WHERE attendances.event_id = events.event_id) as join_count
`).
Joins("JOIN attendances ON attendances.event_id = events.event_id").
Where("attendances.user_id = ?", userId).
Order("events.start_time DESC").
Limit(int(limit)).
Offset(int(offset)).
Scan(&results).Error
if err != nil {
return nil, err
}
return &results, nil
}