From 6dfab23234136cd82aa3654bb8727ca847054744 Mon Sep 17 00:00:00 2001 From: Roland Osborne Date: Thu, 3 Feb 2022 13:34:03 -0800 Subject: [PATCH] restructured card data to optimise for notifications --- doc/api.oa3 | 186 +++++++++++----------- net/server/internal/api_clearCardNotes.go | 5 +- net/server/internal/api_contact.go | 2 +- net/server/internal/api_setCardNotes.go | 5 +- net/server/internal/api_setCardProfile.go | 2 +- net/server/internal/api_setOpenMessage.go | 1 - net/server/internal/modelUtil.go | 50 +++--- net/server/internal/models.go | 33 ++-- net/server/internal/routers.go | 6 +- net/server/internal/store/schema.go | 2 +- net/server/internal/testUtil.go | 2 +- net/server/internal/ucAddContact_test.go | 36 +++-- 12 files changed, 169 insertions(+), 161 deletions(-) diff --git a/doc/api.oa3 b/doc/api.oa3 index c5d493fc..4ff0141b 100644 --- a/doc/api.oa3 +++ b/doc/api.oa3 @@ -835,13 +835,6 @@ paths: operationId: get-groups security: - bearerAuth: [] - parameters: - - name: groupRevision - in: query - description: only return updated groups since specified revision - required: false - schema: - type: string responses: '200': description: successful operation @@ -1080,7 +1073,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/CardData' + $ref: '#/components/schemas/CardDetail' '401': description: permission denied '404': @@ -1315,12 +1308,12 @@ paths: '500': description: internal server error - /contact/cards/{cardId}/data: + /contact/cards/{cardId}/detail: get: tags: - contact - description: Get specified card data. Access granted to app tokens for account holder. - operationId: get-card-data + description: Get specified card detail. Access granted to app tokens for account holder. + operationId: get-card-detail security: - bearerAuth: [] parameters: @@ -1336,7 +1329,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/CardData' + $ref: '#/components/schemas/CardDetail' '401': description: permission denied '404': @@ -1367,7 +1360,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/CardData' + $ref: '#/components/schemas/CardDetail' '401': description: permission denied '404': @@ -1401,7 +1394,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/CardData' + $ref: '#/components/schemas/CardDetail' '401': description: permission denied '404': @@ -1438,7 +1431,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/CardData' + $ref: '#/components/schemas/CardDetail' '401': description: permission denied '404': @@ -1473,7 +1466,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/CardData' + $ref: '#/components/schemas/CardDetail' '401': description: permission denied '404': @@ -1531,30 +1524,6 @@ paths: type: integer format: int64 - /contact/label/revision: - put: - tags: - - contact - description: Set label revision for contact. This is intend to be invoked automatically anytime a contact updates their label or sharing. Access granted to contact tokens. - operationId: set-label-revision - security: - - bearerAuth: [] - responses: - '200': - description: revision set - '401': - description: not authorized - '410': - description: account disabled - '500': - description: internal server error - requestBody: - content: - application/json: - schema: - type: integer - format: int64 - /contact/view/revision: put: tags: @@ -2435,19 +2404,6 @@ paths: operationId: get-labels security: - bearerAuth: [] - parameters: - - name: viewRevision - in: query - description: only return updated if view matches - required: false - schema: - type: string - - name: labelRevision - in: query - description: only return updated if view matches - required: false - schema: - type: string responses: '200': description: successful operation @@ -4096,6 +4052,9 @@ components: required: - node properties: + revision: + type: integer + format: int64 handle: type: string name: @@ -4104,41 +4063,70 @@ components: type: string location: type: string - revision: - type: integer - format: int64 imageSet: type: boolean + version: + type: string node: type: string + CardDetail: + type: object + required: + - revision + properties: + revision: + type: integer + format: int64 + notes: + type: string + groups: + type: array + items: + type: string + Card: type: object required: - cardId + - revision - cardData properties: cardId: type: string + revision: + type: number + format: int64 cardData: $ref: '#/components/schemas/CardData' - + + CardData: type: object required: + - guid - status - - cardProfile - - cardData + - token + - detailRevision + - profileRevision - notifiedProfile - notifiedContent + - notifiedLabel - notifiedView properties: - cardId: + guid: type: string - cardProfile: - $ref: '#/components/schemas/CardProfile' - cardData: - $ref: '#/components/schemas/CardData' + status: + type: string + enum: [ pending, confirmed, requested, connecting, connected ] + token: + type: string + detailRevision: + type: integer + format: int64 + profileRevision: + type: integer + format: int64 notifiedProfile: type: integer format: int64 @@ -4151,17 +4139,6 @@ components: notifiedView: type: integer format: int64 - status: - type: string - enum: [ pending, confirmed, requested, connecting, connected ] - notes: - type: string - token: - type: string - groups: - type: array - items: - type: string Asset: type: object @@ -4332,6 +4309,8 @@ components: type: object required: - articleId + - articleBlockId + - revision - dataType - data - created @@ -4344,6 +4323,11 @@ components: properties: articleId: type: string + articleBlockId: + type: string + revision: + type: integer + format: int64 dataType: type: string data: @@ -4375,25 +4359,37 @@ components: type: integer format: int64 + ArticleView: + type: object + required: + - articleId + - revision + - tagRevision + properties: + articleId: + type: string + revision: + type: integer + format: int64 + tagRevision: + type: integer + format: int64 + Group: type: object required: - groupId - - groupData - properties: - groupId: - type: string - groupData: - $ref: '#/components/schemas/GroupData' - - GroupData: - type: object - required: + - revision - dataType - data - created - updated properties: + groupId: + type: string + revision: + type: integer + format: int64 dataType: type: string data: @@ -4409,22 +4405,18 @@ components: type: object required: - labelId - - labelData - properties: - labelId: - type: string - labelData: - $ref: '#/components/schemas/LabelData' - - LabelData: - type: object - required: - - dataType + - labelRevision + - type - data - created - modified properties: - dataType: + labelId: + type: string + labelRevision: + type: integer + format: int64 + type: type: string data: type: string diff --git a/net/server/internal/api_clearCardNotes.go b/net/server/internal/api_clearCardNotes.go index 9cbedeca..a8d695d0 100644 --- a/net/server/internal/api_clearCardNotes.go +++ b/net/server/internal/api_clearCardNotes.go @@ -22,7 +22,7 @@ func ClearCardNotes(w http.ResponseWriter, r *http.Request) { // load referenced card var slot store.CardSlot - if err := store.DB.Preload("Card.Groups.GroupSlot").Where("account_id = ? AND card_slot_id = ?", account.ID, cardId).First(&slot).Error; err != nil { + if err := store.DB.Preload("Card").Where("account_id = ? AND card_slot_id = ?", account.ID, cardId).First(&slot).Error; err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { ErrResponse(w, http.StatusInternalServerError, err) } else { @@ -37,6 +37,7 @@ func ClearCardNotes(w http.ResponseWriter, r *http.Request) { // update card slot.Revision = account.CardRevision + 1 + slot.Card.DetailRevision += 1 slot.Card.Notes = "" // save and update contact revision @@ -58,6 +59,6 @@ func ClearCardNotes(w http.ResponseWriter, r *http.Request) { } SetStatus(account) - WriteResponse(w, getCardModel(&slot)); + WriteResponse(w, getCardDetailModel(&slot)); } diff --git a/net/server/internal/api_contact.go b/net/server/internal/api_contact.go index 8914dccf..df012248 100644 --- a/net/server/internal/api_contact.go +++ b/net/server/internal/api_contact.go @@ -18,7 +18,7 @@ func ClearCardGroup(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -func GetCardData(w http.ResponseWriter, r *http.Request) { +func GetCardDetail(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") w.WriteHeader(http.StatusOK) } diff --git a/net/server/internal/api_setCardNotes.go b/net/server/internal/api_setCardNotes.go index bb86fe9b..d0aadae3 100644 --- a/net/server/internal/api_setCardNotes.go +++ b/net/server/internal/api_setCardNotes.go @@ -28,7 +28,7 @@ func SetCardNotes(w http.ResponseWriter, r *http.Request) { // load referenced card var slot store.CardSlot - if err := store.DB.Preload("Card.Groups.GroupSlot").Where("account_id = ? AND card_slot_id = ?", account.ID, cardId).First(&slot).Error; err != nil { + if err := store.DB.Preload("Card").Where("account_id = ? AND card_slot_id = ?", account.ID, cardId).First(&slot).Error; err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { ErrResponse(w, http.StatusInternalServerError, err) } else { @@ -43,6 +43,7 @@ func SetCardNotes(w http.ResponseWriter, r *http.Request) { // update card slot.Revision = account.CardRevision + 1 + slot.Card.DetailRevision += 1 slot.Card.Notes = notes // save and update contact revision @@ -64,6 +65,6 @@ func SetCardNotes(w http.ResponseWriter, r *http.Request) { } SetStatus(account) - WriteResponse(w, getCardModel(&slot)); + WriteResponse(w, getCardDetailModel(&slot)); } diff --git a/net/server/internal/api_setCardProfile.go b/net/server/internal/api_setCardProfile.go index 801129bd..d5be2100 100644 --- a/net/server/internal/api_setCardProfile.go +++ b/net/server/internal/api_setCardProfile.go @@ -87,6 +87,6 @@ func SetCardProfile(w http.ResponseWriter, r *http.Request) { } SetStatus(account) - WriteResponse(w, getCardModel(&slot)); + WriteResponse(w, getCardProfileModel(&slot)); } diff --git a/net/server/internal/api_setOpenMessage.go b/net/server/internal/api_setOpenMessage.go index c3023a6a..34461afb 100644 --- a/net/server/internal/api_setOpenMessage.go +++ b/net/server/internal/api_setOpenMessage.go @@ -149,7 +149,6 @@ func SetOpenMessage(w http.ResponseWriter, r *http.Request) { if card.Status == APP_CARDCONNECTING { card.Status = APP_CARDCONNECTED } - card.DataRevision += 1 card.OutToken = connect.Token // save contact card diff --git a/net/server/internal/modelUtil.go b/net/server/internal/modelUtil.go index e265c8a1..2e53e008 100644 --- a/net/server/internal/modelUtil.go +++ b/net/server/internal/modelUtil.go @@ -12,12 +12,6 @@ func getCardModel(slot *store.CardSlot) *Card { } } - // populate group id list - var groups []string; - for _, group := range slot.Card.Groups { - groups = append(groups, group.GroupSlot.GroupSlotId) - } - return &Card{ CardId: slot.CardSlotId, Revision: slot.Revision, @@ -26,25 +20,43 @@ func getCardModel(slot *store.CardSlot) *Card { NotifiedContent: slot.Card.NotifiedContent, NotifiedLabel: slot.Card.NotifiedLabel, NotifiedView: slot.Card.NotifiedView, - CardProfile: &CardProfile{ - Guid: slot.Card.Guid, - Handle: slot.Card.Username, - Name: slot.Card.Name, - Description: slot.Card.Description, - Location: slot.Card.Location, - Revision: slot.Card.ProfileRevision, - ImageSet: slot.Card.Image != "", - Version: slot.Card.Version, - Node: slot.Card.Node, - }, + ProfileRevision: slot.Card.ProfileRevision, + DetailRevision: slot.Card.DetailRevision, + Guid: slot.Card.Guid, Status: slot.Card.Status, - Notes: slot.Card.Notes, Token: slot.Card.OutToken, - Groups: groups, }, } } +func getCardDetailModel(slot *store.CardSlot) *CardDetail { + + var groups []string; + for _, group := range slot.Card.Groups { + groups = append(groups, group.GroupSlot.GroupSlotId) + } + + return &CardDetail{ + Revision: slot.Card.DetailRevision, + Notes: slot.Card.Notes, + Groups: groups, + } +} + +func getCardProfileModel(slot *store.CardSlot) *CardProfile { + + return &CardProfile{ + Revision: slot.Card.ProfileRevision, + Handle: slot.Card.Username, + Name: slot.Card.Name, + Description: slot.Card.Description, + Location: slot.Card.Location, + ImageSet: slot.Card.Image != "", + Version: slot.Card.Version, + Node: slot.Card.Node, + } +} + func getGroupModel(slot *store.GroupSlot) *Group { if slot.Group == nil { return &Group{ diff --git a/net/server/internal/models.go b/net/server/internal/models.go index 9882a8c3..9a287f34 100644 --- a/net/server/internal/models.go +++ b/net/server/internal/models.go @@ -84,44 +84,39 @@ type Asset struct { type Card struct { CardId string `json:"cardId"` - Revision int64 `json:"revision"` - CardData *CardData `json:"cardData"` + Revision int64 `json:"revision,omitempty"` + CardData *CardData `json:"articleData"` } type CardData struct { - CardProfile *CardProfile `json:"cardProfile"` + Guid string `json:"guid"` + Status string `json:"status"` + Token string `json:"token,omitempty"` + DetailRevision int64 `json:"detailRevision"` + ProfileRevision int64 `json:"profileRevision"` NotifiedProfile int64 `json:"notifiedProfile"` NotifiedContent int64 `json:"notifiedContent"` - NotifiedLabel int64 `json:"notifiedLabel"` + NotifiedLabel int64 `json:"notifiedLabel"` NotifiedView int64 `json:"notifiedView"` - Status string `json:"status"` +} + +type CardDetail struct { + Revision int64 `json:"revision,omitempty"` Notes string `json:"notes,omitempty"` - Token string `json:"token,omitempty"` Groups []string `json:"groups,omitempty"` } type CardProfile struct { - Guid string `json:"guid"` + Revision int64 `json:"revision,omitempty"` Handle string `json:"handle,omitempty"` Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` Location string `json:"location,omitempty"` - Revision int64 `json:"revision,omitempty"` ImageSet bool `json:"imageSet,omitempty"` - Version string `json:"version"` + Version string `json:"version"` Node string `json:"node"` } -type ContentArticlesBody struct { - Labels []string `json:"labels"` - Groups []string `json:"groups"` -} - -type ContentLabelsBody struct { - Type_ string `json:"type"` - Data string `json:"data"` -} - type Dialogue struct { DialogueId string `json:"dialogueId"` DialogueRevison int64 `json:"dialogueRevison,omitempty"` diff --git a/net/server/internal/routers.go b/net/server/internal/routers.go index 4c03138e..47d5f8d2 100644 --- a/net/server/internal/routers.go +++ b/net/server/internal/routers.go @@ -300,10 +300,10 @@ var routes = Routes{ }, Route{ - "GetCardData", + "GetCardDetail", strings.ToUpper("Get"), - "/contact/cards/{cardId}/data", - GetCardData, + "/contact/cards/{cardId}/detail", + GetCardDetail, }, Route{ diff --git a/net/server/internal/store/schema.go b/net/server/internal/store/schema.go index e247f0aa..1df6a705 100644 --- a/net/server/internal/store/schema.go +++ b/net/server/internal/store/schema.go @@ -175,11 +175,11 @@ type Card struct { Version string `gorm:"not null"` Node string `gorm:"not null"` ProfileRevision int64 `gorm:"not null"` + DetailRevision int64 `gorm:"not null"` Status string `gorm:"not null"` InToken string `gorm:"not null;index:cardguid,unique"` OutToken string Notes string - DataRevision int64 `gorm:"not null"` Created int64 `gorm:"autoCreateTime"` Updated int64 `gorm:"autoUpdateTime"` ViewRevision int64 `gorm:"not null"` diff --git a/net/server/internal/testUtil.go b/net/server/internal/testUtil.go index 101c477b..bced9970 100644 --- a/net/server/internal/testUtil.go +++ b/net/server/internal/testUtil.go @@ -300,7 +300,7 @@ func GetCardToken(account string, cardId string) (token string, err error) { err = errors.New("card not connected") return } - token = card.CardData.CardProfile.Guid + "." + card.CardData.Token + token = card.CardData.Guid + "." + card.CardData.Token return } diff --git a/net/server/internal/ucAddContact_test.go b/net/server/internal/ucAddContact_test.go index 28a1f4a4..8c085764 100644 --- a/net/server/internal/ucAddContact_test.go +++ b/net/server/internal/ucAddContact_test.go @@ -13,7 +13,10 @@ func TestAddContact(t *testing.T) { var r *Revision var msg DataMessage var cards []Card - var card *Card + var detail int64 + var profile int64 + var cardProfile *CardProfile + var cardDetail *CardDetail // setup testing group set, err = AddTestGroup("addaccount") @@ -40,35 +43,40 @@ func TestAddContact(t *testing.T) { assert.NoError(t, SendEndpointTest(GetCards, "GET", "/contact/cards?cardRevision=" + strconv.FormatInt(rev.Card, 10), nil, nil, APP_TOKENAPP, set.B.Token, &cards)) assert.Equal(t, 1, len(cards)) - assert.Equal(t, set.A.Guid, cards[0].CardData.CardProfile.Guid) - assert.NotEqual(t, "Namer", cards[0].CardData.CardProfile.Name) + assert.Equal(t, set.A.Guid, cards[0].CardData.Guid) + profile = cards[0].CardData.ProfileRevision rev = r - card = &Card{} + cardProfile = &CardProfile{} assert.NoError(t, SendEndpointTest(GetProfileMessage, "GET", "/profile/message", nil, nil, APP_TOKENCONTACT, set.B.A.Token, &msg)) - assert.NoError(t, SendEndpointTest(SetCardProfile, "PUT", "/contact/cards/{cardId}/profile", &map[string]string{"cardId":cards[0].CardId}, msg, APP_TOKENAPP, set.B.Token, &card)) + assert.NoError(t, SendEndpointTest(SetCardProfile, "PUT", "/contact/cards/{cardId}/profile", &map[string]string{"cardId":cards[0].CardId}, msg, APP_TOKENAPP, set.B.Token, cardProfile)) + assert.Equal(t, "Namer", cardProfile.Name) r = GetTestRevision(set.B.Revisions) assert.NotEqual(t, rev.Card, r.Card) assert.NoError(t, SendEndpointTest(GetCards, "GET", "/contact/cards?cardRevision=" + strconv.FormatInt(rev.Card, 10), nil, nil, APP_TOKENAPP, set.B.Token, &cards)) assert.Equal(t, 1, len(cards)) - assert.Equal(t, set.A.Guid, cards[0].CardData.CardProfile.Guid) - assert.Equal(t, "Namer", cards[0].CardData.CardProfile.Name) + assert.Equal(t, set.A.Guid, cards[0].CardData.Guid) + assert.NotEqual(t, profile, cards[0].CardData.ProfileRevision) + detail = cards[0].CardData.DetailRevision rev = r - card = &Card{} - assert.NoError(t, SendEndpointTest(SetCardNotes, "PUT", "/contact/cards/{cardId}/notes", &map[string]string{"cardId":cards[0].CardId}, "some interesting notes", APP_TOKENAPP, set.B.Token, &card)) - assert.Equal(t, "some interesting notes", card.CardData.Notes) + cardDetail = &CardDetail{} + assert.NoError(t, SendEndpointTest(SetCardNotes, "PUT", "/contact/cards/{cardId}/notes", &map[string]string{"cardId":cards[0].CardId}, "some interesting notes", APP_TOKENAPP, set.B.Token, cardDetail)) + assert.Equal(t, "some interesting notes", cardDetail.Notes) r = GetTestRevision(set.B.Revisions) assert.NotEqual(t, rev.Card, r.Card) rev = r - card = &Card{} - assert.NoError(t, SendEndpointTest(ClearCardNotes, "DELETE", "/contact/cards/{cardId}/notes", &map[string]string{"cardId":cards[0].CardId}, nil, APP_TOKENAPP, set.B.Token, &card)) - assert.Equal(t, "", card.CardData.Notes) + cardDetail = &CardDetail{} + assert.NoError(t, SendEndpointTest(ClearCardNotes, "DELETE", "/contact/cards/{cardId}/notes", &map[string]string{"cardId":cards[0].CardId}, nil, APP_TOKENAPP, set.B.Token, cardDetail)) + assert.Equal(t, "", cardDetail.Notes) r = GetTestRevision(set.B.Revisions) assert.NotEqual(t, rev.Card, r.Card) - rev = r + assert.NoError(t, SendEndpointTest(GetCards, "GET", "/contact/cards?cardRevision=" + strconv.FormatInt(rev.Card, 10), nil, nil, APP_TOKENAPP, set.B.Token, &cards)) + assert.Equal(t, 1, len(cards)) + assert.Equal(t, set.A.Guid, cards[0].CardData.Guid) + assert.NotEqual(t, detail, cards[0].CardData.DetailRevision) }