From 1826a51ebd023b5491a7066b8a7e77badedc13e0 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 21 Jul 2025 19:57:39 -0700 Subject: [PATCH 1/9] submissions: maps db --- pkg/datastore/datastore.go | 11 ++++ pkg/datastore/gormstore/db.go | 1 + pkg/datastore/gormstore/gormstore.go | 4 ++ pkg/datastore/gormstore/maps.go | 84 ++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 pkg/datastore/gormstore/maps.go diff --git a/pkg/datastore/datastore.go b/pkg/datastore/datastore.go index 1903bd4..0c43d1c 100644 --- a/pkg/datastore/datastore.go +++ b/pkg/datastore/datastore.go @@ -25,6 +25,7 @@ const ( type Datastore interface { AuditEvents() AuditEvents + Maps() Maps Mapfixes() Mapfixes Operations() Operations Submissions() Submissions @@ -40,6 +41,16 @@ type AuditEvents interface { List(ctx context.Context, filters OptionalMap, page model.Page) ([]model.AuditEvent, error) } +type Maps interface { + Get(ctx context.Context, id int64) (model.Map, error) + GetList(ctx context.Context, id []int64) ([]model.Map, error) + Create(ctx context.Context, smap model.Map) (model.Map, error) + Update(ctx context.Context, id int64, values OptionalMap) error + Delete(ctx context.Context, id int64) error + List(ctx context.Context, filters OptionalMap, page model.Page) ([]model.Map, error) + IncrementLoadCount(ctx context.Context, id int64) error +} + type Mapfixes interface { Get(ctx context.Context, id int64) (model.Mapfix, error) GetList(ctx context.Context, id []int64) ([]model.Mapfix, error) diff --git a/pkg/datastore/gormstore/db.go b/pkg/datastore/gormstore/db.go index 127cfe0..bf1c8ae 100644 --- a/pkg/datastore/gormstore/db.go +++ b/pkg/datastore/gormstore/db.go @@ -32,6 +32,7 @@ func New(ctx *cli.Context) (datastore.Datastore, error) { if ctx.Bool("migrate") { if err := db.AutoMigrate( &model.AuditEvent{}, + &model.Map{}, &model.Mapfix{}, &model.Operation{}, &model.Submission{}, diff --git a/pkg/datastore/gormstore/gormstore.go b/pkg/datastore/gormstore/gormstore.go index da8fe14..a4a7720 100644 --- a/pkg/datastore/gormstore/gormstore.go +++ b/pkg/datastore/gormstore/gormstore.go @@ -13,6 +13,10 @@ func (g Gormstore) AuditEvents() datastore.AuditEvents { return &AuditEvents{db: g.db} } +func (g Gormstore) Maps() datastore.Maps { + return &Maps{db: g.db} +} + func (g Gormstore) Mapfixes() datastore.Mapfixes { return &Mapfixes{db: g.db} } diff --git a/pkg/datastore/gormstore/maps.go b/pkg/datastore/gormstore/maps.go new file mode 100644 index 0000000..a47e27f --- /dev/null +++ b/pkg/datastore/gormstore/maps.go @@ -0,0 +1,84 @@ +package gormstore + +import ( + "context" + "errors" + + "git.itzana.me/strafesnet/maps-service/pkg/datastore" + "git.itzana.me/strafesnet/maps-service/pkg/model" + "gorm.io/gorm" +) + +type Maps struct { + db *gorm.DB +} + +func (env *Maps) Get(ctx context.Context, id int64) (model.Map, error) { + var mdl model.Map + if err := env.db.First(&mdl, id).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return mdl, datastore.ErrNotExist + } + return mdl, err + } + return mdl, nil +} + +func (env *Maps) GetList(ctx context.Context, id []int64) ([]model.Map, error) { + var mapList []model.Map + if err := env.db.Find(&mapList, "id IN ?", id).Error; err != nil { + return mapList, err + } + + return mapList, nil +} + +func (env *Maps) Create(ctx context.Context, smap model.Map) (model.Map, error) { + if err := env.db.Create(&smap).Error; err != nil { + return smap, err + } + + return smap, nil +} + +func (env *Maps) Update(ctx context.Context, id int64, values datastore.OptionalMap) error { + if err := env.db.Model(&model.Map{}).Where("id = ?", id).Updates(values.Map()).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return datastore.ErrNotExist + } + return err + } + + return nil +} + +func (env *Maps) IncrementLoadCount(ctx context.Context, id int64) error { + if err := env.db.Model(&model.Map{}).Where("id = ?", id).UpdateColumn("load_count", gorm.Expr("load_count + ?", 1)).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return datastore.ErrNotExist + } + return err + } + + return nil +} + +func (env *Maps) Delete(ctx context.Context, id int64) error { + if err := env.db.Delete(&model.Map{}, id).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return datastore.ErrNotExist + } + return err + } + + return nil +} + +func (env *Maps) List(ctx context.Context, filters datastore.OptionalMap, page model.Page) ([]model.Map, error) { + var events []model.Map + if err := env.db.Where(filters.Map()).Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&events).Error; err != nil { + return nil, err + } + + return events, nil +} -- 2.49.1 From f417111bcf67a3b5463aba051b266b791bb609b6 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 21 Jul 2025 22:25:30 -0700 Subject: [PATCH 2/9] submissions: switch maps to maps-service --- pkg/service/maps.go | 175 +++++++++++++++++++++++-------------- pkg/web_api/maps.go | 2 +- pkg/web_api/submissions.go | 15 ++-- 3 files changed, 119 insertions(+), 73 deletions(-) diff --git a/pkg/service/maps.go b/pkg/service/maps.go index ee7b1fa..ea612e1 100644 --- a/pkg/service/maps.go +++ b/pkg/service/maps.go @@ -2,54 +2,94 @@ package service import ( "context" - "time" "git.itzana.me/strafesnet/go-grpc/maps" "git.itzana.me/strafesnet/maps-service/pkg/model" + "git.itzana.me/strafesnet/maps-service/pkg/datastore" ) // Optional map used to update an object -type MapUpdate maps.MapRequest +type MapUpdate datastore.OptionalMap -func NewMapUpdate(id int64) *MapUpdate { - item := MapUpdate{ - ID: id, - } - return &item +func NewMapUpdate() MapUpdate { + update := datastore.Optional() + return MapUpdate(update) } -func (update *MapUpdate) SetDisplayName(display_name string) { - update.DisplayName = &display_name + +func (update MapUpdate) SetDisplayName(display_name string) { + datastore.OptionalMap(update).Add("display_name", display_name) } -func (update *MapUpdate) SetCreator(creator string) { - update.Creator = &creator +func (update MapUpdate) SetCreator(creator string) { + datastore.OptionalMap(update).Add("creator", creator) } -func (update *MapUpdate) SetGameID(game_id int32) { - update.GameID = &game_id +func (update MapUpdate) SetGameID(game_id uint32) { + datastore.OptionalMap(update).Add("game_id", game_id) } -func (update *MapUpdate) SetDate(date int64) { - update.Date = &date +func (update MapUpdate) SetDate(date int64) { + datastore.OptionalMap(update).Add("date", date) +} +func (update MapUpdate) SetSubmitter(submitter uint64) { + datastore.OptionalMap(update).Add("submitter", submitter) +} +func (update MapUpdate) SetThumbnail(thumbnail uint64) { + datastore.OptionalMap(update).Add("thumbnail", thumbnail) +} +func (update MapUpdate) SetAssetVersion(asset_version uint64) { + datastore.OptionalMap(update).Add("asset_version", asset_version) +} +func (update MapUpdate) SetModes(modes uint32) { + datastore.OptionalMap(update).Add("modes", modes) +} + +// getters +func (update MapUpdate) GetDisplayName() (string, bool) { + value, ok := datastore.OptionalMap(update).Map()["display_name"].(string) + return value, ok +} +func (update MapUpdate) GetCreator() (string, bool) { + value, ok := datastore.OptionalMap(update).Map()["creator"].(string) + return value, ok +} +func (update MapUpdate) GetGameID() (uint32, bool) { + value, ok := datastore.OptionalMap(update).Map()["game_id"].(uint32) + return value, ok +} +func (update MapUpdate) GetDate() (int64, bool) { + value, ok := datastore.OptionalMap(update).Map()["date"].(int64) + return value, ok } // Optional map used to find matching objects -type MapFilter maps.MapFilter +type MapFilter datastore.OptionalMap -func NewMapFilter() *MapFilter { - item := MapFilter{} - return &item +func NewMapFilter( +) MapFilter { + filter := datastore.Optional() + return MapFilter(filter) } -func (filter *MapFilter) SetDisplayName(display_name string) { - filter.DisplayName = &display_name +func (update MapFilter) SetDisplayName(display_name string) { + datastore.OptionalMap(update).Add("display_name", display_name) } -func (filter *MapFilter) SetCreator(creator string) { - filter.Creator = &creator +func (update MapFilter) SetCreator(creator string) { + datastore.OptionalMap(update).Add("creator", creator) } -func (filter *MapFilter) SetGameID(game_id int32) { - filter.GameID = &game_id +func (update MapFilter) SetGameID(game_id uint32) { + datastore.OptionalMap(update).Add("game_id", game_id) +} +func (update MapFilter) SetSubmitter(submitter uint64) { + datastore.OptionalMap(update).Add("submitter", submitter) } func (svc *Service) CreateMap(ctx context.Context, item model.Map) (int64, error) { + // 2 jobs: + // create map on maps-service + map_item, err := svc.db.Maps().Create(ctx, item) + if err != nil { + return 0, err + } + // create map on data-service date := item.Date.Unix() - id_message, err := svc.maps.Create(ctx, &maps.MapRequest{ + _, err = svc.maps.Create(ctx, &maps.MapRequest{ ID: item.ID, DisplayName: &item.DisplayName, Creator: &item.Creator, @@ -60,57 +100,58 @@ func (svc *Service) CreateMap(ctx context.Context, item model.Map) (int64, error return 0, err } - return id_message.ID, nil + return map_item.ID, nil } -func (svc *Service) ListMaps(ctx context.Context, filter *MapFilter, page model.Page) ([]model.Map, error) { - page_request := maps.Pagination{ - Size: page.Size, - Number: page.Number, - } - request := maps.ListRequest{ - Filter: (*maps.MapFilter)(filter), - Page: &page_request, - } +func (svc *Service) ListMaps(ctx context.Context, filter MapFilter, page model.Page) ([]model.Map, error) { + return svc.db.Maps().List(ctx, datastore.OptionalMap(filter), page) +} - items, err := svc.maps.List(ctx, &request) - if err != nil { - return nil, err - } - - resp := make([]model.Map, len(items.Maps)) - for i, item := range items.Maps { - resp[i].ID = item.ID - resp[i].DisplayName = item.DisplayName - resp[i].Creator = item.Creator - resp[i].GameID = item.GameID - resp[i].Date = time.Unix(item.Date, 0) - } - - return resp, nil +func (svc *Service) GetMapList(ctx context.Context, ids []int64) ([]model.Map, error) { + return svc.db.Maps().GetList(ctx, ids) } func (svc *Service) DeleteMap(ctx context.Context, id int64) error { - _, err := svc.maps.Delete(ctx, &maps.IdMessage{ID: id}) - return err + // Do not delete the "embedded" map, since it deletes times. + // _, err := svc.maps.Delete(ctx, &maps.IdMessage{ID: id}) + return svc.db.Maps().Delete(ctx, id) } -func (svc *Service) GetMap(ctx context.Context, id int64) (*model.Map, error) { - item, err := svc.maps.Get(ctx, &maps.IdMessage{ID: id}) +func (svc *Service) GetMap(ctx context.Context, id int64) (model.Map, error) { + return svc.db.Maps().Get(ctx, id) +} + +func (svc *Service) UpdateMap(ctx context.Context, id int64, pmap MapUpdate) error { + // 2 jobs: + // update map on maps-service + err := svc.db.Maps().Update(ctx, id, datastore.OptionalMap(pmap)) if err != nil { - return nil, err + return err } - - return &model.Map{ - ID: item.ID, - DisplayName: item.DisplayName, - Creator: item.Creator, - GameID: item.GameID, - Date: time.Unix(item.Date, 0), - }, nil + // update map on data-service + update := maps.MapRequest{ + ID: id, + } + if display_name, ok := pmap.GetDisplayName(); ok { + update.DisplayName = &display_name + } + if creator, ok := pmap.GetCreator(); ok { + update.Creator = &creator + } + if game_id, ok := pmap.GetGameID(); ok { + game_id_int32 := int32(game_id) + update.GameID = &game_id_int32 + } + if date, ok := pmap.GetDate(); ok { + update.Date = &date + } + _, err = svc.maps.Update(ctx, &update) + if err != nil { + return err + } + return nil } -func (svc *Service) UpdateMap(ctx context.Context, pmap *MapUpdate) error { - _, err := svc.maps.Update(ctx, (*maps.MapRequest)(pmap)) - return err +func (svc *Service) IncrementMapLoadCount(ctx context.Context, id int64) error { + return svc.db.Maps().IncrementLoadCount(ctx, id) } diff --git a/pkg/web_api/maps.go b/pkg/web_api/maps.go index e40e587..42cce62 100644 --- a/pkg/web_api/maps.go +++ b/pkg/web_api/maps.go @@ -24,7 +24,7 @@ func (svc *Service) ListMaps(ctx context.Context, params api.ListMapsParams) ([] filter.SetCreator(creator) } if game_id, game_id_ok := params.GameID.Get(); game_id_ok{ - filter.SetGameID(game_id) + filter.SetGameID(uint32(game_id)) } items, err := svc.inner.ListMaps(ctx, diff --git a/pkg/web_api/submissions.go b/pkg/web_api/submissions.go index a4e9230..158701b 100644 --- a/pkg/web_api/submissions.go +++ b/pkg/web_api/submissions.go @@ -1079,11 +1079,16 @@ func (svc *Service) ReleaseSubmissions(ctx context.Context, request []api.Releas var GameID = int32(submission.GameID) // create each map with go-grpc _, err := svc.inner.CreateMap(ctx, model.Map{ - ID: int64(submission.UploadedAssetID), - DisplayName: submission.DisplayName, - Creator: submission.Creator, - GameID: GameID, - Date: time.Unix(date, 0), + ID: int64(submission.UploadedAssetID), + DisplayName: submission.DisplayName, + Creator: submission.Creator, + GameID: GameID, + Date: time.Unix(date, 0), + Submitter: int64(submission.Submitter), + // Thumbnail: 0, + // AssetVersion: 0, + // LoadCount: 0, + // Modes: 0, }) if err != nil { return err -- 2.49.1 From ce4e37dc64890a5769b89bbbf35a969d9eb0041e Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 21 Jul 2025 22:05:07 -0700 Subject: [PATCH 3/9] submissions: update go-grpc for maps_extended --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1b5d891..cc627d2 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22 toolchain go1.23.3 require ( - git.itzana.me/strafesnet/go-grpc v0.0.0-20250719033306-150dea07cf00 + git.itzana.me/strafesnet/go-grpc v0.0.0-20250724030029-845bea991815 git.itzana.me/strafesnet/utils v0.0.0-20220716194944-d8ca164052f9 github.com/dchest/siphash v1.2.3 github.com/go-faster/errors v0.7.1 diff --git a/go.sum b/go.sum index 003bde8..99b670a 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -git.itzana.me/strafesnet/go-grpc v0.0.0-20250719033306-150dea07cf00 h1:L9HiJzMrXCKZhZz+RyUr5RXdMcGQMU85aap6L+QQDZ0= -git.itzana.me/strafesnet/go-grpc v0.0.0-20250719033306-150dea07cf00/go.mod h1:X7XTRUScRkBWq8q8bplbeso105RPDlnY7J6Wy1IwBMs= +git.itzana.me/strafesnet/go-grpc v0.0.0-20250724030029-845bea991815 h1:hkuOnehphRXUq/2z2UYgoqTq5MJj1GsWfshyc7bXda8= +git.itzana.me/strafesnet/go-grpc v0.0.0-20250724030029-845bea991815/go.mod h1:X7XTRUScRkBWq8q8bplbeso105RPDlnY7J6Wy1IwBMs= git.itzana.me/strafesnet/utils v0.0.0-20220716194944-d8ca164052f9 h1:7lU6jyR7S7Rhh1dnUp7GyIRHUTBXZagw8F4n4hOyxLw= git.itzana.me/strafesnet/utils v0.0.0-20220716194944-d8ca164052f9/go.mod h1:uyYerSieEt4v0MJCdPLppG0LtJ4Yj035vuTetWGsxjY= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -- 2.49.1 From 36f9e2db5ffe3c0296d392b159b407395282e975 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 21 Jul 2025 23:10:30 -0700 Subject: [PATCH 4/9] submissions: grpc controller --- pkg/cmds/serve.go | 5 ++ pkg/controller/maps.go | 186 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 pkg/controller/maps.go diff --git a/pkg/cmds/serve.go b/pkg/cmds/serve.go index 274e2fc..c01b503 100644 --- a/pkg/cmds/serve.go +++ b/pkg/cmds/serve.go @@ -7,9 +7,11 @@ import ( "git.itzana.me/strafesnet/go-grpc/auth" "git.itzana.me/strafesnet/go-grpc/maps" + "git.itzana.me/strafesnet/go-grpc/maps_extended" "git.itzana.me/strafesnet/go-grpc/users" "git.itzana.me/strafesnet/go-grpc/validator" "git.itzana.me/strafesnet/maps-service/pkg/api" + "git.itzana.me/strafesnet/maps-service/pkg/controller" "git.itzana.me/strafesnet/maps-service/pkg/datastore/gormstore" "git.itzana.me/strafesnet/maps-service/pkg/roblox" "git.itzana.me/strafesnet/maps-service/pkg/service" @@ -162,6 +164,9 @@ func serve(ctx *cli.Context) error { grpcServer := grpc.NewServer() + maps_controller := controller.NewMapsController(&svc_inner) + maps_extended.RegisterMapsServiceServer(grpcServer,&maps_controller) + mapfix_controller := validator_controller.NewMapfixesController(&svc_inner) operation_controller := validator_controller.NewOperationsController(&svc_inner) script_controller := validator_controller.NewScriptsController(&svc_inner) diff --git a/pkg/controller/maps.go b/pkg/controller/maps.go new file mode 100644 index 0000000..49c5d18 --- /dev/null +++ b/pkg/controller/maps.go @@ -0,0 +1,186 @@ +package controller + +import ( + "context" + "time" + + "git.itzana.me/strafesnet/go-grpc/maps_extended" + "git.itzana.me/strafesnet/maps-service/pkg/model" + "git.itzana.me/strafesnet/maps-service/pkg/service" +) + +type Maps struct { + *maps_extended.UnimplementedMapsServiceServer + inner *service.Service +} + +func NewMapsController( + inner *service.Service, +) Maps { + return Maps{ + inner: inner, + } +} + +func (svc *Maps) Create(ctx context.Context, request *maps_extended.MapCreate) (*maps_extended.MapId, error) { + id, err := svc.inner.CreateMap(ctx, model.Map{ + ID: request.ID, + DisplayName: request.DisplayName, + Creator: request.Creator, + GameID: int32(request.GameID), + Submitter: int64(request.Submitter), + Date: time.Unix(request.Date, 0), + Thumbnail: int64(request.Thumbnail), + AssetVersion: int64(request.AssetVersion), + LoadCount: 0, + Modes: request.Modes, + }) + if err != nil { + return nil, err + } + + return &maps_extended.MapId{ + ID: id, + }, nil +} + +func (svc *Maps) Delete(ctx context.Context, request *maps_extended.MapId) (*maps_extended.NullResponse, error) { + err := svc.inner.DeleteMap(ctx, request.ID) + if err != nil { + return nil, err + } + return &maps_extended.NullResponse{}, nil +} +func (svc *Maps) Get(ctx context.Context, request *maps_extended.MapId) (*maps_extended.MapResponse, error) { + item, err := svc.inner.GetMap(ctx, request.ID) + if err != nil { + return nil, err + } + + return &maps_extended.MapResponse{ + ID: item.ID, + DisplayName: item.DisplayName, + Creator: item.Creator, + GameID: uint32(item.GameID), + Date: item.Date.Unix(), + CreatedAt: item.CreatedAt.Unix(), + UpdatedAt: item.UpdatedAt.Unix(), + Submitter: uint64(item.Submitter), + Thumbnail: uint64(item.Thumbnail), + AssetVersion: uint64(item.AssetVersion), + LoadCount: item.LoadCount, + Modes: item.Modes, + }, nil +} +func (svc *Maps) GetList(ctx context.Context, request *maps_extended.MapIdList) (*maps_extended.MapList, error) { + items, err := svc.inner.GetMapList(ctx, request.ID) + if err != nil { + return nil, err + } + + resp := maps_extended.MapList{} + resp.Maps = make([]*maps_extended.MapResponse, len(items)) + for i, item := range items { + resp.Maps[i] = &maps_extended.MapResponse{ + ID: item.ID, + DisplayName: item.DisplayName, + Creator: item.Creator, + GameID: uint32(item.GameID), + Date: item.Date.Unix(), + CreatedAt: item.CreatedAt.Unix(), + UpdatedAt: item.UpdatedAt.Unix(), + Submitter: uint64(item.Submitter), + Thumbnail: uint64(item.Thumbnail), + AssetVersion: uint64(item.AssetVersion), + LoadCount: item.LoadCount, + Modes: item.Modes, + } + } + + return &resp, nil +} +func (svc *Maps) List(ctx context.Context, request *maps_extended.ListRequest) (*maps_extended.MapList, error) { + filter := service.NewMapFilter() + if request.Filter.DisplayName != nil { + filter.SetDisplayName(*request.Filter.DisplayName) + } + if request.Filter.Creator != nil { + filter.SetCreator(*request.Filter.Creator) + } + if request.Filter.GameID != nil { + filter.SetGameID(*request.Filter.GameID) + } + if request.Filter.Submitter != nil { + filter.SetSubmitter(*request.Filter.Submitter) + } + + items, err := svc.inner.ListMaps(ctx, filter, model.Page{ + Number: int32(request.Page.Number), + Size: int32(request.Page.Size), + }) + if err != nil { + return nil, err + } + + resp := maps_extended.MapList{} + resp.Maps = make([]*maps_extended.MapResponse, len(items)) + for i, item := range items { + resp.Maps[i] = &maps_extended.MapResponse{ + ID: item.ID, + DisplayName: item.DisplayName, + Creator: item.Creator, + GameID: uint32(item.GameID), + Date: item.Date.Unix(), + CreatedAt: item.CreatedAt.Unix(), + UpdatedAt: item.UpdatedAt.Unix(), + Submitter: uint64(item.Submitter), + Thumbnail: uint64(item.Thumbnail), + AssetVersion: uint64(item.AssetVersion), + LoadCount: item.LoadCount, + Modes: item.Modes, + } + } + + return &resp, nil +} +func (svc *Maps) Update(ctx context.Context, request *maps_extended.MapUpdate) (*maps_extended.NullResponse, error) { + update := service.NewMapUpdate() + if request.DisplayName != nil { + update.SetDisplayName(*request.DisplayName) + } + if request.Creator != nil { + update.SetCreator(*request.Creator) + } + if request.GameID != nil { + update.SetGameID(*request.GameID) + } + if request.Date != nil { + update.SetDate(*request.Date) + } + if request.Submitter != nil { + update.SetSubmitter(*request.Submitter) + } + if request.Thumbnail != nil { + update.SetThumbnail(*request.Thumbnail) + } + if request.AssetVersion != nil { + update.SetAssetVersion(*request.AssetVersion) + } + if request.Modes != nil { + update.SetModes(*request.Modes) + } + + err := svc.inner.UpdateMap(ctx, request.ID, update) + if err != nil { + return nil, err + } + return &maps_extended.NullResponse{}, nil +} + +func (svc *Maps) IncrementLoadCount(ctx context.Context, request *maps_extended.MapId) (*maps_extended.NullResponse, error) { + err := svc.inner.IncrementMapLoadCount(ctx, request.ID) + if err != nil { + return nil, err + } + return &maps_extended.NullResponse{}, nil +} -- 2.49.1 From 89ef254b7209a3cc43a84b94082beddbfc065506 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Wed, 23 Jul 2025 18:31:16 -0700 Subject: [PATCH 5/9] openapi: maps migration endpoint --- openapi.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/openapi.yaml b/openapi.yaml index 89cdcd1..9c070e2 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -80,6 +80,21 @@ paths: application/json: schema: $ref: "#/components/schemas/Error" + /migrate-maps: + post: + summary: Perform maps migration + operationId: migrateMaps + tags: + - Maps + responses: + "200": + description: Successful response + default: + description: General Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" /maps: get: summary: Get list of maps -- 2.49.1 From 859004f264a72b4c371ad3b622755eb7379bc45a Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Wed, 23 Jul 2025 18:32:13 -0700 Subject: [PATCH 6/9] openapi: generate --- pkg/api/oas_client_gen.go | 111 ++ pkg/api/oas_handlers_gen.go | 180 +++ pkg/api/oas_operations_gen.go | 1 + pkg/api/oas_response_decoders_gen.go | 60 + pkg/api/oas_response_encoders_gen.go | 7 + pkg/api/oas_router_gen.go | 2054 +++++++++++++------------- pkg/api/oas_schemas_gen.go | 3 + pkg/api/oas_security_gen.go | 1 + pkg/api/oas_server_gen.go | 6 + pkg/api/oas_unimplemented_gen.go | 9 + 10 files changed, 1441 insertions(+), 991 deletions(-) diff --git a/pkg/api/oas_client_gen.go b/pkg/api/oas_client_gen.go index bc9a36b..67be7d2 100644 --- a/pkg/api/oas_client_gen.go +++ b/pkg/api/oas_client_gen.go @@ -301,6 +301,12 @@ type Invoker interface { // // GET /submissions ListSubmissions(ctx context.Context, params ListSubmissionsParams) (*Submissions, error) + // MigrateMaps invokes migrateMaps operation. + // + // Perform maps migration. + // + // POST /migrate-maps + MigrateMaps(ctx context.Context) error // ReleaseSubmissions invokes releaseSubmissions operation. // // Release a set of uploaded maps. @@ -6121,6 +6127,111 @@ func (c *Client) sendListSubmissions(ctx context.Context, params ListSubmissions return result, nil } +// MigrateMaps invokes migrateMaps operation. +// +// Perform maps migration. +// +// POST /migrate-maps +func (c *Client) MigrateMaps(ctx context.Context) error { + _, err := c.sendMigrateMaps(ctx) + return err +} + +func (c *Client) sendMigrateMaps(ctx context.Context) (res *MigrateMapsOK, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("migrateMaps"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/migrate-maps"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, MigrateMapsOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/migrate-maps" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + { + type bitset = [1]uint8 + var satisfied bitset + { + stage = "Security:CookieAuth" + switch err := c.securityCookieAuth(ctx, MigrateMapsOperation, r); { + case err == nil: // if NO error + satisfied[0] |= 1 << 0 + case errors.Is(err, ogenerrors.ErrSkipClientSecurity): + // Skip this security. + default: + return res, errors.Wrap(err, "security \"CookieAuth\"") + } + } + + if ok := func() bool { + nextRequirement: + for _, requirement := range []bitset{ + {0b00000001}, + } { + for i, mask := range requirement { + if satisfied[i]&mask != mask { + continue nextRequirement + } + } + return true + } + return false + }(); !ok { + return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied + } + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeMigrateMapsResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + // ReleaseSubmissions invokes releaseSubmissions operation. // // Release a set of uploaded maps. diff --git a/pkg/api/oas_handlers_gen.go b/pkg/api/oas_handlers_gen.go index 197e414..1ed5ef0 100644 --- a/pkg/api/oas_handlers_gen.go +++ b/pkg/api/oas_handlers_gen.go @@ -8433,6 +8433,186 @@ func (s *Server) handleListSubmissionsRequest(args [0]string, argsEscaped bool, } } +// handleMigrateMapsRequest handles migrateMaps operation. +// +// Perform maps migration. +// +// POST /migrate-maps +func (s *Server) handleMigrateMapsRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + statusWriter := &codeRecorder{ResponseWriter: w} + w = statusWriter + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("migrateMaps"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/migrate-maps"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), MigrateMapsOperation, + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Add Labeler to context. + labeler := &Labeler{attrs: otelAttrs} + ctx = contextWithLabeler(ctx, labeler) + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + code := statusWriter.status + if code != 0 { + codeAttr := semconv.HTTPResponseStatusCode(code) + attrs = append(attrs, codeAttr) + span.SetAttributes(codeAttr) + } + attrOpt := metric.WithAttributes(attrs...) + + // Increment request counter. + s.requests.Add(ctx, 1, attrOpt) + + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) + }() + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + + // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status + // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, + // unless there was another error (e.g., network error receiving the response body; or 3xx codes with + // max redirects exceeded), in which case status MUST be set to Error. + code := statusWriter.status + if code >= 100 && code < 500 { + span.SetStatus(codes.Error, stage) + } + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + if code != 0 { + attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) + } + + s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: MigrateMapsOperation, + ID: "migrateMaps", + } + ) + { + type bitset = [1]uint8 + var satisfied bitset + { + sctx, ok, err := s.securityCookieAuth(ctx, MigrateMapsOperation, r) + if err != nil { + err = &ogenerrors.SecurityError{ + OperationContext: opErrContext, + Security: "CookieAuth", + Err: err, + } + if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil { + defer recordError("Security:CookieAuth", err) + } + return + } + if ok { + satisfied[0] |= 1 << 0 + ctx = sctx + } + } + + if ok := func() bool { + nextRequirement: + for _, requirement := range []bitset{ + {0b00000001}, + } { + for i, mask := range requirement { + if satisfied[i]&mask != mask { + continue nextRequirement + } + } + return true + } + return false + }(); !ok { + err = &ogenerrors.SecurityError{ + OperationContext: opErrContext, + Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, + } + if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil { + defer recordError("Security", err) + } + return + } + } + + var response *MigrateMapsOK + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: MigrateMapsOperation, + OperationSummary: "Perform maps migration", + OperationID: "migrateMaps", + Body: nil, + Params: middleware.Parameters{}, + Raw: r, + } + + type ( + Request = struct{} + Params = struct{} + Response = *MigrateMapsOK + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + nil, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + err = s.h.MigrateMaps(ctx) + return response, err + }, + ) + } else { + err = s.h.MigrateMaps(ctx) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + defer recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + defer recordError("Internal", err) + } + return + } + + if err := encodeMigrateMapsResponse(response, w, span); err != nil { + defer recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + // handleReleaseSubmissionsRequest handles releaseSubmissions operation. // // Release a set of uploaded maps. diff --git a/pkg/api/oas_operations_gen.go b/pkg/api/oas_operations_gen.go index b5a33a8..066af28 100644 --- a/pkg/api/oas_operations_gen.go +++ b/pkg/api/oas_operations_gen.go @@ -51,6 +51,7 @@ const ( ListScriptsOperation OperationName = "ListScripts" ListSubmissionAuditEventsOperation OperationName = "ListSubmissionAuditEvents" ListSubmissionsOperation OperationName = "ListSubmissions" + MigrateMapsOperation OperationName = "MigrateMaps" ReleaseSubmissionsOperation OperationName = "ReleaseSubmissions" SessionRolesOperation OperationName = "SessionRoles" SessionUserOperation OperationName = "SessionUser" diff --git a/pkg/api/oas_response_decoders_gen.go b/pkg/api/oas_response_decoders_gen.go index 958d0d9..b39e901 100644 --- a/pkg/api/oas_response_decoders_gen.go +++ b/pkg/api/oas_response_decoders_gen.go @@ -3595,6 +3595,66 @@ func decodeListSubmissionsResponse(resp *http.Response) (res *Submissions, _ err return res, errors.Wrap(defRes, "error") } +func decodeMigrateMapsResponse(resp *http.Response) (res *MigrateMapsOK, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + return &MigrateMapsOK{}, nil + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + func decodeReleaseSubmissionsResponse(resp *http.Response) (res *ReleaseSubmissionsCreated, _ error) { switch resp.StatusCode { case 201: diff --git a/pkg/api/oas_response_encoders_gen.go b/pkg/api/oas_response_encoders_gen.go index fb923c6..fb4db75 100644 --- a/pkg/api/oas_response_encoders_gen.go +++ b/pkg/api/oas_response_encoders_gen.go @@ -484,6 +484,13 @@ func encodeListSubmissionsResponse(response *Submissions, w http.ResponseWriter, return nil } +func encodeMigrateMapsResponse(response *MigrateMapsOK, w http.ResponseWriter, span trace.Span) error { + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + return nil +} + func encodeReleaseSubmissionsResponse(response *ReleaseSubmissionsCreated, w http.ResponseWriter, span trace.Span) error { w.WriteHeader(201) span.SetStatus(codes.Ok, http.StatusText(201)) diff --git a/pkg/api/oas_router_gen.go b/pkg/api/oas_router_gen.go index 1dc226d..aa62a2d 100644 --- a/pkg/api/oas_router_gen.go +++ b/pkg/api/oas_router_gen.go @@ -61,9 +61,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { break } switch elem[0] { - case 'm': // Prefix: "map" + case 'm': // Prefix: "m" - if l := len("map"); len(elem) >= l && elem[0:l] == "map" { + if l := len("m"); len(elem) >= l && elem[0:l] == "m" { elem = elem[l:] } else { break @@ -73,50 +73,500 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { break } switch elem[0] { - case 'f': // Prefix: "fixes" + case 'a': // Prefix: "ap" - if l := len("fixes"); len(elem) >= l && elem[0:l] == "fixes" { + if l := len("ap"); len(elem) >= l && elem[0:l] == "ap" { elem = elem[l:] } else { break } if len(elem) == 0 { - switch r.Method { - case "GET": - s.handleListMapfixesRequest([0]string{}, elemIsEscaped, w, r) - case "POST": - s.handleCreateMapfixRequest([0]string{}, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "GET,POST") - } - - return + break } switch elem[0] { - case '/': // Prefix: "/" + case 'f': // Prefix: "fixes" - if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + if l := len("fixes"); len(elem) >= l && elem[0:l] == "fixes" { elem = elem[l:] } else { break } - // Param: "MapfixID" - // Match until "/" - idx := strings.IndexByte(elem, '/') - if idx < 0 { - idx = len(elem) + if len(elem) == 0 { + switch r.Method { + case "GET": + s.handleListMapfixesRequest([0]string{}, elemIsEscaped, w, r) + case "POST": + s.handleCreateMapfixRequest([0]string{}, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "GET,POST") + } + + return + } + switch elem[0] { + case '/': // Prefix: "/" + + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + // Param: "MapfixID" + // Match until "/" + idx := strings.IndexByte(elem, '/') + if idx < 0 { + idx = len(elem) + } + args[0] = elem[:idx] + elem = elem[idx:] + + if len(elem) == 0 { + switch r.Method { + case "GET": + s.handleGetMapfixRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "GET") + } + + return + } + switch elem[0] { + case '/': // Prefix: "/" + + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'a': // Prefix: "audit-events" + + if l := len("audit-events"); len(elem) >= l && elem[0:l] == "audit-events" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "GET": + s.handleListMapfixAuditEventsRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "GET") + } + + return + } + + case 'c': // Prefix: "com" + + if l := len("com"); len(elem) >= l && elem[0:l] == "com" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'm': // Prefix: "ment" + + if l := len("ment"); len(elem) >= l && elem[0:l] == "ment" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleCreateMapfixAuditCommentRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + case 'p': // Prefix: "pleted" + + if l := len("pleted"); len(elem) >= l && elem[0:l] == "pleted" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleSetMapfixCompletedRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + } + + case 'm': // Prefix: "model" + + if l := len("model"); len(elem) >= l && elem[0:l] == "model" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleUpdateMapfixModelRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + case 's': // Prefix: "status/" + + if l := len("status/"); len(elem) >= l && elem[0:l] == "status/" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'r': // Prefix: "re" + + if l := len("re"); len(elem) >= l && elem[0:l] == "re" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'j': // Prefix: "ject" + + if l := len("ject"); len(elem) >= l && elem[0:l] == "ject" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleActionMapfixRejectRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + case 'q': // Prefix: "quest-changes" + + if l := len("quest-changes"); len(elem) >= l && elem[0:l] == "quest-changes" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleActionMapfixRequestChangesRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + case 's': // Prefix: "set-" + + if l := len("set-"); len(elem) >= l && elem[0:l] == "set-" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 's': // Prefix: "submitting" + + if l := len("submitting"); len(elem) >= l && elem[0:l] == "submitting" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleActionMapfixResetSubmittingRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + case 'u': // Prefix: "uploading" + + if l := len("uploading"); len(elem) >= l && elem[0:l] == "uploading" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleActionMapfixValidatedRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + case 'v': // Prefix: "validating" + + if l := len("validating"); len(elem) >= l && elem[0:l] == "validating" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleActionMapfixAcceptedRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + } + + case 't': // Prefix: "try-validate" + + if l := len("try-validate"); len(elem) >= l && elem[0:l] == "try-validate" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleActionMapfixRetryValidateRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + case 'v': // Prefix: "voke" + + if l := len("voke"); len(elem) >= l && elem[0:l] == "voke" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleActionMapfixRevokeRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + } + + case 't': // Prefix: "trigger-" + + if l := len("trigger-"); len(elem) >= l && elem[0:l] == "trigger-" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 's': // Prefix: "submit" + + if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + switch r.Method { + case "POST": + s.handleActionMapfixTriggerSubmitRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + switch elem[0] { + case '-': // Prefix: "-unchecked" + + if l := len("-unchecked"); len(elem) >= l && elem[0:l] == "-unchecked" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleActionMapfixTriggerSubmitUncheckedRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + } + + case 'u': // Prefix: "upload" + + if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleActionMapfixTriggerUploadRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + case 'v': // Prefix: "validate" + + if l := len("validate"); len(elem) >= l && elem[0:l] == "validate" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleActionMapfixTriggerValidateRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + } + + } + + } + + } + + } + + case 's': // Prefix: "s" + + if l := len("s"); len(elem) >= l && elem[0:l] == "s" { + elem = elem[l:] + } else { + break } - args[0] = elem[:idx] - elem = elem[idx:] if len(elem) == 0 { switch r.Method { case "GET": - s.handleGetMapfixRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) + s.handleListMapsRequest([0]string{}, elemIsEscaped, w, r) default: s.notAllowed(w, r, "GET") } @@ -132,13 +582,31 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { break } + // Param: "MapID" + // Match until "/" + idx := strings.IndexByte(elem, '/') + if idx < 0 { + idx = len(elem) + } + args[0] = elem[:idx] + elem = elem[idx:] + if len(elem) == 0 { - break + switch r.Method { + case "GET": + s.handleGetMapRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "GET") + } + + return } switch elem[0] { - case 'a': // Prefix: "audit-events" + case '/': // Prefix: "/download" - if l := len("audit-events"); len(elem) >= l && elem[0:l] == "audit-events" { + if l := len("/download"); len(elem) >= l && elem[0:l] == "/download" { elem = elem[l:] } else { break @@ -148,7 +616,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Leaf node. switch r.Method { case "GET": - s.handleListMapfixAuditEventsRequest([1]string{ + s.handleDownloadMapAssetRequest([1]string{ args[0], }, elemIsEscaped, w, r) default: @@ -158,465 +626,31 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - case 'c': // Prefix: "com" - - if l := len("com"); len(elem) >= l && elem[0:l] == "com" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - break - } - switch elem[0] { - case 'm': // Prefix: "ment" - - if l := len("ment"); len(elem) >= l && elem[0:l] == "ment" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "POST": - s.handleCreateMapfixAuditCommentRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - - case 'p': // Prefix: "pleted" - - if l := len("pleted"); len(elem) >= l && elem[0:l] == "pleted" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "POST": - s.handleSetMapfixCompletedRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - - } - - case 'm': // Prefix: "model" - - if l := len("model"); len(elem) >= l && elem[0:l] == "model" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "POST": - s.handleUpdateMapfixModelRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - - case 's': // Prefix: "status/" - - if l := len("status/"); len(elem) >= l && elem[0:l] == "status/" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - break - } - switch elem[0] { - case 'r': // Prefix: "re" - - if l := len("re"); len(elem) >= l && elem[0:l] == "re" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - break - } - switch elem[0] { - case 'j': // Prefix: "ject" - - if l := len("ject"); len(elem) >= l && elem[0:l] == "ject" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "POST": - s.handleActionMapfixRejectRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - - case 'q': // Prefix: "quest-changes" - - if l := len("quest-changes"); len(elem) >= l && elem[0:l] == "quest-changes" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "POST": - s.handleActionMapfixRequestChangesRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - - case 's': // Prefix: "set-" - - if l := len("set-"); len(elem) >= l && elem[0:l] == "set-" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - break - } - switch elem[0] { - case 's': // Prefix: "submitting" - - if l := len("submitting"); len(elem) >= l && elem[0:l] == "submitting" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "POST": - s.handleActionMapfixResetSubmittingRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - - case 'u': // Prefix: "uploading" - - if l := len("uploading"); len(elem) >= l && elem[0:l] == "uploading" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "POST": - s.handleActionMapfixValidatedRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - - case 'v': // Prefix: "validating" - - if l := len("validating"); len(elem) >= l && elem[0:l] == "validating" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "POST": - s.handleActionMapfixAcceptedRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - - } - - case 't': // Prefix: "try-validate" - - if l := len("try-validate"); len(elem) >= l && elem[0:l] == "try-validate" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "POST": - s.handleActionMapfixRetryValidateRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - - case 'v': // Prefix: "voke" - - if l := len("voke"); len(elem) >= l && elem[0:l] == "voke" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "POST": - s.handleActionMapfixRevokeRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - - } - - case 't': // Prefix: "trigger-" - - if l := len("trigger-"); len(elem) >= l && elem[0:l] == "trigger-" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - break - } - switch elem[0] { - case 's': // Prefix: "submit" - - if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - switch r.Method { - case "POST": - s.handleActionMapfixTriggerSubmitRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - switch elem[0] { - case '-': // Prefix: "-unchecked" - - if l := len("-unchecked"); len(elem) >= l && elem[0:l] == "-unchecked" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "POST": - s.handleActionMapfixTriggerSubmitUncheckedRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - - } - - case 'u': // Prefix: "upload" - - if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "POST": - s.handleActionMapfixTriggerUploadRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - - case 'v': // Prefix: "validate" - - if l := len("validate"); len(elem) >= l && elem[0:l] == "validate" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "POST": - s.handleActionMapfixTriggerValidateRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - - } - - } - } } } - case 's': // Prefix: "s" + case 'i': // Prefix: "igrate-maps" - if l := len("s"); len(elem) >= l && elem[0:l] == "s" { + if l := len("igrate-maps"); len(elem) >= l && elem[0:l] == "igrate-maps" { elem = elem[l:] } else { break } if len(elem) == 0 { + // Leaf node. switch r.Method { - case "GET": - s.handleListMapsRequest([0]string{}, elemIsEscaped, w, r) + case "POST": + s.handleMigrateMapsRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET") + s.notAllowed(w, r, "POST") } return } - switch elem[0] { - case '/': // Prefix: "/" - - if l := len("/"); len(elem) >= l && elem[0:l] == "/" { - elem = elem[l:] - } else { - break - } - - // Param: "MapID" - // Match until "/" - idx := strings.IndexByte(elem, '/') - if idx < 0 { - idx = len(elem) - } - args[0] = elem[:idx] - elem = elem[idx:] - - if len(elem) == 0 { - switch r.Method { - case "GET": - s.handleGetMapRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "GET") - } - - return - } - switch elem[0] { - case '/': // Prefix: "/download" - - if l := len("/download"); len(elem) >= l && elem[0:l] == "/download" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "GET": - s.handleDownloadMapAssetRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "GET") - } - - return - } - - } - - } } @@ -1481,9 +1515,9 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { break } switch elem[0] { - case 'm': // Prefix: "map" + case 'm': // Prefix: "m" - if l := len("map"); len(elem) >= l && elem[0:l] == "map" { + if l := len("m"); len(elem) >= l && elem[0:l] == "m" { elem = elem[l:] } else { break @@ -1493,63 +1527,43 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { break } switch elem[0] { - case 'f': // Prefix: "fixes" + case 'a': // Prefix: "ap" - if l := len("fixes"); len(elem) >= l && elem[0:l] == "fixes" { + if l := len("ap"); len(elem) >= l && elem[0:l] == "ap" { elem = elem[l:] } else { break } if len(elem) == 0 { - switch method { - case "GET": - r.name = ListMapfixesOperation - r.summary = "Get list of mapfixes" - r.operationID = "listMapfixes" - r.pathPattern = "/mapfixes" - r.args = args - r.count = 0 - return r, true - case "POST": - r.name = CreateMapfixOperation - r.summary = "Trigger the validator to create a mapfix" - r.operationID = "createMapfix" - r.pathPattern = "/mapfixes" - r.args = args - r.count = 0 - return r, true - default: - return - } + break } switch elem[0] { - case '/': // Prefix: "/" + case 'f': // Prefix: "fixes" - if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + if l := len("fixes"); len(elem) >= l && elem[0:l] == "fixes" { elem = elem[l:] } else { break } - // Param: "MapfixID" - // Match until "/" - idx := strings.IndexByte(elem, '/') - if idx < 0 { - idx = len(elem) - } - args[0] = elem[:idx] - elem = elem[idx:] - if len(elem) == 0 { switch method { case "GET": - r.name = GetMapfixOperation - r.summary = "Retrieve map with ID" - r.operationID = "getMapfix" - r.pathPattern = "/mapfixes/{MapfixID}" + r.name = ListMapfixesOperation + r.summary = "Get list of mapfixes" + r.operationID = "listMapfixes" + r.pathPattern = "/mapfixes" r.args = args - r.count = 1 + r.count = 0 + return r, true + case "POST": + r.name = CreateMapfixOperation + r.summary = "Trigger the validator to create a mapfix" + r.operationID = "createMapfix" + r.pathPattern = "/mapfixes" + r.args = args + r.count = 0 return r, true default: return @@ -1564,13 +1578,537 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { break } + // Param: "MapfixID" + // Match until "/" + idx := strings.IndexByte(elem, '/') + if idx < 0 { + idx = len(elem) + } + args[0] = elem[:idx] + elem = elem[idx:] + if len(elem) == 0 { - break + switch method { + case "GET": + r.name = GetMapfixOperation + r.summary = "Retrieve map with ID" + r.operationID = "getMapfix" + r.pathPattern = "/mapfixes/{MapfixID}" + r.args = args + r.count = 1 + return r, true + default: + return + } } switch elem[0] { - case 'a': // Prefix: "audit-events" + case '/': // Prefix: "/" - if l := len("audit-events"); len(elem) >= l && elem[0:l] == "audit-events" { + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'a': // Prefix: "audit-events" + + if l := len("audit-events"); len(elem) >= l && elem[0:l] == "audit-events" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "GET": + r.name = ListMapfixAuditEventsOperation + r.summary = "Retrieve a list of audit events" + r.operationID = "listMapfixAuditEvents" + r.pathPattern = "/mapfixes/{MapfixID}/audit-events" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + case 'c': // Prefix: "com" + + if l := len("com"); len(elem) >= l && elem[0:l] == "com" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'm': // Prefix: "ment" + + if l := len("ment"); len(elem) >= l && elem[0:l] == "ment" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = CreateMapfixAuditCommentOperation + r.summary = "Post a comment to the audit log" + r.operationID = "createMapfixAuditComment" + r.pathPattern = "/mapfixes/{MapfixID}/comment" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + case 'p': // Prefix: "pleted" + + if l := len("pleted"); len(elem) >= l && elem[0:l] == "pleted" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = SetMapfixCompletedOperation + r.summary = "Called by maptest when a player completes the map" + r.operationID = "setMapfixCompleted" + r.pathPattern = "/mapfixes/{MapfixID}/completed" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + } + + case 'm': // Prefix: "model" + + if l := len("model"); len(elem) >= l && elem[0:l] == "model" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = UpdateMapfixModelOperation + r.summary = "Update model following role restrictions" + r.operationID = "updateMapfixModel" + r.pathPattern = "/mapfixes/{MapfixID}/model" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + case 's': // Prefix: "status/" + + if l := len("status/"); len(elem) >= l && elem[0:l] == "status/" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'r': // Prefix: "re" + + if l := len("re"); len(elem) >= l && elem[0:l] == "re" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'j': // Prefix: "ject" + + if l := len("ject"); len(elem) >= l && elem[0:l] == "ject" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = ActionMapfixRejectOperation + r.summary = "Role Reviewer changes status from Submitted -> Rejected" + r.operationID = "actionMapfixReject" + r.pathPattern = "/mapfixes/{MapfixID}/status/reject" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + case 'q': // Prefix: "quest-changes" + + if l := len("quest-changes"); len(elem) >= l && elem[0:l] == "quest-changes" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = ActionMapfixRequestChangesOperation + r.summary = "Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested" + r.operationID = "actionMapfixRequestChanges" + r.pathPattern = "/mapfixes/{MapfixID}/status/request-changes" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + case 's': // Prefix: "set-" + + if l := len("set-"); len(elem) >= l && elem[0:l] == "set-" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 's': // Prefix: "submitting" + + if l := len("submitting"); len(elem) >= l && elem[0:l] == "submitting" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = ActionMapfixResetSubmittingOperation + r.summary = "Role Submitter manually resets submitting softlock and changes status from Submitting -> UnderConstruction" + r.operationID = "actionMapfixResetSubmitting" + r.pathPattern = "/mapfixes/{MapfixID}/status/reset-submitting" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + case 'u': // Prefix: "uploading" + + if l := len("uploading"); len(elem) >= l && elem[0:l] == "uploading" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = ActionMapfixValidatedOperation + r.summary = "Role Admin manually resets uploading softlock and changes status from Uploading -> Validated" + r.operationID = "actionMapfixValidated" + r.pathPattern = "/mapfixes/{MapfixID}/status/reset-uploading" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + case 'v': // Prefix: "validating" + + if l := len("validating"); len(elem) >= l && elem[0:l] == "validating" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = ActionMapfixAcceptedOperation + r.summary = "Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted" + r.operationID = "actionMapfixAccepted" + r.pathPattern = "/mapfixes/{MapfixID}/status/reset-validating" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + } + + case 't': // Prefix: "try-validate" + + if l := len("try-validate"); len(elem) >= l && elem[0:l] == "try-validate" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = ActionMapfixRetryValidateOperation + r.summary = "Role Reviewer re-runs validation and changes status from Accepted -> Validating" + r.operationID = "actionMapfixRetryValidate" + r.pathPattern = "/mapfixes/{MapfixID}/status/retry-validate" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + case 'v': // Prefix: "voke" + + if l := len("voke"); len(elem) >= l && elem[0:l] == "voke" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = ActionMapfixRevokeOperation + r.summary = "Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction" + r.operationID = "actionMapfixRevoke" + r.pathPattern = "/mapfixes/{MapfixID}/status/revoke" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + } + + case 't': // Prefix: "trigger-" + + if l := len("trigger-"); len(elem) >= l && elem[0:l] == "trigger-" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 's': // Prefix: "submit" + + if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + switch method { + case "POST": + r.name = ActionMapfixTriggerSubmitOperation + r.summary = "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting" + r.operationID = "actionMapfixTriggerSubmit" + r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-submit" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + switch elem[0] { + case '-': // Prefix: "-unchecked" + + if l := len("-unchecked"); len(elem) >= l && elem[0:l] == "-unchecked" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = ActionMapfixTriggerSubmitUncheckedOperation + r.summary = "Role Reviewer changes status from ChangesRequested -> Submitting" + r.operationID = "actionMapfixTriggerSubmitUnchecked" + r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-submit-unchecked" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + } + + case 'u': // Prefix: "upload" + + if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = ActionMapfixTriggerUploadOperation + r.summary = "Role Admin changes status from Validated -> Uploading" + r.operationID = "actionMapfixTriggerUpload" + r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-upload" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + case 'v': // Prefix: "validate" + + if l := len("validate"); len(elem) >= l && elem[0:l] == "validate" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = ActionMapfixTriggerValidateOperation + r.summary = "Role Reviewer triggers validation and changes status from Submitted -> Validating" + r.operationID = "actionMapfixTriggerValidate" + r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-validate" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + } + + } + + } + + } + + } + + case 's': // Prefix: "s" + + if l := len("s"); len(elem) >= l && elem[0:l] == "s" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + switch method { + case "GET": + r.name = ListMapsOperation + r.summary = "Get list of maps" + r.operationID = "listMaps" + r.pathPattern = "/maps" + r.args = args + r.count = 0 + return r, true + default: + return + } + } + switch elem[0] { + case '/': // Prefix: "/" + + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + // Param: "MapID" + // Match until "/" + idx := strings.IndexByte(elem, '/') + if idx < 0 { + idx = len(elem) + } + args[0] = elem[:idx] + elem = elem[idx:] + + if len(elem) == 0 { + switch method { + case "GET": + r.name = GetMapOperation + r.summary = "Retrieve map with ID" + r.operationID = "getMap" + r.pathPattern = "/maps/{MapID}" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + switch elem[0] { + case '/': // Prefix: "/download" + + if l := len("/download"); len(elem) >= l && elem[0:l] == "/download" { elem = elem[l:] } else { break @@ -1580,10 +2118,10 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { // Leaf node. switch method { case "GET": - r.name = ListMapfixAuditEventsOperation - r.summary = "Retrieve a list of audit events" - r.operationID = "listMapfixAuditEvents" - r.pathPattern = "/mapfixes/{MapfixID}/audit-events" + r.name = DownloadMapAssetOperation + r.summary = "Download the map asset" + r.operationID = "downloadMapAsset" + r.pathPattern = "/maps/{MapID}/download" r.args = args r.count = 1 return r, true @@ -1592,434 +2130,28 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { } } - case 'c': // Prefix: "com" - - if l := len("com"); len(elem) >= l && elem[0:l] == "com" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - break - } - switch elem[0] { - case 'm': // Prefix: "ment" - - if l := len("ment"); len(elem) >= l && elem[0:l] == "ment" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "POST": - r.name = CreateMapfixAuditCommentOperation - r.summary = "Post a comment to the audit log" - r.operationID = "createMapfixAuditComment" - r.pathPattern = "/mapfixes/{MapfixID}/comment" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - case 'p': // Prefix: "pleted" - - if l := len("pleted"); len(elem) >= l && elem[0:l] == "pleted" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "POST": - r.name = SetMapfixCompletedOperation - r.summary = "Called by maptest when a player completes the map" - r.operationID = "setMapfixCompleted" - r.pathPattern = "/mapfixes/{MapfixID}/completed" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - } - - case 'm': // Prefix: "model" - - if l := len("model"); len(elem) >= l && elem[0:l] == "model" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "POST": - r.name = UpdateMapfixModelOperation - r.summary = "Update model following role restrictions" - r.operationID = "updateMapfixModel" - r.pathPattern = "/mapfixes/{MapfixID}/model" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - case 's': // Prefix: "status/" - - if l := len("status/"); len(elem) >= l && elem[0:l] == "status/" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - break - } - switch elem[0] { - case 'r': // Prefix: "re" - - if l := len("re"); len(elem) >= l && elem[0:l] == "re" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - break - } - switch elem[0] { - case 'j': // Prefix: "ject" - - if l := len("ject"); len(elem) >= l && elem[0:l] == "ject" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "POST": - r.name = ActionMapfixRejectOperation - r.summary = "Role Reviewer changes status from Submitted -> Rejected" - r.operationID = "actionMapfixReject" - r.pathPattern = "/mapfixes/{MapfixID}/status/reject" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - case 'q': // Prefix: "quest-changes" - - if l := len("quest-changes"); len(elem) >= l && elem[0:l] == "quest-changes" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "POST": - r.name = ActionMapfixRequestChangesOperation - r.summary = "Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested" - r.operationID = "actionMapfixRequestChanges" - r.pathPattern = "/mapfixes/{MapfixID}/status/request-changes" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - case 's': // Prefix: "set-" - - if l := len("set-"); len(elem) >= l && elem[0:l] == "set-" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - break - } - switch elem[0] { - case 's': // Prefix: "submitting" - - if l := len("submitting"); len(elem) >= l && elem[0:l] == "submitting" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "POST": - r.name = ActionMapfixResetSubmittingOperation - r.summary = "Role Submitter manually resets submitting softlock and changes status from Submitting -> UnderConstruction" - r.operationID = "actionMapfixResetSubmitting" - r.pathPattern = "/mapfixes/{MapfixID}/status/reset-submitting" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - case 'u': // Prefix: "uploading" - - if l := len("uploading"); len(elem) >= l && elem[0:l] == "uploading" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "POST": - r.name = ActionMapfixValidatedOperation - r.summary = "Role Admin manually resets uploading softlock and changes status from Uploading -> Validated" - r.operationID = "actionMapfixValidated" - r.pathPattern = "/mapfixes/{MapfixID}/status/reset-uploading" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - case 'v': // Prefix: "validating" - - if l := len("validating"); len(elem) >= l && elem[0:l] == "validating" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "POST": - r.name = ActionMapfixAcceptedOperation - r.summary = "Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted" - r.operationID = "actionMapfixAccepted" - r.pathPattern = "/mapfixes/{MapfixID}/status/reset-validating" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - } - - case 't': // Prefix: "try-validate" - - if l := len("try-validate"); len(elem) >= l && elem[0:l] == "try-validate" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "POST": - r.name = ActionMapfixRetryValidateOperation - r.summary = "Role Reviewer re-runs validation and changes status from Accepted -> Validating" - r.operationID = "actionMapfixRetryValidate" - r.pathPattern = "/mapfixes/{MapfixID}/status/retry-validate" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - case 'v': // Prefix: "voke" - - if l := len("voke"); len(elem) >= l && elem[0:l] == "voke" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "POST": - r.name = ActionMapfixRevokeOperation - r.summary = "Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction" - r.operationID = "actionMapfixRevoke" - r.pathPattern = "/mapfixes/{MapfixID}/status/revoke" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - } - - case 't': // Prefix: "trigger-" - - if l := len("trigger-"); len(elem) >= l && elem[0:l] == "trigger-" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - break - } - switch elem[0] { - case 's': // Prefix: "submit" - - if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - switch method { - case "POST": - r.name = ActionMapfixTriggerSubmitOperation - r.summary = "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting" - r.operationID = "actionMapfixTriggerSubmit" - r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-submit" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - switch elem[0] { - case '-': // Prefix: "-unchecked" - - if l := len("-unchecked"); len(elem) >= l && elem[0:l] == "-unchecked" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "POST": - r.name = ActionMapfixTriggerSubmitUncheckedOperation - r.summary = "Role Reviewer changes status from ChangesRequested -> Submitting" - r.operationID = "actionMapfixTriggerSubmitUnchecked" - r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-submit-unchecked" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - } - - case 'u': // Prefix: "upload" - - if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "POST": - r.name = ActionMapfixTriggerUploadOperation - r.summary = "Role Admin changes status from Validated -> Uploading" - r.operationID = "actionMapfixTriggerUpload" - r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-upload" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - case 'v': // Prefix: "validate" - - if l := len("validate"); len(elem) >= l && elem[0:l] == "validate" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "POST": - r.name = ActionMapfixTriggerValidateOperation - r.summary = "Role Reviewer triggers validation and changes status from Submitted -> Validating" - r.operationID = "actionMapfixTriggerValidate" - r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-validate" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - } - - } - } } } - case 's': // Prefix: "s" + case 'i': // Prefix: "igrate-maps" - if l := len("s"); len(elem) >= l && elem[0:l] == "s" { + if l := len("igrate-maps"); len(elem) >= l && elem[0:l] == "igrate-maps" { elem = elem[l:] } else { break } if len(elem) == 0 { + // Leaf node. switch method { - case "GET": - r.name = ListMapsOperation - r.summary = "Get list of maps" - r.operationID = "listMaps" - r.pathPattern = "/maps" + case "POST": + r.name = MigrateMapsOperation + r.summary = "Perform maps migration" + r.operationID = "migrateMaps" + r.pathPattern = "/migrate-maps" r.args = args r.count = 0 return r, true @@ -2027,66 +2159,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { return } } - switch elem[0] { - case '/': // Prefix: "/" - - if l := len("/"); len(elem) >= l && elem[0:l] == "/" { - elem = elem[l:] - } else { - break - } - - // Param: "MapID" - // Match until "/" - idx := strings.IndexByte(elem, '/') - if idx < 0 { - idx = len(elem) - } - args[0] = elem[:idx] - elem = elem[idx:] - - if len(elem) == 0 { - switch method { - case "GET": - r.name = GetMapOperation - r.summary = "Retrieve map with ID" - r.operationID = "getMap" - r.pathPattern = "/maps/{MapID}" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - switch elem[0] { - case '/': // Prefix: "/download" - - if l := len("/download"); len(elem) >= l && elem[0:l] == "/download" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "GET": - r.name = DownloadMapAssetOperation - r.summary = "Download the map asset" - r.operationID = "downloadMapAsset" - r.pathPattern = "/maps/{MapID}/download" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - } - - } } diff --git a/pkg/api/oas_schemas_gen.go b/pkg/api/oas_schemas_gen.go index 26b80ca..35db0c6 100644 --- a/pkg/api/oas_schemas_gen.go +++ b/pkg/api/oas_schemas_gen.go @@ -587,6 +587,9 @@ func (s *Mapfixes) SetMapfixes(val []Mapfix) { s.Mapfixes = val } +// MigrateMapsOK is response for MigrateMaps operation. +type MigrateMapsOK struct{} + // Ref: #/components/schemas/Operation type Operation struct { OperationID int32 `json:"OperationID"` diff --git a/pkg/api/oas_security_gen.go b/pkg/api/oas_security_gen.go index 100c173..4fb1167 100644 --- a/pkg/api/oas_security_gen.go +++ b/pkg/api/oas_security_gen.go @@ -67,6 +67,7 @@ var operationRolesCookieAuth = map[string][]string{ DeleteScriptPolicyOperation: []string{}, DownloadMapAssetOperation: []string{}, GetOperationOperation: []string{}, + MigrateMapsOperation: []string{}, ReleaseSubmissionsOperation: []string{}, SessionRolesOperation: []string{}, SessionUserOperation: []string{}, diff --git a/pkg/api/oas_server_gen.go b/pkg/api/oas_server_gen.go index bc8d72e..ee1ddc3 100644 --- a/pkg/api/oas_server_gen.go +++ b/pkg/api/oas_server_gen.go @@ -280,6 +280,12 @@ type Handler interface { // // GET /submissions ListSubmissions(ctx context.Context, params ListSubmissionsParams) (*Submissions, error) + // MigrateMaps implements migrateMaps operation. + // + // Perform maps migration. + // + // POST /migrate-maps + MigrateMaps(ctx context.Context) error // ReleaseSubmissions implements releaseSubmissions operation. // // Release a set of uploaded maps. diff --git a/pkg/api/oas_unimplemented_gen.go b/pkg/api/oas_unimplemented_gen.go index 2c74330..238e748 100644 --- a/pkg/api/oas_unimplemented_gen.go +++ b/pkg/api/oas_unimplemented_gen.go @@ -420,6 +420,15 @@ func (UnimplementedHandler) ListSubmissions(ctx context.Context, params ListSubm return r, ht.ErrNotImplemented } +// MigrateMaps implements migrateMaps operation. +// +// Perform maps migration. +// +// POST /migrate-maps +func (UnimplementedHandler) MigrateMaps(ctx context.Context) error { + return ht.ErrNotImplemented +} + // ReleaseSubmissions implements releaseSubmissions operation. // // Release a set of uploaded maps. -- 2.49.1 From bdfd1a0b23399175601a361cbeb8f5895c6bee0f Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 22 Jul 2025 19:46:35 -0700 Subject: [PATCH 7/9] submissions: temporary migration endpoint --- pkg/service/maps.go | 32 +++++++++++++++++++++++++++++++- pkg/web_api/maps.go | 23 +++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/pkg/service/maps.go b/pkg/service/maps.go index ea612e1..4294f10 100644 --- a/pkg/service/maps.go +++ b/pkg/service/maps.go @@ -2,10 +2,11 @@ package service import ( "context" + "time" "git.itzana.me/strafesnet/go-grpc/maps" - "git.itzana.me/strafesnet/maps-service/pkg/model" "git.itzana.me/strafesnet/maps-service/pkg/datastore" + "git.itzana.me/strafesnet/maps-service/pkg/model" ) // Optional map used to update an object @@ -80,6 +81,35 @@ func (update MapFilter) SetSubmitter(submitter uint64) { datastore.OptionalMap(update).Add("submitter", submitter) } +func (svc *Service) TEMP_DoMapsMigration(ctx context.Context) (error) { + // get all maps + maps, err := svc.maps.List(ctx, &maps.ListRequest{}) + if err != nil { + return err + } + // create all maps + for _, item := range maps.Maps { + migrated := model.Map{ + ID: item.ID, + DisplayName: item.DisplayName, + Creator: item.Creator, + GameID: item.GameID, + Date: time.Unix(item.Date, 0), + // CreatedAt: time.Time{}, + // UpdatedAt: time.Time{}, + // Submitter: 0, + // Thumbnail: 0, + // AssetVersion: 0, + // LoadCount: 0, + // Modes: 0, + } + _, err := svc.db.Maps().Create(ctx, migrated) + if err != nil { + return err + } + } + return nil +} func (svc *Service) CreateMap(ctx context.Context, item model.Map) (int64, error) { // 2 jobs: // create map on maps-service diff --git a/pkg/web_api/maps.go b/pkg/web_api/maps.go index 42cce62..c3bdde0 100644 --- a/pkg/web_api/maps.go +++ b/pkg/web_api/maps.go @@ -9,6 +9,29 @@ import ( "git.itzana.me/strafesnet/maps-service/pkg/service" ) +// MigrateMaps implements migrateMaps operation. +// +// Perform maps migration. +// +// POST /migrate +func (svc *Service) MigrateMaps(ctx context.Context) (error) { + userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle) + if !ok { + return ErrUserInfo + } + + has_role, err := userInfo.HasRoleSubmissionRelease() + if err != nil { + return err + } + + if !has_role { + return ErrPermissionDeniedNeedRoleSubmissionRelease + } + + return svc.inner.TEMP_DoMapsMigration(ctx) +} + // ListMaps implements listMaps operation. // // Get list of maps. -- 2.49.1 From a4cefd263d5d53376351b225cdd7791af1aa3b68 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Wed, 23 Jul 2025 22:19:42 -0700 Subject: [PATCH 8/9] submissions: maps: guard against null pointers --- pkg/controller/maps.go | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/pkg/controller/maps.go b/pkg/controller/maps.go index 49c5d18..2110034 100644 --- a/pkg/controller/maps.go +++ b/pkg/controller/maps.go @@ -2,6 +2,7 @@ package controller import ( "context" + "errors" "time" "git.itzana.me/strafesnet/go-grpc/maps_extended" @@ -9,6 +10,10 @@ import ( "git.itzana.me/strafesnet/maps-service/pkg/service" ) +var ( + PageError = errors.New("Pagination required") +) + type Maps struct { *maps_extended.UnimplementedMapsServiceServer inner *service.Service @@ -100,18 +105,24 @@ func (svc *Maps) GetList(ctx context.Context, request *maps_extended.MapIdList) return &resp, nil } func (svc *Maps) List(ctx context.Context, request *maps_extended.ListRequest) (*maps_extended.MapList, error) { + if request.Page == nil { + return nil, PageError + } + filter := service.NewMapFilter() - if request.Filter.DisplayName != nil { - filter.SetDisplayName(*request.Filter.DisplayName) - } - if request.Filter.Creator != nil { - filter.SetCreator(*request.Filter.Creator) - } - if request.Filter.GameID != nil { - filter.SetGameID(*request.Filter.GameID) - } - if request.Filter.Submitter != nil { - filter.SetSubmitter(*request.Filter.Submitter) + if request.Filter != nil { + if request.Filter.DisplayName != nil { + filter.SetDisplayName(*request.Filter.DisplayName) + } + if request.Filter.Creator != nil { + filter.SetCreator(*request.Filter.Creator) + } + if request.Filter.GameID != nil { + filter.SetGameID(*request.Filter.GameID) + } + if request.Filter.Submitter != nil { + filter.SetSubmitter(*request.Filter.Submitter) + } } items, err := svc.inner.ListMaps(ctx, filter, model.Page{ -- 2.49.1 From 2578a74ddbd1b4493d839b100550f68bb7eee739 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Wed, 23 Jul 2025 23:18:34 -0700 Subject: [PATCH 9/9] submissions: use unsigned ints in maps struct --- pkg/controller/maps.go | 8 ++++---- pkg/model/map.go | 8 ++++---- pkg/service/maps.go | 5 +++-- pkg/web_api/maps.go | 4 ++-- pkg/web_api/submissions.go | 5 ++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/pkg/controller/maps.go b/pkg/controller/maps.go index 2110034..d751d64 100644 --- a/pkg/controller/maps.go +++ b/pkg/controller/maps.go @@ -32,11 +32,11 @@ func (svc *Maps) Create(ctx context.Context, request *maps_extended.MapCreate) ( ID: request.ID, DisplayName: request.DisplayName, Creator: request.Creator, - GameID: int32(request.GameID), - Submitter: int64(request.Submitter), + GameID: request.GameID, + Submitter: request.Submitter, Date: time.Unix(request.Date, 0), - Thumbnail: int64(request.Thumbnail), - AssetVersion: int64(request.AssetVersion), + Thumbnail: request.Thumbnail, + AssetVersion: request.AssetVersion, LoadCount: 0, Modes: request.Modes, }) diff --git a/pkg/model/map.go b/pkg/model/map.go index 314b678..78298f3 100644 --- a/pkg/model/map.go +++ b/pkg/model/map.go @@ -6,13 +6,13 @@ type Map struct { ID int64 DisplayName string Creator string - GameID int32 + GameID uint32 Date time.Time // Release date CreatedAt time.Time UpdatedAt time.Time - Submitter int64 // UserID of submitter - Thumbnail int64 // AssetID of thumbnail - AssetVersion int64 // Version number for LoadAssetVersion + Submitter uint64 // UserID of submitter + Thumbnail uint64 // AssetID of thumbnail + AssetVersion uint64 // Version number for LoadAssetVersion LoadCount uint32 // How many times the map has been loaded Modes uint32 // Number of modes (always at least one) } diff --git a/pkg/service/maps.go b/pkg/service/maps.go index 4294f10..beb6809 100644 --- a/pkg/service/maps.go +++ b/pkg/service/maps.go @@ -93,7 +93,7 @@ func (svc *Service) TEMP_DoMapsMigration(ctx context.Context) (error) { ID: item.ID, DisplayName: item.DisplayName, Creator: item.Creator, - GameID: item.GameID, + GameID: uint32(item.GameID), Date: time.Unix(item.Date, 0), // CreatedAt: time.Time{}, // UpdatedAt: time.Time{}, @@ -119,11 +119,12 @@ func (svc *Service) CreateMap(ctx context.Context, item model.Map) (int64, error } // create map on data-service date := item.Date.Unix() + game_id := int32(item.GameID) _, err = svc.maps.Create(ctx, &maps.MapRequest{ ID: item.ID, DisplayName: &item.DisplayName, Creator: &item.Creator, - GameID: &item.GameID, + GameID: &game_id, Date: &date, }) if err != nil { diff --git a/pkg/web_api/maps.go b/pkg/web_api/maps.go index c3bdde0..0475992 100644 --- a/pkg/web_api/maps.go +++ b/pkg/web_api/maps.go @@ -67,7 +67,7 @@ func (svc *Service) ListMaps(ctx context.Context, params api.ListMapsParams) ([] ID: item.ID, DisplayName: item.DisplayName, Creator: item.Creator, - GameID: item.GameID, + GameID: int32(item.GameID), Date: item.Date.Unix(), }) } @@ -90,7 +90,7 @@ func (svc *Service) GetMap(ctx context.Context, params api.GetMapParams) (*api.M ID: mapResponse.ID, DisplayName: mapResponse.DisplayName, Creator: mapResponse.Creator, - GameID: mapResponse.GameID, + GameID: int32(mapResponse.GameID), Date: mapResponse.Date.Unix(), }, nil } diff --git a/pkg/web_api/submissions.go b/pkg/web_api/submissions.go index 158701b..a167454 100644 --- a/pkg/web_api/submissions.go +++ b/pkg/web_api/submissions.go @@ -1076,15 +1076,14 @@ func (svc *Service) ReleaseSubmissions(ctx context.Context, request []api.Releas for i,submission := range submissions{ date := request[i].Date.Unix() - var GameID = int32(submission.GameID) // create each map with go-grpc _, err := svc.inner.CreateMap(ctx, model.Map{ ID: int64(submission.UploadedAssetID), DisplayName: submission.DisplayName, Creator: submission.Creator, - GameID: GameID, + GameID: submission.GameID, Date: time.Unix(date, 0), - Submitter: int64(submission.Submitter), + Submitter: submission.Submitter, // Thumbnail: 0, // AssetVersion: 0, // LoadCount: 0, -- 2.49.1