From ae2435e915b351fcb2de0c27f0d4e5fda781467a Mon Sep 17 00:00:00 2001 From: Roland Osborne Date: Tue, 15 Feb 2022 15:17:06 -0800 Subject: [PATCH] adding get articles endpoint --- doc/api.oa3 | 6 + net/server/internal/api_content.go | 5 - net/server/internal/api_getArticles.go | 10 +- net/server/internal/api_getChannels.go | 159 +++++++++++++++++++++++++ 4 files changed, 170 insertions(+), 10 deletions(-) create mode 100644 net/server/internal/api_getChannels.go diff --git a/doc/api.oa3 b/doc/api.oa3 index c8d76dc5..dca8c2cf 100644 --- a/doc/api.oa3 +++ b/doc/api.oa3 @@ -1835,6 +1835,12 @@ paths: required: false schema: type: string + - name: types + in: query + description: return only channels of specified types + required: false + schema: + type: string responses: '200': description: successful operation diff --git a/net/server/internal/api_content.go b/net/server/internal/api_content.go index 88a0eb33..3b33e19c 100644 --- a/net/server/internal/api_content.go +++ b/net/server/internal/api_content.go @@ -93,11 +93,6 @@ func GetChannelTopics(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -func GetChannels(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json; charset=UTF-8") - w.WriteHeader(http.StatusOK) -} - func RemoveChannel(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 e85e1728..26758da0 100644 --- a/net/server/internal/api_getArticles.go +++ b/net/server/internal/api_getArticles.go @@ -72,7 +72,7 @@ func GetArticles(w http.ResponseWriter, r *http.Request) { } for _, slot := range slots { - if !typesSet || hasType(types, slot.Article) { + if !typesSet || hasArticleType(types, slot.Article) { response = append(response, getArticleModel(&slot, true, true)) } } @@ -109,8 +109,8 @@ func GetArticles(w http.ResponseWriter, r *http.Request) { } for _, slot := range slots { - shared := isShared(card.Guid, slot.Article) - if !typesSet || hasType(types, slot.Article) { + shared := isArticleShared(card.Guid, slot.Article) + if !typesSet || hasArticleType(types, slot.Article) { response = append(response, getArticleModel(&slot, shared, false)) } } @@ -126,7 +126,7 @@ func GetArticles(w http.ResponseWriter, r *http.Request) { WriteResponse(w, response) } -func isShared(guid string, article *store.Article) bool { +func isArticleShared(guid string, article *store.Article) bool { if article == nil { return false } @@ -140,7 +140,7 @@ func isShared(guid string, article *store.Article) bool { return false } -func hasType(types []string, article *store.Article) bool { +func hasArticleType(types []string, article *store.Article) bool { if article == nil { return false } diff --git a/net/server/internal/api_getChannels.go b/net/server/internal/api_getChannels.go new file mode 100644 index 00000000..78097b33 --- /dev/null +++ b/net/server/internal/api_getChannels.go @@ -0,0 +1,159 @@ +package databag + +import ( + "strings" + "errors" + "strconv" + "net/http" + "encoding/json" + "databag/internal/store" +) + +func GetChannels(w http.ResponseWriter, r *http.Request) { + var channelRevisionSet bool + var channelRevision int64 + var viewRevisionSet bool + var viewRevision int64 + var typesSet bool + var types []string + + channel := r.FormValue("channelRevision") + if channel != "" { + var err error + channelRevisionSet = true + if channelRevision, err = strconv.ParseInt(channel, 10, 64); err != nil { + ErrResponse(w, http.StatusBadRequest, err) + return + } + } + + view := r.FormValue("viewRevision") + if view != "" { + var err error + viewRevisionSet = true + if viewRevision, err = strconv.ParseInt(view, 10, 64); err != nil { + ErrResponse(w, http.StatusBadRequest, err) + return + } + } + + schemas := r.FormValue("types") + if schemas != "" { + var err error + typesSet = true + dec := json.NewDecoder(strings.NewReader(schemas)) + if dec.Decode(&types) != nil { + ErrResponse(w, http.StatusBadRequest, err) + return + } + } + + var response []*Channel + tokenType := r.Header.Get("TokenType") + if tokenType == APP_TOKENAPP { + + account, code, err := BearerAppToken(r, false); + if err != nil { + ErrResponse(w, code, err) + return + } + + var slots []store.ChannelSlot + if channelRevisionSet { + if err := store.DB.Preload("Channel").Where("account_id = ? AND revision > ?", account.ID, channelRevision).Find(&slots).Error; err != nil { + ErrResponse(w, http.StatusInternalServerError, err) + return + } + } else { + if err := store.DB.Preload("Channel").Where("account_id = ? AND channel_id != 0", account.ID).Find(&slots).Error; err != nil { + ErrResponse(w, http.StatusInternalServerError, err) + return + } + } + + for _, slot := range slots { + if !typesSet || hasChannelType(types, slot.Channel) { + response = append(response, getChannelModel(&slot, true, true)) + } + } + + w.Header().Set("Channel-Revision", strconv.FormatInt(account.ChannelRevision, 10)) + + } else if tokenType == APP_TOKENCONTACT { + + card, code, err := BearerContactToken(r, true) + if err != nil { + ErrResponse(w, code, err) + return + } + + if viewRevisionSet || channelRevisionSet { + if viewRevision != card.ViewRevision { + ErrResponse(w, http.StatusGone, errors.New("channel view has changed")) + return + } + } + + account := &card.Account + var slots []store.ChannelSlot + if channelRevisionSet { + if err := store.DB.Preload("Channel.Groups.Cards").Where("account_id = ? AND revision > ?", account.ID, channelRevision).Find(&slots).Error; err != nil { + ErrResponse(w, http.StatusInternalServerError, err) + return + } + } else { + if err := store.DB.Preload("Channel.Groups.Cards").Where("account_id = ? AND channel_id != 0", account.ID).Find(&slots).Error; err != nil { + ErrResponse(w, http.StatusInternalServerError, err) + return + } + } + + for _, slot := range slots { + shared := isChannelShared(card.Guid, slot.Channel) + if !typesSet || hasChannelType(types, slot.Channel) { + response = append(response, getChannelModel(&slot, shared, false)) + } + } + + w.Header().Set("Channel-Revision", strconv.FormatInt(account.ChannelRevision, 10)) + w.Header().Set("View-Revision", strconv.FormatInt(card.ViewRevision, 10)) + + } else { + ErrResponse(w, http.StatusBadRequest, errors.New("invalid token type")) + return + } + + WriteResponse(w, response) +} + +func isChannelShared(guid string, channel *store.Channel) bool { + if channel == nil { + return false + } + for _, card := range channel.Cards { + if guid == card.Guid { + return true + } + } + for _, group := range channel.Groups { + for _, card := range group.Cards { + if guid == card.Guid { + return true + } + } + } + return false +} + +func hasChannelType(types []string, channel *store.Channel) bool { + if channel == nil { + return false + } + for _, schema := range types { + if schema == channel.DataType { + return true + } + } + return false +} +