Skip to content

Commit

Permalink
Merge pull request #125 from wepala/WEOS-1359
Browse files Browse the repository at this point in the history
Weos 1359 - As a developer I should be able have a datetime field automatically update on update
  • Loading branch information
atoniaw authored Feb 28, 2022
2 parents f2e175d + 90bc8f7 commit 87e0388
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 1 deletion.
5 changes: 5 additions & 0 deletions api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,14 @@ components:
lastUpdated:
type: string
format: date-time
x-update:
- Add Blog
- Update Blog
created:
type: string
format: date-time
x-update:
- Add Blog
required:
- title
- url
Expand Down
1 change: 1 addition & 0 deletions context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const HeaderXLogLevel = "X-LOG-LEVEL"

//add more keys here if needed
const ACCOUNT_ID ContextKey = "ACCOUNT_ID"
const OPERATION_ID = "OPERATION_ID"
const USER_ID ContextKey = "USER_ID"
const LOG_LEVEL ContextKey = "LOG_LEVEL"
const REQUEST_ID ContextKey = "REQUEST_ID"
Expand Down
44 changes: 44 additions & 0 deletions controllers/rest/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package rest_test
import (
"bytes"
"encoding/json"
"github.com/labstack/echo/v4"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
Expand Down Expand Up @@ -432,3 +434,45 @@ func TestRESTAPI_Initialize_DiscoveryAddedToGet(t *testing.T) {
t.Errorf("expected to find get path")
}
}

func TestRESTAPI_Integration_AutomaticallyUpdateDateTime(t *testing.T) {
tapi, err := api.New("./fixtures/blog.yaml")
if err != nil {
t.Fatalf("un expected error loading spec '%s'", err)
}
err = tapi.Initialize(nil)
if err != nil {
t.Fatalf("un expected error loading spec '%s'", err)
}
e := tapi.EchoInstance()
t.Run("automatically updating create", func(t *testing.T) {
mockBlog := map[string]interface{}{"title": "Test Blog", "url": "www.testBlog.com"}
reqBytes, err := json.Marshal(mockBlog)
if err != nil {
t.Fatalf("error setting up request %s", err)
}
body := bytes.NewReader(reqBytes)
resp := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodPost, "/blogs", body)
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
e.ServeHTTP(resp, req)
if resp.Result().StatusCode != http.StatusCreated {
t.Errorf("expected the response code to be %d, got %d", http.StatusCreated, resp.Result().StatusCode)
}
defer resp.Result().Body.Close()
tResults, err := ioutil.ReadAll(resp.Result().Body)
if err != nil {
t.Errorf("unexpect error: %s", err)
}
results := map[string]interface{}{}
err = json.Unmarshal(tResults, &results)
if err != nil {
t.Errorf("unexpect error: %s", err)
}
if results["created"] == nil || results["lastUpdated"] == nil {
t.Errorf("unexpect error expected to find created and lastUpdated")
}

})

}
5 changes: 5 additions & 0 deletions controllers/rest/fixtures/blog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,14 @@ components:
lastUpdated:
type: string
format: date-time
x-update:
- Add Blog
- Update Blog
created:
type: string
format: date-time
x-update:
- Add Blog
required:
- title
- url
Expand Down
3 changes: 3 additions & 0 deletions controllers/rest/middleware_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ func Context(api *RESTAPI, projection projections.Projection, commandDispatcher

cc, err = parseResponses(c, cc, operation)

//add OperationID to context
cc = context.WithValue(cc, weosContext.OPERATION_ID, operation.OperationID)

//parse request body based on content type
var payload []byte
ct := c.Request().Header.Get("Content-Type")
Expand Down
22 changes: 22 additions & 0 deletions controllers/rest/middleware_context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -509,4 +509,26 @@ func TestContext(t *testing.T) {
e.GET("/blogs", handler)
e.ServeHTTP(resp, req)
})

t.Run("add operationId to context", func(t *testing.T) {
path := swagger.Paths.Find("/blogs")
mw := rest.Context(restApi, nil, nil, nil, entityFactory, path, path.Get)
handler := mw(func(ctxt echo.Context) error {
//check that certain parameters are in the context
cc := ctxt.Request().Context()
value := cc.Value(context.OPERATION_ID)
if value == nil {
t.Fatalf("expected the operation id to have a value")
}
if value.(string) != "Get Blogs" {
t.Fatalf("expected the operation id to be Get Blogs")
}
return nil
})
e := echo.New()
resp := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/blogs", nil)
e.GET("/blogs", handler)
e.ServeHTTP(resp, req)
})
}
25 changes: 25 additions & 0 deletions model/content_entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,3 +378,28 @@ func (w *ContentEntity) UnmarshalJSON(data []byte) error {
err = json.Unmarshal(data, &w.Property)
return err
}

