diff --git a/net/server/internal/api_content.go b/net/server/internal/api_content.go index 857a7a40..8b3c1c8f 100644 --- a/net/server/internal/api_content.go +++ b/net/server/internal/api_content.go @@ -23,8 +23,4 @@ func RemoveChannelTopic(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -func RemoveChannelTopicTag(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_removeChannelTopicTag.go b/net/server/internal/api_removeChannelTopicTag.go new file mode 100644 index 00000000..df3b5096 --- /dev/null +++ b/net/server/internal/api_removeChannelTopicTag.go @@ -0,0 +1,120 @@ +package databag + +import ( + "time" + "errors" + "net/http" + "gorm.io/gorm" + "github.com/gorilla/mux" + "databag/internal/store" +) + +func RemoveChannelTopicTag(w http.ResponseWriter, r *http.Request) { + + // scan parameters + params := mux.Vars(r) + channelId := params["channelId"] + topicId := params["topicId"] + tagId := params["tagId"] + + channelSlot, guid, err, code := getChannelSlot(r, false) + if err != nil { + ErrResponse(w, code, err) + return + } + act := &channelSlot.Account + + // load topic + var topicSlot store.TopicSlot + if ret := store.DB.Preload("Topic.Tags.TagSlot").Preload("Topic.Channel.ChannelSlot").Where("account_id = ? AND topic_slot_id = ?", act.ID, topicId).First(&topicSlot).Error; ret != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + ErrResponse(w, http.StatusNotFound, ret) + } else { + ErrResponse(w, http.StatusInternalServerError, ret) + } + } + if topicSlot.Topic == nil { + ErrResponse(w, http.StatusNotFound, errors.New("referenced empty topic")) + return + } + if topicSlot.Topic.Channel.ChannelSlot.ChannelSlotId != channelId { + ErrResponse(w, http.StatusNotFound, errors.New("channel topic not found")) + return + } + + // extract specified tag + var tag *store.Tag + var tags []store.Tag + for _, t := range topicSlot.Topic.Tags { + if t.TagSlot.TagSlotId == tagId { + tag = &t + } else { + tags = append(tags, t) + } + } + topicSlot.Topic.Tags = tags; + + // check if tag was found + if tag == nil { + ErrResponse(w, http.StatusNotFound, errors.New("tag not found")) + return + } + + // check permission + if tag.Guid != guid { + ErrResponse(w, http.StatusUnauthorized, errors.New("not creator of tag")) + return + } + + err = store.DB.Transaction(func(tx *gorm.DB) error { + + if res := tx.Delete(tag).Error; res != nil { + return res + } + if res := tx.Model(&tag.TagSlot).Update("revision", act.ChannelRevision + 1).Error; res != nil { + return res + } + if res := tx.Model(&topicSlot.Topic).Update("tag_count", len(topicSlot.Topic.Tags)).Error; res != nil { + return res + } + if res := tx.Model(&topicSlot.Topic).Update("tag_revision", act.ChannelRevision + 1).Error; res != nil { + return res + } + if res := tx.Model(&topicSlot.Topic).Update("tag_updated", time.Now().Unix()).Error; res != nil { + return res + } + if res := tx.Model(&topicSlot).Update("revision", act.ChannelRevision + 1).Error; res != nil { + return res + } + if res := tx.Model(&channelSlot).Update("revision", act.ChannelRevision + 1).Error; res != nil { + return res + } + if res := tx.Model(act).Update("channel_revision", act.ChannelRevision + 1).Error; res != nil { + return res + } + return nil + }) + if err != nil { + ErrResponse(w, http.StatusInternalServerError, err) + return + } + + // determine affected contact list + cards := make(map[string]store.Card) + for _, card := range channelSlot.Channel.Cards { + cards[card.Guid] = card + } + for _, group := range channelSlot.Channel.Groups { + for _, card := range group.Cards { + cards[card.Guid] = card + } + } + + SetStatus(act) + for _, card := range cards { + SetContactChannelNotification(act, &card) + } + WriteResponse(w, nil) +} + + diff --git a/net/server/internal/ucTopicShare_test.go b/net/server/internal/ucTopicShare_test.go index 7017c7e1..5d2c876a 100644 --- a/net/server/internal/ucTopicShare_test.go +++ b/net/server/internal/ucTopicShare_test.go @@ -17,6 +17,8 @@ func TestTopicShare(t *testing.T) { header := make(map[string][]string) var err error var data []byte + var aRev *Revision + var cRev *Revision // setup testing group set, err := AddTestGroup("topicshare") @@ -101,17 +103,35 @@ func TestTopicShare(t *testing.T) { assert.NoError(t, ApiTestMsg(GetChannelTopics, "GET", "/content/channels/{channelId}/topics", ¶ms, nil, APP_TOKENAPP, set.A.Token, topics, nil)) + aRev = GetTestRevision(set.A.Revisions) + cRev = GetTestRevision(set.C.Revisions) + // add a tag to topic tag := Tag{} subject = &Subject{ DataType: "tagdatatype", Data: "subjectfromA" } assert.NoError(t, ApiTestMsg(AddChannelTopicTag, "POST", "/content/channels/{channelId}/topics/{topicId}", - ¶ms, subject, APP_TOKENAPP, set.A.Token, tag, nil)) + ¶ms, subject, APP_TOKENAPP, set.A.Token, &tag, nil)) + + assert.NotEqual(t, aRev.Channel, GetTestRevision(set.A.Revisions).Channel) + assert.NotEqual(t, cRev.Card, GetTestRevision(set.C.Revisions).Card) // get tags for topic - tags := []Tag{} + tags := &[]Tag{} assert.NoError(t, ApiTestMsg(GetChannelTopicTags, "GET", "/content/channels/{channelId}/topics/{topicId}", - ¶ms, nil, APP_TOKENCONTACT, set.C.A.Token, &tags, nil)) - assert.Equal(t, 1, len(tags)) + ¶ms, nil, APP_TOKENCONTACT, set.C.A.Token, tags, nil)) + assert.Equal(t, 1, len(*tags)) + + // delete topic tag + params["tagId"] = tag.Id + assert.NoError(t, ApiTestMsg(RemoveChannelTopicTag, "DELETE", "/content/channels/{channelId}/topics/{topicId}/tags/{tagId}", + ¶ms, nil, APP_TOKENAPP, set.A.Token, nil, nil)) + + // get tags for topic + tags = &[]Tag{} + assert.NoError(t, ApiTestMsg(GetChannelTopicTags, "GET", "/content/channels/{channelId}/topics/{topicId}", + ¶ms, nil, APP_TOKENCONTACT, set.C.A.Token, tags, nil)) +PrintMsg(tags) + assert.Equal(t, 0, len(*tags)) // get list of assets assets = []Asset{}