1 Commits

Author SHA1 Message Date
dec94da015 wip: web: clone submissions page for maps
All checks were successful
continuous-integration/drone/push Build is passing
2025-04-01 14:16:39 -07:00
35 changed files with 128 additions and 941 deletions

View File

@@ -86,21 +86,6 @@ paths:
parameters:
- $ref: "#/components/parameters/Page"
- $ref: "#/components/parameters/Limit"
- name: DisplayName
in: query
schema:
type: string
maxLength: 128
- name: Creator
in: query
schema:
type: string
maxLength: 128
- name: GameID
in: query
schema:
type: integer
format: int32
- name: Sort
in: query
schema:
@@ -1033,9 +1018,6 @@ components:
Mapfix:
required:
- ID
- DisplayName
- Creator
- GameID
- CreatedAt
- UpdatedAt
- Submitter
@@ -1050,15 +1032,6 @@ components:
ID:
type: integer
format: int64
DisplayName:
type: string
maxLength: 128
Creator:
type: string
maxLength: 128
GameID:
type: integer
format: int32
CreatedAt:
type: integer
format: int64
@@ -1087,23 +1060,11 @@ components:
maxLength: 256
MapfixCreate:
required:
- DisplayName
- Creator
- GameID
- AssetID
- AssetVersion
- TargetAssetID
type: object
properties:
DisplayName:
type: string
maxLength: 128
Creator:
type: string
maxLength: 128
GameID:
type: integer
format: int32
AssetID:
type: integer
format: int64

View File

