mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
testing add topic
This commit is contained in:
parent
9f09191c43
commit
898ad9f4ac
21
doc/api.oa3
21
doc/api.oa3
@ -2434,7 +2434,7 @@ paths:
|
||||
tags:
|
||||
- content
|
||||
description: Get list of assets assigned to an channel. The original assets will only be available to the account holder to provent the accidental sharing of content metadata. Access is granted to the app token of the account holder and the contact token of accounts the channel has been shared with.
|
||||
operationId: get-channel-assets
|
||||
operationId: get-channel-topic-assets
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
@ -2469,7 +2469,7 @@ paths:
|
||||
tags:
|
||||
- content
|
||||
description: Add an an asset to the to an channel. The original posted asset is referenced in the asset list with a null transform. The transformed assets are referenced accordingly. Transforming the asset strips it of metadata and transcodes it into a specified format. Access is granted to the app token of the account holder.
|
||||
operationId: add-channel-asset
|
||||
operationId: add-channel-topic-asset
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
@ -2525,7 +2525,7 @@ paths:
|
||||
tags:
|
||||
- content
|
||||
description: Get asset assigned to an channel. The endpoint supports byte-range requests and responds with the content-type set appropriatly. Access granted to the app tokens of the account holder and in the case of non-original assets, the contact token for accounts with which the channel is shared.
|
||||
operationId: get-channel-asset
|
||||
operationId: get-channel-topic-asset
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
@ -2567,7 +2567,7 @@ paths:
|
||||
tags:
|
||||
- content
|
||||
description: Remove an asset from an channel. Access granted to app tokens of the account holder.
|
||||
operationId: remove-channel-asset
|
||||
operationId: remove-channel-topic-asset
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
@ -2606,7 +2606,7 @@ paths:
|
||||
tags:
|
||||
- content
|
||||
description: Set confirmed state of the channel. Until the confirmed state has been set to true, the channel will not be visible to contacts with which the channel is shared. Access granted to the app tokens of the acocunt holder.
|
||||
operationId: set-channel-confirmed
|
||||
operationId: set-channel-topic-confirmed
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
@ -3155,7 +3155,8 @@ components:
|
||||
id:
|
||||
type: string
|
||||
revision:
|
||||
type: int64
|
||||
type: integer
|
||||
format: int64
|
||||
data:
|
||||
$ref: '#/components/schemas/ChannelData'
|
||||
|
||||
@ -3235,7 +3236,7 @@ components:
|
||||
topicDetail:
|
||||
$ref: '#/components/schemas/TopicDetail'
|
||||
topicTags::
|
||||
$ref: '#/components/schemas/TopicSize'
|
||||
$ref: '#/components/schemas/TopicTags'
|
||||
|
||||
TopicDetail:
|
||||
type: object
|
||||
@ -3244,7 +3245,7 @@ components:
|
||||
- dataType
|
||||
- data
|
||||
- created
|
||||
- modified
|
||||
- updated
|
||||
- status
|
||||
properties:
|
||||
guid:
|
||||
@ -3256,14 +3257,14 @@ components:
|
||||
created:
|
||||
type: integer
|
||||
format: int64
|
||||
modified:
|
||||
updated:
|
||||
type: integer
|
||||
format: int64
|
||||
status:
|
||||
type: string
|
||||
enum: [ unconfirmed, confirmed, complete, error ]
|
||||
|
||||
TopicSize:
|
||||
TopicTags:
|
||||
type: object
|
||||
required:
|
||||
- tagCount
|
||||
|
136
net/server/internal/api_addChannelTopic.go
Normal file
136
net/server/internal/api_addChannelTopic.go
Normal file
@ -0,0 +1,136 @@
|
||||
package databag
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"gorm.io/gorm"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/google/uuid"
|
||||
"databag/internal/store"
|
||||
)
|
||||
|
||||
func AddChannelTopic(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// scan parameters
|
||||
params := mux.Vars(r)
|
||||
channelId := params["channelId"]
|
||||
|
||||
var subject Subject
|
||||
if err := ParseRequest(r, w, &subject); err != nil {
|
||||
ErrResponse(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
var guid string
|
||||
var act *store.Account
|
||||
tokenType := r.Header.Get("TokenType")
|
||||
if tokenType == APP_TOKENAPP {
|
||||
account, code, err := BearerAppToken(r, false);
|
||||
if err != nil {
|
||||
ErrResponse(w, code, err)
|
||||
return
|
||||
}
|
||||
act = account
|
||||
guid = account.Guid
|
||||
} else if tokenType == APP_TOKENCONTACT {
|
||||
card, code, err := BearerContactToken(r, true)
|
||||
if err != nil {
|
||||
ErrResponse(w, code, err)
|
||||
return
|
||||
}
|
||||
act = &card.Account
|
||||
guid = card.Guid
|
||||
} else {
|
||||
ErrResponse(w, http.StatusBadRequest, errors.New("unknown token type"))
|
||||
return
|
||||
}
|
||||
|
||||
// load channel
|
||||
var channelSlot store.ChannelSlot
|
||||
if err := store.DB.Preload("Channel.Cards").Preload("Channel.Groups.Cards").Where("account_id = ? AND channel_slot_id = ?", act.ID, channelId).First(&channelSlot).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
ErrResponse(w, http.StatusNotFound, err)
|
||||
} else {
|
||||
ErrResponse(w, http.StatusInternalServerError, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if channelSlot.Channel == nil {
|
||||
ErrResponse(w, http.StatusNotFound, errors.New("referenced empty channel"))
|
||||
return
|
||||
}
|
||||
|
||||
// check if a member
|
||||
if tokenType == APP_TOKENCONTACT {
|
||||
if !isMember(guid, channelSlot.Channel.Cards) {
|
||||
ErrResponse(w, http.StatusUnauthorized, errors.New("not a member of channel"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
topicSlot := &store.TopicSlot{}
|
||||
err := store.DB.Transaction(func(tx *gorm.DB) error {
|
||||
|
||||
// add new record
|
||||
topic := &store.Topic{}
|
||||
topic.Data = subject.Data
|
||||
topic.DataType = subject.DataType
|
||||
topic.Channel = channelSlot.Channel
|
||||
topic.TagCount = 0
|
||||
topic.Guid = guid
|
||||
topic.DetailRevision = act.ChannelRevision + 1
|
||||
topic.TagRevision = act.ChannelRevision + 1
|
||||
topic.Status = APP_TOPICUNCONFIRMED
|
||||
if res := tx.Save(topic).Error; res != nil {
|
||||
return res
|
||||
}
|
||||
topicSlot.TopicSlotId = uuid.New().String()
|
||||
topicSlot.AccountID = act.ID
|
||||
topicSlot.TopicID = topic.ID
|
||||
topicSlot.Revision = act.ChannelRevision + 1
|
||||
topicSlot.Topic = topic
|
||||
if res := tx.Save(topicSlot).Error; res != nil {
|
||||
return res
|
||||
}
|
||||
|
||||
// update parent revision
|
||||
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, getTopicModel(topicSlot, true, true))
|
||||
}
|
||||
|
||||
func isMember(guid string, cards []store.Card) bool {
|
||||
for _, card := range cards {
|
||||
if guid == card.Guid {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -18,11 +18,6 @@ func AddChannelAsset(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func AddChannelTopic(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func AddChannelTopicTag(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
0
net/server/internal/model
Normal file
0
net/server/internal/model
Normal file
@ -215,3 +215,55 @@ func getChannelModel(slot *store.ChannelSlot, showData bool, showList bool) *Cha
|
||||
|
||||
|
||||
|
||||
func getTopicRevisionModel(slot *store.TopicSlot, showData bool) *Topic {
|
||||
|
||||
if !showData || slot.Topic == nil {
|
||||
return &Topic{
|
||||
Id: slot.TopicSlotId,
|
||||
Revision: slot.Revision,
|
||||
}
|
||||
}
|
||||
|
||||
return &Topic{
|
||||
Id: slot.TopicSlotId,
|
||||
Revision: slot.Revision,
|
||||
Data: &TopicData {
|
||||
DetailRevision: slot.Topic.DetailRevision,
|
||||
TagRevision: slot.Topic.TagRevision,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getTopicModel(slot *store.TopicSlot, showData bool, showList bool) *Topic {
|
||||
|
||||
if !showData || slot.Topic == nil {
|
||||
return &Topic{
|
||||
Id: slot.TopicSlotId,
|
||||
Revision: slot.Revision,
|
||||
}
|
||||
}
|
||||
|
||||
return &Topic{
|
||||
Id: slot.TopicSlotId,
|
||||
Revision: slot.Revision,
|
||||
Data: &TopicData {
|
||||
DetailRevision: slot.Topic.DetailRevision,
|
||||
TopicDetail: &TopicDetail{
|
||||
Guid: slot.Topic.Guid,
|
||||
DataType: slot.Topic.DataType,
|
||||
Data: slot.Topic.Data,
|
||||
Created: slot.Topic.Created,
|
||||
Updated: slot.Topic.Updated,
|
||||
Status: slot.Topic.Status,
|
||||
},
|
||||
TagRevision: slot.Topic.TagRevision,
|
||||
TopicTags: &TopicTags{
|
||||
TagCount: slot.Topic.TagCount,
|
||||
TagUpdated: slot.Topic.TagUpdated,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -363,7 +363,7 @@ type Tag struct {
|
||||
|
||||
Id string `json:"id"`
|
||||
|
||||
Revision string `json:"revision"`
|
||||
Revision int64 `json:"revision"`
|
||||
|
||||
Data *TagData `json:"data"`
|
||||
}
|
||||
@ -385,7 +385,7 @@ type Topic struct {
|
||||
|
||||
Id string `json:"id"`
|
||||
|
||||
Revision string `json:"revision"`
|
||||
Revision int64 `json:"revision"`
|
||||
|
||||
Data *TopicData `json:"data"`
|
||||
}
|
||||
@ -398,7 +398,7 @@ type TopicData struct {
|
||||
|
||||
TopicDetail *TopicDetail `json:"topicDetail,omitempty"`
|
||||
|
||||
TopicTags *TopicSize `json:"topicTags:,omitempty"`
|
||||
TopicTags *TopicTags `json:"topicTags:,omitempty"`
|
||||
}
|
||||
|
||||
type TopicDetail struct {
|
||||
@ -411,12 +411,12 @@ type TopicDetail struct {
|
||||
|
||||
Created int64 `json:"created"`
|
||||
|
||||
Modified int64 `json:"modified"`
|
||||
Updated int64 `json:"updated"`
|
||||
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type TopicSize struct {
|
||||
type TopicTags struct {
|
||||
|
||||
TagCount int32 `json:"tagCount"`
|
||||
|
||||
|
@ -224,9 +224,9 @@ type Topic struct {
|
||||
Status string `gorm:"not null;index"`
|
||||
Created int64 `gorm:"autoCreateTime"`
|
||||
Updated int64 `gorm:"autoUpdateTime"`
|
||||
SizeRevision int64 `gorm:"not null"`
|
||||
TagUpdated int64 `gorm:"not null"`
|
||||
TagRevision uint64 `gorm:"not null"`
|
||||
TagCount int32 `gorm:"not null"`
|
||||
TagUpdated int64 `gorm:"autoUpdateTime"`
|
||||
TagRevision int64 `gorm:"not null"`
|
||||
Channel *Channel
|
||||
Assets []Asset
|
||||
Tags []Tag
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func TestTopicShare(t *testing.T) {
|
||||
var topic *Topic
|
||||
var channel *Channel
|
||||
var subject *Subject
|
||||
params := make(map[string]string)
|
||||
@ -68,7 +69,22 @@ func TestTopicShare(t *testing.T) {
|
||||
assert.Zero(t, bytes.Compare(img, data))
|
||||
|
||||
|
||||
// add a topc
|
||||
topic = &Topic{}
|
||||
subject = &Subject{ DataType: "topicdatatype", Data: "subjectfromA" }
|
||||
assert.NoError(t, ApiTestMsg(AddChannelTopic, "POST", "/content/channels/{channelId}/topics",
|
||||
¶ms, subject, APP_TOKENAPP, set.A.Token, topic, nil))
|
||||
topic = &Topic{}
|
||||
subject = &Subject{ DataType: "topicdatatype", Data: "subjectfromB" }
|
||||
assert.NoError(t, ApiTestMsg(AddChannelTopic, "POST", "/content/channels/{channelId}/topics",
|
||||
¶ms, subject, APP_TOKENCONTACT, set.B.A.Token, topic, nil))
|
||||
topic = &Topic{}
|
||||
subject = &Subject{ DataType: "topicdatatype", Data: "subjectfromC" }
|
||||
assert.NoError(t, ApiTestMsg(AddChannelTopic, "POST", "/content/channels/{channelId}/topics",
|
||||
¶ms, subject, APP_TOKENCONTACT, set.C.A.Token, topic, nil))
|
||||
|
||||
|
||||
PrintMsg(topic)
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user