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
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

View File

@ -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));
}

View File

@ -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)
}

View File

@ -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));
}

View File

@ -87,6 +87,6 @@ func SetCardProfile(w http.ResponseWriter, r *http.Request) {
}
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 {
card.Status = APP_CARDCONNECTED
}
card.DataRevision += 1
card.OutToken = connect.Token
// 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{
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{

View File

@ -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"`

View File

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

View File

@ -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"`

View File

@ -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
}

View File

@ -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)
}