Skip to content

Commit

Permalink
Enable changing product of a draft document via the API (hashicorp-fo…
Browse files Browse the repository at this point in the history
…rge#111)

* Enable changing a document product in the database via upsert

* Fix comment

* Enable changing product of a draft document via the API

* Fix comment

Co-authored-by: Jeff Daley <[email protected]>

---------

Co-authored-by: Jeff Daley <[email protected]>
  • Loading branch information
jfreda and jeffdaley authored Mar 29, 2023
1 parent a142649 commit eebaf9e
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 4 deletions.
39 changes: 38 additions & 1 deletion internal/api/drafts.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type DraftsRequest struct {
type DraftsPatchRequest struct {
Approvers []string `json:"approvers,omitempty"`
Contributors []string `json:"contributors,omitempty"`
Product string `json:"product,omitempty"`
Summary string `json:"summary,omitempty"`
// Tags []string `json:"tags,omitempty"`
Title string `json:"title,omitempty"`
Expand Down Expand Up @@ -432,7 +433,8 @@ func DraftsDocumentHandler(
l hclog.Logger,
ar *algolia.Client,
aw *algolia.Client,
s *gw.Service) http.Handler {
s *gw.Service,
db *gorm.DB) http.Handler {

return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Get document ID from URL path
Expand Down Expand Up @@ -633,6 +635,22 @@ func DraftsDocumentHandler(
return
}

// Validate product if it is in the patch request.
if req.Product != "" {
p := models.Product{Name: req.Product}
if err := p.Get(db); err != nil {
l.Error("error getting product",
"error", err,
"method", r.Method,
"path", r.URL.Path,
"product", req.Product,
"doc_id", docId)
http.Error(w, "Bad request: invalid product",
http.StatusBadRequest)
return
}
}

// Compare contributors in request and stored object in Algolia
// before we save the patched objected
// Find out contributors to share the document with
Expand Down Expand Up @@ -717,6 +735,25 @@ func DraftsDocumentHandler(
"contributors_count", len(contributorsToRemoveSharing))
}

// Update product in the database (if it is in the patch request).
if req.Product != "" {
d := models.Document{
GoogleFileID: docId,
Product: models.Product{Name: req.Product},
}
if err := d.Upsert(db); err != nil {
l.Error("error upserting document to update product",
"error", err,
"method", r.Method,
"path", r.URL.Path,
"product", req.Product,
"doc_id", docId)
http.Error(w, "Error patching document draft",
http.StatusInternalServerError)
return
}
}

// Save new modified draft doc object in Algolia.
res, err := aw.Drafts.SaveObject(docObj)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/commands/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ func (c *Command) Run(args []string) int {
{"/api/v1/drafts",
api.DraftsHandler(cfg, c.Log, algoSearch, algoWrite, goog, db)},
{"/api/v1/drafts/",
api.DraftsDocumentHandler(cfg, c.Log, algoSearch, algoWrite, goog)},
api.DraftsDocumentHandler(cfg, c.Log, algoSearch, algoWrite, goog, db)},
{"/api/v1/me/subscriptions",
api.MeSubscriptionsHandler(cfg, c.Log, goog, db)},
{"/api/v1/people", api.PeopleDataHandler(cfg, c.Log, goog)},
Expand Down
13 changes: 11 additions & 2 deletions pkg/models/document.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ type Document struct {
// DocumentModifiedAt is the time the document was last modified.
DocumentModifiedAt time.Time

// DocumentNumber is a document identifier containing a product/area
// abbreviation and a number (e.g., "TF-123").
// DocumentNumber is a document number unique to each product/area. It
// pairs with the product abbreviation to form a document identifier
// (e.g., "TF-123").
DocumentNumber int `gorm:"index:latest_product_number"`

// DocumentType is the document type.
Expand Down Expand Up @@ -306,6 +307,14 @@ func (d *Document) createAssocations(db *gorm.DB) error {
d.OwnerID = &d.Owner.ID
}

// Get product if ProductID is not set.
if d.ProductID == 0 && d.Product.Name != "" {
if err := d.Product.Get(db); err != nil {
return fmt.Errorf("error getting product: %w", err)
}
d.ProductID = d.Product.ID
}

return nil
}

Expand Down
87 changes: 87 additions & 0 deletions pkg/models/document_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,93 @@ func TestDocumentModel(t *testing.T) {
})
})

t.Run("Update Product field using Upsert", func(t *testing.T) {
db, tearDownTest := setupTest(t, dsn)
defer tearDownTest(t)

t.Run("Create a document type", func(t *testing.T) {
_, require := assert.New(t), require.New(t)
dt := DocumentType{
Name: "DT1",
LongName: "DocumentType1",
}
err := dt.FirstOrCreate(db)
require.NoError(err)
})

t.Run("Create a product", func(t *testing.T) {
_, require := assert.New(t), require.New(t)
p := Product{
Name: "Product1",
Abbreviation: "P1",
}
err := p.FirstOrCreate(db)
require.NoError(err)
})

t.Run("Create a document by Upsert", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
d := Document{
GoogleFileID: "fileID1",
DocumentType: DocumentType{
Name: "DT1",
LongName: "DocumentType1",
},
Product: Product{
Name: "Product1",
},
}
err := d.Upsert(db)
require.NoError(err)
assert.EqualValues(1, d.ID)
assert.Equal("fileID1", d.GoogleFileID)
assert.Equal("Product1", d.Product.Name)
assert.Equal("P1", d.Product.Abbreviation)
assert.EqualValues(1, d.Product.ID)
})

t.Run("Get the document", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
d := Document{
GoogleFileID: "fileID1",
}
err := d.Get(db)
require.NoError(err)
assert.EqualValues(1, d.ID)
assert.Equal("fileID1", d.GoogleFileID)
assert.Equal("Product1", d.Product.Name)
assert.Equal("P1", d.Product.Abbreviation)
assert.EqualValues(1, d.Product.ID)
})

t.Run("Create a second product", func(t *testing.T) {
_, require := assert.New(t), require.New(t)
p := Product{
Name: "Product2",
Abbreviation: "P2",
}
err := p.FirstOrCreate(db)
require.NoError(err)
})

t.Run("Update the Product field by Upsert", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
d := Document{
GoogleFileID: "fileID1",
Product: Product{
Name: "Product2",
},
}
err := d.Upsert(db)
require.NoError(err)
assert.EqualValues(1, d.ID)
assert.Equal("fileID1", d.GoogleFileID)
assert.Equal("Product2", d.Product.Name)
assert.Equal("P2", d.Product.Abbreviation)
assert.EqualValues(2, d.Product.ID)
})
})

t.Run("Upsert a document with custom fields", func(t *testing.T) {
db, tearDownTest := setupTest(t, dsn)
defer tearDownTest(t)
Expand Down

0 comments on commit eebaf9e

Please sign in to comment.