mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
added filtering of articles
This commit is contained in:
parent
b1e0a17506
commit
a6ea2a7be1
@ -45,13 +45,14 @@ func AddArticle(w http.ResponseWriter, r *http.Request) {
|
|||||||
Status: APP_ARTICLEUNCONFIRMED,
|
Status: APP_ARTICLEUNCONFIRMED,
|
||||||
TagUpdated: time.Now().Unix(),
|
TagUpdated: time.Now().Unix(),
|
||||||
TagRevision: 1,
|
TagRevision: 1,
|
||||||
|
TagCount: 0,
|
||||||
Labels: append(groups, labels...),
|
Labels: append(groups, labels...),
|
||||||
};
|
};
|
||||||
if res := store.DB.Save(articleData).Error; res != nil {
|
if res := store.DB.Save(articleData).Error; res != nil {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if res := store.DB.Where("article_data_id is null AND account_id = ?", account.ID).First(&article).Error; res != nil {
|
if res := store.DB.Where("article_data_id = 0 AND account_id = ?", account.ID).First(&article).Error; res != nil {
|
||||||
if errors.Is(res, gorm.ErrRecordNotFound) {
|
if errors.Is(res, gorm.ErrRecordNotFound) {
|
||||||
article = &store.Article{
|
article = &store.Article{
|
||||||
ArticleId: uuid.New().String(),
|
ArticleId: uuid.New().String(),
|
||||||
@ -73,6 +74,9 @@ func AddArticle(w http.ResponseWriter, r *http.Request) {
|
|||||||
if ret := store.DB.Preload("ArticleData.Labels.Groups").Where("id = ?", article.ID).First(article).Error; ret != nil {
|
if ret := store.DB.Preload("ArticleData.Labels.Groups").Where("id = ?", article.ID).First(article).Error; ret != nil {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
if ret := tx.Model(&account).Update("content_revision", account.ContentRevision + 1).Error; ret != nil {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -82,7 +86,7 @@ func AddArticle(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
SetContentNotification(account)
|
SetContentNotification(account)
|
||||||
SetStatus(account)
|
SetStatus(account)
|
||||||
WriteResponse(w, getArticleModel(article, 0))
|
WriteResponse(w, getArticleModel(article, false, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,11 +51,6 @@ func AddGroup(w http.ResponseWriter, r *http.Request) {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintMsg("ADDED")
|
|
||||||
PrintMsg(group.GroupId)
|
|
||||||
PrintMsg(label.LabelId)
|
|
||||||
PrintMsg("***")
|
|
||||||
|
|
||||||
if res := tx.Model(&account).Update("group_revision", account.GroupRevision + 1).Error; res != nil {
|
if res := tx.Model(&account).Update("group_revision", account.GroupRevision + 1).Error; res != nil {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -88,21 +88,11 @@ func GetArticleTags(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetArticles(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetLabels(w http.ResponseWriter, r *http.Request) {
|
func GetLabels(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)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveArticle(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
}
|
|
||||||
|
|
||||||
func RemoveArticleAsset(w http.ResponseWriter, r *http.Request) {
|
func RemoveArticleAsset(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)
|
||||||
|
104
net/server/internal/api_getArticles.go
Normal file
104
net/server/internal/api_getArticles.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package databag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
"net/http"
|
||||||
|
"databag/internal/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetArticles(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var res error
|
||||||
|
var viewRevision int64
|
||||||
|
var contentRevision int64
|
||||||
|
|
||||||
|
view := r.FormValue("viewRevision")
|
||||||
|
if view != "" {
|
||||||
|
if viewRevision, res = strconv.ParseInt(view, 10, 64); res != nil {
|
||||||
|
ErrResponse(w, http.StatusBadRequest, res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content := r.FormValue("contentRevision")
|
||||||
|
if content != "" {
|
||||||
|
if contentRevision, res = strconv.ParseInt(content, 10, 64); res != nil {
|
||||||
|
ErrResponse(w, http.StatusBadRequest, res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenType := r.Header.Get("TokenType")
|
||||||
|
var response []*Article
|
||||||
|
if tokenType == APP_TOKENAPP {
|
||||||
|
|
||||||
|
account, code, err := BearerAppToken(r, false)
|
||||||
|
if err != nil {
|
||||||
|
ErrResponse(w, code, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var articles []store.Article
|
||||||
|
if err := getAccountArticles(account, contentRevision, &articles); err != nil {
|
||||||
|
ErrResponse(w, http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, article := range articles {
|
||||||
|
response = append(response, getArticleModel(&article, false, true))
|
||||||
|
}
|
||||||
|
} else if tokenType == APP_TOKENCONTACT {
|
||||||
|
|
||||||
|
card, code, err := BearerContactToken(r)
|
||||||
|
if err != nil {
|
||||||
|
ErrResponse(w, code, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if viewRevision != card.ViewRevision + card.Account.ViewRevision {
|
||||||
|
contentRevision = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var articles []store.Article
|
||||||
|
if err := getContactArticles(card, contentRevision, &articles); err != nil {
|
||||||
|
ErrResponse(w, http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, article := range articles {
|
||||||
|
response = append(response, getArticleModel(&article, true, isShared(&article, card.Guid)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ErrResponse(w, http.StatusBadRequest, errors.New("invalid token type"))
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteResponse(w, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// better if this filtering was done in gorm or sql
|
||||||
|
func isShared(article *store.Article, guid string) bool {
|
||||||
|
if article.ArticleData == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, label := range article.ArticleData.Labels {
|
||||||
|
for _, group := range label.Groups {
|
||||||
|
for _, card := range group.Cards {
|
||||||
|
if card.Guid == guid {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAccountArticles(account *store.Account, revision int64, articles *[]store.Article) error {
|
||||||
|
return store.DB.Preload("ArticleData.Labels.Groups").Where("account_id = ? AND revision > ?", account.ID, revision).Find(articles).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func getContactArticles(card *store.Card, revision int64, articles *[]store.Article) error {
|
||||||
|
return store.DB.Preload("ArticleData.Labels.Groups.Cards").Where("account_id = ? AND revision > ?", card.Account.ID, revision).Find(articles).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
56
net/server/internal/api_removeArticle.go
Normal file
56
net/server/internal/api_removeArticle.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package databag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"databag/internal/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RemoveArticle(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
account, code, err := BearerAppToken(r, false)
|
||||||
|
if err != nil {
|
||||||
|
ErrResponse(w, code, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
params := mux.Vars(r)
|
||||||
|
articleId := params["articleId"]
|
||||||
|
|
||||||
|
err = store.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
|
var article store.Article
|
||||||
|
if res := store.DB.Preload("ArticleData").Where("account_id = ? AND article_id = ?", account.ID, articleId).First(&article).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
if article.ArticleData == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if res := tx.Delete(article.ArticleData).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
article.ArticleDataID = 0
|
||||||
|
article.ArticleData = nil
|
||||||
|
if res := tx.Save(&article).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
if res := tx.Model(&account).Update("content_revision", account.ContentRevision).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
ErrResponse(w, http.StatusNotFound, err)
|
||||||
|
} else {
|
||||||
|
ErrResponse(w, http.StatusInternalServerError, err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
SetContentNotification(account)
|
||||||
|
SetStatus(account)
|
||||||
|
WriteResponse(w, nil)
|
||||||
|
}
|
||||||
|
|
@ -139,7 +139,7 @@ func BearerContactToken(r *http.Request) (*store.Card, int, error) {
|
|||||||
|
|
||||||
// find token record
|
// find token record
|
||||||
var card store.Card
|
var card store.Card
|
||||||
if err := store.DB.Preload("Account").Where("account_id = ? AND InToken = ?", target, access).First(&card).Error; err != nil {
|
if err := store.DB.Preload("Account").Where("account_id = ? AND in_token = ?", target, access).First(&card).Error; err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, http.StatusNotFound, err
|
return nil, http.StatusNotFound, err
|
||||||
} else {
|
} else {
|
||||||
|
@ -49,9 +49,9 @@ func getGroupModel(group *store.Group) *Group {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getArticleModel(article *store.Article, tagCount int32) *Article {
|
func getArticleModel(article *store.Article, contact bool, shared bool) *Article {
|
||||||
|
|
||||||
if article.ArticleData == nil {
|
if !shared || article.ArticleData == nil {
|
||||||
return &Article{
|
return &Article{
|
||||||
ArticleId: article.ArticleId,
|
ArticleId: article.ArticleId,
|
||||||
Revision: article.Revision,
|
Revision: article.Revision,
|
||||||
@ -62,8 +62,10 @@ func getArticleModel(article *store.Article, tagCount int32) *Article {
|
|||||||
var groups []string;
|
var groups []string;
|
||||||
var labels []string;
|
var labels []string;
|
||||||
for _, label := range article.ArticleData.Labels {
|
for _, label := range article.ArticleData.Labels {
|
||||||
if label.Direct && len(label.Groups) > 0 {
|
if label.Direct {
|
||||||
|
if !contact && len(label.Groups) > 0 {
|
||||||
groups = append(groups, label.Groups[0].GroupId)
|
groups = append(groups, label.Groups[0].GroupId)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
labels = append(labels, label.LabelId)
|
labels = append(labels, label.LabelId)
|
||||||
}
|
}
|
||||||
@ -78,7 +80,7 @@ func getArticleModel(article *store.Article, tagCount int32) *Article {
|
|||||||
Status: article.ArticleData.Status,
|
Status: article.ArticleData.Status,
|
||||||
Labels: labels,
|
Labels: labels,
|
||||||
Groups: groups,
|
Groups: groups,
|
||||||
TagCount: tagCount,
|
TagCount: article.ArticleData.TagCount,
|
||||||
Created: article.ArticleData.Created,
|
Created: article.ArticleData.Created,
|
||||||
Updated: article.ArticleData.Updated,
|
Updated: article.ArticleData.Updated,
|
||||||
TagUpdated: article.ArticleData.TagUpdated,
|
TagUpdated: article.ArticleData.TagUpdated,
|
||||||
|
@ -106,6 +106,7 @@ type Group struct {
|
|||||||
Data string
|
Data string
|
||||||
Created int64 `gorm:"autoCreateTime"`
|
Created int64 `gorm:"autoCreateTime"`
|
||||||
Updated int64 `gorm:"autoUpdateTime"`
|
Updated int64 `gorm:"autoUpdateTime"`
|
||||||
|
Cards []Card `gorm:"many2many:card_groups"`
|
||||||
Label Label //reference to label for direct assignment to articles
|
Label Label //reference to label for direct assignment to articles
|
||||||
Account Account
|
Account Account
|
||||||
}
|
}
|
||||||
@ -148,8 +149,8 @@ type Card struct {
|
|||||||
NotifiedView int64
|
NotifiedView int64
|
||||||
NotifiedContent int64
|
NotifiedContent int64
|
||||||
NotifiedProfile int64
|
NotifiedProfile int64
|
||||||
Groups []Group `gorm:"many2many:card_groups;"`
|
|
||||||
Account Account `gorm:"references:Guid"`
|
Account Account `gorm:"references:Guid"`
|
||||||
|
Groups []Group `gorm:"many2many:card_groups"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Asset struct {
|
type Asset struct {
|
||||||
@ -172,7 +173,7 @@ type Article struct {
|
|||||||
ArticleId string `gorm:"not null;index:article,unique"`
|
ArticleId string `gorm:"not null;index:article,unique"`
|
||||||
AccountID uint `gorm:"not null;index:article,unique"`
|
AccountID uint `gorm:"not null;index:article,unique"`
|
||||||
Revision int64 `gorm:"not null"`
|
Revision int64 `gorm:"not null"`
|
||||||
ArticleDataID uint
|
ArticleDataID uint `gorm:"not null;default:0"`
|
||||||
ArticleData *ArticleData
|
ArticleData *ArticleData
|
||||||
Account Account
|
Account Account
|
||||||
}
|
}
|
||||||
@ -187,6 +188,7 @@ type ArticleData struct {
|
|||||||
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"`
|
||||||
|
TagCount int32 `gorm:"not null"`
|
||||||
TagRevision int64 `gorm:"not null"`
|
TagRevision int64 `gorm:"not null"`
|
||||||
Labels []Label `gorm:"many2many:article_labels;"`
|
Labels []Label `gorm:"many2many:article_labels;"`
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,7 @@ func SendEndpointTest(
|
|||||||
name string,
|
name string,
|
||||||
params *map[string]string,
|
params *map[string]string,
|
||||||
body interface{},
|
body interface{},
|
||||||
|
tokenType string,
|
||||||
token string,
|
token string,
|
||||||
response interface{},
|
response interface{},
|
||||||
) (err error) {
|
) (err error) {
|
||||||
@ -71,7 +72,7 @@ func SendEndpointTest(
|
|||||||
r = mux.SetURLVars(r, *params)
|
r = mux.SetURLVars(r, *params)
|
||||||
}
|
}
|
||||||
if token != "" {
|
if token != "" {
|
||||||
r.Header.Add("TokenType", APP_TOKENAPP)
|
r.Header.Add("TokenType", tokenType)
|
||||||
SetBearerAuth(r, token)
|
SetBearerAuth(r, token)
|
||||||
}
|
}
|
||||||
endpoint(w, r)
|
endpoint(w, r)
|
||||||
@ -205,6 +206,7 @@ func AddTestGroup(prefix string) (*TestGroup, error) {
|
|||||||
if g.A.B.Token, err = GetCardToken(g.A.Token, g.A.B.CardId); err != nil {
|
if g.A.B.Token, err = GetCardToken(g.A.Token, g.A.B.CardId); err != nil {
|
||||||
return g, err
|
return g, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.B.A.Token, err = GetCardToken(g.B.Token, g.B.A.CardId); err != nil {
|
if g.B.A.Token, err = GetCardToken(g.B.Token, g.B.A.CardId); err != nil {
|
||||||
return g, err
|
return g, err
|
||||||
}
|
}
|
||||||
|
@ -10,24 +10,42 @@ func TestAddArticle(t *testing.T) {
|
|||||||
var err error
|
var err error
|
||||||
var rev *Revision
|
var rev *Revision
|
||||||
var article Article
|
var article Article
|
||||||
|
var articles *[]Article
|
||||||
|
var articleAccess *ArticleAccess
|
||||||
|
|
||||||
// setup testing group
|
// setup testing group
|
||||||
set, err = AddTestGroup("addarticle")
|
set, err = AddTestGroup("addarticle")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// initial revision
|
// initial revision
|
||||||
rev = GetTestRevision(set.A.Revisions)
|
rev = GetTestRevision(set.B.Revisions)
|
||||||
|
|
||||||
// create article
|
// create article
|
||||||
articleAccess := &ArticleAccess{ Groups: []string{set.A.B.GroupId} }
|
articleAccess = &ArticleAccess{ Groups: []string{set.A.B.GroupId} }
|
||||||
assert.NoError(t, SendEndpointTest(AddArticle, "POST", "/content/articles", nil, articleAccess, set.A.Token, &article))
|
assert.NoError(t, SendEndpointTest(AddArticle, "POST", "/content/articles", nil, articleAccess, APP_TOKENAPP, set.A.Token, &article))
|
||||||
PrintMsg(article);
|
|
||||||
|
|
||||||
// check revisions
|
assert.NoError(t, SendEndpointTest(AddArticle, "POST", "/content/articles", nil, articleAccess, APP_TOKENAPP, set.A.Token, &article))
|
||||||
rev = GetTestRevision(set.A.Revisions)
|
|
||||||
|
|
||||||
|
assert.NoError(t, SendEndpointTest(RemoveArticle, "DELETE", "/content/articls/" + article.ArticleId, &map[string]string{"articleId": article.ArticleId }, nil, APP_TOKENAPP, set.A.Token, nil))
|
||||||
|
|
||||||
|
articles = &[]Article{}
|
||||||
|
assert.NoError(t, SendEndpointTest(GetArticles, "GET", "/content/articles", nil, nil, APP_TOKENAPP, set.A.Token, articles))
|
||||||
|
assert.Equal(t, 2, len(*articles))
|
||||||
|
assert.True(t, (*articles)[0].ArticleData != nil || (*articles)[1].ArticleData != nil)
|
||||||
|
assert.True(t, (*articles)[0].ArticleData == nil || (*articles)[1].ArticleData == nil)
|
||||||
|
|
||||||
|
articles = &[]Article{}
|
||||||
|
assert.NoError(t, SendEndpointTest(GetArticles, "GET", "/content/articles", nil, nil, APP_TOKENCONTACT, set.B.A.Token, articles))
|
||||||
|
assert.Equal(t, 2, len(*articles))
|
||||||
|
assert.True(t, (*articles)[0].ArticleData != nil || (*articles)[1].ArticleData != nil)
|
||||||
|
assert.True(t, (*articles)[0].ArticleData == nil || (*articles)[1].ArticleData == nil)
|
||||||
|
|
||||||
|
articles = &[]Article{}
|
||||||
|
assert.NoError(t, SendEndpointTest(GetArticles, "GET", "/content/articles", nil, nil, APP_TOKENCONTACT, set.C.A.Token, articles))
|
||||||
|
assert.Equal(t, 2, len(*articles))
|
||||||
|
assert.True(t, (*articles)[0].ArticleData == nil && (*articles)[1].ArticleData == nil)
|
||||||
|
|
||||||
// view article
|
// view article
|
||||||
|
assert.NotEqual(t, GetTestRevision(set.B.Revisions).Card, rev)
|
||||||
|
|
||||||
PrintMsg(rev)
|
|
||||||
}
|
}
|
||||||
|
@ -138,8 +138,6 @@ func TestGroupContact(t *testing.T) {
|
|||||||
vars["groupId"] = group.GroupId
|
vars["groupId"] = group.GroupId
|
||||||
r = mux.SetURLVars(r, vars)
|
r = mux.SetURLVars(r, vars)
|
||||||
SetBearerAuth(r, a)
|
SetBearerAuth(r, a)
|
||||||
PrintMsg(group.GroupId)
|
|
||||||
PrintMsg("REMOVED")
|
|
||||||
RemoveGroup(w, r)
|
RemoveGroup(w, r)
|
||||||
assert.NoError(t, ReadResponse(w, &group))
|
assert.NoError(t, ReadResponse(w, &group))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user