test for clearing card group

This commit is contained in:
Roland Osborne 2022-02-11 13:07:39 -08:00
parent 342c9a79d9
commit ee2e9edd68
12 changed files with 231 additions and 45 deletions

View File

@ -2045,12 +2045,12 @@ paths:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/Subject' $ref: '#/components/schemas/Subject'
/content/channels/{channelId}/groups/{groupId}: /content/channels/{channelId}/groups/{groupId}:
put: put:
tags: tags:
- content - content
description: Set group for channels. Access granted to app tokens for account holder. description: Set group for read access to channel. Access granted to app tokens for account holder.
operationId: set-channel-group operationId: set-channel-group
security: security:
- bearerAuth: [] - bearerAuth: []
@ -2085,7 +2085,7 @@ paths:
delete: delete:
tags: tags:
- content - content
description: Clear sharing group for channel. Access granted to app tokens for account holder. description: Clear read access to channel for group. Access granted to app tokens for account holder.
operationId: clear-channel-group operationId: clear-channel-group
security: security:
- bearerAuth: [] - bearerAuth: []
@ -2118,6 +2118,78 @@ paths:
'500': '500':
description: internal server error description: internal server error
/content/channels/{channelId}/cards/{cardId}:
put:
tags:
- content
description: Set card for write access to channel. Access granted to app tokens for account holder.
operationId: set-channel-card
security:
- bearerAuth: []
parameters:
- name: channelId
in: path
description: specified channel id
required: true
schema:
type: string
- name: cardId
in: path
description: specified card id
required: true
schema:
type: string
responses:
'200':
description: success
content:
application/json:
schema:
$ref: '#/components/schemas/Channel'
'401':
description: permission denied
'404':
description: card or group not found
'410':
description: account disabled
'500':
description: internal server error
delete:
tags:
- content
description: Clear write access to channel for card. Access granted to app tokens for account holder.
operationId: clear-channel-card
security:
- bearerAuth: []
parameters:
- name: channelId
in: path
description: specified channel id
required: true
schema:
type: string
- name: cardId
in: path
description: specified card id
required: true
schema:
type: string
responses:
'200':
description: success
content:
application/json:
schema:
$ref: '#/components/schemas/Channel'
'401':
description: permission denied
'404':
description: card or group not found
'410':
description: account disabled
'500':
description: internal server error
/content/channels/{channelId}/topics: /content/channels/{channelId}/topics:
get: get:
tags: tags:
@ -3141,18 +3213,12 @@ components:
updated: updated:
type: integer type: integer
format: int64 format: int64
viewers: groups:
$ref: '#/components/schemas/ChannelGroups'
cards:
type: array type: array
items: items:
type: string type: string
viewerGroups:
$ref: '#/components/schemas/ChannelGroups'
members:
type: array
items:
type: string
memberGroups:
$ref: '#/components/schemas/ChannelGroups'
ChannelSize: ChannelSize:
type: object type: object
@ -3520,3 +3586,4 @@ components:
scheme: bearer scheme: bearer

View File

@ -0,0 +1,84 @@
package databag
import (
"errors"
"net/http"
"gorm.io/gorm"
"github.com/gorilla/mux"
"databag/internal/store"
)
func ClearCardGroup(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 cardSlot store.CardSlot
if err := store.DB.Preload("Card").Where("account_id = ? AND card_slot_id = ?", account.ID, cardId).First(&cardSlot).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusNotFound, err)
} else {
ErrResponse(w, http.StatusInternalServerError, err)
}
return
}
if cardSlot.Card == nil {
ErrResponse(w, http.StatusNotFound, errors.New("card has been deleted"))
return
}
// load referenced group
var groupSlot store.GroupSlot
if err := store.DB.Preload("Group").Where("account_id = ? AND group_slot_id = ?", account.ID, groupId).First(&groupSlot).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusInternalServerError, err)
} else {
ErrResponse(w, http.StatusNotFound, err)
}
return
}
if groupSlot.Group == nil {
ErrResponse(w, http.StatusNotFound, errors.New("referenced deleted group"))
return
}
// save and update revision
cardSlot.Revision = account.CardRevision + 1
err = store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Model(&cardSlot.Card).Association("Groups").Delete(groupSlot.Group); res != nil {
return res
}
if res := tx.Model(&cardSlot.Card).Update("detail_revision", cardSlot.Card.DetailRevision + 1).Error; res != nil {
return res
}
if res := tx.Model(&cardSlot.Card).Update("view_revision", cardSlot.Card.ViewRevision + 1).Error; res != nil {
return res
}
if res := tx.Model(&cardSlot).Update("revision", account.CardRevision + 1).Error; res != nil {
return res
}
if res := tx.Model(&account).Update("card_revision", account.CardRevision + 1).Error; res != nil {
return res
}
return nil
})
if err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
SetContactViewNotification(account, cardSlot.Card)
SetStatus(account)
WriteResponse(w, getCardModel(&cardSlot))
}

