adding group test

This commit is contained in:
Roland Osborne 2022-01-24 21:22:33 -08:00
parent b9880227ed
commit 2a8fe4b6b8
16 changed files with 344 additions and 130 deletions

View File

@ -859,7 +859,11 @@ paths:
- bearerAuth: [] - bearerAuth: []
responses: responses:
'200': '200':
description: entry created description: success
content:
application/json:
schema:
$ref: '#/components/schemas/Group'
'401': '401':
description: permission denied description: permission denied
'410': '410':
@ -870,15 +874,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
type: object $ref: '#/components/schemas/Subject'
required:
- type
- data
properties:
type:
type: string
data:
type: string
/share/groups/{groupId}: /share/groups/{groupId}:
put: put:
@ -898,6 +894,10 @@ paths:
responses: responses:
'200': '200':
description: success description: success
content:
application/json:
schema:
$ref: '#/components/schemas/Group'
'401': '401':
description: permission denied description: permission denied
'404': '404':
@ -910,15 +910,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
type: object $ref: '#/components/schemas/Subject'
required:
- type
- data
properties:
type:
type: string
data:
type: string
delete: delete:
tags: tags:
- share - share
@ -4022,6 +4014,17 @@ components:
location: location:
type: string type: string
Subject:
type: object
required:
- dataType
- data
properties:
dataType:
type: string
data:
type: string
Account: Account:
type: object type: object
required: required:
@ -4358,25 +4361,25 @@ components:
type: object type: object
required: required:
- groupId - groupId
- groupRevision - revision
- type - dataType
- data - data
- created - created
- modified - updated
properties: properties:
groupId: groupId:
type: string type: string
groupRevision: revision:
type: integer type: integer
format: int64 format: int64
type: dataType:
type: string type: string
data: data:
type: string type: string
created: created:
type: integer type: integer
format: int64 format: int64
modified: updated:
type: integer type: integer
format: int64 format: int64

View File

@ -8,7 +8,7 @@ require (
github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect github.com/gorilla/websocket v1.4.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.3 // indirect github.com/jinzhu/now v1.1.4 // indirect
github.com/kr/pretty v0.3.0 // indirect github.com/kr/pretty v0.3.0 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-sqlite3 v1.14.9 // indirect github.com/mattn/go-sqlite3 v1.14.9 // indirect
@ -19,5 +19,5 @@ require (
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
gorm.io/driver/sqlite v1.2.6 // indirect gorm.io/driver/sqlite v1.2.6 // indirect
gorm.io/gorm v1.22.4 // indirect gorm.io/gorm v1.22.5 // indirect
) )

View File

@ -13,6 +13,8 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI= github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI=
github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
@ -43,3 +45,5 @@ gorm.io/driver/sqlite v1.2.6/go.mod h1:gyoX0vHiiwi0g49tv+x2E7l8ksauLK0U/gShcdUsj
gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.22.4 h1:8aPcyEJhY0MAt8aY6Dc524Pn+pO29K+ydu+e/cXSpQM= gorm.io/gorm v1.22.4 h1:8aPcyEJhY0MAt8aY6Dc524Pn+pO29K+ydu+e/cXSpQM=
gorm.io/gorm v1.22.4/go.mod h1:1aeVC+pe9ZmvKZban/gW4QPra7PRoTEssyc922qCAkk= gorm.io/gorm v1.22.4/go.mod h1:1aeVC+pe9ZmvKZban/gW4QPra7PRoTEssyc922qCAkk=
gorm.io/gorm v1.22.5 h1:lYREBgc02Be/5lSCTuysZZDb6ffL2qrat6fg9CFbvXU=
gorm.io/gorm v1.22.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=

View File

