From 6117d56f242f2d4006b5ed02d1532dd0da67cd60 Mon Sep 17 00:00:00 2001 From: Roland Osborne Date: Sat, 5 Feb 2022 20:41:52 -0800 Subject: [PATCH] optimized view revision notification --- net/server/internal/api_content.go | 5 -- net/server/internal/api_getArticles.go | 4 +- net/server/internal/api_getLabels.go | 4 +- net/server/internal/api_getOpenMessage.go | 4 +- net/server/internal/api_removeGroup.go | 17 ++++-- net/server/internal/api_removeLabel.go | 74 +++++++++++++++++++++++ net/server/internal/api_setLabelGroup.go | 21 ++++--- net/server/internal/api_setOpenMessage.go | 2 +- net/server/internal/notify.go | 4 +- net/server/internal/store/schema.go | 1 - net/server/internal/ucAddArticle_test.go | 11 ++++ 11 files changed, 120 insertions(+), 27 deletions(-) create mode 100644 net/server/internal/api_removeLabel.go diff --git a/net/server/internal/api_content.go b/net/server/internal/api_content.go index bedd9385..c76347ff 100644 --- a/net/server/internal/api_content.go +++ b/net/server/internal/api_content.go @@ -93,11 +93,6 @@ func RemoveArticleTag(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -func RemoveLabel(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json; charset=UTF-8") - w.WriteHeader(http.StatusOK) -} - func SetArticleConfirmed(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") w.WriteHeader(http.StatusOK) diff --git a/net/server/internal/api_getArticles.go b/net/server/internal/api_getArticles.go index 963defe2..a832cd82 100644 --- a/net/server/internal/api_getArticles.go +++ b/net/server/internal/api_getArticles.go @@ -58,7 +58,7 @@ func GetArticles(w http.ResponseWriter, r *http.Request) { return } - if viewRevision != card.ViewRevision + card.Account.ViewRevision { + if viewRevision != card.ViewRevision { if revisionSet { ErrResponse(w, http.StatusGone, errors.New("article view unavailable")) return @@ -79,7 +79,7 @@ func GetArticles(w http.ResponseWriter, r *http.Request) { } } - w.Header().Set("View-Revision", strconv.FormatInt(card.ViewRevision + card.Account.ViewRevision, 10)) + w.Header().Set("View-Revision", strconv.FormatInt(card.ViewRevision, 10)) w.Header().Set("Content-Revision", strconv.FormatInt(card.Account.ContentRevision, 10)) } else { ErrResponse(w, http.StatusBadRequest, errors.New("invalid token type")) diff --git a/net/server/internal/api_getLabels.go b/net/server/internal/api_getLabels.go index c0c1e8fd..ac57e006 100644 --- a/net/server/internal/api_getLabels.go +++ b/net/server/internal/api_getLabels.go @@ -58,7 +58,7 @@ func GetLabels(w http.ResponseWriter, r *http.Request) { return } - if viewRevision != card.ViewRevision + card.Account.ViewRevision { + if viewRevision != card.ViewRevision { if revisionSet { ErrResponse(w, http.StatusGone, errors.New("label view unavailable")) return @@ -79,7 +79,7 @@ func GetLabels(w http.ResponseWriter, r *http.Request) { } } - w.Header().Set("View-Revision", strconv.FormatInt(card.ViewRevision + card.Account.ViewRevision, 10)) + w.Header().Set("View-Revision", strconv.FormatInt(card.ViewRevision, 10)) w.Header().Set("Label-Revision", strconv.FormatInt(card.Account.LabelRevision, 10)) } else { ErrResponse(w, http.StatusBadRequest, errors.New("invalid token type")) diff --git a/net/server/internal/api_getOpenMessage.go b/net/server/internal/api_getOpenMessage.go index f5f91ec7..743489d4 100644 --- a/net/server/internal/api_getOpenMessage.go +++ b/net/server/internal/api_getOpenMessage.go @@ -40,9 +40,9 @@ func GetOpenMessage(w http.ResponseWriter, r *http.Request) { connect := &Connect{ Contact: slot.Card.Guid, Token: slot.Card.InToken, - ContentRevision: account.ContentRevision + account.ViewRevision + slot.Card.ViewRevision, + ContentRevision: account.ContentRevision, ProfileRevision: account.ProfileRevision, - ViewRevision: account.ViewRevision + slot.Card.ViewRevision, + ViewRevision: slot.Card.ViewRevision, LabelRevision: account.LabelRevision, Handle: account.Username, Name: detail.Name, diff --git a/net/server/internal/api_removeGroup.go b/net/server/internal/api_removeGroup.go index 38ae0c43..ee25a982 100644 --- a/net/server/internal/api_removeGroup.go +++ b/net/server/internal/api_removeGroup.go @@ -19,7 +19,7 @@ func RemoveGroup(w http.ResponseWriter, r *http.Request) { groupId := params["groupId"] 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 err := store.DB.Preload("Group.GroupData").Preload("Group.Cards").Where("account_id = ? AND group_slot_id = ?", account.ID, groupId).First(&slot).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { ErrResponse(w, http.StatusNotFound, err) } else { @@ -27,6 +27,8 @@ func RemoveGroup(w http.ResponseWriter, r *http.Request) { } return } + cards := slot.Group.Cards + notify := []*store.Card{} err = store.DB.Transaction(func(tx *gorm.DB) error { if res := tx.Model(slot.Group).Association("Cards").Clear(); res != nil { @@ -38,15 +40,18 @@ func RemoveGroup(w http.ResponseWriter, r *http.Request) { if res := tx.Delete(&slot.Group).Error; res != nil { return res } + for _, card := range cards { + if res := tx.Model(&card).Update("ViewRevision", card.ViewRevision + 1).Error; res != nil { + return res + } + notify = append(notify, &card) + } slot.GroupID = 0 slot.Group = nil slot.Revision = account.GroupRevision + 1 if res := tx.Save(&slot).Error; res != nil { return res } - if res := tx.Model(&account).Updates(store.Account{ViewRevision: account.ViewRevision + 1, GroupRevision: account.GroupRevision + 1}).Error; res != nil { - return res - } return nil }) if err != nil { @@ -54,8 +59,10 @@ func RemoveGroup(w http.ResponseWriter, r *http.Request) { return } + for _, card := range notify { + SetContactViewNotification(account, card) + } SetStatus(account) - SetViewNotification(account) WriteResponse(w, nil) } diff --git a/net/server/internal/api_removeLabel.go b/net/server/internal/api_removeLabel.go new file mode 100644 index 00000000..2202d0a8 --- /dev/null +++ b/net/server/internal/api_removeLabel.go @@ -0,0 +1,74 @@ +package databag + +import ( + "errors" + "net/http" + "gorm.io/gorm" + "github.com/gorilla/mux" + "databag/internal/store" +) + +func RemoveLabel(w http.ResponseWriter, r *http.Request) { + + account, code, err := BearerAppToken(r, false) + if err != nil { + ErrResponse(w, code, err) + return + } + params := mux.Vars(r) + labelId := params["labelId"] + + var slot store.LabelSlot + if err := store.DB.Preload("Label.LabelData").Preload("Label.Groups.Cards").Where("account_id = ? AND label_slot_id = ?", account.ID, labelId).First(&slot).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + ErrResponse(w, http.StatusNotFound, err) + } else { + ErrResponse(w, http.StatusInternalServerError, err) + } + return + } + groups := slot.Label.Groups + notify := map[string]*store.Card{} + + err = store.DB.Transaction(func(tx *gorm.DB) error { + if res := tx.Model(slot.Label).Association("Groups").Clear(); res != nil { + return res + } + if res := tx.Delete(&slot.Label.LabelData).Error; res != nil { + return res + } + if res := tx.Delete(&slot.Label).Error; res != nil { + return res + } + for _, group := range groups { + for _, card := range group.Cards { + if res := tx.Model(&card).Update("ViewRevision", card.ViewRevision + 1).Error; res != nil { + return res + } + notify[card.Guid] = &card + } + } + + slot.LabelID = 0 + slot.Label = nil + slot.Revision = account.LabelRevision + 1 + if res := tx.Save(&slot).Error; res != nil { + return res + } + if res := tx.Model(&account).Updates(store.Account{LabelRevision: account.LabelRevision + 1}).Error; res != nil { + return res + } + return nil + }) + if err != nil { + ErrResponse(w, http.StatusInternalServerError, err) + return + } + + for _, card := range notify { + SetContactViewNotification(account, card) + } + SetStatus(account) + WriteResponse(w, nil) +} + diff --git a/net/server/internal/api_setLabelGroup.go b/net/server/internal/api_setLabelGroup.go index 33f00e49..3bde43c9 100644 --- a/net/server/internal/api_setLabelGroup.go +++ b/net/server/internal/api_setLabelGroup.go @@ -36,7 +36,7 @@ func SetLabelGroup(w http.ResponseWriter, r *http.Request) { } groupSlot := &store.GroupSlot{} - if err := store.DB.Preload("Group.GroupSlot").Where("account_id = ? AND group_slot_id = ?", account.ID, groupId).First(&groupSlot).Error; err != nil { + if err := store.DB.Preload("Group.GroupSlot").Preload("Group.Cards").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 { @@ -48,9 +48,18 @@ func SetLabelGroup(w http.ResponseWriter, r *http.Request) { ErrResponse(w, http.StatusNotFound, errors.New("referenced empty group slot")) return } + cards := &groupSlot.Group.Cards + notify := []*store.Card{} err = store.DB.Transaction(func(tx *gorm.DB) error { + for _, card := range *cards { + if res := tx.Model(&card).Update("ViewRevision", card.ViewRevision + 1).Error; res != nil { + return res; + } + notify = append(notify, &card) + } + if res := tx.Model(labelSlot.Label).Association("Groups").Append(groupSlot.Group); res != nil { return res } @@ -63,10 +72,6 @@ func SetLabelGroup(w http.ResponseWriter, r *http.Request) { return res } - if res := tx.Model(account).Update("view_revision", account.ViewRevision + 1).Error; res != nil { - return res - } - return nil }) if err != nil { @@ -74,8 +79,10 @@ func SetLabelGroup(w http.ResponseWriter, r *http.Request) { return } - SetViewNotification(account) - SetLabelNotification(account) + for _, card := range notify { + SetContactViewNotification(account, card) + SetContactLabelNotification(account, card) + } SetStatus(account) WriteResponse(w, getLabelModel(labelSlot, true, true)) } diff --git a/net/server/internal/api_setOpenMessage.go b/net/server/internal/api_setOpenMessage.go index bc3b3ae3..f903a947 100644 --- a/net/server/internal/api_setOpenMessage.go +++ b/net/server/internal/api_setOpenMessage.go @@ -191,7 +191,7 @@ func SetOpenMessage(w http.ResponseWriter, r *http.Request) { status := &ContactStatus{ Token: slot.Card.InToken, Status: slot.Card.Status, - ViewRevision: slot.Card.ViewRevision + account.ViewRevision, + ViewRevision: slot.Card.ViewRevision, LabelRevision: account.LabelRevision, ProfileRevision: account.ProfileRevision, ContentRevision: account.ContentRevision, diff --git a/net/server/internal/notify.go b/net/server/internal/notify.go index 84063e93..5d4397a6 100644 --- a/net/server/internal/notify.go +++ b/net/server/internal/notify.go @@ -209,7 +209,7 @@ func SetViewNotification(account *store.Account) { Node: card.Node, Module: APP_NOTIFYVIEW, Token: card.OutToken, - Revision: account.ViewRevision + card.ViewRevision, + Revision: card.ViewRevision, } if err := tx.Save(notification).Error; err != nil { return err @@ -236,7 +236,7 @@ func SetContactViewNotification(account *store.Account, card *store.Card) { Node: card.Node, Module: APP_NOTIFYVIEW, Token: card.OutToken, - Revision: account.ViewRevision + card.ViewRevision, + Revision: card.ViewRevision, } if res := store.DB.Save(notification).Error; res != nil { diff --git a/net/server/internal/store/schema.go b/net/server/internal/store/schema.go index 3904ed23..9bafe6a4 100644 --- a/net/server/internal/store/schema.go +++ b/net/server/internal/store/schema.go @@ -71,7 +71,6 @@ type Account struct { CardRevision int64 `gorm:"not null;default:1"` DialogueRevision int64 `gorm:"not null;default:1"` InsightRevision int64 `gorm:"not null;default:1"` - ViewRevision int64 `gorm:"not null;default:1"` Created int64 `gorm:"autoCreateTime"` Disabled bool `gorm:"not null;default:false"` AccountDetail AccountDetail diff --git a/net/server/internal/ucAddArticle_test.go b/net/server/internal/ucAddArticle_test.go index 5bdae128..c3fd8796 100644 --- a/net/server/internal/ucAddArticle_test.go +++ b/net/server/internal/ucAddArticle_test.go @@ -164,4 +164,15 @@ func TestAddArticle(t *testing.T) { view, err = strconv.ParseInt(resp.Header["View-Revision"][0], 10, 64) assert.NoError(t, err) assert.Equal(t, cards[0].CardData.NotifiedView, view) + + vars = &map[string]string{ "labelId": label.LabelId, } + assert.NoError(t, SendEndpointTest(RemoveLabel, "DELETE", "/content/labels/{labelId}", vars, nil, APP_TOKENAPP, set.A.Token, nil)) + + labels = &[]Label{} + assert.NoError(t, SendEndpointTest(GetLabels, "GET", "/content/labels", nil, nil, APP_TOKENCONTACT, set.C.A.Token, labels)) + assert.Equal(t, 0, len(*labels)) + + articles = &[]Article{} + assert.NoError(t, SendEndpointTest(GetArticles, "GET", "/content/articles", nil, nil, APP_TOKENCONTACT, set.C.A.Token, articles)) + assert.Equal(t, 0, len(*articles)) }