@@ -3682,57 +3682,6 @@ func (c *Client) sendListMapfixes(ctx context.Context, params ListMapfixesParams
return res, errors.Wrap(err, "encode query")
}
}
{
// Encode "DisplayName" parameter.
cfg := uri.QueryParameterEncodingConfig{
Name: "DisplayName",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
if val, ok := params.DisplayName.Get(); ok {
return e.EncodeValue(conv.StringToString(val))
}
return nil
}); err != nil {
return res, errors.Wrap(err, "encode query")
}
}
{
// Encode "Creator" parameter.
cfg := uri.QueryParameterEncodingConfig{
Name: "Creator",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
if val, ok := params.Creator.Get(); ok {
return e.EncodeValue(conv.StringToString(val))
}
return nil
}); err != nil {
return res, errors.Wrap(err, "encode query")
}
}
{
// Encode "GameID" parameter.
cfg := uri.QueryParameterEncodingConfig{
Name: "GameID",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
if val, ok := params.GameID.Get(); ok {
return e.EncodeValue(conv.Int32ToString(val))
}
return nil
}); err != nil {
return res, errors.Wrap(err, "encode query")
}
}
{
// Encode "Sort" parameter.
cfg := uri.QueryParameterEncodingConfig{

View File

@@ -5408,18 +5408,6 @@ func (s *Server) handleListMapfixesRequest(args [0]string, argsEscaped bool, w h
Name: "Limit",
In: "query",
}: params.Limit,
{
Name: "DisplayName",
In: "query",
}: params.DisplayName,
{
Name: "Creator",
In: "query",
}: params.Creator,
{
Name: "GameID",
In: "query",
}: params.GameID,
{
Name: "Sort",
In: "query",

View File

@@ -235,18 +235,6 @@ func (s *Mapfix) encodeFields(e *jx.Encoder) {
e.FieldStart("ID")
e.Int64(s.ID)
}
{
e.FieldStart("DisplayName")
e.Str(s.DisplayName)
}
{
e.FieldStart("Creator")
e.Str(s.Creator)
}
{
e.FieldStart("GameID")
e.Int32(s.GameID)
}
{
e.FieldStart("CreatedAt")
e.Int64(s.CreatedAt)
@@ -285,20 +273,17 @@ func (s *Mapfix) encodeFields(e *jx.Encoder) {
}
}
var jsonFieldsNameOfMapfix = [13]string{
0: "ID",
1: "DisplayName",
2: "Creator",
3: "GameID",
4: "CreatedAt",
5: "UpdatedAt",
6: "Submitter",
7: "AssetID",
8: "AssetVersion",
9: "Completed",
10: "TargetAssetID",
11: "StatusID",
12: "StatusMessage",
var jsonFieldsNameOfMapfix = [10]string{
0: "ID",
1: "CreatedAt",
2: "UpdatedAt",
3: "Submitter",
4: "AssetID",
5: "AssetVersion",
6: "Completed",
7: "TargetAssetID",
8: "StatusID",
9: "StatusMessage",
}
// Decode decodes Mapfix from json.
@@ -322,44 +307,8 @@ func (s *Mapfix) Decode(d *jx.Decoder) error {
}(); err != nil {
return errors.Wrap(err, "decode field \"ID\"")
}
case "DisplayName":
requiredBitSet[0] |= 1 << 1
if err := func() error {
v, err := d.Str()
s.DisplayName = string(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"DisplayName\"")
}
case "Creator":
requiredBitSet[0] |= 1 << 2
if err := func() error {
v, err := d.Str()
s.Creator = string(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Creator\"")
}
case "GameID":
requiredBitSet[0] |= 1 << 3
if err := func() error {
v, err := d.Int32()
s.GameID = int32(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"GameID\"")
}
case "CreatedAt":
requiredBitSet[0] |= 1 << 4
requiredBitSet[0] |= 1 << 1
if err := func() error {
v, err := d.Int64()
s.CreatedAt = int64(v)
@@ -371,7 +320,7 @@ func (s *Mapfix) Decode(d *jx.Decoder) error {
return errors.Wrap(err, "decode field \"CreatedAt\"")
}
case "UpdatedAt":
requiredBitSet[0] |= 1 << 5
requiredBitSet[0] |= 1 << 2
if err := func() error {
v, err := d.Int64()
s.UpdatedAt = int64(v)
@@ -383,7 +332,7 @@ func (s *Mapfix) Decode(d *jx.Decoder) error {
return errors.Wrap(err, "decode field \"UpdatedAt\"")
}
case "Submitter":
requiredBitSet[0] |= 1 << 6
requiredBitSet[0] |= 1 << 3
if err := func() error {
v, err := d.Int64()
s.Submitter = int64(v)
@@ -395,7 +344,7 @@ func (s *Mapfix) Decode(d *jx.Decoder) error {
return errors.Wrap(err, "decode field \"Submitter\"")
}
case "AssetID":
requiredBitSet[0] |= 1 << 7
requiredBitSet[0] |= 1 << 4
if err := func() error {
v, err := d.Int64()
s.AssetID = int64(v)
@@ -407,7 +356,7 @@ func (s *Mapfix) Decode(d *jx.Decoder) error {
return errors.Wrap(err, "decode field \"AssetID\"")
}
case "AssetVersion":
requiredBitSet[1] |= 1 << 0
requiredBitSet[0] |= 1 << 5
if err := func() error {
v, err := d.Int64()
s.AssetVersion = int64(v)
@@ -419,7 +368,7 @@ func (s *Mapfix) Decode(d *jx.Decoder) error {
return errors.Wrap(err, "decode field \"AssetVersion\"")
}
case "Completed":
requiredBitSet[1] |= 1 << 1
requiredBitSet[0] |= 1 << 6
if err := func() error {
v, err := d.Bool()
s.Completed = bool(v)
@@ -431,7 +380,7 @@ func (s *Mapfix) Decode(d *jx.Decoder) error {
return errors.Wrap(err, "decode field \"Completed\"")
}
case "TargetAssetID":
requiredBitSet[1] |= 1 << 2
requiredBitSet[0] |= 1 << 7
if err := func() error {
v, err := d.Int64()
s.TargetAssetID = int64(v)
@@ -443,7 +392,7 @@ func (s *Mapfix) Decode(d *jx.Decoder) error {
return errors.Wrap(err, "decode field \"TargetAssetID\"")
}
case "StatusID":
requiredBitSet[1] |= 1 << 3
requiredBitSet[1] |= 1 << 0
if err := func() error {
v, err := d.Int32()
s.StatusID = int32(v)
@@ -455,7 +404,7 @@ func (s *Mapfix) Decode(d *jx.Decoder) error {
return errors.Wrap(err, "decode field \"StatusID\"")
}
case "StatusMessage":
requiredBitSet[1] |= 1 << 4
requiredBitSet[1] |= 1 << 1
if err := func() error {
v, err := d.Str()
s.StatusMessage = string(v)
@@ -477,7 +426,7 @@ func (s *Mapfix) Decode(d *jx.Decoder) error {
var failures []validate.FieldError
for i, mask := range [2]uint8{
0b11111111,
0b00011111,
0b00000011,
} {
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
// Mask only required fields and check equality to mask using XOR.
@@ -532,18 +481,6 @@ func (s *MapfixCreate) Encode(e *jx.Encoder) {
// encodeFields encodes fields.
func (s *MapfixCreate) encodeFields(e *jx.Encoder) {
{
e.FieldStart("DisplayName")
e.Str(s.DisplayName)
}
{
e.FieldStart("Creator")
e.Str(s.Creator)
}
{
e.FieldStart("GameID")
e.Int32(s.GameID)
}
{
e.FieldStart("AssetID")
e.Int64(s.AssetID)
@@ -558,13 +495,10 @@ func (s *MapfixCreate) encodeFields(e *jx.Encoder) {
}
}
var jsonFieldsNameOfMapfixCreate = [6]string{
0: "DisplayName",
1: "Creator",
2: "GameID",
3: "AssetID",
4: "AssetVersion",
5: "TargetAssetID",
var jsonFieldsNameOfMapfixCreate = [3]string{
0: "AssetID",
1: "AssetVersion",
2: "TargetAssetID",
}
// Decode decodes MapfixCreate from json.
@@ -576,44 +510,8 @@ func (s *MapfixCreate) Decode(d *jx.Decoder) error {
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
switch string(k) {
case "DisplayName":
requiredBitSet[0] |= 1 << 0
if err := func() error {
v, err := d.Str()
s.DisplayName = string(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"DisplayName\"")
}
case "Creator":
requiredBitSet[0] |= 1 << 1
if err := func() error {
v, err := d.Str()
s.Creator = string(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Creator\"")
}
case "GameID":
requiredBitSet[0] |= 1 << 2
if err := func() error {
v, err := d.Int32()
s.GameID = int32(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"GameID\"")
}
case "AssetID":
requiredBitSet[0] |= 1 << 3
requiredBitSet[0] |= 1 << 0
if err := func() error {
v, err := d.Int64()
s.AssetID = int64(v)
@@ -625,7 +523,7 @@ func (s *MapfixCreate) Decode(d *jx.Decoder) error {
return errors.Wrap(err, "decode field \"AssetID\"")
}
case "AssetVersion":
requiredBitSet[0] |= 1 << 4
requiredBitSet[0] |= 1 << 1
if err := func() error {
v, err := d.Int64()
s.AssetVersion = int64(v)
@@ -637,7 +535,7 @@ func (s *MapfixCreate) Decode(d *jx.Decoder) error {
return errors.Wrap(err, "decode field \"AssetVersion\"")
}
case "TargetAssetID":
requiredBitSet[0] |= 1 << 5
requiredBitSet[0] |= 1 << 2
if err := func() error {
v, err := d.Int64()
s.TargetAssetID = int64(v)
@@ -658,7 +556,7 @@ func (s *MapfixCreate) Decode(d *jx.Decoder) error {
// Validate required fields.
var failures []validate.FieldError
for i, mask := range [1]uint8{
0b00111111,
0b00000111,
} {
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
// Mask only required fields and check equality to mask using XOR.

View File

@@ -1601,12 +1601,9 @@ func decodeGetSubmissionParams(args [1]string, argsEscaped bool, r *http.Request
// ListMapfixesParams is parameters of listMapfixes operation.
type ListMapfixesParams struct {
Page int32
Limit int32
DisplayName OptString
Creator OptString
GameID OptInt32
Sort OptInt32
Page int32
Limit int32
Sort OptInt32
}
func unpackListMapfixesParams(packed middleware.Parameters) (params ListMapfixesParams) {
@@ -1624,33 +1621,6 @@ func unpackListMapfixesParams(packed middleware.Parameters) (params ListMapfixes
}
params.Limit = packed[key].(int32)
}
{
key := middleware.ParameterKey{
Name: "DisplayName",
In: "query",
}
if v, ok := packed[key]; ok {
params.DisplayName = v.(OptString)
}
}
{
key := middleware.ParameterKey{
Name: "Creator",
In: "query",
}
if v, ok := packed[key]; ok {
params.Creator = v.(OptString)
}
}
{
key := middleware.ParameterKey{
Name: "GameID",
In: "query",
}
if v, ok := packed[key]; ok {
params.GameID = v.(OptInt32)
}
}
{
key := middleware.ParameterKey{
Name: "Sort",
@@ -1771,175 +1741,6 @@ func decodeListMapfixesParams(args [0]string, argsEscaped bool, r *http.Request)
Err: err,
}
}
// Decode query: DisplayName.
if err := func() error {
cfg := uri.QueryParameterDecodingConfig{
Name: "DisplayName",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.HasParam(cfg); err == nil {
if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
var paramsDotDisplayNameVal string
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToString(val)
if err != nil {
return err
}
paramsDotDisplayNameVal = c
return nil
}(); err != nil {
return err
}
params.DisplayName.SetTo(paramsDotDisplayNameVal)
return nil
}); err != nil {
return err
}
if err := func() error {
if value, ok := params.DisplayName.Get(); ok {
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(value)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
return err
}
}
return nil
}(); err != nil {
return err
}
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "DisplayName",
In: "query",
Err: err,
}
}
// Decode query: Creator.
if err := func() error {
cfg := uri.QueryParameterDecodingConfig{
Name: "Creator",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.HasParam(cfg); err == nil {
if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
var paramsDotCreatorVal string
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToString(val)
if err != nil {
return err
}
paramsDotCreatorVal = c
return nil
}(); err != nil {
return err
}
params.Creator.SetTo(paramsDotCreatorVal)
return nil
}); err != nil {
return err
}
if err := func() error {
if value, ok := params.Creator.Get(); ok {
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(value)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
return err
}
}
return nil
}(); err != nil {
return err
}
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "Creator",
In: "query",
Err: err,
}
}
// Decode query: GameID.
if err := func() error {
cfg := uri.QueryParameterDecodingConfig{
Name: "GameID",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.HasParam(cfg); err == nil {
if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
var paramsDotGameIDVal int32
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt32(val)
if err != nil {
return err
}
paramsDotGameIDVal = c
return nil
}(); err != nil {
return err
}
params.GameID.SetTo(paramsDotGameIDVal)
return nil
}); err != nil {
return err
}
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "GameID",
In: "query",
Err: err,
}
}
// Decode query: Sort.
if err := func() error {
cfg := uri.QueryParameterDecodingConfig{

View File

@@ -72,14 +72,6 @@ func (s *Server) decodeCreateMapfixRequest(r *http.Request) (
}
return req, close, err
}
if err := func() error {
if err := request.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
return req, close, errors.Wrap(err, "validate")
}
return &request, close, nil
default:
return req, close, validate.InvalidContentType(ct)

View File

@@ -156,9 +156,6 @@ func (s *ID) SetID(val int64) {
// Ref: #/components/schemas/Mapfix
type Mapfix struct {
ID int64 `json:"ID"`
DisplayName string `json:"DisplayName"`
Creator string `json:"Creator"`
GameID int32 `json:"GameID"`
CreatedAt int64 `json:"CreatedAt"`
UpdatedAt int64 `json:"UpdatedAt"`
Submitter int64 `json:"Submitter"`
@@ -175,21 +172,6 @@ func (s *Mapfix) GetID() int64 {
return s.ID
}
// GetDisplayName returns the value of DisplayName.
func (s *Mapfix) GetDisplayName() string {
return s.DisplayName
}
// GetCreator returns the value of Creator.
func (s *Mapfix) GetCreator() string {
return s.Creator
}
// GetGameID returns the value of GameID.
func (s *Mapfix) GetGameID() int32 {
return s.GameID
}
// GetCreatedAt returns the value of CreatedAt.
func (s *Mapfix) GetCreatedAt() int64 {
return s.CreatedAt
@@ -240,21 +222,6 @@ func (s *Mapfix) SetID(val int64) {
s.ID = val
}
// SetDisplayName sets the value of DisplayName.
func (s *Mapfix) SetDisplayName(val string) {
s.DisplayName = val
}
// SetCreator sets the value of Creator.
func (s *Mapfix) SetCreator(val string) {
s.Creator = val
}
// SetGameID sets the value of GameID.
func (s *Mapfix) SetGameID(val int32) {
s.GameID = val
}
// SetCreatedAt sets the value of CreatedAt.
func (s *Mapfix) SetCreatedAt(val int64) {
s.CreatedAt = val
@@ -302,27 +269,9 @@ func (s *Mapfix) SetStatusMessage(val string) {
// Ref: #/components/schemas/MapfixCreate
type MapfixCreate struct {
DisplayName string `json:"DisplayName"`
Creator string `json:"Creator"`
GameID int32 `json:"GameID"`
AssetID int64 `json:"AssetID"`
AssetVersion int64 `json:"AssetVersion"`
TargetAssetID int64 `json:"TargetAssetID"`
}
// GetDisplayName returns the value of DisplayName.
func (s *MapfixCreate) GetDisplayName() string {
return s.DisplayName
}
// GetCreator returns the value of Creator.
func (s *MapfixCreate) GetCreator() string {
return s.Creator
}
// GetGameID returns the value of GameID.
func (s *MapfixCreate) GetGameID() int32 {
return s.GameID
AssetID int64 `json:"AssetID"`
AssetVersion int64 `json:"AssetVersion"`
TargetAssetID int64 `json:"TargetAssetID"`
}
// GetAssetID returns the value of AssetID.
@@ -340,21 +289,6 @@ func (s *MapfixCreate) GetTargetAssetID() int64 {
return s.TargetAssetID
}
// SetDisplayName sets the value of DisplayName.
func (s *MapfixCreate) SetDisplayName(val string) {
s.DisplayName = val
}
// SetCreator sets the value of Creator.
func (s *MapfixCreate) SetCreator(val string) {
s.Creator = val
}
// SetGameID sets the value of GameID.
func (s *MapfixCreate) SetGameID(val int32) {
s.GameID = val
}
// SetAssetID sets the value of AssetID.
func (s *MapfixCreate) SetAssetID(val int64) {
s.AssetID = val

View File

@@ -14,44 +14,6 @@ func (s *Mapfix) Validate() error {
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.DisplayName)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "DisplayName",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.Creator)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Creator",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
@@ -77,56 +39,6 @@ func (s *Mapfix) Validate() error {
return nil
}
func (s *MapfixCreate) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.DisplayName)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "DisplayName",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.Creator)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Creator",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *Script) Validate() error {
if s == nil {
return validate.ErrNilPointer

View File

@@ -31,7 +31,6 @@ func New(ctx *cli.Context) (datastore.Datastore, error) {
if ctx.Bool("migrate") {
if err := db.AutoMigrate(
&model.Mapfix{},
&model.Submission{},
&model.Script{},
&model.ScriptPolicy{},

View File

@@ -23,9 +23,6 @@ const (
type Mapfix struct {
ID int64 `gorm:"primaryKey"`
DisplayName string
Creator string
GameID int32
CreatedAt time.Time
UpdatedAt time.Time
Submitter int64 // UserID

View File

@@ -95,9 +95,6 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixCreate)
mapfix, err := svc.DB.Mapfixes().Create(ctx, model.Mapfix{
ID: 0,
DisplayName: request.DisplayName,
Creator: request.Creator,
GameID: request.GameID,
Submitter: int64(userId),
AssetID: request.AssetID,
AssetVersion: request.AssetVersion,
@@ -125,9 +122,6 @@ func (svc *Service) GetMapfix(ctx context.Context, params api.GetMapfixParams) (
}
return &api.Mapfix{
ID: mapfix.ID,
DisplayName: mapfix.DisplayName,
Creator: mapfix.Creator,
GameID: mapfix.GameID,
CreatedAt: mapfix.CreatedAt.Unix(),
UpdatedAt: mapfix.UpdatedAt.Unix(),
Submitter: int64(mapfix.Submitter),
@@ -148,16 +142,6 @@ func (svc *Service) GetMapfix(ctx context.Context, params api.GetMapfixParams) (
func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesParams) ([]api.Mapfix, error) {
filter := datastore.Optional()
if params.DisplayName.IsSet(){
filter.Add("display_name", params.DisplayName.Value)
}
if params.Creator.IsSet(){
filter.Add("creator", params.Creator.Value)
}
if params.GameID.IsSet(){
filter.Add("game_id", params.GameID.Value)
}
sort := datastore.ListSort(params.Sort.Or(int32(datastore.ListSortDisabled)))
items, err := svc.DB.Mapfixes().List(ctx, filter, model.Page{
@@ -172,9 +156,6 @@ func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesPar
for _, item := range items {
resp = append(resp, api.Mapfix{
ID: item.ID,
DisplayName: item.DisplayName,
Creator: item.Creator,
GameID: item.GameID,
CreatedAt: item.CreatedAt.Unix(),
UpdatedAt: item.UpdatedAt.Unix(),
Submitter: int64(item.Submitter),

View File

@@ -17,15 +17,10 @@ var (
// Submissions roles bitflag
type Roles int32
var (
// Only users with this role are allowed to submit models they don't own
RolesSubmissionCreateNotModelOwner Roles = 1<<8
RolesMapfixCreateNotModelOwner Roles = 1<<7
RolesSubmissionUpload Roles = 1<<6
RolesSubmissionReview Roles = 1<<5
RolesSubmissionRelease Roles = 1<<4
RolesScriptWrite Roles = 1<<3
RolesMapfixUpload Roles = 1<<2
RolesMapfixReview Roles = 1<<1
RolesMapUpload Roles = 1<<2
RolesMapReview Roles = 1<<1
RolesMapDownload Roles = 1<<0
RolesEmpty Roles = 0
)
@@ -37,13 +32,13 @@ var (
RoleQuat GroupRole = 255
RoleItzaname GroupRole = 254
RoleStagingDeveloper GroupRole = 240
RolesAll Roles = ^RolesEmpty
RolesAll Roles = RolesScriptWrite|RolesSubmissionRelease|RolesMapUpload|RolesMapReview|RolesMapDownload
// has SubmissionUpload
RoleMapAdmin GroupRole = 128
RolesMapAdmin Roles = RolesSubmissionRelease|RolesSubmissionUpload|RolesSubmissionReview|RolesSubmissionCreateNotModelOwner|RolesMapCouncil
// has MapfixReview
RolesMapAdmin Roles = RolesSubmissionRelease|RolesMapUpload|RolesMapReview|RolesMapDownload
// has SubmissionReview
RoleMapCouncil GroupRole = 64
RolesMapCouncil Roles = RolesMapfixReview|RolesMapfixUpload|RolesMapfixCreateNotModelOwner|RolesMapAccess
RolesMapCouncil Roles = RolesMapReview|RolesMapUpload|RolesMapDownload
// access to downloading maps
RoleMapAccess GroupRole = 32
RolesMapAccess Roles = RolesMapDownload
@@ -133,17 +128,11 @@ func (usr UserInfoHandle) GetRoles() (Roles, error) {
}
// RoleThumbnail
func (usr UserInfoHandle) HasRoleMapfixCreateNotModelOwner() (bool, error) {
return usr.hasRoles(RolesMapfixCreateNotModelOwner)
}
func (usr UserInfoHandle) HasRoleSubmissionCreateNotModelOwner() (bool, error) {
return usr.hasRoles(RolesSubmissionCreateNotModelOwner)
}
func (usr UserInfoHandle) HasRoleMapfixUpload() (bool, error) {
return usr.hasRoles(RolesMapfixUpload)
return usr.hasRoles(RolesMapUpload)
}
func (usr UserInfoHandle) HasRoleMapfixReview() (bool, error) {
return usr.hasRoles(RolesMapfixReview)
return usr.hasRoles(RolesMapReview)
}
func (usr UserInfoHandle) HasRoleMapDownload() (bool, error) {
return usr.hasRoles(RolesMapDownload)
@@ -152,10 +141,10 @@ func (usr UserInfoHandle) HasRoleSubmissionRelease() (bool, error) {
return usr.hasRoles(RolesSubmissionRelease)
}
func (usr UserInfoHandle) HasRoleSubmissionUpload() (bool, error) {
return usr.hasRoles(RolesSubmissionUpload)
return usr.hasRoles(RolesMapUpload)
}
func (usr UserInfoHandle) HasRoleSubmissionReview() (bool, error) {
return usr.hasRoles(RolesSubmissionReview)
return usr.hasRoles(RolesMapReview)
}
func (usr UserInfoHandle) HasRoleScriptWrite() (bool, error) {
return usr.hasRoles(RolesScriptWrite)

View File

@@ -1,4 +1,4 @@
import type { MapfixInfo } from "@/app/ts/Mapfix";
import type { SubmissionInfo } from "@/app/ts/Submission";
import { Button } from "@mui/material"
import Window from "./_window";
import SendIcon from '@mui/icons-material/Send';
@@ -9,10 +9,10 @@ interface CommentersProps {
}
interface CreatorAndReviewStatus {
asset_id: MapfixInfo["AssetID"],
creator: MapfixInfo["DisplayName"],
review: MapfixInfo["StatusID"],
status_message: MapfixInfo["StatusMessage"],
asset_id: SubmissionInfo["AssetID"],
creator: SubmissionInfo["DisplayName"],
review: SubmissionInfo["StatusID"],
status_message: SubmissionInfo["StatusMessage"],
comments: Comment[],
name: string
}

View File

@@ -1,7 +1,7 @@
import { MapfixInfo } from "@/app/ts/Mapfix"
import { SubmissionInfo } from "@/app/ts/Submission"
interface AssetID {
id: MapfixInfo["AssetID"]
id: SubmissionInfo["AssetID"]
}
function MapImage() {
@@ -11,4 +11,4 @@ function MapImage() {
export {
type AssetID,
MapImage
}
}

View File

@@ -7,17 +7,17 @@ type Review = Actions | "Accept" | "Validate" | "Upload" | "Reset Uploading
interface ReviewButton {
name: Review,
action: ApiActions,
mapfixId: string,
submissionId: string,
color: ButtonOwnProps["color"]
}
interface ReviewId {
mapfixId: string
submissionId: string
}
async function ReviewButtonClicked(action: ApiActions, mapfixId: string) {
async function ReviewButtonClicked(action: ApiActions, submissionId: string) {
try {
const response = await fetch(`/api/mapfixes/${mapfixId}/status/${action}`, {
const response = await fetch(`/api/submissions/${submissionId}/status/${action}`, {
method: "POST",
headers: {
"Content-type": "application/json",
@@ -33,7 +33,7 @@ async function ReviewButtonClicked(action: ApiActions, mapfixId: string) {
window.location.reload();
} catch (error) {
console.error("Error updating mapfix status:", error);
console.error("Error updating submission status:", error);
}
}
@@ -41,11 +41,11 @@ function ReviewButton(props: ReviewButton) {
return <Button
color={props.color}
variant="contained"
onClick={() => { ReviewButtonClicked(props.action, props.mapfixId) }}>{props.name}</Button>
onClick={() => { ReviewButtonClicked(props.action, props.submissionId) }}>{props.name}</Button>
}
export default function ReviewButtons(props: ReviewId) {
const mapfixId = props.mapfixId
const submissionId = props.submissionId
// When is each button visible?
// Multiple buttons can be visible at once.
// Action | Role | When Current Status is One of:
@@ -61,14 +61,14 @@ export default function ReviewButtons(props: ReviewId) {
// ResetUploading | MapAdmin | Uploading
return (
<section className="review-set">
<ReviewButton color="info" name="Submit" action="submit" mapfixId={mapfixId}/>
<ReviewButton color="info" name="Revoke" action="revoke" mapfixId={mapfixId}/>
<ReviewButton color="info" name="Accept" action="trigger-validate" mapfixId={mapfixId}/>
<ReviewButton color="info" name="Validate" action="retry-validate" mapfixId={mapfixId}/>
<ReviewButton color="error" name="Reject" action="reject" mapfixId={mapfixId}/>
<ReviewButton color="info" name="Upload" action="trigger-upload" mapfixId={mapfixId}/>
<ReviewButton color="error" name="Reset Uploading (fix softlocked status)" action="reset-uploading" mapfixId={mapfixId}/>
<ReviewButton color="error" name="Reset Validating (fix softlocked status)" action="reset-validating" mapfixId={mapfixId}/>
<ReviewButton color="info" name="Submit" action="submit" submissionId={submissionId}/>
<ReviewButton color="info" name="Revoke" action="revoke" submissionId={submissionId}/>
<ReviewButton color="info" name="Accept" action="trigger-validate" submissionId={submissionId}/>
<ReviewButton color="info" name="Validate" action="retry-validate" submissionId={submissionId}/>
<ReviewButton color="error" name="Reject" action="reject" submissionId={submissionId}/>
<ReviewButton color="info" name="Upload" action="trigger-upload" submissionId={submissionId}/>
<ReviewButton color="error" name="Reset Uploading (fix softlocked status)" action="reset-uploading" submissionId={submissionId}/>
<ReviewButton color="error" name="Reset Validating (fix softlocked status)" action="reset-validating" submissionId={submissionId}/>
</section>
)
}

View File

@@ -1,54 +0,0 @@
@use "../../../../globals.scss";
::placeholder {
color: var(--placeholder-text)
}
.form-spacer {
margin-bottom: 20px;
&:last-of-type {
margin-top: 15px;
}
}
#target-asset-radio {
color: var(--text-color);
font-size: globals.$form-label-fontsize;
}
.form-field {
width: 850px;
& label, & input {
color: var(--text-color);
}
& fieldset {
border-color: rgb(100,100,100);
}
& span {
color: white;
}
}
main {
display: grid;
justify-content: center;
align-items: center;
margin-inline: auto;
width: 700px;
}
header h1 {
text-align: center;
color: var(--text-color);
}
form {
display: grid;
gap: 25px;
fieldset {
border: blue
}
}

View File

@@ -1,65 +0,0 @@
import { FormControl, Select, InputLabel, MenuItem } from "@mui/material";
import { styled } from '@mui/material/styles';
import InputBase from '@mui/material/InputBase';
import React from "react";
import { SelectChangeEvent } from "@mui/material";
// TODO: Properly style everything instead of pasting 🤚
type GameSelectionProps = {
game: number;
setGame: React.Dispatch<React.SetStateAction<number>>;
};
const BootstrapInput = styled(InputBase)(({ theme }) => ({
'label + &': {
marginTop: theme.spacing(3),
},
'& .MuiInputBase-input': {
backgroundColor: '#0000',
color: '#FFF',
border: '1px solid rgba(175, 175, 175, 0.66)',
fontSize: 16,
padding: '10px 26px 10px 12px',
transition: theme.transitions.create(['border-color', 'box-shadow']),
fontFamily: [
'-apple-system',
'BlinkMacSystemFont',
'"Segoe UI"',
'Roboto',
'"Helvetica Neue"',
'Arial',
'sans-serif',
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"',
].join(','),
'&:focus': {
borderRadius: 4,
borderColor: '#80bdff',
boxShadow: '0 0 0 0.2rem rgba(0,123,255,.25)',
},
},
}));
export default function GameSelection({ game, setGame }: GameSelectionProps) {
const handleChange = (event: SelectChangeEvent) => {
setGame(Number(event.target.value)); // TODO: Change later!! there's 100% a proper way of doing this
};
return (
<FormControl>
<InputLabel sx={{ color: "#646464" }}>Game</InputLabel>
<Select
value={String(game)}
label="Game"
onChange={handleChange}
input={<BootstrapInput />}
>
<MenuItem value={1}>Bhop</MenuItem>
<MenuItem value={2}>Surf</MenuItem>
<MenuItem value={3}>Fly Trials</MenuItem>
</Select>
</FormControl>
);
}

View File

@@ -1,98 +0,0 @@
"use client"
import { Button, TextField } from "@mui/material"
import GameSelection from "./_game";
import SendIcon from '@mui/icons-material/Send';
import Webpage from "@/app/_components/webpage";
import { useParams } from "next/navigation";
import React, { useState } from "react";
import "./(styles)/page.scss"
interface MapfixPayload {
DisplayName: string;
Creator: string;
GameID: number;
AssetID: number;
AssetVersion: number;
TargetAssetID: number;
}
interface IdResponse {
ID: number;
}
export default function MapfixInfoPage() {
const [game, setGame] = useState(1);
const dynamicId = useParams<{ mapId: string }>();
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const form = event.currentTarget;
const formData = new FormData(form);
const payload: MapfixPayload = {
DisplayName: (formData.get("display-name") as string) ?? "unknown", // TEMPORARY! TODO: Change
Creator: (formData.get("creator") as string) ?? "unknown", // TEMPORARY! TODO: Change
GameID: game,
AssetID: Number((formData.get("asset-id") as string) ?? "0"),
AssetVersion: 0,
TargetAssetID: Number(dynamicId.mapId),
};
console.log(payload)
console.log(JSON.stringify(payload))
try {
// Send the POST request
const response = await fetch("/api/mapfixes", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
// Check if the HTTP request was successful
if (!response.ok) {
const errorDetails = await response.text();
// Throw an error with detailed information
throw new Error(`HTTP error! status: ${response.status}, details: ${errorDetails}`);
}
// Allow any HTTP status
const id_response:IdResponse = await response.json();
// navigate to newly created mapfix
window.location.assign(`/mapfixes/${id_response.ID}`)
} catch (error) {
console.error("Error submitting data:", error);
}
};
return (
<Webpage>
<main>
<header>
<h1>Submit Mapfix</h1>
<span className="spacer form-spacer"></span>
</header>
<form onSubmit={handleSubmit}>
{/* TODO: Add form data for mapfixes, such as changes they did, and any times that need to be deleted & what styles */}
<TextField className="form-field" id="display-name" name="display-name" label="Display Name" variant="outlined"/>
<TextField className="form-field" id="creator" name="creator" label="Creator" variant="outlined"/>
<TextField className="form-field" id="asset-id" name="asset-id" label="Asset ID" variant="outlined"/>
{/* I think this is Quat's job to figure this one out (to be set when someone clicks review(?)) */} {/* <TextField className="form-field" id="asset-version" label="Asset Version" variant="outlined"/> */}
<GameSelection game={game} setGame={setGame} />
<span className="spacer form-spacer"></span>
<Button type="submit" variant="contained" startIcon={<SendIcon/>} sx={{
width: "400px",
height: "50px",
marginInline: "auto"
}}>Submit</Button>
</form>
</main>
</Webpage>
)
}

View File

@@ -1,6 +1,6 @@
"use client"
import { MapfixInfo, MapfixStatusToString } from "@/app/ts/Mapfix";
import { SubmissionInfo, SubmissionStatusToString } from "@/app/ts/Submission";
import type { CreatorAndReviewStatus } from "./_comments";
import { MapImage } from "./_map";
import { useParams } from "next/navigation";
@@ -15,7 +15,7 @@ import { useState, useEffect } from "react";
import "./(styles)/page.scss";
interface ReviewId {
mapfixId: string
submissionId: string
}
function Ratings() {
@@ -39,20 +39,20 @@ function Ratings() {
)
}
function RatingArea(mapfix: ReviewId) {
function RatingArea(submission: ReviewId) {
return (
<aside className="review-area">
<section className="map-image-area">
<MapImage/>
</section>
<Ratings/>
<ReviewButtons mapfixId={mapfix.mapfixId}/>
<ReviewButtons submissionId={submission.submissionId}/>
</aside>
)
}
function TitleAndComments(stats: CreatorAndReviewStatus) {
const Review = MapfixStatusToString(stats.review)
const Review = SubmissionStatusToString(stats.review)
// TODO: hide status message when status is not "Accepted"
return (
@@ -72,22 +72,22 @@ function TitleAndComments(stats: CreatorAndReviewStatus) {
)
}
export default function MapfixInfoPage() {
const dynamicId = useParams<{mapfixId: string}>()
export default function SubmissionInfoPage() {
const dynamicId = useParams<{submissionId: string}>()
const [mapfix, setMapfix] = useState<MapfixInfo | null>(null)
const [submission, setSubmission] = useState<SubmissionInfo | null>(null)
useEffect(() => { // needs to be client sided since server doesn't have a session, nextjs got mad at me for exporting an async function: (https://nextjs.org/docs/messages/no-async-client-component)
async function getMapfix() {
const res = await fetch(`/api/mapfixes/${dynamicId.mapfixId}`)
async function getSubmission() {
const res = await fetch(`/api/submissions/${dynamicId.submissionId}`)
if (res.ok) {
setMapfix(await res.json())
setSubmission(await res.json())
}
}
getMapfix()
}, [dynamicId.mapfixId])
getSubmission()
}, [dynamicId.submissionId])
if (!mapfix) {
if (!submission) {
return <Webpage>
{/* TODO: Add skeleton loading thingy ? Maybe ? (https://mui.com/material-ui/react-skeleton/) */}
</Webpage>
@@ -96,8 +96,8 @@ export default function MapfixInfoPage() {
<Webpage>
<main className="map-page-main">
<section className="review-section">
<RatingArea mapfixId={dynamicId.mapfixId}/>
<TitleAndComments name={mapfix.DisplayName} creator={mapfix.Creator} review={mapfix.StatusID} status_message={mapfix.StatusMessage} asset_id={mapfix.AssetID} comments={[]}/>
<RatingArea submissionId={dynamicId.submissionId}/>
<TitleAndComments name={submission.DisplayName} creator={submission.Creator} review={submission.StatusID} status_message={submission.StatusMessage} asset_id={submission.AssetID} comments={[]}/>
</section>
</main>
</Webpage>

View File

@@ -38,4 +38,4 @@ export default function SubmissionCard(props: SubmissionCardProps) {
</div>
</Link>
);
}
}

View File

@@ -1,20 +1,20 @@
'use client'
import React, { useState, useEffect } from "react";
import { MapfixInfo } from "../ts/Mapfix";
import MapfixCard from "./_card";
import { SubmissionInfo } from "../ts/Submission";
import SubmissionCard from "./_card";
import Webpage from "@/app/_components/webpage";
import "./(styles)/page.scss";
export default function MapfixInfoPage() {
const [mapfixes, setMapfixes] = useState<MapfixInfo[]>([])
export default function SubmissionInfoPage() {
const [submissions, setSubmissions] = useState<SubmissionInfo[]>([])
const [currentPage, setCurrentPage] = useState(0);
const cardsPerPage = 24; // built to fit on a 1920x1080 monitor
const totalPages = Math.ceil(mapfixes.length / cardsPerPage);
const totalPages = Math.ceil(submissions.length / cardsPerPage);
const currentCards = mapfixes.slice(
const currentCards = submissions.slice(
currentPage * cardsPerPage,
(currentPage + 1) * cardsPerPage
);
@@ -32,19 +32,19 @@ export default function MapfixInfoPage() {
};
useEffect(() => {
async function fetchMapfixes() {
const res = await fetch('/api/mapfixes?Page=1&Limit=100')
async function fetchSubmissions() {
const res = await fetch('/api/submissions?Page=1&Limit=100')
if (res.ok) {
setMapfixes(await res.json())
setSubmissions(await res.json())
}
}
setTimeout(() => {
fetchMapfixes()
fetchSubmissions()
}, 50);
}, [])
if (!mapfixes) {
if (!submissions) {
return <Webpage>
<main>
Loading...
@@ -52,10 +52,10 @@ export default function MapfixInfoPage() {
</Webpage>
}
if (mapfixes && mapfixes.length == 0) {
if (submissions && submissions.length == 0) {
return <Webpage>
<main>
Mapfixes list is empty.
Submissions list is empty.
</main>
</Webpage>
}
@@ -93,14 +93,14 @@ export default function MapfixInfoPage() {
<button onClick={nextPage} disabled={currentPage === totalPages - 1}>&gt;</button>
</div>
<div className="grid">
{currentCards.map((mapfix) => (
<MapfixCard
key={mapfix.ID}
id={mapfix.ID}
assetId={mapfix.AssetID}
displayName={mapfix.DisplayName}
author={mapfix.Creator}
rating={mapfix.StatusID}
{currentCards.map((submission) => (
<SubmissionCard
key={submission.ID}
id={submission.ID}
assetId={submission.AssetID}
displayName={submission.DisplayName}
author={submission.Creator}
rating={submission.StatusID}
/>
))}
</div>

View File

@@ -71,7 +71,7 @@ export default function SubmissionInfoPage() {
<Webpage>
<main>
<header>
<h1>Submit New Map</h1>
<h1>Submit Asset</h1>
<span className="spacer form-spacer"></span>
</header>
<form onSubmit={handleSubmit}>

View File

@@ -1,4 +1,4 @@
const enum MapfixStatus {
const enum SubmissionStatus {
UnderConstruction = 0,
Submitted = 1,
ChangesRequested = 2,
@@ -8,9 +8,10 @@ const enum MapfixStatus {
Uploading = 6,
Uploaded = 7,
Rejected = 8,
Released = 9,
}
interface MapfixInfo {
interface SubmissionInfo {
readonly ID: number,
readonly DisplayName: string,
readonly Creator: string,
@@ -23,29 +24,31 @@ interface MapfixInfo {
readonly ValidatedAssetVersion: number,
readonly Completed: boolean,
readonly TargetAssetID: number,
readonly StatusID: MapfixStatus
readonly StatusID: SubmissionStatus
readonly StatusMessage: string,
}
function MapfixStatusToString(mapfix_status: MapfixStatus): string {
switch (mapfix_status) {
case MapfixStatus.Rejected:
return "REJECTED"
case MapfixStatus.Uploading:
function SubmissionStatusToString(submission_status: SubmissionStatus): string {
switch (submission_status) {
case SubmissionStatus.Released:
return "RELEASED"
case SubmissionStatus.Rejected:
return "REJECTED"
case SubmissionStatus.Uploading:
return "UPLOADING"
case MapfixStatus.Uploaded:
case SubmissionStatus.Uploaded:
return "UPLOADED"
case MapfixStatus.Validated:
case SubmissionStatus.Validated:
return "VALIDATED"
case MapfixStatus.Validating:
case SubmissionStatus.Validating:
return "VALIDATING"
case MapfixStatus.Accepted:
case SubmissionStatus.Accepted:
return "ACCEPTED"
case MapfixStatus.ChangesRequested:
case SubmissionStatus.ChangesRequested:
return "CHANGES REQUESTED"
case MapfixStatus.Submitted:
case SubmissionStatus.Submitted:
return "SUBMITTED"
case MapfixStatus.UnderConstruction:
case SubmissionStatus.UnderConstruction:
return "UNDER CONSTRUCTION"
default:
return "UNKNOWN"
@@ -53,7 +56,7 @@ function MapfixStatusToString(mapfix_status: MapfixStatus): string {
}
export {
MapfixStatus,
MapfixStatusToString,
type MapfixInfo
SubmissionStatus,
SubmissionStatusToString,
type SubmissionInfo
}