Files
cms-server/service/service_event/update.go
Asai Neko a6224eb957
Some checks failed
Server Check Build (NixCN CMS) TeamCity build finished
Server Prod Build (NixCN CMS) TeamCity build failed
Fix lv40+ can't edit event info in event update service
Signed-off-by: Asai Neko <sugar@sne.moe>
2026-04-28 14:04:10 +08:00

213 lines
6.1 KiB
Go

package service_event
import (
"context"
"errors"
"nixcn-cms/data"
"nixcn-cms/internal/exception"
"nixcn-cms/service/shared"
"nixcn-cms/tracer"
"time"
"github.com/google/uuid"
)
type EventUpdateData struct {
EventId string `json:"event_id" validate:"required"`
Name *string `json:"name"`
Subtitle *string `json:"subtitle"`
Description *string `json:"description"`
AttendanceGuide *string `json:"attendance_guide"`
StartTime *time.Time `json:"start_time"`
EndTime *time.Time `json:"end_time"`
Thumbnail *string `json:"thumbnail"`
IsAgendaPublished *bool `json:"is_agenda_published"`
Quota *int64 `json:"quota"`
Limit *int64 `json:"limit"`
// immutable — presence triggers rejection
Type *string `json:"type" swaggerignore:"true"`
EnableKYC *bool `json:"enable_kyc" swaggerignore:"true"`
UserId string `json:"user_id" swaggerignore:"true"`
PermissionLevel uint `json:"permission_level" swaggerignore:"true"`
}
type EventUpdatePayload struct {
Context context.Context
Data *EventUpdateData
}
type EventUpdateResult struct {
Common shared.CommonResult
}
func (self *EventServiceImpl) Update(payload *EventUpdatePayload) (result *EventUpdateResult) {
ctx, span := tracer.StartSpan(
payload.Context,
"service_event",
"update",
)
defer span.End()
ctx = exception.ContextWithService(ctx, exception.ServiceEventUpdate)
if payload.Data.Type != nil || payload.Data.EnableKYC != nil {
exc := exception.New(
exception.WithStatus(exception.StatusUser),
exception.WithType(exception.TypeSpecific),
exception.WithOriginal(exception.EventUpdateImmutableField),
exception.WithError(errors.New("type and enable_kyc are immutable after creation")),
).Throw(ctx)
result = &EventUpdateResult{
Common: shared.CommonResult{HttpCode: 400, Exception: exc},
}
return
}
eventId, err := uuid.Parse(payload.Data.EventId)
if err != nil {
exc := exception.New(
exception.WithStatus(exception.StatusUser),
exception.WithType(exception.TypeCommon),
exception.WithOriginal(exception.CommonErrorUuidParseFailed),
exception.WithError(err),
).Throw(ctx)
result = &EventUpdateResult{
Common: shared.CommonResult{HttpCode: 400, Exception: exc},
}
return
}
userId, err := uuid.Parse(payload.Data.UserId)
if err != nil {
exc := exception.New(
exception.WithStatus(exception.StatusServer),
exception.WithType(exception.TypeCommon),
exception.WithOriginal(exception.CommonErrorUuidParseFailed),
exception.WithError(err),
).Throw(ctx)
result = &EventUpdateResult{
Common: shared.CommonResult{HttpCode: 500, Exception: exc},
}
return
}
eventData, err := new(data.Event).GetEventById(ctx, eventId)
if err != nil {
exc := exception.New(
exception.WithStatus(exception.StatusServer),
exception.WithType(exception.TypeCommon),
exception.WithOriginal(exception.CommonErrorDatabase),
exception.WithError(err),
).Throw(ctx)
result = &EventUpdateResult{
Common: shared.CommonResult{HttpCode: 500, Exception: exc},
}
return
}
if eventData == nil {
exc := exception.New(
exception.WithStatus(exception.StatusUser),
exception.WithType(exception.TypeCommon),
exception.WithOriginal(exception.CommonErrorInvalidInput),
exception.WithError(errors.New("event not found")),
).Throw(ctx)
result = &EventUpdateResult{
Common: shared.CommonResult{HttpCode: 404, Exception: exc},
}
return
}
// Lv40+ users (admins) bypass the event-owner restriction.
if eventData.Owner != userId && payload.Data.PermissionLevel < 40 {
exc := exception.New(
exception.WithStatus(exception.StatusUser),
exception.WithType(exception.TypeSpecific),
exception.WithOriginal(exception.EventUpdateNotOwner),
exception.WithError(errors.New("only the event owner may update this event")),
).Throw(ctx)
result = &EventUpdateResult{
Common: shared.CommonResult{HttpCode: 403, Exception: exc},
}
return
}
var opts []data.EventOption
if payload.Data.Name != nil {
opts = append(opts, data.WithEventName(*payload.Data.Name))
}
if payload.Data.Subtitle != nil {
opts = append(opts, data.WithEventSubtitle(*payload.Data.Subtitle))
}
if payload.Data.Description != nil {
opts = append(opts, data.WithEventDescription(*payload.Data.Description))
}
if payload.Data.StartTime != nil {
opts = append(opts, data.WithEventStartTime(*payload.Data.StartTime))
}
if payload.Data.EndTime != nil {
opts = append(opts, data.WithEventEndTime(*payload.Data.EndTime))
}
if payload.Data.Thumbnail != nil {
opts = append(opts, data.WithThumbnail(*payload.Data.Thumbnail))
}
if payload.Data.AttendanceGuide != nil {
opts = append(opts, data.WithAttendanceGuide(*payload.Data.AttendanceGuide))
}
if payload.Data.Quota != nil {
opts = append(opts, data.WithQuota(*payload.Data.Quota))
}
if payload.Data.Limit != nil {
opts = append(opts, data.WithLimit(*payload.Data.Limit))
}
if payload.Data.IsAgendaPublished != nil {
opts = append(opts, data.WithIsAgendaPublished(*payload.Data.IsAgendaPublished))
}
if len(opts) == 0 {
exc := exception.New(
exception.WithStatus(exception.StatusSuccess),
exception.WithType(exception.TypeCommon),
exception.WithOriginal(exception.CommonSuccess),
).Throw(ctx)
result = &EventUpdateResult{
Common: shared.CommonResult{HttpCode: 200, Exception: exc},
}
return
}
if err := new(data.Event).PatchByEventId(ctx, eventId, opts...); err != nil {
exc := exception.New(
exception.WithStatus(exception.StatusServer),
exception.WithType(exception.TypeCommon),
exception.WithOriginal(exception.CommonErrorDatabase),
exception.WithError(err),
).Throw(ctx)
result = &EventUpdateResult{
Common: shared.CommonResult{HttpCode: 500, Exception: exc},
}
return
}
exc := exception.New(
exception.WithStatus(exception.StatusSuccess),
exception.WithType(exception.TypeCommon),
exception.WithOriginal(exception.CommonSuccess),
).Throw(ctx)
result = &EventUpdateResult{
Common: shared.CommonResult{HttpCode: 200, Exception: exc},
}
return
}