restructured card data to optimise for notifications

This commit is contained in:
Roland Osborne 2022-02-03 13:34:03 -08:00
parent 8cdf70a4cd
commit 6dfab23234
12 changed files with 169 additions and 161 deletions

View File

@ -835,13 +835,6 @@ paths:
operationId: get-groups operationId: get-groups
security: security:
- bearerAuth: [] - bearerAuth: []
parameters:
- name: groupRevision
in: query
description: only return updated groups since specified revision
required: false
schema:
type: string
responses: responses:
'200': '200':
description: successful operation description: successful operation
@ -1080,7 +1073,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/CardData' $ref: '#/components/schemas/CardDetail'
'401': '401':
description: permission denied description: permission denied
'404': '404':
@ -1315,12 +1308,12 @@ paths:
'500': '500':
description: internal server error description: internal server error
/contact/cards/{cardId}/data: /contact/cards/{cardId}/detail:
get: get:
tags: tags:
- contact - contact
description: Get specified card data. Access granted to app tokens for account holder. description: Get specified card detail. Access granted to app tokens for account holder.
operationId: get-card-data operationId: get-card-detail
security: security:
- bearerAuth: [] - bearerAuth: []
parameters: parameters:
@ -1336,7 +1329,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/CardData' $ref: '#/components/schemas/CardDetail'
'401': '401':
description: permission denied description: permission denied
'404': '404':
@ -1367,7 +1360,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/CardData' $ref: '#/components/schemas/CardDetail'
'401': '401':
description: permission denied description: permission denied
'404': '404':
@ -1401,7 +1394,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/CardData' $ref: '#/components/schemas/CardDetail'
'401': '401':
description: permission denied description: permission denied
'404': '404':
@ -1438,7 +1431,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/CardData' $ref: '#/components/schemas/CardDetail'
'401': '401':
description: permission denied description: permission denied
'404': '404':
@ -1473,7 +1466,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/CardData' $ref: '#/components/schemas/CardDetail'
'401': '401':
description: permission denied description: permission denied
'404': '404':
@ -1531,30 +1524,6 @@ paths:
type: integer type: integer
format: int64 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: /contact/view/revision:
put: put:
tags: tags:
@ -2435,19 +2404,6 @@ paths:
operationId: get-labels operationId: get-labels
security: security:
- bearerAuth: [] - 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: responses:
'200': '200':
description: successful operation description: successful operation
@ -4096,6 +4052,9 @@ components:
required: required:
- node - node
properties: properties:
revision:
type: integer
format: int64
handle: handle:
type: string type: string
name: name:
@ -4104,41 +4063,70 @@ components:
type: string type: string
location: location:
type: string type: string
revision:
type: integer
format: int64
imageSet: imageSet:
type: boolean type: boolean
version:
type: string
node: node:
type: string type: string
CardDetail:
type: object
required:
- revision
properties:
revision:
type: integer
format: int64
notes:
type: string
groups:
type: array
items:
type: string
Card: Card:
type: object type: object
required: required:
- cardId - cardId
- revision
- cardData - cardData
properties: properties:
cardId: cardId:
type: string type: string
revision:
type: number
format: int64
cardData: cardData:
$ref: '#/components/schemas/CardData' $ref: '#/components/schemas/CardData'
CardData: CardData:
type: object type: object
required: required:
- guid
- status - status
- cardProfile - token
- cardData - detailRevision
- profileRevision
- notifiedProfile - notifiedProfile
- notifiedContent - notifiedContent
- notifiedLabel
- notifiedView - notifiedView
properties: properties:
cardId: guid:
type: string type: string
cardProfile: status:
$ref: '#/components/schemas/CardProfile' type: string
cardData: enum: [ pending, confirmed, requested, connecting, connected ]
$ref: '#/components/schemas/CardData' token:
type: string
detailRevision:
type: integer
format: int64
profileRevision:
type: integer
format: int64
notifiedProfile: notifiedProfile:
type: integer type: integer
format: int64 format: int64
@ -4151,17 +4139,6 @@ components:
notifiedView: notifiedView:
type: integer type: integer
format: int64 format: int64
status:
type: string
enum: [ pending, confirmed, requested, connecting, connected ]
notes:
type: string
token:
type: string
groups:
type: array
items:
type: string
Asset: Asset:
type: object type: object
@ -4332,6 +4309,8 @@ components:
type: object type: object
required: required:
- articleId - articleId
- articleBlockId
- revision
- dataType - dataType
- data - data
- created - created
@ -4344,6 +4323,11 @@ components:
properties: properties:
articleId: articleId:
type: string type: string
articleBlockId:
type: string
revision:
type: integer
format: int64
dataType: dataType:
type: string type: string
data: data:
@ -4375,25 +4359,37 @@ components:
type: integer type: integer
format: int64 format: int64
ArticleView:
type: object
required:
- articleId
- revision
- tagRevision
properties:
articleId:
type: string
revision:
type: integer
format: int64
tagRevision:
type: integer
format: int64
Group: Group:
type: object type: object
required: required:
- groupId - groupId
- groupData - revision
properties:
groupId:
type: string
groupData:
$ref: '#/components/schemas/GroupData'
GroupData:
type: object
required:
- dataType - dataType
- data - data
- created - created
- updated - updated
properties: properties:
groupId:
type: string
revision:
type: integer
format: int64
dataType: dataType:
type: string type: string
data: data:
@ -4409,22 +4405,18 @@ components:
type: object type: object
required: required:
- labelId - labelId
- labelData - labelRevision
properties: - type
labelId:
type: string
labelData:
$ref: '#/components/schemas/LabelData'
LabelData:
type: object
required:
- dataType
- data - data
- created - created
- modified - modified
properties: properties:
dataType: labelId:
type: string
labelRevision:
type: integer
format: int64
type:
type: string type: string
data: data:
type: string type: string