View File

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

@ -33,6 +33,11 @@ func AddChannelTopicTag(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
func ClearChannelCard(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func ClearChannelGroup(w http.ResponseWriter, r *http.Request) { func ClearChannelGroup(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)
@ -118,6 +123,11 @@ func RemoveChannelTopicTag(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
func SetChannelCard(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetChannelConfirmed(w http.ResponseWriter, r *http.Request) { func SetChannelConfirmed(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

@ -18,7 +18,7 @@ func GetCard(w http.ResponseWriter, r *http.Request) {
cardId := mux.Vars(r)["cardId"] cardId := mux.Vars(r)["cardId"]
var slot store.CardSlot var slot store.CardSlot
if err := store.DB.Preload("Card.Groups").Where("account_id = ? AND card_slot_id = ?", account.ID, cardId).First(&slot).Error; err != nil { if err := store.DB.Preload("Card.Groups.GroupSlot").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.StatusNotFound, err) ErrResponse(w, http.StatusNotFound, err)
} else { } else {

View File

@ -32,7 +32,7 @@ func NotifyArticleRevision(card *store.Card, revision int64) error {
act := &card.Account act := &card.Account
err := store.DB.Transaction(func(tx *gorm.DB) error { err := store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Model(card).Where("id = ?", card.ID).Update("notified_profile", revision).Error; res != nil { if res := tx.Model(card).Where("id = ?", card.ID).Update("notified_article", revision).Error; res != nil {
return res return res
} }
if res := tx.Model(&card.CardSlot).Where("id = ?", card.CardSlot.ID).Update("revision", act.CardRevision+1).Error; res != nil { if res := tx.Model(&card.CardSlot).Where("id = ?", card.CardSlot.ID).Update("revision", act.CardRevision+1).Error; res != nil {

View File

@ -51,19 +51,22 @@ func SetCardGroup(w http.ResponseWriter, r *http.Request) {
} }
// save and update revision // save and update revision
slot.Card.Groups = append(slot.Card.Groups, *groupSlot.Group)
slot.Card.ViewRevision += 1
slot.Revision = account.CardRevision + 1
err = store.DB.Transaction(func(tx *gorm.DB) error { err = store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Model(&slot.Card).Association("Groups").Append(groupSlot.Group); res != nil {
return res
}
if res := tx.Model(&slot.Card).Update("detail_revision", slot.Card.DetailRevision + 1).Error; res != nil {
return res
}
if res := tx.Model(&slot.Card).Update("view_revision", slot.Card.ViewRevision + 1).Error; res != nil {
return res
}
if res := tx.Model(&slot).Update("revision", account.CardRevision + 1).Error; res != nil {
return res
}
if res := tx.Model(&account).Update("card_revision", account.CardRevision + 1).Error; res != nil { if res := tx.Model(&account).Update("card_revision", account.CardRevision + 1).Error; res != nil {
return res return res
} }
if res := tx.Save(&slot.Card).Error; res != nil {
return res
}
if res := tx.Preload("CardData.Groups").Save(&slot).Error; res != nil {
return res
}
return nil return nil
}) })
if err != nil { if err != nil {

View File

@ -32,7 +32,7 @@ func NotifyChannelRevision(card *store.Card, revision int64) error {
act := &card.Account act := &card.Account
err := store.DB.Transaction(func(tx *gorm.DB) error { err := store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Model(card).Where("id = ?", card.ID).Update("notified_profile", revision).Error; res != nil { if res := tx.Model(card).Where("id = ?", card.ID).Update("notified_channel", revision).Error; res != nil {
return res return res
} }
if res := tx.Model(&card.CardSlot).Where("id = ?", card.CardSlot.ID).Update("revision", act.CardRevision+1).Error; res != nil { if res := tx.Model(&card.CardSlot).Where("id = ?", card.CardSlot.ID).Update("revision", act.CardRevision+1).Error; res != nil {

View File

@ -32,7 +32,7 @@ func NotifyViewRevision(card *store.Card, revision int64) error {
act := &card.Account act := &card.Account
err := store.DB.Transaction(func(tx *gorm.DB) error { err := store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Model(card).Where("id = ?", card.ID).Update("notified_profile", revision).Error; res != nil { if res := tx.Model(card).Where("id = ?", card.ID).Update("notified_view", revision).Error; res != nil {
return res return res
} }
if res := tx.Model(&card.CardSlot).Where("id = ?", card.CardSlot.ID).Update("revision", act.CardRevision+1).Error; res != nil { if res := tx.Model(&card.CardSlot).Where("id = ?", card.CardSlot.ID).Update("revision", act.CardRevision+1).Error; res != nil {

View File

@ -177,13 +177,9 @@ type ChannelDetail struct {
Updated int64 `json:"updated"` Updated int64 `json:"updated"`
Viewers []string `json:"viewers,omitempty"` Groups *ChannelGroups `json:"groups,omitempty"`
ViewerGroups *ChannelGroups `json:"viewerGroups,omitempty"` Cards []string `json:"cards"`
Members []string `json:"members,omitempty"`
MemberGroups *ChannelGroups `json:"memberGroups,omitempty"`
} }
type ChannelGroups struct { type ChannelGroups struct {

View File

@ -145,13 +145,6 @@ var routes = Routes{
GetAccountUsername, GetAccountUsername,
}, },
Route{
"GetCard",
strings.ToUpper("Get"),
"/contact/cards/{cardId}",
GetCard,
},
Route{ Route{
"GetPublicStatus", "GetPublicStatus",
strings.ToUpper("Get"), strings.ToUpper("Get"),
@ -523,6 +516,13 @@ var routes = Routes{
AddChannelTopicTag, AddChannelTopicTag,
}, },
Route{
"ClearChannelCard",
strings.ToUpper("Delete"),
"/content/channels/{channelId}/cards/{cardId}",
ClearChannelCard,
},
Route{ Route{
"ClearChannelGroup", "ClearChannelGroup",
strings.ToUpper("Delete"), strings.ToUpper("Delete"),
@ -642,6 +642,13 @@ var routes = Routes{
RemoveChannelTopicTag, RemoveChannelTopicTag,
}, },
Route{
"SetChannelCard",
strings.ToUpper("Put"),
"/content/channels/{channelId}/cards/{cardId}",
SetChannelCard,
},
Route{ Route{
"SetChannelConfirmed", "SetChannelConfirmed",
strings.ToUpper("Put"), strings.ToUpper("Put"),
@ -719,3 +726,4 @@ var routes = Routes{
Status, Status,
}, },
} }

View File

@ -10,7 +10,7 @@ import (
func TestContactSync(t *testing.T) { func TestContactSync(t *testing.T) {
var profile Profile var profile Profile
var msg DataMessage var msg DataMessage
var card Card var card *Card
param := map[string]string{} param := map[string]string{}
var img []byte var img []byte
var data []byte var data []byte
@ -21,6 +21,7 @@ func TestContactSync(t *testing.T) {
var detailRevision int64 var detailRevision int64
var detail CardDetail var detail CardDetail
var rev *Revision var rev *Revision
var viewRevision int64
// setup testing group // setup testing group
set, err := AddTestGroup("contactsync") set, err := AddTestGroup("contactsync")
@ -72,7 +73,7 @@ func TestContactSync(t *testing.T) {
// clear card notes // clear card notes
GetTestRevision(set.B.Revisions) GetTestRevision(set.B.Revisions)
assert.NoError(t, ApiTestMsg(ClearCardNotes, "DELETE", "/conact/cards/{cardId}/notes", assert.NoError(t, ApiTestMsg(ClearCardNotes, "DELETE", "/contact/cards/{cardId}/notes",
&param, nil, APP_TOKENAPP, set.B.Token, &detail, nil)) &param, nil, APP_TOKENAPP, set.B.Token, &detail, nil))
assert.NotEqual(t, rev.Card, GetTestRevision(set.B.Revisions).Card) assert.NotEqual(t, rev.Card, GetTestRevision(set.B.Revisions).Card)
cards = &[]Card{} cards = &[]Card{}
@ -81,4 +82,26 @@ func TestContactSync(t *testing.T) {
assert.Equal(t, 1, len(*cards)) assert.Equal(t, 1, len(*cards))
assert.NotEqual(t, detailRevision, (*cards)[0].Data.DetailRevision) assert.NotEqual(t, detailRevision, (*cards)[0].Data.DetailRevision)
// remove card from group
card = &Card{}
param["cardId"] = set.B.A.CardId
assert.NoError(t, ApiTestMsg(GetCard, "GET", "/contact/cards/{cardId}",
&param, nil, APP_TOKENAPP, set.B.Token, card, nil))
viewRevision = card.Data.NotifiedView
card = &Card{}
param["cardId"] = set.A.B.CardId
param["groupId"] = set.A.B.GroupId
assert.NoError(t, ApiTestMsg(ClearCardGroup, "DELETE", "/contact/cards/{cardId}/groups/{groupId}",
&param, nil, APP_TOKENAPP, set.A.Token, card, nil))
assert.Equal(t, 0, len(card.Data.CardDetail.Groups))
assert.NotEqual(t, rev.Card, GetTestRevision(set.B.Revisions).Card)
card = &Card{}
param["cardId"] = set.B.A.CardId
assert.NoError(t, ApiTestMsg(GetCard, "GET", "/contact/cards/{cardId}",
&param, nil, APP_TOKENAPP, set.B.Token, card, nil))
assert.NotEqual(t, viewRevision, card.Data.NotifiedView)
PrintMsg(card)
} }