package service import ( "context" "strings" roomv1 "hyapp.local/api/proto/room/v1" "hyapp/pkg/appcode" "hyapp/pkg/xerr" ) var adminSeatCandidates = []int32{10, 15, 20, 25, 30} func (s *Service) AdminGetRoomSeatConfig(ctx context.Context, _ *roomv1.AdminGetRoomSeatConfigRequest) (*roomv1.AdminGetRoomSeatConfigResponse, error) { config, err := s.currentRoomSeatConfig(ctx) if err != nil { return nil, err } return &roomv1.AdminGetRoomSeatConfigResponse{Config: seatConfigToAdminProto(config), ServerTimeMs: s.clock.Now().UnixMilli()}, nil } func (s *Service) AdminUpdateRoomSeatConfig(ctx context.Context, req *roomv1.AdminUpdateRoomSeatConfigRequest) (*roomv1.AdminUpdateRoomSeatConfigResponse, error) { if req == nil { return nil, xerr.New(xerr.InvalidArgument, "room seat config is required") } config, err := normalizeRoomSeatConfig(RoomSeatConfig{ AppCode: appcode.FromContext(ctx), AllowedSeatCounts: req.GetAllowedSeatCounts(), DefaultSeatCount: req.GetDefaultSeatCount(), UpdatedAtMS: s.clock.Now().UTC().UnixMilli(), }) if err != nil { return nil, xerr.New(xerr.InvalidArgument, err.Error()) } if err := s.repository.UpsertRoomSeatConfig(ctx, config); err != nil { return nil, err } return &roomv1.AdminUpdateRoomSeatConfigResponse{Config: seatConfigToAdminProto(config), ServerTimeMs: config.UpdatedAtMS}, nil } func (s *Service) AdminListRoomPins(ctx context.Context, req *roomv1.AdminListRoomPinsRequest) (*roomv1.AdminListRoomPinsResponse, error) { nowMS := s.clock.Now().UTC().UnixMilli() pins, total, err := s.repository.AdminListRoomPins(ctx, AdminRoomPinQuery{ Page: int(req.GetPage()), PageSize: int(req.GetPageSize()), Keyword: strings.TrimSpace(req.GetKeyword()), Status: strings.TrimSpace(req.GetStatus()), RegionID: req.GetVisibleRegionId(), NowMS: nowMS, }) if err != nil { return nil, err } out := make([]*roomv1.AdminRoomPin, 0, len(pins)) for _, pin := range pins { out = append(out, roomPinToAdminProto(pin)) } return &roomv1.AdminListRoomPinsResponse{Pins: out, Total: total, ServerTimeMs: nowMS}, nil } func (s *Service) AdminCreateRoomPin(ctx context.Context, req *roomv1.AdminCreateRoomPinRequest) (*roomv1.AdminCreateRoomPinResponse, error) { if req == nil || strings.TrimSpace(req.GetRoomId()) == "" { return nil, xerr.New(xerr.InvalidArgument, "room id is required") } if req.GetWeight() < 0 || req.GetDurationDays() <= 0 { return nil, xerr.New(xerr.InvalidArgument, "room pin weight or duration is invalid") } nowMS := s.clock.Now().UTC().UnixMilli() pin, ok, err := s.repository.AdminCreateRoomPin(ctx, AdminCreateRoomPinInput{ RoomID: strings.TrimSpace(req.GetRoomId()), Weight: req.GetWeight(), DurationDays: req.GetDurationDays(), AdminID: req.GetAdminId(), NowMS: nowMS, }) if err != nil { return nil, err } if !ok { return nil, xerr.New(xerr.Conflict, "room is not active or not found") } return &roomv1.AdminCreateRoomPinResponse{Pin: roomPinToAdminProto(pin), ServerTimeMs: nowMS}, nil } func (s *Service) AdminCancelRoomPin(ctx context.Context, req *roomv1.AdminCancelRoomPinRequest) (*roomv1.AdminCancelRoomPinResponse, error) { if req == nil || req.GetPinId() <= 0 { return nil, xerr.New(xerr.InvalidArgument, "room pin id is invalid") } nowMS := s.clock.Now().UTC().UnixMilli() pin, ok, err := s.repository.AdminCancelRoomPin(ctx, req.GetPinId(), req.GetAdminId(), nowMS) if err != nil { return nil, err } if !ok { return nil, xerr.New(xerr.NotFound, "room pin not found") } return &roomv1.AdminCancelRoomPinResponse{Pin: roomPinToAdminProto(pin), ServerTimeMs: nowMS}, nil } func seatConfigToAdminProto(config RoomSeatConfig) *roomv1.AdminRoomSeatConfig { return &roomv1.AdminRoomSeatConfig{ CandidateSeatCounts: append([]int32(nil), adminSeatCandidates...), AllowedSeatCounts: append([]int32(nil), config.AllowedSeatCounts...), DefaultSeatCount: config.DefaultSeatCount, UpdatedAtMs: config.UpdatedAtMS, } } func roomPinToAdminProto(pin AdminRoomPinEntry) *roomv1.AdminRoomPin { return &roomv1.AdminRoomPin{ Id: pin.ID, VisibleRegionId: pin.VisibleRegionID, RoomId: pin.RoomID, Weight: pin.Weight, Status: pin.Status, PinnedAtMs: pin.PinnedAtMS, ExpiresAtMs: pin.ExpiresAtMS, CancelledAtMs: pin.CancelledAtMS, CreatedByAdminId: pin.CreatedByAdminID, CancelledByAdminId: pin.CancelledByAdminID, CreatedAtMs: pin.CreatedAtMS, UpdatedAtMs: pin.UpdatedAtMS, Room: &roomv1.AdminRoomPinRoom{ RoomId: pin.RoomID, RoomShortId: pin.RoomShortID, VisibleRegionId: pin.VisibleRegionID, OwnerUserId: pin.OwnerUserID, Title: pin.Title, CoverUrl: pin.CoverURL, Status: pin.RoomStatus, }, } }