//UpdateTime updates auto update time values on the payload
func (w *ContentEntity) UpdateTime(operationID string, data []byte) ([]byte, error) {
scheme := w.Schema
payload := map[string]interface{}{}
json.Unmarshal(data, &payload)
for key, p := range scheme.Properties {
routes := []string{}
routeBytes, _ := json.Marshal(p.Value.Extensions["x-update"])
json.Unmarshal(routeBytes, &routes)
for _, r := range routes {
if r == operationID {
if p.Value.Format == "date-time" {
payload[key] = time.Now()
}
}
}
}
newPayload, err := json.Marshal(payload)
if err != nil {
return nil, err
}

return newPayload, nil
}
33 changes: 33 additions & 0 deletions model/content_entity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,3 +370,36 @@ func TestContentEntity_Delete(t *testing.T) {
}

}

func TestContentEntity_UpdateTime(t *testing.T) {
//load open api spec
api, err := rest.New("../controllers/rest/fixtures/blog.yaml")
schemas := rest.CreateSchema(context.TODO(), api.EchoInstance(), api.Swagger)
contentType := "Blog"
entityFactory := new(model.DefaultEntityFactory).FromSchemaAndBuilder(contentType, api.Swagger.Components.Schemas[contentType].Value, schemas[contentType])
if err != nil {
t.Fatalf("error setting up entity factory")
}
entity, err := entityFactory.NewEntity(context.TODO())
if err != nil {
t.Fatalf("error generating entity '%s'", err)
}

mapPayload := map[string]interface{}{"title": "update time", "description": "new time", "url": "www.MyBlog.com"}
newPayload, errr := json.Marshal(mapPayload)
if errr != nil {
t.Fatalf("error marshalling Payload '%s'", err)
}

updatedTimePayload, errrr := entity.UpdateTime("Update Blog", newPayload)
if errrr != nil {
t.Fatalf("error updating time payload '%s'", err)
}

tempPayload := map[string]interface{}{}
json.Unmarshal(updatedTimePayload, &tempPayload)

if tempPayload["lastUpdated"] == "" {
t.Fatalf("expected the lastupdated field to not be blank")
}
}
38 changes: 37 additions & 1 deletion model/domain_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func (s *DomainService) Update(ctx context.Context, payload json.RawMessage, ent
seqNo = seq
}

existingEntity, err := s.GetContentEntity(ctx, entityFactory, weosID)
existingEntity, err = s.GetContentEntity(ctx, entityFactory, weosID)
if err != nil {
return nil, NewDomainError("invalid: unexpected error fetching existing entity", entityType, weosID, err)
}
Expand Down Expand Up @@ -161,6 +161,15 @@ func (s *DomainService) Update(ctx context.Context, payload json.RawMessage, ent
}
}

//update default time update values based on routes
operation, ok := ctx.Value(weosContext.OPERATION_ID).(string)
if ok {
newPayload, err = existingEntity.UpdateTime(operation, newPayload)
}
if err != nil {
return nil, err
}

updatedEntity, err = existingEntity.Update(ctx, newPayload)
if err != nil {
return nil, err
Expand Down Expand Up @@ -200,6 +209,15 @@ func (s *DomainService) Update(ctx context.Context, payload json.RawMessage, ent
return nil, err
}

//update default time update values based on routes
operation, ok := ctx.Value(weosContext.OPERATION_ID).(string)
if ok {
newPayload, err = existingEntity.UpdateTime(operation, newPayload)
if err != nil {
return nil, err
}
}

updatedEntity, err = existingEntity.Update(ctx, newPayload)
if err != nil {
s.logger.Errorf("error updating entity", err)
Expand Down Expand Up @@ -275,6 +293,15 @@ func (s *DomainService) Delete(ctx context.Context, entityID string, entityType
return nil, err
}

//update default time update values based on routes
operation, ok := ctx.Value(weosContext.OPERATION_ID).(string)
if ok {
existingEntityPayload, err = existingEntity.UpdateTime(operation, existingEntityPayload)
if err != nil {
return nil, err
}
}

deletedEntity, err = existingEntity.Delete(existingEntityPayload)
if err != nil {
return nil, err
Expand All @@ -301,6 +328,15 @@ func (s *DomainService) Delete(ctx context.Context, entityID string, entityType
return nil, err
}

//update default time update values based on routes
operation, ok := ctx.Value(weosContext.OPERATION_ID).(string)
if ok {
data, err = existingEntity.UpdateTime(operation, data)
if err != nil {
return nil, err
}
}

deletedEntity, err = existingEntity.Delete(data)
if err != nil {
return nil, err
Expand Down
12 changes: 12 additions & 0 deletions model/receiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"encoding/json"
"errors"
"fmt"

weosContext "github.com/wepala/weos/context"
"golang.org/x/net/context"
)

Expand Down Expand Up @@ -35,6 +37,16 @@ func CreateHandler(ctx context.Context, command *Command, eventStore EventReposi
logger.Error(err)
return err
}

//update default time update values based on routes
operation, ok := ctx.Value(weosContext.OPERATION_ID).(string)
if ok {
payload, err = newEntity.UpdateTime(operation, payload)
if err != nil {
return err
}
}

//use the entity id that was passed with the command
newEntity.ID = command.Metadata.EntityID
//add create event
Expand Down

0 comments on commit 87e0388

Please sign in to comment.