testing group removal

This commit is contained in:
Roland Osborne 2022-02-12 00:08:30 -08:00
parent 3b85a6e023
commit ea17a74c99
8 changed files with 292 additions and 34 deletions

View File

@ -1,30 +0,0 @@
/*
* DataBag
*
* DataBag provides storage for decentralized identity based self-hosting apps. It is intended to support sharing of personal data and hosting group conversations.
*
* API version: 0.0.1
* Contact: roland.osborne@gmail.com
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package databag
import (
"net/http"
)
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) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func UpdateGroup(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}

View File

@ -0,0 +1,49 @@
package databag
import (
"strconv"
"net/http"
"databag/internal/store"
)
func GetGroups(w http.ResponseWriter, r *http.Request) {
var groupRevisionSet bool
var groupRevision int64
account, code, err := BearerAppToken(r, false);
if err != nil {
ErrResponse(w, code, err)
return
}
group := r.FormValue("revision")
if group != "" {
groupRevisionSet = true
if groupRevision, err = strconv.ParseInt(group, 10, 64); err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
}
var slots []store.GroupSlot
if groupRevisionSet {
if err := store.DB.Preload("Group.GroupData").Where("account_id = ? AND revision > ?", account.ID, groupRevision).Find(&slots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
} else {
if err := store.DB.Preload("Group.GroupData").Where("account_id = ? AND group_id != 0", account.ID).Find(&slots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
}
var response []*Group
for _, slot := range slots {
response = append(response, getGroupModel(&slot))
}
w.Header().Set("Group-Revision", strconv.FormatInt(account.GroupRevision, 10))
WriteResponse(w, response)
}

View File

@ -22,7 +22,7 @@ func RemoveCard(w http.ResponseWriter, r *http.Request) {
// load referenced card
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").Preload("Card.Channels.ChannelSlot").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,7 +37,14 @@ func RemoveCard(w http.ResponseWriter, r *http.Request) {
// save and update contact revision
err = store.DB.Transaction(func(tx *gorm.DB) error {
// TODO clear from channels
for _, channel := range slot.Card.Channels {
if res := tx.Model(&channel).Association("Cards").Delete(&slot.Card); res != nil {
return res
}
if res := tx.Model(&channel.ChannelSlot).Update("revision", account.ChannelRevision + 1).Error; res != nil {
return res
}
}
if res := tx.Model(&slot.Card).Association("Groups").Clear(); res != nil {
return res
}
@ -54,6 +61,9 @@ func RemoveCard(w http.ResponseWriter, r *http.Request) {
if res := tx.Model(&account).Update("card_revision", account.CardRevision + 1).Error; res != nil {
return res
}
if res := tx.Model(&account).Update("channel_revision", account.ChannelRevision + 1).Error; res != nil {
return res
}
return nil
})
if err != nil {
@ -61,6 +71,7 @@ func RemoveCard(w http.ResponseWriter, r *http.Request) {
return
}
SetChannelNotification(account)
SetStatus(account)
WriteResponse(w, nil);
}

View File

@ -0,0 +1,94 @@
package databag
import (
"errors"
"net/http"
"gorm.io/gorm"
"github.com/gorilla/mux"
"databag/internal/store"
)
func RemoveGroup(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)
groupId := params["groupId"]
// load referenced group
var slot store.GroupSlot
if err := store.DB.Preload("Group.Cards.CardSlot").Where("account_id = ? AND group_slot_id = ?", account.ID, groupId).First(&slot).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusInternalServerError, err)
} else {
ErrResponse(w, http.StatusNotFound, err)
}
return
}
if slot.Group == nil {
ErrResponse(w, http.StatusNotFound, errors.New("group has been deleted"))
return
}
var cards []*store.Card
for _, card := range slot.Group.Cards {
cards = append(cards, &card)
}
// save and update contact revision
err = store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Model(&slot.Group).Association("Channels").Clear(); res != nil {
return res
}
if res := tx.Model(&slot.Group).Association("Articles").Clear(); res != nil {
return res
}
for _, card := range cards {
if res := tx.Model(card).Update("view_revision", card.ViewRevision + 1).Error; res != nil {
return res
}
if res := tx.Model(card).Update("detail_revision", card.DetailRevision + 1).Error; res != nil {
return res
}
if res := tx.Model(card.CardSlot).Update("revision", account.CardRevision + 1).Error; res != nil {
return res
}
}
if res := tx.Model(&slot.Group).Association("Cards").Clear(); res != nil {
return res
}
if res := tx.Delete(&slot.Group).Error; res != nil {
return res
}
slot.Group = nil
if res := tx.Model(&slot).Update("group_id", 0).Error; res != nil {
return res
}
if res := tx.Model(&slot).Update("revision", account.GroupRevision + 1).Error; res != nil {
return res
}
if res := tx.Model(&account).Update("group_revision", account.GroupRevision + 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
}
for _, card := range cards {
SetContactViewNotification(account, card)
}
SetStatus(account)
WriteResponse(w, nil);
}

View File

@ -0,0 +1,68 @@
package databag
import (
"errors"
"net/http"
"gorm.io/gorm"
"github.com/gorilla/mux"
"databag/internal/store"
)
func UpdateGroup(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)
groupId := params["groupId"]
var subject Subject
if err := ParseRequest(r, w, &subject); err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
// load referenced group
var slot store.GroupSlot
if err := store.DB.Preload("Group.GroupData").Where("account_id = ? AND group_slot_id = ?", account.ID, groupId).First(&slot).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusInternalServerError, err)
} else {
ErrResponse(w, http.StatusNotFound, err)
}
return
}
if slot.Group == nil {
ErrResponse(w, http.StatusNotFound, errors.New("group has been deleted"))
return
}
// save and update contact revision
err = store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Model(&slot.Group.GroupData).Update("data", subject.Data).Error; res != nil {
return res
}
if res := tx.Model(&slot.Group).Update("data_type", subject.DataType).Error; res != nil {
return res
}
if res := tx.Model(&slot).Update("revision", account.GroupRevision + 1).Error; res != nil {
return res
}
if res := tx.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(&slot));
}

View File

@ -184,4 +184,36 @@ func SetContactChannelNotification(account *store.Account, card *store.Card) {
}
}
// notify all cards of channel change
// when card is deleted
func SetChannelNotification(account *store.Account) {
// select all connected cards
var cards []store.Card
if err := store.DB.Where("account_id = ? AND status = ?", account.Guid, APP_CARDCONNECTED).Find(&cards).Error; err != nil {
ErrMsg(err)
return
}
// add new notification for each card
err := store.DB.Transaction(func(tx *gorm.DB) error {
for _, card := range cards {
notification := &store.Notification{
Node: card.Node,
Module: APP_NOTIFYCHANNEL,
Token: card.OutToken,
Revision: account.ChannelRevision,
}
if err := tx.Save(notification).Error; err != nil {
return err
}
notify <- notification
}
return nil
})
if err != nil {
ErrMsg(err)
}
}

View File

@ -111,6 +111,8 @@ type Group struct {
Created int64 `gorm:"autoCreateTime"`
Updated int64 `gorm:"autoUpdateTime"`
Cards []Card `gorm:"many2many:card_groups"`
Channels []Channel `gorm:"many2many:channel_groups"`
Articles []Article `gorm:"many2many:article_groups"`
GroupData GroupData
GroupSlot GroupSlot
}
@ -156,6 +158,7 @@ type Card struct {
NotifiedProfile int64
Account Account `gorm:"references:Guid"`
Groups []Group `gorm:"many2many:card_groups"`
Channels []Channel `gorm:"many2many:channel_cards"`
CardSlot CardSlot
}
@ -199,8 +202,8 @@ type Channel struct {
SizeRevision int64 `gorm:"not null"`
TopicUpdated int64
TopicCount int64
Viewers []Group `gorm:"many2many:viewer_groups;"`
Members []Group `gorm:"many2many:member_groups;"`
Groups []Group `gorm:"many2many:channel_groups;"`
Cards []Card `gorm:"many2many:channel_cards;"`
ChannelSlot ChannelSlot
}

View File

@ -22,6 +22,7 @@ func TestContactSync(t *testing.T) {
var detail CardDetail
var rev *Revision
var viewRevision int64
var groups *[]Group
// setup testing group
set, err := AddTestGroup("contactsync")
@ -143,4 +144,34 @@ func TestContactSync(t *testing.T) {
assert.NoError(t, ApiTestMsg(GetCard, "GET", "/contact/cards/{cardId}",
&param, nil, APP_TOKENAPP, set.A.Token, card, nil))
assert.Nil(t, card.Data)
// update and delete group
param["groupId"] = set.D.C.GroupId
subject := &Subject{ DataType: "contactsynctype", Data: "contactsyncdata" }
assert.NoError(t, ApiTestMsg(UpdateGroup, "PUT", "/alias/groups/{groupId}",
&param, subject, APP_TOKENAPP, set.D.Token, nil, nil))
groups = &[]Group{}
assert.NoError(t, ApiTestMsg(GetGroups, "GET", "/alias/groups",
nil, nil, APP_TOKENAPP, set.D.Token, groups, nil))
assert.Equal(t, 1, len(*groups))
assert.Equal(t, "contactsynctype", (*groups)[0].Data.DataType)
assert.Equal(t, "contactsyncdata", (*groups)[0].Data.Data)
rev = GetTestRevision(set.C.Revisions)
card = &Card{}
param["cardId"] = set.C.D.CardId
assert.NoError(t, ApiTestMsg(GetCard, "GET", "/contact/cards/{cardId}",
&param, nil, APP_TOKENAPP, set.C.Token, card, nil))
viewRevision = card.Data.NotifiedView
param["groupId"] = set.D.C.GroupId
assert.NoError(t, ApiTestMsg(RemoveGroup, "GET", "/alias/groups/{groupId}",
&param, nil, APP_TOKENAPP, set.D.Token, nil, nil))
groups = &[]Group{}
assert.NoError(t, ApiTestMsg(GetGroups, "GET", "/alias/groups",
nil, nil, APP_TOKENAPP, set.D.Token, groups, nil))
assert.Equal(t, 0, len(*groups))
assert.NotEqual(t, rev.Card, GetTestRevision(set.C.Revisions).Card)
card = &Card{}
assert.NoError(t, ApiTestMsg(GetCard, "GET", "/contact/cards/{cardId}",
&param, nil, APP_TOKENAPP, set.C.Token, card, nil))
assert.NotEqual(t, viewRevision, card.Data.NotifiedView)
}