View File

@ -22,7 +22,7 @@ func ClearCardNotes(w http.ResponseWriter, r *http.Request) {
// load referenced card // load referenced card
var slot store.CardSlot 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) { if !errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusInternalServerError, err) ErrResponse(w, http.StatusInternalServerError, err)
} else { } else {
@ -37,6 +37,7 @@ func ClearCardNotes(w http.ResponseWriter, r *http.Request) {
// update card // update card
slot.Revision = account.CardRevision + 1 slot.Revision = account.CardRevision + 1
slot.Card.DetailRevision += 1
slot.Card.Notes = "" slot.Card.Notes = ""
// save and update contact revision // save and update contact revision
@ -58,6 +59,6 @@ func ClearCardNotes(w http.ResponseWriter, r *http.Request) {
} }
SetStatus(account) SetStatus(account)
WriteResponse(w, getCardModel(&slot)); WriteResponse(w, getCardDetailModel(&slot));
} }

View File

@ -18,7 +18,7 @@ func ClearCardGroup(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) 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.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }

View File

@ -28,7 +28,7 @@ func SetCardNotes(w http.ResponseWriter, r *http.Request) {
// load referenced card // load referenced card
var slot store.CardSlot 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) { if !errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusInternalServerError, err) ErrResponse(w, http.StatusInternalServerError, err)
} else { } else {
@ -43,6 +43,7 @@ func SetCardNotes(w http.ResponseWriter, r *http.Request) {
// update card // update card
slot.Revision = account.CardRevision + 1 slot.Revision = account.CardRevision + 1
slot.Card.DetailRevision += 1
slot.Card.Notes = notes slot.Card.Notes = notes
// save and update contact revision // save and update contact revision
@ -64,6 +65,6 @@ func SetCardNotes(w http.ResponseWriter, r *http.Request) {
} }
SetStatus(account) SetStatus(account)
WriteResponse(w, getCardModel(&slot)); WriteResponse(w, getCardDetailModel(&slot));
} }

View File

@ -87,6 +87,6 @@ func SetCardProfile(w http.ResponseWriter, r *http.Request) {
} }
SetStatus(account) SetStatus(account)
WriteResponse(w, getCardModel(&slot)); WriteResponse(w, getCardProfileModel(&slot));
} }

View File