@ -0,0 +1,50 @@
package databag
import (
"net/http"
"gorm.io/gorm"
"github.com/google/uuid"
"databag/internal/store"
)
func AddGroup(w http.ResponseWriter, r *http.Request) {
account, code, err := BearerAppToken(r, false)
if err != nil {
ErrResponse(w, code, err)
return
}
var subject Subject
if err := ParseRequest(r, w, &subject); err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
group := &store.Group{
GroupId: uuid.New().String(),
AccountID: account.ID,
Revision: 0,
DataType: subject.DataType,
Data: subject.Data,
}
err = store.DB.Transaction(func(tx *gorm.DB) error {
if res := store.DB.Save(group).Error; res != nil {
return res
}
if res := store.DB.Model(&account).Update("group_revision", account.GroupRevision + 1).Error; res != nil {
return res
}
return nil
})
if err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
SetStatus(account)
WriteResponse(w, getGroupModel(group))
}

View File

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

@ -0,0 +1,28 @@
package databag
import (
"net/http"
"databag/internal/store"
)
func GetGroups(w http.ResponseWriter, r *http.Request) {
account, code, err := BearerAppToken(r, false)
if err != nil {
ErrResponse(w, code, err)
return
}
var storeGroups []store.Group
if err := store.DB.Where("account_id = ?", account.ID).Find(&storeGroups).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
var groups []*Group
for _, group := range storeGroups {
groups = append(groups, getGroupModel(&group))
}
WriteResponse(w, groups)
}

View File

@ -0,0 +1,79 @@
package databag
import (
"errors"
"net/http"
"gorm.io/gorm"
"github.com/gorilla/mux"
"databag/internal/store"
)
func SetCardGroup(w http.ResponseWriter, r *http.Request) {
account, code, err := BearerAppToken(r, false);
if err != nil {
ErrResponse(w, code, err)
return
}
// scan parameters
params := mux.Vars(r)
cardId := params["cardId"]
groupId := params["groupId"]
// load referenced card
var card store.Card
if err := store.DB.Where("account_id = ? AND card_id = ?", account.Guid, cardId).First(&card).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusInternalServerError, err)
} else {
ErrResponse(w, http.StatusNotFound, err)
}
return
}
// load referenced group
var group store.Group
if err := store.DB.Where("account_id = ? AND group_id = ?", account.ID, groupId).First(&group).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusInternalServerError, err)
} else {
ErrResponse(w, http.StatusNotFound, err)
}
return
}
// save and update revision
card.Groups = append(card.Groups, group)
card.ViewRevision += 1
card.DataRevision += 1
err = store.DB.Transaction(func(tx *gorm.DB) error {
if res := store.DB.Model(&account).Update("card_revision", account.CardRevision + 1).Error; res != nil {
return res
}
if res := store.DB.Preload("Groups").Save(&card).Error; res != nil {
return res
}
return nil
})
if err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
cardData := &CardData{
Revision: card.DataRevision,
Status: card.Status,
Notes: card.Notes,
Token: card.OutToken,
Groups: nil,
}
for _, group := range card.Groups {
cardData.Groups = append(cardData.Groups, group.GroupId)
}
WriteResponse(w, cardData)
SetContactContentNotification(account, &card)
SetStatus(account)
}

View File

