All checks were successful
Server Check Build (NixCN CMS) TeamCity build finished
Options Signed-off-by: Asai Neko <sugar@sne.moe>
332 lines
9.2 KiB
Go
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
|
|
}
|