Skip to content

Commit

Permalink
Merge pull request #308 from rstudio/dotnomad/title-api
Browse files Browse the repository at this point in the history
Add `PUT /api/deployment/title` endpoint to set title
  • Loading branch information
dotNomad authored Oct 25, 2023
2 parents a07a132 + 2f4f144 commit de5fac5
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 0 deletions.
7 changes: 7 additions & 0 deletions internal/services/api/deployments/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
type DeploymentsService interface {
GetDeployment() *state.Deployment
SetDeploymentFiles(files []string) *state.Deployment
SetDeploymentTitle(title string) *state.Deployment
}

func CreateDeploymentsService(deployment *state.Deployment) DeploymentsService {
Expand Down Expand Up @@ -37,3 +38,9 @@ func (s deploymentsService) SetDeploymentFiles(files []string) *state.Deployment

return s.deployment
}

func (s deploymentsService) SetDeploymentTitle(title string) *state.Deployment {
s.deployment.Connect.Content.Title = title

return s.deployment
}
12 changes: 12 additions & 0 deletions internal/services/api/deployments/services_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,15 @@ func (s *ServicesSuite) TestSetDeploymentFiles() {
s.Equal(src, res)
s.Equal(res.Manifest.Files, bundles.ManifestFileMap{"file": bundles.ManifestFile{Checksum: ""}})
}

func (s *ServicesSuite) TestSetDeploymentTitle() {
src := state.NewDeployment()
s.Equal(src.Connect.Content.Title, "")

service := CreateDeploymentsService(src)

title := "new-title"
res := service.SetDeploymentTitle(title)
s.Equal(src, res)
s.Equal(res.Connect.Content.Title, "new-title")
}
33 changes: 33 additions & 0 deletions internal/services/api/put_deployment_title.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package api

// Copyright (C) 2023 by Posit Software, PBC.

import (
"encoding/json"
"net/http"

"github.com/rstudio/connect-client/internal/logging"
"github.com/rstudio/connect-client/internal/services/api/deployments"
)

type PutDeploymentTitleRequestBody struct {
Title string `json:"title"`
}

func PutDeploymentTitleHandlerFunc(deploymentsService deployments.DeploymentsService, log logging.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
dec := json.NewDecoder(r.Body)
dec.DisallowUnknownFields()
var b PutDeploymentTitleRequestBody
err := dec.Decode(&b)
if err != nil {
BadRequestJson(w, r, log, err)
return
}

d := deploymentsService.SetDeploymentTitle(b.Title)

w.Header().Set("content-type", "application/json")
json.NewEncoder(w).Encode(d)
}
}
84 changes: 84 additions & 0 deletions internal/services/api/put_deployment_title_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package api

// Copyright (C) 2023 by Posit Software, PBC.

import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"

"github.com/rstudio/connect-client/internal/logging"
"github.com/rstudio/connect-client/internal/state"
"github.com/rstudio/connect-client/internal/util/utiltest"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
)

type PutDeploymentTitleHandlerFuncSuite struct {
utiltest.Suite
log logging.Logger
}

func TestPutDeploymentTitleHandlerFuncSuite(t *testing.T) {
suite.Run(t, new(PutDeploymentTitleHandlerFuncSuite))
}

func (s *PutDeploymentTitleHandlerFuncSuite) SetupSuite() {
s.log = logging.New()
}

func (s *PutDeploymentTitleHandlerFuncSuite) TestPutDeploymentTitleHandlerFunc() {
deploymentsService := new(MockDeploymentsService)
h := PutDeploymentTitleHandlerFunc(deploymentsService, s.log)
s.NotNil(h)
}

func (s *PutDeploymentTitleHandlerFuncSuite) TestPutDeploymentTitleHandler() {

src := state.NewDeployment()
deploymentsService := new(MockDeploymentsService)
deploymentsService.On("SetDeploymentTitle", mock.Anything).Return(src)

var b PutDeploymentTitleRequestBody = PutDeploymentTitleRequestBody{
Title: "new-title",
}
j, _ := json.Marshal(b)
br := bytes.NewReader(j)
req, err := http.NewRequest("PUT", "", br)
s.NoError(err)

h := PutDeploymentTitleHandlerFunc(deploymentsService, s.log)

rec := httptest.NewRecorder()

h(rec, req)

s.Equal(http.StatusOK, rec.Result().StatusCode)
s.Equal("application/json", rec.Header().Get("content-type"))

res := &state.Deployment{}
dec := json.NewDecoder(rec.Body)
dec.DisallowUnknownFields()
s.NoError(dec.Decode(res))

s.Equal(src, res)
}

func (s *PutDeploymentTitleHandlerFuncSuite) TestPutDeploymentTitleHandlerFuncBadRequestJson() {

deploymentsService := new(MockDeploymentsService)

br := bytes.NewReader([]byte{})
req, err := http.NewRequest("PUT", "", br)
s.NoError(err)

h := PutDeploymentTitleHandlerFunc(deploymentsService, s.log)

rec := httptest.NewRecorder()

h(rec, req)

s.Equal(http.StatusBadRequest, rec.Result().StatusCode)
}
5 changes: 5 additions & 0 deletions internal/services/api/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ func (m *MockDeploymentsService) SetDeploymentFiles(files []string) *state.Deplo
return args.Get(0).(*state.Deployment)
}

func (m *MockDeploymentsService) SetDeploymentTitle(title string) *state.Deployment {
args := m.Called()
return args.Get(0).(*state.Deployment)
}

type MockFilesService struct {
mock.Mock
files.FilesService
Expand Down
4 changes: 4 additions & 0 deletions internal/services/ui/ui_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ func RouterHandlerFunc(afs afero.Fs, publishArgs *cli_types.PublishArgs, lister
r.Handle(ToPath("deployment"), api.GetDeploymentHandlerFunc(deploymentsService)).
Methods(http.MethodGet)

// PUT /api/deployment/title
r.Handle(ToPath("deployment", "title"), api.PutDeploymentTitleHandlerFunc(deploymentsService, log)).
Methods(http.MethodPut)

// PUT /api/deployment/files
r.Handle(ToPath("deployment", "files"), api.PutDeploymentFilesHandlerFunc(deploymentsService, log)).
Methods(http.MethodPut)
Expand Down

0 comments on commit de5fac5

Please sign in to comment.