@ -149,7 +149,6 @@ func SetOpenMessage(w http.ResponseWriter, r *http.Request) {
if card.Status == APP_CARDCONNECTING { if card.Status == APP_CARDCONNECTING {
card.Status = APP_CARDCONNECTED card.Status = APP_CARDCONNECTED
} }
card.DataRevision += 1
card.OutToken = connect.Token card.OutToken = connect.Token
// save contact card // save contact card

View File

@ -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{ return &Card{
CardId: slot.CardSlotId, CardId: slot.CardSlotId,
Revision: slot.Revision, Revision: slot.Revision,
@ -26,25 +20,43 @@ func getCardModel(slot *store.CardSlot) *Card {
NotifiedContent: slot.Card.NotifiedContent, NotifiedContent: slot.Card.NotifiedContent,
NotifiedLabel: slot.Card.NotifiedLabel, NotifiedLabel: slot.Card.NotifiedLabel,
NotifiedView: slot.Card.NotifiedView, NotifiedView: slot.Card.NotifiedView,
CardProfile: &CardProfile{ ProfileRevision: slot.Card.ProfileRevision,
Guid: slot.Card.Guid, DetailRevision: slot.Card.DetailRevision,
Handle: slot.Card.Username, Guid: slot.Card.Guid,
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,
},
Status: slot.Card.Status, Status: slot.Card.Status,
Notes: slot.Card.Notes,
Token: slot.Card.OutToken, 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 { func getGroupModel(slot *store.GroupSlot) *Group {
if slot.Group == nil { if slot.Group == nil {
return &Group{ return &Group{

View File

@ -84,44 +84,39 @@ type Asset struct {
type Card struct { type Card struct {
CardId string `json:"cardId"` CardId string `json:"cardId"`
Revision int64 `json:"revision"` Revision int64 `json:"revision,omitempty"`
CardData *CardData `json:"cardData"` CardData *CardData `json:"articleData"`
} }
type CardData struct { 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"` NotifiedProfile int64 `json:"notifiedProfile"`
NotifiedContent int64 `json:"notifiedContent"` NotifiedContent int64 `json:"notifiedContent"`
NotifiedLabel int64 `json:"notifiedLabel"` NotifiedLabel int64 `json:"notifiedLabel"`
NotifiedView int64 `json:"notifiedView"` NotifiedView int64 `json:"notifiedView"`
Status string `json:"status"` }
type CardDetail struct {
Revision int64 `json:"revision,omitempty"`
Notes string `json:"notes,omitempty"` Notes string `json:"notes,omitempty"`
Token string `json:"token,omitempty"`
Groups []string `json:"groups,omitempty"` Groups []string `json:"groups,omitempty"`
} }
type CardProfile struct { type CardProfile struct {
Guid string `json:"guid"` Revision int64 `json:"revision,omitempty"`
Handle string `json:"handle,omitempty"` Handle string `json:"handle,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
Location string `json:"location,omitempty"` Location string `json:"location,omitempty"`
Revision int64 `json:"revision,omitempty"`
ImageSet bool `json:"imageSet,omitempty"` ImageSet bool `json:"imageSet,omitempty"`
Version string `json:"version"` Version string `json:"version"`
Node string `json:"node"` 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 { type Dialogue struct {
DialogueId string `json:"dialogueId"` DialogueId string `json:"dialogueId"`
DialogueRevison int64 `json:"dialogueRevison,omitempty"` DialogueRevison int64 `json:"dialogueRevison,omitempty"`

View File

@ -300,10 +300,10 @@ var routes = Routes{
}, },
Route{ Route{
"GetCardData", "GetCardDetail",
strings.ToUpper("Get"), strings.ToUpper("Get"),
"/contact/cards/{cardId}/data", "/contact/cards/{cardId}/detail",
GetCardData, GetCardDetail,
}, },
Route{ Route{

View File

@ -175,11 +175,11 @@ type Card struct {
Version string `gorm:"not null"` Version string `gorm:"not null"`
Node string `gorm:"not null"` Node string `gorm:"not null"`
ProfileRevision int64 `gorm:"not null"` ProfileRevision int64 `gorm:"not null"`
DetailRevision int64 `gorm:"not null"`
Status string `gorm:"not null"` Status string `gorm:"not null"`
InToken string `gorm:"not null;index:cardguid,unique"` InToken string `gorm:"not null;index:cardguid,unique"`
OutToken string OutToken string
Notes string Notes string
DataRevision int64 `gorm:"not null"`
Created int64 `gorm:"autoCreateTime"` Created int64 `gorm:"autoCreateTime"`
Updated int64 `gorm:"autoUpdateTime"` Updated int64 `gorm:"autoUpdateTime"`
ViewRevision int64 `gorm:"not null"` ViewRevision int64 `gorm:"not null"`

View File

@ -300,7 +300,7 @@ func GetCardToken(account string, cardId string) (token string, err error) {
err = errors.New("card not connected") err = errors.New("card not connected")
return return
} }
token = card.CardData.CardProfile.Guid + "." + card.CardData.Token token = card.CardData.Guid + "." + card.CardData.Token
return return
} }

View File

@ -13,7 +13,10 @@ func TestAddContact(t *testing.T) {
var r *Revision var r *Revision
var msg DataMessage var msg DataMessage
var cards []Card var cards []Card
var card *Card var detail int64
var profile int64
var cardProfile *CardProfile
var cardDetail *CardDetail
// setup testing group // setup testing group
set, err = AddTestGroup("addaccount") 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.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, 1, len(cards))
assert.Equal(t, set.A.Guid, cards[0].CardData.CardProfile.Guid) assert.Equal(t, set.A.Guid, cards[0].CardData.Guid)
assert.NotEqual(t, "Namer", cards[0].CardData.CardProfile.Name) profile = cards[0].CardData.ProfileRevision
rev = r 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(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) r = GetTestRevision(set.B.Revisions)
assert.NotEqual(t, rev.Card, r.Card) 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.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, 1, len(cards))
assert.Equal(t, set.A.Guid, cards[0].CardData.CardProfile.Guid) assert.Equal(t, set.A.Guid, cards[0].CardData.Guid)
assert.Equal(t, "Namer", cards[0].CardData.CardProfile.Name) assert.NotEqual(t, profile, cards[0].CardData.ProfileRevision)
detail = cards[0].CardData.DetailRevision
rev = r rev = r
card = &Card{} 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, &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, cardDetail))
assert.Equal(t, "some interesting notes", card.CardData.Notes) assert.Equal(t, "some interesting notes", cardDetail.Notes)
r = GetTestRevision(set.B.Revisions) r = GetTestRevision(set.B.Revisions)
assert.NotEqual(t, rev.Card, r.Card) assert.NotEqual(t, rev.Card, r.Card)
rev = r rev = r
card = &Card{} 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, &card)) 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, "", card.CardData.Notes) assert.Equal(t, "", cardDetail.Notes)
r = GetTestRevision(set.B.Revisions) r = GetTestRevision(set.B.Revisions)
assert.NotEqual(t, rev.Card, r.Card) 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)
} }