@ -13,16 +13,6 @@ import (
"net/http" "net/http"
) )
func AddGroup(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetGroups(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func RemoveGroup(w http.ResponseWriter, r *http.Request) { func RemoveGroup(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

@ -24,6 +24,7 @@ const APP_MODULEPROFILE = "profile"
const APP_MODULECONTENT = "content" const APP_MODULECONTENT = "content"
const APP_TOKENAPP = "app" const APP_TOKENAPP = "app"
const APP_TOKENCONTACT = "contact" const APP_TOKENCONTACT = "contact"
const APP_NOTIFYBUFFER = 4096
func AppCardStatus(status string) bool { func AppCardStatus(status string) bool {
if status == APP_CARDPENDING { if status == APP_CARDPENDING {

View File

@ -7,6 +7,13 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
type TestAccount struct {
AppToken string
ContactGuid string
ContactToken string
ContactCardId string
}
func AddTestContacts(t *testing.T, prefix string, count int) []string { func AddTestContacts(t *testing.T, prefix string, count int) []string {
var access []string var access []string
@ -52,32 +59,35 @@ func AddTestContacts(t *testing.T, prefix string, count int) []string {
return access return access
} }
func ConnectTestContacts(t *testing.T, accessA string, accessB string) (contact [2]string) { func ConnectTestContacts(t *testing.T, accessA string, accessB string) (contact [2]TestAccount) {
var card Card var card Card
var msg DataMessage var msg DataMessage
var vars map[string]string var vars map[string]string
var contactStatus ContactStatus var contactStatus ContactStatus
var id string var id string
access := [2]string{accessA, accessB} contact[0].AppToken = accessA
contact[1].AppToken = accessB
// get A identity message // get A identity message
r, w, _ := NewRequest("GET", "/profile/message", nil) r, w, _ := NewRequest("GET", "/profile/message", nil)
r.Header.Add("TokenType", APP_TOKENAPP) r.Header.Add("TokenType", APP_TOKENAPP)
SetBearerAuth(r, access[0]) SetBearerAuth(r, accessA)
GetProfileMessage(w, r) GetProfileMessage(w, r)
assert.NoError(t, ReadResponse(w, &msg)) assert.NoError(t, ReadResponse(w, &msg))
// add A card in B // add A card in B
r, w, _ = NewRequest("POST", "/contact/cards", &msg) r, w, _ = NewRequest("POST", "/contact/cards", &msg)
SetBearerAuth(r, access[1]) SetBearerAuth(r, accessB)
AddCard(w, r) AddCard(w, r)
assert.NoError(t, ReadResponse(w, &card)) assert.NoError(t, ReadResponse(w, &card))
contact[1].ContactCardId = card.CardId
contact[1].ContactGuid = card.CardProfile.Guid
// update A status to connecting // update A status to connecting
r, w, _ = NewRequest("PUT", "/contact/cards/{cardId}/status", APP_CARDCONNECTING) r, w, _ = NewRequest("PUT", "/contact/cards/{cardId}/status", APP_CARDCONNECTING)
vars = map[string]string{ "cardId": card.CardId } vars = map[string]string{ "cardId": card.CardId }
r = mux.SetURLVars(r, vars) r = mux.SetURLVars(r, vars)
SetBearerAuth(r, access[1]) SetBearerAuth(r, accessB)
SetCardStatus(w, r) SetCardStatus(w, r)
assert.NoError(t, ReadResponse(w, &card)) assert.NoError(t, ReadResponse(w, &card))
@ -85,7 +95,7 @@ func ConnectTestContacts(t *testing.T, accessA string, accessB string) (contact
r, w, _ = NewRequest("GET", "/contact/cards/{cardId}/openMessage", nil) r, w, _ = NewRequest("GET", "/contact/cards/{cardId}/openMessage", nil)
vars = map[string]string{ "cardId": card.CardId } vars = map[string]string{ "cardId": card.CardId }
r = mux.SetURLVars(r, vars) r = mux.SetURLVars(r, vars)
SetBearerAuth(r, access[1]) SetBearerAuth(r, accessB)
GetOpenMessage(w, r) GetOpenMessage(w, r)
assert.NoError(t, ReadResponse(w, &msg)) assert.NoError(t, ReadResponse(w, &msg))
id = card.CardId id = card.CardId
@ -97,7 +107,7 @@ func ConnectTestContacts(t *testing.T, accessA string, accessB string) (contact
// get view of cards in A // get view of cards in A
r, w, _ = NewRequest("GET", "/contact/cards/view", nil) r, w, _ = NewRequest("GET", "/contact/cards/view", nil)
SetBearerAuth(r, access[0]) SetBearerAuth(r, accessA)
GetCardView(w, r) GetCardView(w, r)
var views []CardView var views []CardView
assert.NoError(t, ReadResponse(w, &views)) assert.NoError(t, ReadResponse(w, &views))
@ -107,15 +117,17 @@ func ConnectTestContacts(t *testing.T, accessA string, accessB string) (contact
r, w, _ = NewRequest("GET", "/contact/cards/{cardId}", nil) r, w, _ = NewRequest("GET", "/contact/cards/{cardId}", nil)
vars = map[string]string{ "cardId": views[0].CardId } vars = map[string]string{ "cardId": views[0].CardId }
r = mux.SetURLVars(r, vars) r = mux.SetURLVars(r, vars)
SetBearerAuth(r, access[0]) SetBearerAuth(r, accessA)
GetCard(w, r) GetCard(w, r)
assert.NoError(t, ReadResponse(w, &card)) assert.NoError(t, ReadResponse(w, &card))
contact[0].ContactCardId = card.CardId
contact[0].ContactGuid = card.CardProfile.Guid
// update B status to connecting // update B status to connecting
r, w, _ = NewRequest("PUT", "/contact/cards/{cardId}/status", APP_CARDCONNECTING) r, w, _ = NewRequest("PUT", "/contact/cards/{cardId}/status", APP_CARDCONNECTING)
vars = map[string]string{ "cardId": views[0].CardId } vars = map[string]string{ "cardId": views[0].CardId }
r = mux.SetURLVars(r, vars) r = mux.SetURLVars(r, vars)
SetBearerAuth(r, access[0]) SetBearerAuth(r, accessA)
SetCardStatus(w, r) SetCardStatus(w, r)
assert.NoError(t, ReadResponse(w, &card)) assert.NoError(t, ReadResponse(w, &card))
@ -123,7 +135,7 @@ func ConnectTestContacts(t *testing.T, accessA string, accessB string) (contact
r, w, _ = NewRequest("GET", "/contact/cards/{cardId}/openMessage", nil) r, w, _ = NewRequest("GET", "/contact/cards/{cardId}/openMessage", nil)
vars = map[string]string{ "cardId": views[0].CardId } vars = map[string]string{ "cardId": views[0].CardId }
r = mux.SetURLVars(r, vars) r = mux.SetURLVars(r, vars)
SetBearerAuth(r, access[0]) SetBearerAuth(r, accessA)
GetOpenMessage(w, r) GetOpenMessage(w, r)
assert.NoError(t, ReadResponse(w, &msg)) assert.NoError(t, ReadResponse(w, &msg))
@ -137,19 +149,19 @@ func ConnectTestContacts(t *testing.T, accessA string, accessB string) (contact
r, w, _ = NewRequest("PUT", "/contact/cards/{cardId}/status?token=" + contactStatus.Token, APP_CARDCONNECTED) r, w, _ = NewRequest("PUT", "/contact/cards/{cardId}/status?token=" + contactStatus.Token, APP_CARDCONNECTED)
vars = map[string]string{ "cardId": views[0].CardId } vars = map[string]string{ "cardId": views[0].CardId }
r = mux.SetURLVars(r, vars) r = mux.SetURLVars(r, vars)
SetBearerAuth(r, access[0]) SetBearerAuth(r, accessA)
SetCardStatus(w, r) SetCardStatus(w, r)
assert.NoError(t, ReadResponse(w, &card)) assert.NoError(t, ReadResponse(w, &card))
// extract contact tokens // extract contact tokens
contact[0] = card.CardData.Token contact[0].ContactToken = card.CardData.Token
r, w, _ = NewRequest("GET", "/contact/cards/{cardId}", nil) r, w, _ = NewRequest("GET", "/contact/cards/{cardId}", nil)
vars = map[string]string{ "cardId": id } vars = map[string]string{ "cardId": id }
r = mux.SetURLVars(r, vars) r = mux.SetURLVars(r, vars)
SetBearerAuth(r, access[1]) SetBearerAuth(r, accessB)
GetCard(w, r) GetCard(w, r)
assert.NoError(t, ReadResponse(w, &card)) assert.NoError(t, ReadResponse(w, &card))
contact[1] = card.CardData.Token contact[1].ContactToken = card.CardData.Token
return return
} }

View File

@ -7,7 +7,7 @@ import (
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
SetHideLog(true) // SetHideLog(true)
SetKeySize(2048) SetKeySize(2048)
store.SetPath("file::memory:?cache=shared"); store.SetPath("file::memory:?cache=shared");
// store.SetPath("databag.db"); // store.SetPath("databag.db");

View File

@ -37,3 +37,13 @@ func getCardModel(card *store.Card) *Card {
} }
} }
func getGroupModel(group *store.Group) *Group {
return &Group{
GroupId: group.GroupId,
Revision: group.Revision,
DataType: group.DataType,
Data: group.Data,
Created: group.Created,
Updated: group.Updated,
}
}

View File

@ -38,6 +38,11 @@ type AppData struct {
Image string `json:"image,omitempty"` Image string `json:"image,omitempty"`
} }
type Subject struct {
DataType string `json:"dataType"`
Data string `json:"data"`
}
type Article struct { type Article struct {
ArticleId string `json:"articleId"` ArticleId string `json:"articleId"`
ArticleRevision int64 `json:"articleRevision"` ArticleRevision int64 `json:"articleRevision"`
@ -137,11 +142,11 @@ type DialogueInsights struct {
type Group struct { type Group struct {
GroupId string `json:"groupId"` GroupId string `json:"groupId"`
GroupRevision int64 `json:"groupRevision"` Revision int64 `json:"revision"`
Type_ string `json:"type"` DataType string `json:"dataType"`
Data string `json:"data"` Data string `json:"data"`
Created int64 `json:"created"` Created int64 `json:"created"`
Modified int64 `json:"modified"` Updated int64 `json:"updated"`
} }
type GroupsGroupIdBody struct { type GroupsGroupIdBody struct {

View File

@ -6,7 +6,7 @@ import (
"databag/internal/store" "databag/internal/store"
) )
var notify = make(chan *store.Notification) var notify = make(chan *store.Notification, APP_NOTIFYBUFFER)
var notifyExit = make(chan bool) var notifyExit = make(chan bool)
func ExitNotifications() { func ExitNotifications() {
@ -139,34 +139,25 @@ func SetContentNotification(account *store.Account) {
// notify single card of content change // notify single card of content change
// card.View incremented by adding or removing card from group or label // card.View incremented by adding or removing card from group or label
func SetContactContentNotification(account *store.Account, cardId string) { func SetContactContentNotification(account *store.Account, card *store.Card) {
// select card if connected if card.Status != APP_CARDCONNECTED {
var cards []store.Card
if err := store.DB.Where("account_id = ? AND status = ? AND card_id = ?", account.Guid, APP_CARDCONNECTED, cardId).Find(&cards).Error; err != nil {
ErrMsg(err)
return return
} }
// add new notification for card // add new notification for card
err := store.DB.Transaction(func(tx *gorm.DB) error {
for _, card := range cards {
notification := &store.Notification{ notification := &store.Notification{
Node: card.Node, Node: card.Node,
Module: APP_MODULECONTENT, Module: APP_MODULECONTENT,
Token: card.OutToken, Token: card.OutToken,
Revision: account.ViewRevision + account.ContentRevision + card.ViewRevision, Revision: account.ViewRevision + account.ContentRevision + card.ViewRevision,
} }
if err := tx.Save(notification).Error; err != nil {
return err if res := store.DB.Save(notification).Error; res != nil {
} ErrMsg(res)
} else {
notify <- notification notify <- notification
} }
return nil
})
if err != nil {
ErrMsg(err)
}
} }

View File

@ -11,16 +11,11 @@ func AutoMigrate(db *gorm.DB) {
db.AutoMigrate(&Group{}); db.AutoMigrate(&Group{});
db.AutoMigrate(&Label{}); db.AutoMigrate(&Label{});
db.AutoMigrate(&Card{}); db.AutoMigrate(&Card{});
db.AutoMigrate(&CardGroup{});
db.AutoMigrate(&LabelGroup{});
db.AutoMigrate(&Asset{}); db.AutoMigrate(&Asset{});
db.AutoMigrate(&Article{}); db.AutoMigrate(&Article{});
db.AutoMigrate(&ArticleAsset{}); db.AutoMigrate(&ArticleAsset{});
db.AutoMigrate(&ArticleTag{}); db.AutoMigrate(&ArticleTag{});
db.AutoMigrate(&ArticleGroup{});
db.AutoMigrate(&ArticleLabel{});
db.AutoMigrate(&Dialogue{}); db.AutoMigrate(&Dialogue{});
db.AutoMigrate(&DialogueMember{});
db.AutoMigrate(&Insight{}); db.AutoMigrate(&Insight{});
db.AutoMigrate(&Topic{}); db.AutoMigrate(&Topic{});
db.AutoMigrate(&TopicAsset{}); db.AutoMigrate(&TopicAsset{});
@ -54,6 +49,9 @@ type AccountToken struct {
Account Account Account Account
} }
// NOTE: card & app reference account by guid, all other tables by id
// because token lookup uses guid and is most common and wanted to avoid join
// int foreign key should be faster, so left other tables with id reference
type Account struct { type Account struct {
ID uint `gorm:"primaryKey;not null;unique;autoIncrement"` ID uint `gorm:"primaryKey;not null;unique;autoIncrement"`
AccountDetailID uint `gorm:"not null"` AccountDetailID uint `gorm:"not null"`
@ -118,6 +116,7 @@ type Label struct {
Data string Data string
Created int64 `gorm:"autoCreateTime"` Created int64 `gorm:"autoCreateTime"`
Updated int64 `gorm:"autoUpdateTime"` Updated int64 `gorm:"autoUpdateTime"`
Groups []Group `gorm:"many2many:label_groups;"`
Account Account Account Account
} }
@ -148,22 +147,6 @@ type Card struct {
Account Account `gorm:"references:Guid"` Account Account `gorm:"references:Guid"`
} }
type CardGroup struct {
ID uint `gorm:"primaryKey;not null;unique;autoIncrement"`
CardID uint `gorm:"not null;index:cardgroup,unique"`
GroupID uint `gorm:"not null;index:cardgroup,unique"`
Card Card
Group Group
}
type LabelGroup struct {
ID uint `gorm:"primaryKey;not null;unique;autoIncrement"`
LabelID uint `gorm:"not null;index:labelgroup,unique"`
GroupID uint `gorm:"not null;index:labelgroup,unique"`
Label Label
Group Group
}
type Asset struct { type Asset struct {
ID uint `gorm:"primaryKey;not null;unique;autoIncrement"` ID uint `gorm:"primaryKey;not null;unique;autoIncrement"`
AssetId string `gorm:"not null;index:asset,unique"` AssetId string `gorm:"not null;index:asset,unique"`
@ -187,10 +170,13 @@ type Article struct {
DataType string `gorm:"index"` DataType string `gorm:"index"`
Data string Data string
Status string `gorm:"not null;index"` Status string `gorm:"not null;index"`
Expires int64
Created int64 `gorm:"autoCreateTime"` Created int64 `gorm:"autoCreateTime"`
Updated int64 `gorm:"autoUpdateTime"` Updated int64 `gorm:"autoUpdateTime"`
TagUpdated int64 `gorm:"not null"` TagUpdated int64 `gorm:"not null"`
TagRevision uint64 `gorm:"not null"` TagRevision uint64 `gorm:"not null"`
Groups []Group `gorm:"many2many:article_groups;"`
Labels []Label `gorm:"many2many:article_labels;"`
Account Account Account Account
} }
@ -216,22 +202,6 @@ type ArticleTag struct {
Card Card Card Card
} }
type ArticleGroup struct {
ID uint `gorm:"primaryKey;not null;unique;autoIncrement"`
ArticleID uint `gorm:"not null;index"`
GroupID uint `gorm:"not null;index"`
Article Article
Group Group
}
type ArticleLabel struct {
ID uint `gorm:"primaryKey;not null;unique;autoIncrement"`
ArticleID uint `gorm:"not null;index"`
LabelID uint `gorm:"not null;index"`
Article Article
Label Label
}
type Dialogue struct { type Dialogue struct {
ID uint `gorm:"primaryKey;not null;unique;autoIncrement"` ID uint `gorm:"primaryKey;not null;unique;autoIncrement"`
DialogueId string `gorm:"not null;index:dialogue,unique"` DialogueId string `gorm:"not null;index:dialogue,unique"`
@ -245,16 +215,8 @@ type Dialogue struct {
MemberRevision uint64 `gorm:"not null"` MemberRevision uint64 `gorm:"not null"`
TopicUpdated int64 TopicUpdated int64
TopicRevision uint64 `gorm:"not null"` TopicRevision uint64 `gorm:"not null"`
Cards []Card `gorm:"many2many:dialog_cards;"`
Account Account Account Account
Cards []Card `gorm:"many2many:dialogue_member"`
}
type DialogueMember struct {
ID uint `gorm:"primaryKey;not null;unique;autoIncrement"`
DialogueID uint `gorm:"not null;index`
CardID uint `gorm:"not null;index`
Created int64 `gorm:"autoCreateTime"`
Card Card
} }
type Insight struct { type Insight struct {

View File

@ -0,0 +1,84 @@
package databag
import (
"time"
"testing"
"encoding/json"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
"github.com/stretchr/testify/assert"
)
func TestGroupContact(t *testing.T) {
var subject *Subject
var group Group
var groups []Group
var groupRevision int64
var cardRevision int64
var revision Revision
var vars map[string]string
var cardData CardData
// connect contacts
access := AddTestContacts(t, "groupcontact", 2);
contact := ConnectTestContacts(t, access[0], access[1])
// app connects websocket
wsA := getTestWebsocket()
announce := Announce{ AppToken: access[0] }
data, _ := json.Marshal(&announce)
wsA.WriteMessage(websocket.TextMessage, data)
// receive revision
wsA.SetReadDeadline(time.Now().Add(2 * time.Second))
_, data, _ = wsA.ReadMessage()
assert.NoError(t, json.Unmarshal(data, &revision))
groupRevision = revision.Group
// add group to conatact 0
subject = &Subject{
DataType: "imagroup",
Data: "group data with name and logo",
}
r, w, _ := NewRequest("POST", "/share/groups", subject)
SetBearerAuth(r, access[0])
AddGroup(w, r)
assert.NoError(t, ReadResponse(w, &group))
// receive revision
wsA.SetReadDeadline(time.Now().Add(2 * time.Second))
_, data, _ = wsA.ReadMessage()
assert.NoError(t, json.Unmarshal(data, &revision))
assert.NotEqual(t, groupRevision, revision.Group)
cardRevision = revision.Card
// set contact group
r, w, _ = NewRequest("PUT", "/contact/cards/{cardId}/groups/{groupId}", nil)
vars = make(map[string]string)
vars["groupId"] = group.GroupId
vars["cardId"] = contact[0].ContactCardId
r = mux.SetURLVars(r, vars)
SetBearerAuth(r, access[0])
SetCardGroup(w, r)
assert.NoError(t, ReadResponse(w, &cardData))
assert.Equal(t, 1, len(cardData.Groups))
// receive revision
wsA.SetReadDeadline(time.Now().Add(2 * time.Second))
_, data, _ = wsA.ReadMessage()
assert.NoError(t, json.Unmarshal(data, &revision))
assert.NotEqual(t, cardRevision, revision.Card)
// show group view
r, w, _ = NewRequest("GET", "/share/groups", nil)
SetBearerAuth(r, access[0])
GetGroups(w, r)
assert.NoError(t, ReadResponse(w, &groups))
assert.Equal(t, 1, len(groups))
PrintMsg(groups)
// add group
// show group view
}