From 9e022ca2653daa4d07bfde7e9ce49e482f9fa577 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Sat, 14 Dec 2024 04:06:49 -0800
Subject: [PATCH] submissions: refactor publishing model

---
 pkg/cmds/serve.go                        | 23 ++++++++++-
 pkg/model/submission.go                  | 10 +++--
 pkg/service/security.go                  |  5 +--
 pkg/service/submissions.go               | 40 +++----------------
 pkg/service_internal/service_internal.go | 25 ++++++++++++
 pkg/service_internal/submissions.go      | 51 ++++++++++++++++++++++++
 6 files changed, 113 insertions(+), 41 deletions(-)
 create mode 100644 pkg/service_internal/service_internal.go
 create mode 100644 pkg/service_internal/submissions.go

diff --git a/pkg/cmds/serve.go b/pkg/cmds/serve.go
index b59f6bb..5dd6afe 100644
--- a/pkg/cmds/serve.go
+++ b/pkg/cmds/serve.go
@@ -2,16 +2,19 @@ package cmds
 
 import (
 	"fmt"
+	"net/http"
+
 	"git.itzana.me/strafesnet/go-grpc/auth"
 	"git.itzana.me/strafesnet/maps-service/pkg/api"
 	"git.itzana.me/strafesnet/maps-service/pkg/datastore/gormstore"
+	internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
 	"git.itzana.me/strafesnet/maps-service/pkg/service"
+	"git.itzana.me/strafesnet/maps-service/pkg/service_internal"
 	"github.com/nats-io/nats.go"
 	log "github.com/sirupsen/logrus"
 	"github.com/urfave/cli/v2"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/credentials/insecure"
-	"net/http"
 )
 
 func NewServeCommand() *cli.Command {
@@ -62,6 +65,12 @@ func NewServeCommand() *cli.Command {
 				Value:   8080,
 				EnvVars: []string{"PORT"},
 			},
+			&cli.IntFlag{
+				Name:    "port-internal",
+				Usage:   "Port to listen on for internal api",
+				Value:   8081,
+				EnvVars: []string{"PORT_INTERNAL"},
+			},
 			&cli.StringFlag{
 				Name:    "auth-rpc-host",
 				Usage:   "Host of auth rpc",
@@ -119,5 +128,17 @@ func serve(ctx *cli.Context) error {
 		log.WithError(err).Fatal("failed to initialize api server")
 	}
 
+	svc2 := &service_internal.Service{
+		DB:   db,
+		Nats: js,
+	}
+
+	srv2, err := internal.NewServer(svc2, nil, internal.WithPathPrefix("/v1"))
+	if err != nil {
+		log.WithError(err).Fatal("failed to initialize api server")
+	}
+
+	// idk how else to do this
+	go http.ListenAndServe(fmt.Sprintf(":%d", ctx.Int("port-internal")), srv2)
 	return http.ListenAndServe(fmt.Sprintf(":%d", ctx.Int("port")), srv)
 }
diff --git a/pkg/model/submission.go b/pkg/model/submission.go
index cb68897..b0a7736 100644
--- a/pkg/model/submission.go
+++ b/pkg/model/submission.go
@@ -5,14 +5,18 @@ import "time"
 type Status int32
 
 const (
-	StatusPublished Status = 8
-	StatusRejected  Status = 7
+	// Phase: Final Status
+	StatusReleased  Status = 9
+	StatusRejected  Status = 8
 
-	StatusPublishing Status = 6
+	// Phase: Testing
+	StatusUploaded   Status = 7 // uploaded to the group, but pending release
+	StatusUploading  Status = 6
 	StatusValidated  Status = 5
 	StatusValidating Status = 4
 	StatusAccepted   Status = 3
 
+	// Phase: Creation
 	StatusChangesRequested  Status = 2
 	StatusSubmitted         Status = 1
 	StatusUnderConstruction Status = 0
diff --git a/pkg/service/security.go b/pkg/service/security.go
index 57016d4..4cc0c7e 100644
--- a/pkg/service/security.go
+++ b/pkg/service/security.go
@@ -23,12 +23,11 @@ var (
 
 type Roles struct {
 	// human roles
-	SubmissionPublish bool
+	SubmissionRelease bool
 	SubmissionReview  bool
 	ScriptWrite       bool
 	// automated roles
 	Maptest   bool
-	Validator bool
 }
 
 type UserInfo struct {
@@ -79,7 +78,7 @@ func (svc SecurityHandler) HandleCookieAuth(ctx context.Context, operationName a
 	// fix this when roblox udpates group roles
 	for _, r := range role.Roles {
 		if RoleMapAdmin <= r.Rank {
-			roles.SubmissionPublish = true
+			roles.SubmissionRelease = true
 		}
 		if RoleMapCouncil <= r.Rank {
 			roles.SubmissionReview = true
diff --git a/pkg/service/submissions.go b/pkg/service/submissions.go
index c2af56d..41ab475 100644
--- a/pkg/service/submissions.go
+++ b/pkg/service/submissions.go
@@ -158,20 +158,6 @@ func (svc *Service) UpdateSubmissionModel(ctx context.Context, params api.Update
 	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusChangesRequested, model.StatusSubmitted, model.StatusUnderConstruction}, pmap)
 }
 
-// ActionSubmissionPublish invokes actionSubmissionPublish operation.
-//
-// Role Validator changes status from Publishing -> Published.
-//
-// POST /submissions/{SubmissionID}/status/publish
-func (svc *Service) ActionSubmissionPublish(ctx context.Context, params api.ActionSubmissionPublishParams) error {
-	println("[ActionSubmissionPublish] Implicit Validator permission granted!")
-
-	// transaction
-	smap := datastore.Optional()
-	smap.Add("status_id", model.StatusPublished)
-	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusPublishing}, smap)
-}
-
 // ActionSubmissionReject invokes actionSubmissionReject operation.
 //
 // Role Reviewer changes status from Submitted -> Rejected.
@@ -272,25 +258,25 @@ func (svc *Service) ActionSubmissionSubmit(ctx context.Context, params api.Actio
 	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusUnderConstruction, model.StatusChangesRequested}, smap)
 }
 
-// ActionSubmissionTriggerPublish invokes actionSubmissionTriggerPublish operation.
+// ActionSubmissionTriggerUpload invokes actionSubmissionTriggerUpload operation.
 //
-// Role Admin changes status from Validated -> Publishing.
+// Role Admin changes status from Validated -> Uploading.
 //
-// POST /submissions/{SubmissionID}/status/trigger-publish
-func (svc *Service) ActionSubmissionTriggerPublish(ctx context.Context, params api.ActionSubmissionTriggerPublishParams) error {
+// POST /submissions/{SubmissionID}/status/trigger-upload
+func (svc *Service) ActionSubmissionTriggerUpload(ctx context.Context, params api.ActionSubmissionTriggerUploadParams) error {
 	userInfo, ok := ctx.Value("UserInfo").(UserInfo)
 	if !ok {
 		return ErrUserInfo
 	}
 
 	// check if caller has required role
-	if !userInfo.Roles.SubmissionPublish {
+	if !userInfo.Roles.SubmissionRelease {
 		return ErrPermissionDenied
 	}
 
 	// transaction
 	smap := datastore.Optional()
-	smap.Add("status_id", model.StatusPublishing)
+	smap.Add("status_id", model.StatusUploading)
 	submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.Status{model.StatusValidated}, smap)
 	if err != nil {
 		return err
@@ -374,17 +360,3 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params
 
 	return nil
 }
-
-// ActionSubmissionValidate invokes actionSubmissionValidate operation.
-//
-// Role Validator changes status from Validating -> Validated.
-//
-// POST /submissions/{SubmissionID}/status/validate
-func (svc *Service) ActionSubmissionValidate(ctx context.Context, params api.ActionSubmissionValidateParams) error {
-	println("[ActionSubmissionValidate] Implicit Validator permission granted!")
-
-	// transaction
-	smap := datastore.Optional()
-	smap.Add("status_id", model.StatusValidated)
-	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidating}, smap)
-}
diff --git a/pkg/service_internal/service_internal.go b/pkg/service_internal/service_internal.go
new file mode 100644
index 0000000..9513793
--- /dev/null
+++ b/pkg/service_internal/service_internal.go
@@ -0,0 +1,25 @@
+package service_internal
+
+import (
+	"context"
+	internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
+	"git.itzana.me/strafesnet/maps-service/pkg/datastore"
+	"github.com/nats-io/nats.go"
+)
+
+type Service struct {
+	DB   datastore.Datastore
+	Nats nats.JetStreamContext
+}
+
+// yay duplicate code
+func (svc *Service) NewError(ctx context.Context, err error) *internal.ErrorStatusCode {
+	status := 500
+	return &internal.ErrorStatusCode{
+		StatusCode: status,
+		Response: internal.Error{
+			Code:    int64(status),
+			Message: err.Error(),
+		},
+	}
+}
diff --git a/pkg/service_internal/submissions.go b/pkg/service_internal/submissions.go
new file mode 100644
index 0000000..bc27f1a
--- /dev/null
+++ b/pkg/service_internal/submissions.go
@@ -0,0 +1,51 @@
+package service_internal
+
+import (
+	"context"
+
+	internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
+	"git.itzana.me/strafesnet/maps-service/pkg/datastore"
+	"git.itzana.me/strafesnet/maps-service/pkg/model"
+)
+
+// ActionSubmissionValidate invokes actionSubmissionValidate operation.
+//
+// Role Validator changes status from Validating -> Validated.
+//
+// POST /submissions/{SubmissionID}/status/validate
+func (svc *Service) ActionSubmissionValidated(ctx context.Context, params internal.ActionSubmissionValidatedParams) error {
+	println("[ActionSubmissionValidate] Implicit Validator permission granted!")
+
+	// transaction
+	smap := datastore.Optional()
+	smap.Add("status_id", model.StatusValidated)
+	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidating}, smap)
+}
+
+// ActionSubmissionReleased implements actionSubmissionReleased operation.
+//
+// (Internal endpoint) Role Releaser changes status from Uploaded -> Released.
+//
+// POST /submissions/{SubmissionID}/status/releaser-released
+func (svc *Service) ActionSubmissionReleased(ctx context.Context, params internal.ActionSubmissionReleasedParams) error {
+	println("[ActionSubmissionReleased] Implicit Validator permission granted!")
+
+	// transaction
+	smap := datastore.Optional()
+	smap.Add("status_id", model.StatusReleased)
+	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusUploaded}, smap)
+}
+
+// ActionSubmissionUploaded implements actionSubmissionUploaded operation.
+//
+// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
+//
+// POST /submissions/{SubmissionID}/status/validator-uploaded
+func (svc *Service) ActionSubmissionUploaded(ctx context.Context, params internal.ActionSubmissionUploadedParams) error {
+	println("[ActionSubmissionUploaded] Implicit Validator permission granted!")
+
+	// transaction
+	smap := datastore.Optional()
+	smap.Add("status_id", model.StatusUploaded)
+	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusUploading}, smap)
+}