removed label based endpoints

This commit is contained in:
Roland Osborne 2022-02-08 12:24:42 -08:00
parent a74b2ee74b
commit d90df5f170
48 changed files with 961 additions and 2661 deletions

View File

@ -43,12 +43,12 @@ paths:
'200':
description: Awaiting announce
/admin/available:
/admin/status:
get:
tags:
- admin
description: Check if portal params have been set
operationId: get-node-available
operationId: get-node-status
responses:
'200':
description: success
@ -58,13 +58,11 @@ paths:
type: boolean
'500':
description: internal server error
/admin/claim:
post:
put:
tags:
- admin
description: Set admin password and node domain
operationId: set-node-claim
operationId: set-node-status
security:
- basicCredentials: []
parameters:
@ -269,12 +267,12 @@ paths:
type: string
format: binary
/account/public/available:
/account/public/status:
get:
tags:
- account
description: Check if a public account can be created.
operationId: get-public-available
operationId: get-public-status
responses:
'200':
description: success
@ -1041,6 +1039,30 @@ paths:
required: false # required for connected
schema:
type: string
- name: profileRevision
in: query
description: profile revision of contact
required: false # required for connected
schema:
type: string
- name: articleRevision
in: query
description: article revision of contact
required: false # required for connected
schema:
type: string
- name: channelRevision
in: query
description: channel revision of contact
required: false # required for connected
schema:
type: string
- name: viewRevision
in: query
description: view revision of contact
required: false # required for connected
schema:
type: string
responses:
'200':
description: success
@ -1159,18 +1181,6 @@ paths:
responses:
'200':
description: successful operation
content:
application/json:
schema:
type: object
required:
- status
properties:
token:
type: string
status:
type: string
enum: [ pending, confirmed, requested, connecting, connected ]
'400':
description: invalid data message
'410':
@ -1474,12 +1484,36 @@ paths:
type: integer
format: int64
/contact/content/revision:
/contact/article/revision:
put:
tags:
- contact
description: Set content revision for contact. This is intend to be invoked automatically anytime a contact updates their content or sharing. Access granted to contact tokens.
operationId: set-content-revision
description: Set artcile revision for contact. This is intend to be invoked automatically anytime a contact updates their content or sharing. Access granted to contact tokens.
operationId: set-article-revision
security:
- bearerAuth: []
responses:
'200':
description: revision set
'401':
description: not authorized
'410':
description: account disabled
'500':
description: internal server error
requestBody:
content:
application/json:
schema:
type: integer
format: int64
/contact/channel/revision:
put:
tags:
- contact
description: Set channel revision for contact. This is intend to be invoked automatically anytime a contact updates their content or sharing. Access granted to contact tokens.
operationId: set-channel-revision
security:
- bearerAuth: []
responses:
@ -1692,15 +1726,7 @@ paths:
content:
application/json:
schema:
type: object
required:
- type
- data
properties:
type:
type: string
data:
type: string
$ref: '#/components/schemas/Subject'
/attribute/articles/{articleId}/groups/{groupId}:
put:
@ -2341,15 +2367,7 @@ paths:
content:
application/json:
schema:
type: object
required:
- type
- data
properties:
type:
type: string
data:
type: string
$ref: '#/components/schemas/Subject'
/content/channels/{channelId}/topics/{topicId}/assets:
get:
@ -2804,7 +2822,7 @@ components:
type: object
required:
- profile
- attribute
- article
- group
- channel
- card
@ -2955,7 +2973,7 @@ components:
id:
type: string
revision:
type: number
type: integer
format: int64
data:
$ref: '#/components/schemas/CardData'
@ -2966,7 +2984,7 @@ components:
- detailRevision
- profileRevision
- notifiedProfile
- notifiedContent
- notifiedArticle
- notifiedChannel
- notifiedView
properties:
@ -2979,7 +2997,7 @@ components:
notifiedProfile:
type: integer
format: int64
notifiedContent:
notifiedArticle:
type: integer
format: int64
notifiedChannel:
@ -3038,7 +3056,7 @@ components:
required:
- id
- revision
- ata
- data
properties:
id:
type: string
@ -3162,7 +3180,8 @@ components:
id:
type: string
revision:
type: string
type: integer
format: int64
data:
$ref: '#/components/schemas/TopicData'
@ -3232,7 +3251,8 @@ components:
id:
type: string
revision:
type: string
type: integer
format: int64
data:
$ref: '#/components/schemas/TagData'
@ -3268,7 +3288,8 @@ components:
id:
type: string
revision:
type: string
type: integer
format: int64
data:
$ref: '#/components/schemas/ArticleData'
@ -3378,12 +3399,15 @@ components:
viewRevision:
type: integer
format: int64
contentRevision:
articleRevision:
type: integer
format: int64
profileRevision:
type: integer
format: int64
channelRevision:
type: integer
format: int64
handle:
type: string
name:
@ -3435,6 +3459,18 @@ components:
properties:
token:
type: string
profileRevision:
type: integer
format: int64
articleRevision:
type: integer
format: int64
channelRevision:
type: integer
format: int64
viewRevision:
type: integer
format: int64
status:
type: string
enum: [ pending, confirmed, requested, connecting, connected ]

View File

@ -53,7 +53,17 @@ func GetAccountStatus(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
func GetPublicClaimable(w http.ResponseWriter, r *http.Request) {
func GetAccountToken(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetAccountUsername(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetPublicStatus(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}

View File

@ -1,103 +0,0 @@
package databag
import (
"time"
"errors"
"net/http"
"gorm.io/gorm"
"github.com/google/uuid"
"databag/internal/store"
)
func AddArticle(w http.ResponseWriter, r *http.Request) {
account, code, err := BearerAppToken(r, false)
if err != nil {
ErrResponse(w, code, err)
return
}
var articleAccess ArticleAccess
if err := ParseRequest(r, w, &articleAccess); err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
var groupSlots []store.GroupSlot
if err := store.DB.Preload("Group").Where("group_slot_id IN ?", articleAccess.Groups).Find(&groupSlots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
var groups []store.Group
for _, slot := range groupSlots {
if slot.Group != nil {
groups = append(groups, *slot.Group)
}
}
var labelSlots []store.LabelSlot
if err := store.DB.Preload("Label").Where("label_slot_id IN ?", articleAccess.Labels).Find(&labelSlots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
var labels []store.Label
for _, slot := range labelSlots {
if slot.Label != nil {
labels = append(labels, *slot.Label)
}
}
// save data and apply transaction
var slot *store.ArticleSlot
err = store.DB.Transaction(func(tx *gorm.DB) error {
article := &store.Article{
Status: APP_ARTICLEUNCONFIRMED,
TagUpdated: time.Now().Unix(),
TagRevision: 1,
TagCount: 0,
Groups: groups,
Labels: labels,
};
if res := tx.Save(article).Error; res != nil {
return res;
}
if res := tx.Where("article_id = 0 AND account_id = ?", account.ID).First(&slot).Error; res != nil {
if errors.Is(res, gorm.ErrRecordNotFound) {
slot = &store.ArticleSlot{
ArticleSlotId: uuid.New().String(),
AccountID: account.ID,
Revision: 1,
ArticleID: article.ID,
Article: article,
}
if ret := tx.Save(slot).Error; ret != nil {
return ret;
}
} else {
return res
}
}
if ret := tx.Model(slot).Update("article_id", article.ID).Error; ret != nil {
return ret;
}
if ret := tx.Preload("Article.Labels.Groups").Where("id = ?", article.ID).First(slot).Error; ret != nil {
return ret;
}
if ret := tx.Model(&account).Update("content_revision", account.ContentRevision + 1).Error; ret != nil {
return ret
}
return nil
})
if err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
SetContentNotification(account)
SetStatus(account)
WriteResponse(w, getArticleModel(slot, false, true))
}

View File

@ -1,71 +0,0 @@
package databag
import (
"net/http"
"errors"
"gorm.io/gorm"
"github.com/google/uuid"
"databag/internal/store"
)
func AddLabel(w http.ResponseWriter, r *http.Request) {
account, code, err := BearerAppToken(r, false)
if err != nil {
ErrResponse(w, code, err)
return
}
var subject Subject
if err := ParseRequest(r, w, &subject); err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
slot := &store.LabelSlot{}
label := &store.Label{}
err = store.DB.Transaction(func(tx *gorm.DB) error {
data := &store.LabelData{
Data: subject.Data,
}
if res := tx.Save(data).Error; res != nil {
return res
}
label.LabelDataID = data.ID
label.LabelData = *data
label.DataType = subject.DataType
if res := tx.Save(label).Error; res != nil {
return res
}
if res := tx.Where("account_id = ? AND label_id = 0", account.ID).First(slot).Error; res != nil {
if errors.Is(res, gorm.ErrRecordNotFound) {
slot.LabelSlotId = uuid.New().String()
slot.AccountID = account.ID
} else {
return res
}
}
slot.LabelID = label.ID
slot.Revision = account.LabelRevision + 1
slot.Label = label
if res := tx.Save(slot).Error; res != nil {
return res
}
if res := tx.Model(&account).Update("label_revision", account.LabelRevision + 1).Error; res != nil {
return res
}
return nil
})
if err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
SetStatus(account)
WriteResponse(w, getLabelModel(slot, true, true))
}

View File

@ -0,0 +1,30 @@
/*
* DataBag
*
* DataBag provides storage for decentralized identity based self-hosting apps. It is intended to support sharing of personal data and hosting group conversations.
*
* API version: 0.0.1
* Contact: roland.osborne@gmail.com
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package databag
import (
"net/http"
)
func GetGroups(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func RemoveGroup(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func UpdateGroup(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}

View File

@ -0,0 +1,50 @@
/*
* DataBag
*
* DataBag provides storage for decentralized identity based self-hosting apps. It is intended to support sharing of personal data and hosting group conversations.
*
* API version: 0.0.1
* Contact: roland.osborne@gmail.com
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package databag
import (
"net/http"
)
func AddArticle(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func ClearArticleGroup(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetArticleSubjectField(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
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 RemoveArticle(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetArticleGroup(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetArticleSubject(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}

View File

@ -1,3 +1,12 @@
/*
* DataBag
*
* DataBag provides storage for decentralized identity based self-hosting apps. It is intended to support sharing of personal data and hosting group conversations.
*
* API version: 0.0.1
* Contact: roland.osborne@gmail.com
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package databag
import (
@ -5,30 +14,7 @@ import (
)
func Authorize(w http.ResponseWriter, r *http.Request) {
account, code, res := BearerAppToken(r, true);
if res != nil {
ErrResponse(w, code, res)
return
}
detail := account.AccountDetail
// extract token from body
var token string
res = ParseRequest(r, w, &token)
if res != nil {
ErrResponse(w, http.StatusBadRequest, res)
return
}
// generate auth DataMessage
auth := Authenticate{ Token: token }
msg, res := WriteDataMessage(detail.PrivateKey, detail.PublicKey, detail.KeyType,
APP_SIGNPKCS1V15, account.Guid, APP_MSGAUTHENTICATE, &auth)
if res != nil {
ErrResponse(w, http.StatusInternalServerError, res)
return
}
WriteResponse(w, msg)
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}

View File

@ -1,64 +0,0 @@
package databag
import (
"errors"
"net/http"
"gorm.io/gorm"
"github.com/gorilla/mux"
"databag/internal/store"
)
func ClearCardNotes(w http.ResponseWriter, r *http.Request) {
account, code, err := BearerAppToken(r, false);
if err != nil {
ErrResponse(w, code, err)
return
}
// scan parameters
params := mux.Vars(r)
cardId := params["cardId"]
// load referenced card
var slot store.CardSlot
if err := store.DB.Preload("Card").Where("account_id = ? AND card_slot_id = ?", account.ID, cardId).First(&slot).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusInternalServerError, err)
} else {
ErrResponse(w, http.StatusNotFound, err)
}
return
}
if slot.Card == nil {
ErrResponse(w, http.StatusNotFound, errors.New("card has been deleted"))
return
}
// update card
slot.Revision = account.CardRevision + 1
slot.Card.DetailRevision += 1
slot.Card.Notes = ""
// save and update contact revision
err = store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Save(&slot.Card).Error; res != nil {
return res
}
if res := tx.Preload("Card").Save(&slot).Error; res != nil {
return res
}
if res := tx.Model(&account).Update("card_revision", account.CardRevision + 1).Error; res != nil {
return res
}
return nil
})
if err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
SetStatus(account)
WriteResponse(w, getCardDetailModel(&slot));
}

View File

@ -18,12 +18,7 @@ func ClearCardGroup(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
func GetCardDetail(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetCardProfile(w http.ResponseWriter, r *http.Request) {
func ClearCardNotes(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
@ -33,6 +28,11 @@ func GetCardProfileImage(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
func GetCards(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetCloseMessage(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
@ -43,6 +43,16 @@ func RemoveCard(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
func SetCardNotes(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetCardProfile(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetCloseMessage(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)

View File

@ -13,107 +13,132 @@ import (
"net/http"
)
func AddArticleAsset(w http.ResponseWriter, r *http.Request) {
func AddChannel(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func AddArticleTag(w http.ResponseWriter, r *http.Request) {
func AddChannelAsset(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func ClearArticleGroup(w http.ResponseWriter, r *http.Request) {
func AddChannelTopic(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func ClearArticleLabel(w http.ResponseWriter, r *http.Request) {
func AddChannelTopicTag(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func ClearLabelGroup(w http.ResponseWriter, r *http.Request) {
func ClearChannelGroup(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetArticle(w http.ResponseWriter, r *http.Request) {
func GetChannelAsset(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetArticleAsset(w http.ResponseWriter, r *http.Request) {
func GetChannelAssets(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetArticleAssets(w http.ResponseWriter, r *http.Request) {
func GetChannelDetail(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetArticleSubjectField(w http.ResponseWriter, r *http.Request) {
func GetChannelSize(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetArticleTag(w http.ResponseWriter, r *http.Request) {
func GetChannelSubjectField(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetArticleTagBlockView(w http.ResponseWriter, r *http.Request) {
func GetChannelTopicDetail(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetArticleTagSubjectField(w http.ResponseWriter, r *http.Request) {
func GetChannelTopicSize(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetArticleTagView(w http.ResponseWriter, r *http.Request) {
func GetChannelTopicSubjectField(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetArticleTags(w http.ResponseWriter, r *http.Request) {
func GetChannelTopicTagSubjectField(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 GetChannelTopicTags(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func RemoveArticleTag(w http.ResponseWriter, r *http.Request) {
func GetChannelTopics(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) {
func GetChannels(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetArticleExpiration(w http.ResponseWriter, r *http.Request) {
func RemoveChannel(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetArticleGroup(w http.ResponseWriter, r *http.Request) {
func RemoveChannelAsset(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetArticleSubject(w http.ResponseWriter, r *http.Request) {
func RemoveChannelTopic(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func UpdateLabel(w http.ResponseWriter, r *http.Request) {
func RemoveChannelTopicTag(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetChannelConfirmed(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetChannelGroup(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetChannelSubject(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetChannelTopicSubject(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetChannelTopicTagSubject(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}

View File

@ -1,174 +0,0 @@
/*
* DataBag
*
* DataBag provides storage for decentralized identity based self-hosting apps. It is intended to support sharing of personal data and hosting group conversations.
*
* API version: 0.0.1
* Contact: roland.osborne@gmail.com
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package databag
import (
"net/http"
)
func AddDialogue(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func AddDialogueInsight(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func AddDialogueTopic(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func AddInsightDialogue(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func AddTopicAsset(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func AddTopicTag(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func ConversationDialoguesDialogueIdTopicsTopicIdConfirmedPut(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetDialogueTopic(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetDialogueTopicSubjectField(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetDialogues(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetInsights(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetTopicAsset(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetTopicAssets(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetTopicBlock(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetTopicBlockView(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetTopicTag(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetTopicTagBlockView(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetTopicTagSubjectField(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetTopicTagView(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetTopicTags(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetTopicViews(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func RemoveDialogue(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func RemoveDialogueInsight(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func RemoveDialogueTopic(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func RemoveTopicAsset(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func RemoveTopicTag(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetDialogueActive(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetDialogueInsightStatus(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetDialogueSubject(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetInsightDialogue(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetInsightStatus(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetTopicSubject(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}

View File

@ -1,125 +0,0 @@
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
var revisionSet bool
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
}
revisionSet = true
}
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.ArticleSlot
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))
}
w.Header().Set("Content-Revision", strconv.FormatInt(account.ContentRevision, 10))
} else if tokenType == APP_TOKENCONTACT {
card, code, err := BearerContactToken(r, false)
if err != nil {
ErrResponse(w, code, err)
return
}
if viewRevision != card.ViewRevision {
if revisionSet {
ErrResponse(w, http.StatusGone, errors.New("article view unavailable"))
return
}
}
var articles []store.ArticleSlot
if err := getContactArticles(card, contentRevision, &articles); err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
for _, article := range articles {
if isArticleShared(&article, card.Guid) {
response = append(response, getArticleModel(&article, true, true))
} else if revisionSet {
response = append(response, getArticleModel(&article, true, false))
}
}
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"))
}
WriteResponse(w, response)
}
// better if this filtering was done in gorm or sql
func isArticleShared(slot *store.ArticleSlot, guid string) bool {
if slot.Article == nil {
return false
}
for _, group := range slot.Article.Groups {
for _, card := range group.Cards {
if card.Guid == guid {
return true
}
}
}
for _, label := range slot.Article.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.ArticleSlot) error {
return store.DB.Preload("Article.Labels.LabelSlot").Preload("Article.Groups.GroupSlot").Preload("Article.Labels.Groups.GroupSlot").Where("account_id = ? AND revision > ?", account.ID, revision).Find(articles).Error
}
func getContactArticles(card *store.Card, revision int64, articles *[]store.ArticleSlot) error {
return store.DB.Preload("Article.Labels.LabelSlot").Preload("Article.Groups.Cards").Preload("Article.Labels.Groups.Cards").Where("account_id = ? AND revision > ?", card.Account.ID, revision).Find(articles).Error
}

View File

@ -8,7 +8,7 @@ import (
"databag/internal/store"
)
func GetCard(w http.ResponseWriter, r *http.Request) {
func GetCardDetail(w http.ResponseWriter, r *http.Request) {
account, code, err := BearerAppToken(r, false);
if err != nil {
@ -26,7 +26,11 @@ func GetCard(w http.ResponseWriter, r *http.Request) {
}
return
}
if slot.Card == nil {
ErrResponse(w, http.StatusNotFound, errors.New("referenced empty card slot"))
return
}
WriteResponse(w, getCardModel(&slot))
WriteResponse(w, getCardDetailModel(&slot))
}

View File

@ -0,0 +1,36 @@
package databag
import (
"errors"
"net/http"
"gorm.io/gorm"
"github.com/gorilla/mux"
"databag/internal/store"
)
func GetCardProfile(w http.ResponseWriter, r *http.Request) {
account, code, err := BearerAppToken(r, false);
if err != nil {
ErrResponse(w, code, err)
return
}
cardId := mux.Vars(r)["cardId"]
var slot store.CardSlot
if err := store.DB.Preload("Card.Groups").Where("account_id = ? AND card_slot_id = ?", account.ID, cardId).First(&slot).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusNotFound, err)
} else {
ErrResponse(w, http.StatusInternalServerError, err)
}
return
}
if slot.Card == nil {
ErrResponse(w, http.StatusNotFound, errors.New("referenced empty card slot"))
return
}
WriteResponse(w, getCardProfileModel(&slot))
}

View File

@ -1,40 +0,0 @@
package databag
import (
"strconv"
"net/http"
"databag/internal/store"
)
func GetCards(w http.ResponseWriter, r *http.Request) {
var res error
var cardRevision int64
card := r.FormValue("cardRevision")
if card != "" {
if cardRevision, res = strconv.ParseInt(card, 10, 64); res != nil {
ErrResponse(w, http.StatusBadRequest, res)
return
}
}
account, code, err := BearerAppToken(r, false);
if err != nil {
ErrResponse(w, code, err)
return
}
var slots []store.CardSlot
if err := store.DB.Preload("Card.Groups.GroupSlot").Where("account_id = ? AND revision > ?", account.ID, cardRevision).Find(&slots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
var response []*Card
for _, slot := range slots {
response = append(response, getCardModel(&slot))
}
w.Header().Set("Card-Revision", strconv.FormatInt(account.CardRevision, 10))
WriteResponse(w, response)
}

View File

@ -1,41 +0,0 @@
package databag
import (
"strconv"
"net/http"
"databag/internal/store"
)
func GetGroups(w http.ResponseWriter, r *http.Request) {
var res error
var groupRevision int64
group := r.FormValue("groupRevision")
if group != "" {
if groupRevision, res = strconv.ParseInt(group, 10, 64); res != nil {
ErrResponse(w, http.StatusBadRequest, res)
return
}
}
account, code, err := BearerAppToken(r, false)
if err != nil {
ErrResponse(w, code, err)
return
}
var slots []store.GroupSlot
if err := store.DB.Preload("Group").Where("account_id = ? AND revision > ?", account.ID, groupRevision).Find(&slots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
var groups []*Group
for _, slot := range slots {
groups = append(groups, getGroupModel(&slot))
}
w.Header().Set("Group-Revision", strconv.FormatInt(account.GroupRevision, 10))
WriteResponse(w, groups)
}

View File

@ -1,116 +0,0 @@
package databag
import (
"errors"
"strconv"
"net/http"
"databag/internal/store"
)
func GetLabels(w http.ResponseWriter, r *http.Request) {
var res error
var viewRevision int64
var labelRevision int64
var revisionSet bool
view := r.FormValue("viewRevision")
if view != "" {
if viewRevision, res = strconv.ParseInt(view, 10, 64); res != nil {
ErrResponse(w, http.StatusBadRequest, res)
return
}
}
label := r.FormValue("labelRevision")
if label != "" {
if labelRevision, res = strconv.ParseInt(label, 10, 64); res != nil {
ErrResponse(w, http.StatusBadRequest, res)
return
}
revisionSet = true
}
tokenType := r.Header.Get("TokenType")
var response []*Label
if tokenType == APP_TOKENAPP {
account, code, err := BearerAppToken(r, false)
if err != nil {
ErrResponse(w, code, err)
return
}
var labels []store.LabelSlot
if err := getAccountLabels(account, labelRevision, &labels); err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
for _, label := range labels {
response = append(response, getLabelModel(&label, false, true))
}
w.Header().Set("Label-Revision", strconv.FormatInt(account.LabelRevision, 10))
} else if tokenType == APP_TOKENCONTACT {
card, code, err := BearerContactToken(r, false)
if err != nil {
ErrResponse(w, code, err)
return
}
if viewRevision != card.ViewRevision {
if revisionSet {
ErrResponse(w, http.StatusGone, errors.New("label view unavailable"))
return
}
}
var labels []store.LabelSlot
if err := getContactLabels(card, labelRevision, &labels); err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
for _, label := range labels {
if isLabelShared(&label, card.Guid) {
response = append(response, getLabelModel(&label, true, true))
} else if revisionSet {
response = append(response, getLabelModel(&label, true, false))
}
}
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"))
}
WriteResponse(w, response)
}
// better if this filtering was done in gorm or sql
func isLabelShared(slot *store.LabelSlot, guid string) bool {
if slot.Label == nil {
return false
}
for _, group := range slot.Label.Groups {
for _, card := range group.Cards {
if card.Guid == guid {
return true
}
}
}
return false
}
func getAccountLabels(account *store.Account, revision int64, labels *[]store.LabelSlot) error {
return store.DB.Preload("Label.Groups.GroupSlot").Where("account_id = ? AND revision > ?", account.ID, revision).Find(labels).Error
}
func getContactLabels(card *store.Card, revision int64, labels *[]store.LabelSlot) error {
return store.DB.Preload("Label.Groups.Cards").Where("account_id = ? AND revision > ?", card.Account.ID, revision).Find(labels).Error
}

View File

@ -7,7 +7,7 @@ import (
"databag/internal/store"
)
func GetNodeClaimable(w http.ResponseWriter, r *http.Request) {
func GetNodeStatus(w http.ResponseWriter, r *http.Request) {
var config store.Config
err := store.DB.Where("config_id = ?", CONFIG_CONFIGURED).First(&config).Error
if err != nil {

View File

@ -40,10 +40,10 @@ func GetOpenMessage(w http.ResponseWriter, r *http.Request) {
connect := &Connect{
Contact: slot.Card.Guid,
Token: slot.Card.InToken,
ContentRevision: account.ContentRevision,
ArticleRevision: account.ArticleRevision,
ProfileRevision: account.ProfileRevision,
ViewRevision: slot.Card.ViewRevision,
LabelRevision: account.LabelRevision,
ChannelRevision: account.ChannelRevision,
Handle: account.Username,
Name: detail.Name,
Description: detail.Description,

View File

@ -1,30 +0,0 @@
package databag
import (
"net/http"
)
func GetProfile(w http.ResponseWriter, r *http.Request) {
account, code, err := BearerAppToken(r, true);
if err != nil {
ErrResponse(w, code, err)
return
}
detail := account.AccountDetail
// send profile data
profile := Profile {
Guid: account.Guid,
Handle: account.Username,
Name: detail.Name,
Description: detail.Description,
Location: detail.Location,
Image: detail.Image,
Revision: account.ProfileRevision,
Version: APP_VERSION,
Node: "https://" + getStrConfigValue(CONFIG_DOMAIN, "") + "/",
}
WriteResponse(w, profile)
}

View File

@ -13,11 +13,21 @@ import (
"net/http"
)
func GetProfile(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func GetProfileImage(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetProfile(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func SetProfileImage(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)

View File

@ -1,63 +0,0 @@
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 slot store.ArticleSlot
if res := store.DB.Preload("Article").Where("account_id = ? AND article_slot_id = ?", account.ID, articleId).First(&slot).Error; res != nil {
return res
}
if slot.Article == nil {
return nil
}
if res := tx.Model(slot.Article).Association("Groups").Clear(); res != nil {
return res
}
if res := tx.Model(slot.Article).Association("Labels").Clear(); res != nil {
return res
}
if res := tx.Delete(slot.Article).Error; res != nil {
return res
}
slot.ArticleID = 0
slot.Revision = account.ContentRevision + 1
slot.Article = nil
if res := tx.Save(&slot).Error; res != nil {
return res
}
if res := tx.Model(&account).Update("content_revision", account.ContentRevision + 1).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)
}

View File

@ -1,68 +0,0 @@
package databag
import (
"errors"
"net/http"
"gorm.io/gorm"
"github.com/gorilla/mux"
"databag/internal/store"
)
func RemoveGroup(w http.ResponseWriter, r *http.Request) {
account, code, err := BearerAppToken(r, false)
if err != nil {
ErrResponse(w, code, err)
return
}
params := mux.Vars(r)
groupId := params["groupId"]
var slot store.GroupSlot
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 {
ErrResponse(w, http.StatusInternalServerError, err)
}
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 {
return res
}
if res := tx.Delete(&slot.Group.GroupData).Error; res != nil {
return res
}
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
}
return nil
})
if err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
for _, card := range notify {
SetContactViewNotification(account, card)
}
SetStatus(account)
WriteResponse(w, nil)
}

View File

@ -1,74 +0,0 @@
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)
}

View File

@ -1,76 +0,0 @@
package databag
import (
"errors"
"net/http"
"gorm.io/gorm"
"github.com/gorilla/mux"
"databag/internal/store"
)
func SetArticleLabel(w http.ResponseWriter, r *http.Request) {
account, code, err := BearerAppToken(r, false);
if err != nil {
ErrResponse(w, code, err)
return
}
// scan parameters
params := mux.Vars(r)
articleId := params["articleId"]
labelId := params["labelId"]
labelSlot := &store.LabelSlot{}
if err := store.DB.Preload("Label.LabelSlot").Where("account_id = ? AND label_slot_id = ?", account.ID, labelId).First(&labelSlot).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusInternalServerError, err)
} else {
ErrResponse(w, http.StatusNotFound, err)
}
return
}
if labelSlot.Label == nil {
ErrResponse(w, http.StatusNotFound, errors.New("referenced empty label slot"))
return
}
articleSlot := &store.ArticleSlot{}
if err := store.DB.Preload("Article.Labels.LabelSlot").Preload("Article.Groups.GroupSlot").Where("account_id = ? AND article_slot_id = ?", account.ID, articleId).First(&articleSlot).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusInternalServerError, err)
} else {
ErrResponse(w, http.StatusNotFound, err)
}
return
}
if articleSlot.Article == nil {
ErrResponse(w, http.StatusNotFound, errors.New("referenced empty article slot"))
return
}
err = store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Model(articleSlot.Article).Association("Labels").Append(labelSlot.Label); res != nil {
return res
}
if res := tx.Model(articleSlot).Update("revision", account.ContentRevision + 1).Error; res != nil {
return res
}
if res := tx.Model(account).Update("content_revision", account.ContentRevision + 1).Error; res != nil {
return res
}
return nil
})
if err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
SetContentNotification(account)
SetStatus(account)
WriteResponse(w, getArticleModel(articleSlot, false, true))
}

View File

@ -6,7 +6,7 @@ import (
"databag/internal/store"
)
func SetContentRevision(w http.ResponseWriter, r *http.Request) {
func SetArticleRevision(w http.ResponseWriter, r *http.Request) {
card, code, err := BearerContactToken(r, false)
if err != nil {
@ -20,7 +20,7 @@ func SetContentRevision(w http.ResponseWriter, r *http.Request) {
return
}
if err := NotifyProfileRevision(card, revision); err != nil {
if err := NotifyArticleRevision(card, revision); err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
@ -28,17 +28,17 @@ func SetContentRevision(w http.ResponseWriter, r *http.Request) {
WriteResponse(w, nil)
}
func NotifyContentRevision(card *store.Card, revision int64) error {
func NotifyArticleRevision(card *store.Card, revision int64) error {
act := &card.Account
err := store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Model(card).Where("id = ?", card.ID).Update("notified_content", revision).Error; res != nil {
if res := tx.Model(card).Where("id = ?", card.ID).Update("notified_profile", revision).Error; res != nil {
return res
}
if res := tx.Model(&card.CardSlot).Where("id = ?", card.CardSlot.ID).Update("revision", act.CardRevision+1).Error; res != nil {
return res
}
if res := tx.Model(act).Where("id = ?", act.ID).Update("card_revision", act.CardRevision + 1).Error; res != nil {
if res := tx.Model(act).Where("id = ?", act.ID).Update("card_revision", act.CardRevision+1).Error; res != nil {
return res
}
return nil

View File

@ -1,70 +0,0 @@
package databag
import (
"errors"
"net/http"
"gorm.io/gorm"
"github.com/gorilla/mux"
"databag/internal/store"
)
func SetCardNotes(w http.ResponseWriter, r *http.Request) {
account, code, err := BearerAppToken(r, false);
if err != nil {
ErrResponse(w, code, err)
return
}
// scan parameters
params := mux.Vars(r)
cardId := params["cardId"]
var notes string
if err := ParseRequest(r, w, &notes); err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
// load referenced card
var slot store.CardSlot
if err := store.DB.Preload("Card").Where("account_id = ? AND card_slot_id = ?", account.ID, cardId).First(&slot).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusInternalServerError, err)
} else {
ErrResponse(w, http.StatusNotFound, err)
}
return
}
if slot.Card == nil {
ErrResponse(w, http.StatusNotFound, errors.New("card has been deleted"))
return
}
// update card
slot.Revision = account.CardRevision + 1
slot.Card.DetailRevision += 1
slot.Card.Notes = notes
// save and update contact revision
err = store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Save(&slot.Card).Error; res != nil {
return res
}
if res := tx.Preload("Card").Save(&slot).Error; res != nil {
return res
}
if res := tx.Model(&account).Update("card_revision", account.CardRevision + 1).Error; res != nil {
return res
}
return nil
})
if err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
SetStatus(account)
WriteResponse(w, getCardDetailModel(&slot));
}

View File

@ -1,92 +0,0 @@
package databag
import (
"errors"
"net/http"
"gorm.io/gorm"
"github.com/gorilla/mux"
"databag/internal/store"
)
func SetCardProfile(w http.ResponseWriter, r *http.Request) {
var msg DataMessage
account, code, err := BearerAppToken(r, false);
if err != nil {
ErrResponse(w, code, err)
return
}
// scan parameters
params := mux.Vars(r)
cardId := params["cardId"]
if err := ParseRequest(r, w, &msg); err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
// load referenced card
var slot store.CardSlot
if err := store.DB.Preload("Card.Groups").Where("account_id = ? AND card_slot_id = ?", account.ID, cardId).First(&slot).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusInternalServerError, err)
} else {
ErrResponse(w, http.StatusNotFound, err)
}
return
}
if slot.Card == nil {
ErrResponse(w, http.StatusNotFound, errors.New("referenced slot is empty"))
return
}
var identity Identity
guid, messageType, _, err := ReadDataMessage(&msg, &identity)
if messageType != APP_MSGIDENTITY || err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
if slot.Card.Guid != guid {
ErrResponse(w, http.StatusBadRequest, errors.New("slot does not contain specified contact"))
return
}
if slot.Card.ProfileRevision >= identity.Revision {
WriteResponse(w, getCardModel(&slot))
return
}
// update card
slot.Card.ProfileRevision = identity.Revision
slot.Card.Username = identity.Handle
slot.Card.Name = identity.Name
slot.Card.Description = identity.Description
slot.Card.Location = identity.Location
slot.Card.Image = identity.Image
slot.Card.Version = identity.Version
slot.Card.Node = identity.Node
slot.Revision = account.CardRevision + 1
// save and update contact revision
err = store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Save(&slot.Card).Error; res != nil {
return res
}
if res := tx.Preload("Card").Save(&slot).Error; res != nil {
return res
}
if res := tx.Model(&account).Update("card_revision", account.CardRevision + 1).Error; res != nil {
return res
}
return nil
})
if err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
SetStatus(account)
WriteResponse(w, getCardProfileModel(&slot));
}

View File

@ -34,18 +34,18 @@ func SetCardStatus(w http.ResponseWriter, r *http.Request) {
return
}
}
var contentRevision int64
content := r.FormValue("contentRevision")
if content != "" {
if contentRevision, res = strconv.ParseInt(content, 10, 64); res != nil {
var articleRevision int64
article := r.FormValue("articleRevision")
if article != "" {
if articleRevision, res = strconv.ParseInt(article, 10, 64); res != nil {
ErrResponse(w, http.StatusBadRequest, res)
return
}
}
var labelRevision int64
label := r.FormValue("labelRevision")
if label != "" {
if labelRevision, res = strconv.ParseInt(label, 10, 64); res != nil {
var channelRevision int64
channel := r.FormValue("channelRevision")
if channel != "" {
if channelRevision, res = strconv.ParseInt(channel, 10, 64); res != nil {
ErrResponse(w, http.StatusBadRequest, res)
return
}
@ -105,8 +105,8 @@ func SetCardStatus(w http.ResponseWriter, r *http.Request) {
}
slot.Card.Status = status
slot.Card.NotifiedView = viewRevision
slot.Card.NotifiedContent = contentRevision
slot.Card.NotifiedLabel = labelRevision
slot.Card.NotifiedArticle = articleRevision
slot.Card.NotifiedChannel = channelRevision
slot.Card.NotifiedProfile = profileRevision
// save and update contact revision

View File

@ -6,7 +6,7 @@ import (
"databag/internal/store"
)
func SetLabelRevision(w http.ResponseWriter, r *http.Request) {
func SetChannelRevision(w http.ResponseWriter, r *http.Request) {
card, code, err := BearerContactToken(r, false)
if err != nil {
@ -20,7 +20,7 @@ func SetLabelRevision(w http.ResponseWriter, r *http.Request) {
return
}
if err := NotifyProfileRevision(card, revision); err != nil {
if err := NotifyChannelRevision(card, revision); err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
@ -28,17 +28,17 @@ func SetLabelRevision(w http.ResponseWriter, r *http.Request) {
WriteResponse(w, nil)
}
func NotifyLabelRevision(card *store.Card, revision int64) error {
func NotifyChannelRevision(card *store.Card, revision int64) error {
act := &card.Account
err := store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Model(card).Where("id = ?", card.ID).Update("notified_label", revision).Error; res != nil {
if res := tx.Model(card).Where("id = ?", card.ID).Update("notified_profile", revision).Error; res != nil {
return res
}
if res := tx.Model(&card.CardSlot).Where("id = ?", card.CardSlot.ID).Update("revision", act.CardRevision+1).Error; res != nil {
return res
}
if res := tx.Model(act).Where("id = ?", act.ID).Update("card_revision", act.CardRevision + 1).Error; res != nil {
if res := tx.Model(act).Where("id = ?", act.ID).Update("card_revision", act.CardRevision+1).Error; res != nil {
return res
}
return nil

View File

@ -1,89 +0,0 @@
package databag
import (
"errors"
"net/http"
"gorm.io/gorm"
"github.com/gorilla/mux"
"databag/internal/store"
)
func SetLabelGroup(w http.ResponseWriter, r *http.Request) {
account, code, err := BearerAppToken(r, false);
if err != nil {
ErrResponse(w, code, err)
return
}
// scan parameters
params := mux.Vars(r)
groupId := params["groupId"]
labelId := params["labelId"]
labelSlot := &store.LabelSlot{}
if err := store.DB.Preload("Label").Where("account_id = ? AND label_slot_id = ?", account.ID, labelId).First(&labelSlot).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusInternalServerError, err)
} else {
ErrResponse(w, http.StatusNotFound, err)
}
return
}
if labelSlot.Label == nil {
ErrResponse(w, http.StatusNotFound, errors.New("referenced empty label slot"))
return
}
groupSlot := &store.GroupSlot{}
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 {
ErrResponse(w, http.StatusNotFound, err)
}
return
}
if groupSlot.Group == nil {
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
}
if res := tx.Model(labelSlot).Update("revision", account.LabelRevision + 1).Error; res != nil {
return res
}
if res := tx.Model(account).Update("label_revision", 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)
SetContactLabelNotification(account, card)
}
SetStatus(account)
WriteResponse(w, getLabelModel(labelSlot, true, true))
}

View File

@ -7,7 +7,7 @@ import (
"databag/internal/store"
)
func SetNodeClaim(w http.ResponseWriter, r *http.Request) {
func SetNodeStatus(w http.ResponseWriter, r *http.Request) {
var config store.Config
err := store.DB.Where("config_id = ?", CONFIG_CONFIGURED).First(&config).Error

View File

@ -67,9 +67,9 @@ func SetOpenMessage(w http.ResponseWriter, r *http.Request) {
card.ProfileRevision = connect.ProfileRevision
card.Status = APP_CARDPENDING
card.NotifiedProfile = connect.ProfileRevision
card.NotifiedContent = connect.ContentRevision
card.NotifiedArticle = connect.ArticleRevision
card.NotifiedView = connect.ViewRevision
card.NotifiedLabel = connect.LabelRevision
card.NotifiedChannel = connect.ChannelRevision
card.OutToken = connect.Token
card.InToken = hex.EncodeToString(data)
card.AccountID = account.Guid
@ -135,14 +135,14 @@ func SetOpenMessage(w http.ResponseWriter, r *http.Request) {
card.Node = connect.Node
card.ProfileRevision = connect.ProfileRevision
}
if connect.ContentRevision > card.NotifiedContent {
card.NotifiedContent = connect.ContentRevision
if connect.ArticleRevision > card.NotifiedArticle {
card.NotifiedArticle = connect.ArticleRevision
}
if connect.ViewRevision > card.NotifiedView {
card.NotifiedView = connect.ViewRevision
}
if connect.LabelRevision > card.NotifiedLabel {
card.NotifiedLabel = connect.LabelRevision
if connect.ChannelRevision > card.NotifiedChannel {
card.NotifiedChannel = connect.ChannelRevision
}
if connect.ProfileRevision > card.NotifiedProfile {
card.NotifiedProfile = connect.ProfileRevision
@ -192,14 +192,10 @@ func SetOpenMessage(w http.ResponseWriter, r *http.Request) {
Token: slot.Card.InToken,
Status: slot.Card.Status,
ViewRevision: slot.Card.ViewRevision,
LabelRevision: account.LabelRevision,
ChannelRevision: account.ChannelRevision,
ProfileRevision: account.ProfileRevision,
ContentRevision: account.ContentRevision,
ArticleRevision: account.ArticleRevision,
}
//SetContactProfileNotification(&account, slot.Card)
//SetContactContentNotification(&account, slot.Card)
//SetContactViewNotification(&account, slot.Card)
//SetContactLabelNotification(&account, slot.Card)
SetStatus(&account)
WriteResponse(w, &status)
}

View File

@ -1,49 +0,0 @@
package databag
import (
"net/http"
"gorm.io/gorm"
"databag/internal/store"
)
func SetProfile(w http.ResponseWriter, r *http.Request) {
account, code, err := BearerAppToken(r, true);
if err != nil {
ErrResponse(w, code, err)
return
}
detail := account.AccountDetail
// extract profile data from body
var profileData ProfileData;
err = ParseRequest(r, w, &profileData)
if err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
// update record
detail.Name = profileData.Name
detail.Location = profileData.Location
detail.Description = profileData.Description
err = store.DB.Transaction(func(tx *gorm.DB) error {
if res := store.DB.Save(&detail).Error; res != nil {
return res
}
if res := store.DB.Model(&account).Update("profile_revision", account.ProfileRevision + 1).Error; res != nil {
return res
}
return nil
})
if err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
SetProfileNotification(account)
SetStatus(account)
WriteResponse(w, nil)
}

View File

@ -20,7 +20,7 @@ func SetViewRevision(w http.ResponseWriter, r *http.Request) {
return
}
if err := NotifyProfileRevision(card, revision); err != nil {
if err := NotifyViewRevision(card, revision); err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
@ -32,13 +32,13 @@ func NotifyViewRevision(card *store.Card, revision int64) error {
act := &card.Account
err := store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Model(card).Where("id = ?", card.ID).Update("notified_view", revision).Error; res != nil {
if res := tx.Model(card).Where("id = ?", card.ID).Update("notified_profile", revision).Error; res != nil {
return res
}
if res := tx.Model(&card.CardSlot).Where("id = ?", card.CardSlot.ID).Update("revision", act.CardRevision+1).Error; res != nil {
return res
}
if res := tx.Model(act).Where("id = ?", act.ID).Update("card_revision", act.CardRevision + 1).Error; res != nil {
if res := tx.Model(act).Where("id = ?", act.ID).Update("card_revision", act.CardRevision+1).Error; res != nil {
return res
}
return nil

View File

@ -95,12 +95,10 @@ func Status(w http.ResponseWriter, r *http.Request) {
func getRevision(account *store.Account) Revision {
var r Revision
r.Profile = account.ProfileRevision
r.Content = account.ContentRevision
r.Label = account.LabelRevision
r.Article = account.ArticleRevision
r.Channel = account.ChannelRevision
r.Group = account.GroupRevision
r.Card = account.CardRevision
r.Dialogue = account.DialogueRevision
r.Insight = account.InsightRevision
return r
}

View File

@ -1,70 +0,0 @@
package databag
import (
"errors"
"net/http"
"gorm.io/gorm"
"github.com/gorilla/mux"
"databag/internal/store"
)
func UpdateGroup(w http.ResponseWriter, r *http.Request) {
account, code, err := BearerAppToken(r, false)
if err != nil {
ErrResponse(w, code, err)
return
}
params := mux.Vars(r)
groupId := params["groupId"]
var subject Subject
if err := ParseRequest(r, w, &subject); err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
// load specified group
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 !errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusInternalServerError, err)
} else {
ErrResponse(w, http.StatusNotFound, err)
}
return
}
if slot.Group == nil {
ErrResponse(w, http.StatusNotFound, errors.New("referenced deleted group"))
return
}
// update specified group
slot.Revision = account.GroupRevision + 1
slot.Group.DataType = subject.DataType
slot.Group.GroupData.Data = subject.Data
err = store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Save(&slot.Group.GroupData).Error; res != nil {
return res
}
if res := tx.Save(&slot.Group).Error; res != nil {
return res
}
if res := tx.Save(&slot).Error; res != nil {
return res
}
if res := tx.Model(&account).Update("group_revision", account.GroupRevision + 1).Error; res != nil {
return res
}
return nil
})
if err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
SetStatus(account)
WriteResponse(w, getGroupModel(&slot))
}

View File

@ -21,8 +21,8 @@ const APP_CARDREQUESTED = "requested"
const APP_CARDCONNECTING = "connecting"
const APP_CARDCONNECTED = "connected"
const APP_NOTIFYPROFILE = "profile"
const APP_NOTIFYCONTENT = "content"
const APP_NOTIFYLABEL = "label"
const APP_NOTIFYARTICLE = "article"
const APP_NOTIFYCHANNEL = "channel"
const APP_NOTIFYVIEW = "view"
const APP_TOKENAPP = "app"
const APP_TOKENCONTACT = "contact"

View File

@ -13,17 +13,17 @@ func TestMain(m *testing.M) {
os.Remove("databag.db")
store.SetPath("databag.db")
r, w, _ := NewRequest("GET", "/admin/claimable", nil)
GetNodeClaimable(w, r)
r, w, _ := NewRequest("GET", "/admin/status", nil)
GetNodeStatus(w, r)
var available bool
if ReadResponse(w, &available) != nil {
panic("server not claimable")
}
// claim server
r, w, _ = NewRequest("PUT", "/admin/claim", nil)
r, w, _ = NewRequest("PUT", "/admin/status", nil)
SetCredentials(r, "admin:pass");
SetNodeClaim(w, r)
SetNodeStatus(w, r)
if ReadResponse(w, nil) != nil {
panic("failed to claim server")
}

View File

@ -8,24 +8,46 @@ func getCardModel(slot *store.CardSlot) *Card {
if slot.Card == nil {
return &Card{
CardId: slot.CardSlotId,
Id: slot.CardSlotId,
Revision: slot.Revision,
}
}
return &Card{
CardId: slot.CardSlotId,
Id: slot.CardSlotId,
Revision: slot.Revision,
CardData: &CardData {
Data: &CardData {
NotifiedProfile: slot.Card.NotifiedProfile,
NotifiedContent: slot.Card.NotifiedContent,
NotifiedLabel: slot.Card.NotifiedLabel,
NotifiedArticle: slot.Card.NotifiedArticle,
NotifiedChannel: slot.Card.NotifiedChannel,
NotifiedView: slot.Card.NotifiedView,
ProfileRevision: slot.Card.ProfileRevision,
DetailRevision: slot.Card.DetailRevision,
CardDetail: getCardDetailModel(slot),
CardProfile: getCardProfileModel(slot),
},
}
}
func getCardRevisionModel(slot *store.CardSlot) *Card {
if slot.Card == nil {
return &Card{
Id: slot.CardSlotId,
Revision: slot.Revision,
}
}
return &Card{
Id: slot.CardSlotId,
Revision: slot.Revision,
Data: &CardData {
NotifiedProfile: slot.Card.NotifiedProfile,
NotifiedArticle: slot.Card.NotifiedArticle,
NotifiedChannel: slot.Card.NotifiedChannel,
NotifiedView: slot.Card.NotifiedView,
ProfileRevision: slot.Card.ProfileRevision,
DetailRevision: slot.Card.DetailRevision,
Guid: slot.Card.Guid,
Status: slot.Card.Status,
Token: slot.Card.OutToken,
},
}
}
@ -38,7 +60,8 @@ func getCardDetailModel(slot *store.CardSlot) *CardDetail {
}
return &CardDetail{
Revision: slot.Card.DetailRevision,
Status: slot.Card.Status,
Token: slot.Card.OutToken,
Notes: slot.Card.Notes,
Groups: groups,
}
@ -47,7 +70,7 @@ func getCardDetailModel(slot *store.CardSlot) *CardDetail {
func getCardProfileModel(slot *store.CardSlot) *CardProfile {
return &CardProfile{
Revision: slot.Card.ProfileRevision,
Guid: slot.Card.Guid,
Handle: slot.Card.Username,
Name: slot.Card.Name,
Description: slot.Card.Description,
@ -61,15 +84,15 @@ func getCardProfileModel(slot *store.CardSlot) *CardProfile {
func getGroupModel(slot *store.GroupSlot) *Group {
if slot.Group == nil {
return &Group{
GroupId: slot.GroupSlotId,
Id: slot.GroupSlotId,
Revision: slot.Revision,
}
}
return &Group{
GroupId: slot.GroupSlotId,
Id: slot.GroupSlotId,
Revision: slot.Revision,
GroupData: &GroupData {
Data: &GroupData {
DataType: slot.Group.DataType,
Data: slot.Group.GroupData.Data,
Created: slot.Group.Created,
@ -78,72 +101,4 @@ func getGroupModel(slot *store.GroupSlot) *Group {
}
}
func getLabelModel(slot *store.LabelSlot, includeData bool, includeGroups bool) *Label {
if !includeData || slot.Label == nil {
return &Label{
LabelId: slot.LabelSlotId,
Revision: slot.Revision,
}
}
var groups *[]string
if includeGroups {
groups = &[]string{}
for _, group := range slot.Label.Groups {
*groups = append(*groups, group.GroupSlot.GroupSlotId)
}
}
return &Label{
LabelId: slot.LabelSlotId,
Revision: slot.Revision,
LabelData: &LabelData{
DataType: slot.Label.DataType,
Data: slot.Label.LabelData.Data,
Created: slot.Label.Created,
Updated: slot.Label.Updated,
Groups: groups,
},
}
}
func getArticleModel(slot *store.ArticleSlot, contact bool, shared bool) *Article {
if !shared || slot.Article == nil {
return &Article{
ArticleId: slot.ArticleSlotId,
Revision: slot.Revision,
}
}
var groups []string
if !contact {
for _, group := range slot.Article.Groups {
groups = append(groups, group.GroupSlot.GroupSlotId)
}
}
var labels []string
for _, label := range slot.Article.Labels {
labels = append(labels, label.LabelSlot.LabelSlotId)
}
return &Article{
ArticleId: slot.ArticleSlotId,
Revision: slot.Revision,
ArticleData: &ArticleData{
DataType: slot.Article.DataType,
Data: slot.Article.Data,
Status: slot.Article.Status,
Labels: labels,
Groups: groups,
TagCount: slot.Article.TagCount,
Created: slot.Article.Created,
Updated: slot.Article.Updated,
TagUpdated: slot.Article.TagUpdated,
TagRevision: slot.Article.TagRevision,
},
}
}

View File

@ -1,319 +1,440 @@
package databag
import (
"os"
//"os"
)
type Account struct {
AccountId string `json:"accountId"`
Profile *Profile `json:"profile"`
Disabled bool `json:"disabled"`
}
type AccountStatus struct {
Disabled bool `json:"disabled"`
StorageUsed float64 `json:"storageUsed"`
StorageAvailable float64 `json:"storageAvailable"`
ForwardingAddress string `json:"forwardingAddress"`
}
type AccountsImportBody struct {
FileName **os.File `json:"fileName,omitempty"`
}
type Announce struct {
AppToken string `json:"appToken"`
}
type App struct {
AppId string `json:"appId"`
AppData *AppData `json:"appData"`
Attached int64 `json:"attached"`
Id string `json:"id"`
Revision int64 `json:"revision"`
Data *AppData `json:"data"`
}
type AppData struct {
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Url string `json:"url,omitempty"`
Image string `json:"image,omitempty"`
}
type Subject struct {
DataType string `json:"dataType"`
Data string `json:"data"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Url string `json:"url,omitempty"`
Image string `json:"image,omitempty"`
Attached int64 `json:"attached"`
}
type Article struct {
ArticleId string `json:"article_id"`
Id string `json:"id"`
Revision int64 `json:"revision"`
ArticleData *ArticleData `json:"articleData"`
Data *ArticleData `json:"data"`
}
type ArticleData struct {
DataType string `json:"type"`
DataType string `json:"dataType"`
Data string `json:"data"`
Created int64 `json:"created"`
Updated int64 `json:"updated"`
Status string `json:"status"`
Labels []string `json:"labels"`
Groups []string `json:"groups,omitempty"`
TagCount int32 `json:"tagCount"`
TagUpdated int64 `json:"tagUpdated,omitempty"`
TagRevision int64 `json:"tagRevision"`
Groups *ArticleGroups `json:"groups,omitempty"`
}
type ArticleAccess struct {
Labels []string `json:"labels"`
type ArticleGroups struct {
Groups []string `json:"groups"`
}
type ArticleIdAssetsBody struct {
FileName **os.File `json:"fileName,omitempty"`
}
type ArticleIdSubjectBody struct {
Type_ string `json:"type"`
Data string `json:"data"`
}
type Asset struct {
AssetId string `json:"assetId"`
Transform string `json:"transform,omitempty"`
Status string `json:"status,omitempty"`
}
type Card struct {
CardId string `json:"cardId"`
Revision int64 `json:"revision,omitempty"`
CardData *CardData `json:"articleData"`
Id string `json:"id"`
Revision int64 `json:"revision"`
Data *CardData `json:"data"`
}
type CardData struct {
Guid string `json:"guid"`
Status string `json:"status"`
Token string `json:"token,omitempty"`
DetailRevision int64 `json:"detailRevision"`
ProfileRevision int64 `json:"profileRevision"`
NotifiedProfile int64 `json:"notifiedProfile"`
NotifiedContent int64 `json:"notifiedContent"`
NotifiedLabel int64 `json:"notifiedLabel"`
NotifiedArticle int64 `json:"notifiedArticle"`
NotifiedChannel int64 `json:"notifiedChannel"`
NotifiedView int64 `json:"notifiedView"`
CardDetail *CardDetail `json:"cardDetail,omitempty"`
CardProfile *CardProfile `json:"cardProfile,omitempty"`
}
type CardDetail struct {
Revision int64 `json:"revision,omitempty"`
Status string `json:"status"`
Token string `json:"token,omitempty"`
Notes string `json:"notes,omitempty"`
Groups []string `json:"groups,omitempty"`
}
type CardProfile struct {
Revision int64 `json:"revision,omitempty"`
Guid string `json:"guid"`
Handle string `json:"handle,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Location string `json:"location,omitempty"`
ImageSet bool `json:"imageSet,omitempty"`
Version string `json:"version"`
Version string `json:"version,omitempty"`
Node string `json:"node"`
}
type Dialogue struct {
DialogueId string `json:"dialogueId"`
DialogueRevison int64 `json:"dialogueRevison,omitempty"`
Type_ string `json:"type"`
Data string `json:"data"`
Created int64 `json:"created"`
Active bool `json:"active"`
InsightRevision int64 `json:"insightRevision,omitempty"`
Insights []DialogueInsights `json:"insights"`
type Channel struct {
Id string `json:"id"`
Revision string `json:"revision"`
Data *ChannelData `json:"data"`
}
type DialogueIdSubjectBody struct {
Type_ string `json:"type"`
Data string `json:"data"`
type ChannelData struct {
DetailRevision int64 `json:"detailRevision"`
TopicRevision int64 `json:"topicRevision"`
ChannelDetail *ChannelDetail `json:"channelDetail,omitempty"`
ChannelTopics *ChannelSize `json:"channelTopics,omitempty"`
}
type DialogueInsights struct {
CardId string `json:"cardId,omitempty"`
Status string `json:"status,omitempty"`
}
type ChannelDetail struct {
type Group struct {
GroupId string `json:"groupId"`
Revision int64 `json:"revision"`
GroupData *GroupData `json:"groupData"`
}
type GroupData struct {
DataType string `json:"dataType"`
Data string `json:"data"`
Created int64 `json:"created"`
Updated int64 `json:"updated"`
Viewers []string `json:"viewers,omitempty"`
ViewerGroups *ChannelGroups `json:"viewerGroups,omitempty"`
Members []string `json:"members,omitempty"`
MemberGroups *ChannelGroups `json:"memberGroups,omitempty"`
}
type GroupsGroupIdBody struct {
Type_ string `json:"type"`
Data string `json:"data"`
type ChannelGroups struct {
Groups []string `json:"groups"`
}
type Insight struct {
InsightId string `json:"insightId"`
InsightRevision int64 `json:"insightRevision"`
CardId string `json:"cardId"`
type ChannelSize struct {
TopicCount int32 `json:"topicCount"`
TopicUpdated int64 `json:"topicUpdated"`
}
type Claim struct {
Token string `json:"token"`
}
type Connect struct {
Contact string `json:"contact"`
Token string `json:"token"`
ViewRevision int64 `json:"viewRevision,omitempty"`
ArticleRevision int64 `json:"articleRevision,omitempty"`
ProfileRevision int64 `json:"profileRevision,omitempty"`
ChannelRevision int64 `json:"channelRevision,omitempty"`
Handle string `json:"handle,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Location string `json:"location,omitempty"`
Image string `json:"image,omitempty"`
Version string `json:"version,omitempty"`
Node string `json:"node,omitempty"`
}
type ContactStatus struct {
Token string `json:"token,omitempty"`
ProfileRevision int64 `json:"profileRevision,omitempty"`
ArticleRevision int64 `json:"articleRevision,omitempty"`
ChannelRevision int64 `json:"channelRevision,omitempty"`
ViewRevision int64 `json:"viewRevision,omitempty"`
Status string `json:"status"`
}
type Label struct {
LabelId string `json:"labelId"`
Revision int64 `json:"revision"`
LabelData *LabelData `json:"labelData"`
type DataMessage struct {
Message string `json:"message"`
KeyType string `json:"keyType"`
PublicKey string `json:"publicKey"`
Signature string `json:"signature"`
SignatureType string `json:"signatureType"`
}
type LabelData struct {
DataType string `json:"type"`
type Disconnect struct {
Contact string `json:"contact"`
}
type Group struct {
Id string `json:"id"`
Revision int64 `json:"revision"`
Data *GroupData `json:"data,omitempty"`
}
type GroupData struct {
DataType string `json:"dataType"`
Data string `json:"data"`
Created int64 `json:"created"`
Updated int64 `json:"updated"`
Groups *[]string `json:"groups,omitempty"`
}
type Identity struct {
Revision int64 `json:"revision"`
Handle string `json:"handle,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Location string `json:"location,omitempty"`
Image string `json:"image,omitempty"`
Version string `json:"version"`
Node string `json:"node"`
}
type NodeConfig struct {
Domain string `json:"domain"`
PublicLimit int64 `json:"publicLimit"`
AccountStorage int64 `json:"accountStorage"`
}
type Profile struct {
Guid string `json:"profileId"`
Guid string `json:"guid"`
Handle string `json:"handle,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Location string `json:"location,omitempty"`
Image string `json:"image,omitempty"`
Revision int64 `json:"revision"`
Version string `json:"version,omitempty"`
Node string `json:"node"`
}
type ProfileData struct {
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Location string `json:"location,omitempty"`
}
type Revision struct {
Profile int64 `json:"profile"`
Content int64 `json:"content"`
Label int64 `json:"label"`
Group int64 `json:"share"`
Article int64 `json:"article"`
Group int64 `json:"group"`
Channel int64 `json:"channel"`
Card int64 `json:"card"`
Dialogue int64 `json:"dialogue"`
Insight int64 `json:"insight"`
}
type ShareGroupsBody struct {
Type_ string `json:"type"`
type SignedData struct {
Guid string `json:"guid"`
Timestamp int64 `json:"timestamp"`
MessageType string `json:"messageType"`
Value string `json:"value"`
}
type Subject struct {
DataType string `json:"dataType"`
Data string `json:"data"`
}
type Tag struct {
TagId string `json:"tagId"`
CardId string `json:"cardId,omitempty"`
Revision int64 `json:"revision"`
Type_ string `json:"type"`
Id string `json:"id"`
Revision string `json:"revision"`
Data *TagData `json:"data"`
}
type TagData struct {
Guid string `json:"guid"`
DataType string `json:"dataType"`
Data string `json:"data"`
Created int64 `json:"created"`
Updated int64 `json:"updated"`
}
type Topic struct {
TopicId string `json:"topicId"`
TopicRevision int64 `json:"topicRevision"`
Type_ string `json:"type"`
Data string `json:"data"`
Created int64 `json:"created"`
Modified int64 `json:"modified"`
Status string `json:"status"`
TagCount int32 `json:"tagCount"`
TagUpdate int64 `json:"tagUpdate,omitempty"`
Id string `json:"id"`
Revision string `json:"revision"`
Data *TopicData `json:"data"`
}
type TopicData struct {
DetailRevision int64 `json:"detailRevision"`
TagRevision int64 `json:"tagRevision"`
TopicDetail *TopicDetail `json:"topicDetail,omitempty"`
TopicTags *TopicSize `json:"topicTags:,omitempty"`
}
type TopicIdAssetsBody struct {
FileName **os.File `json:"fileName,omitempty"`
}
type TopicDetail struct {
type TopicIdSubjectBody struct {
Type_ string `json:"type"`
Data string `json:"data"`
}
type TopicIdTagsBody struct {
Type_ string `json:"type"`
Data string `json:"data"`
}
type Tunnel struct {
CardId string `json:"cardId"`
Type_ string `json:"type"`
Data string `json:"data,omitempty"`
}
type ContactStatus struct {
Token string `json:"token,omitempty"`
Status string `json:"status"`
ViewRevision int64 `json:"viewRevision"`
LabelRevision int64 `json:"labelRevision"`
ContentRevision int64 `json:"contentRevision"`
ProfileRevision int64 `json:"profileRevision,omitempty"`
}
type DataMessage struct {
Message string `json:"message"`
KeyType string `json:"keyType"`
PublicKey string `json:"publicKey"`
Signature string `json:"signature"`
SignatureType string `json:"signatureType"`
}
type SignedData struct {
Guid string `json:"guid"`
Timestamp int64 `json:"timestamp"`
MessageType string `json:"messageType"`
Value string `json:"value"`
DataType string `json:"dataType"`
Data string `json:"data"`
Created int64 `json:"created"`
Modified int64 `json:"modified"`
Status string `json:"status"`
}
type Identity struct {
Revision int64 `json:"revision"`
Handle string `json:"handle,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Location string `json:"location,omitempty"`
Image string `json:"image,omitempty"`
Version string `json:"version"`
Node string `json:"node"`
}
type Connect struct {
Contact string `json:"contact"`
Token string `json:"token"`
ViewRevision int64 `json:"viewRevision"`
LabelRevision int64 `json:"labelRevision"`
ContentRevision int64 `json:"contentRevision"`
ProfileRevision int64 `json:"profileRevision,omitempty"`
Handle string `json:"handle,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Location string `json:"location,omitempty"`
Image string `json:"image,omitempty"`
Version string `json:"version,omitempty"`
Node string `json:"node,omitempty"`
}
type Disconnect struct {
Contact string `json:"contact"`
}
type Authenticate struct {
Token string `json:"token"`
type TopicSize struct {
TagCount int32 `json:"tagCount"`
TagUpdated int64 `json:"tagUpdated"`
}

View File

@ -60,12 +60,12 @@ func SendLocalNotification(notification *store.Notification) {
if err := NotifyProfileRevision(&card, notification.Revision); err != nil {
ErrMsg(err)
}
} else if notification.Module == APP_NOTIFYCONTENT {
if err := NotifyContentRevision(&card, notification.Revision); err != nil {
} else if notification.Module == APP_NOTIFYARTICLE {
if err := NotifyArticleRevision(&card, notification.Revision); err != nil {
ErrMsg(err)
}
} else if notification.Module == APP_NOTIFYLABEL {
if err := NotifyLabelRevision(&card, notification.Revision); err != nil {
} else if notification.Module == APP_NOTIFYCHANNEL {
if err := NotifyChannelRevision(&card, notification.Revision); err != nil {
ErrMsg(err)
}
} else if notification.Module == APP_NOTIFYVIEW {
@ -151,9 +151,9 @@ func SetContentNotification(account *store.Account) {
for _, card := range cards {
notification := &store.Notification{
Node: card.Node,
Module: APP_NOTIFYCONTENT,
Module: APP_NOTIFYARTICLE,
Token: card.OutToken,
Revision: account.ContentRevision,
Revision: account.ArticleRevision,
}
if err := tx.Save(notification).Error; err != nil {
return err
@ -178,9 +178,9 @@ func SetContactContentNotification(account *store.Account, card *store.Card) {
// add new notification for card
notification := &store.Notification{
Node: card.Node,
Module: APP_NOTIFYCONTENT,
Module: APP_NOTIFYARTICLE,
Token: card.OutToken,
Revision: account.ContentRevision,
Revision: account.ArticleRevision,
}
if res := store.DB.Save(notification).Error; res != nil {
@ -263,9 +263,9 @@ func SetLabelNotification(account *store.Account) {
for _, card := range cards {
notification := &store.Notification{
Node: card.Node,
Module: APP_NOTIFYLABEL,
Module: APP_NOTIFYCHANNEL,
Token: card.OutToken,
Revision: account.LabelRevision,
Revision: account.ChannelRevision,
}
if err := tx.Save(notification).Error; err != nil {
return err
@ -290,9 +290,9 @@ func SetContactLabelNotification(account *store.Account, card *store.Card) {
// add new notification for card
notification := &store.Notification{
Node: card.Node,
Module: APP_NOTIFYLABEL,
Module: APP_NOTIFYCHANNEL,
Token: card.OutToken,
Revision: account.LabelRevision,
Revision: account.ChannelRevision,
}
if res := store.DB.Save(notification).Error; res != nil {

View File

@ -141,15 +141,15 @@ var routes = Routes{
Route{
"GetAccountUsername",
strings.ToUpper("Get"),
"/account/claimable",
"/account/available",
GetAccountUsername,
},
Route{
"GetPublicClaimable",
"GetPublicStatus",
strings.ToUpper("Get"),
"/account/public/claimable",
GetPublicClaimable,
"/account/public/status",
GetPublicStatus,
},
Route{
@ -215,13 +215,6 @@ var routes = Routes{
GetNodeAccounts,
},
Route{
"GetNodeClaimable",
strings.ToUpper("Get"),
"/admin/claimable",
GetNodeClaimable,
},
Route{
"GetNodeConfig",
strings.ToUpper("Get"),
@ -229,6 +222,13 @@ var routes = Routes{
GetNodeConfig,
},
Route{
"GetNodeStatus",
strings.ToUpper("Get"),
"/admin/status",
GetNodeStatus,
},
Route{
"ImportAccount",
strings.ToUpper("Post"),
@ -250,13 +250,6 @@ var routes = Routes{
SetNodeAccount,
},
Route{
"SetNodeClaim",
strings.ToUpper("Post"),
"/admin/claim",
SetNodeClaim,
},
Route{
"SetNodeConfig",
strings.ToUpper("Put"),
@ -264,6 +257,90 @@ var routes = Routes{
SetNodeConfig,
},
Route{
"SetNodeStatus",
strings.ToUpper("Put"),
"/admin/status",
SetNodeStatus,
},
Route{
"AddGroup",
strings.ToUpper("Post"),
"/alias/groups",
AddGroup,
},
Route{
"GetGroups",
strings.ToUpper("Get"),
"/alias/groups",
GetGroups,
},
Route{
"RemoveGroup",
strings.ToUpper("Delete"),
"/alias/groups/{groupId}",
RemoveGroup,
},
Route{
"UpdateGroup",
strings.ToUpper("Put"),
"/alias/groups/{groupId}",
UpdateGroup,
},
Route{
"AddArticle",
strings.ToUpper("Post"),
"/attribute/articles",
AddArticle,
},
Route{
"ClearArticleGroup",
strings.ToUpper("Delete"),
"/attribute/articles/{articleId}/groups/{groupId}",
ClearArticleGroup,
},
Route{
"GetArticleSubjectField",
strings.ToUpper("Get"),
"/attribute/articles/{articleId}/subject/{field}",
GetArticleSubjectField,
},
Route{
"GetArticles",
strings.ToUpper("Get"),
"/attribute/articles",
GetArticles,
},
Route{
"RemoveArticle",
strings.ToUpper("Delete"),
"/attribute/articles/{articleId}",
RemoveArticle,
},
Route{
"SetArticleGroup",
strings.ToUpper("Put"),
"/attribute/articles/{articleId}/groups/{groupId}",
SetArticleGroup,
},
Route{
"SetArticleSubject",
strings.ToUpper("Put"),
"/attribute/articles/{articleId}/subject",
SetArticleSubject,
},
Route{
"Authorize",
strings.ToUpper("Put"),
@ -292,13 +369,6 @@ var routes = Routes{
ClearCardNotes,
},
Route{
"GetCard",
strings.ToUpper("Get"),
"/contact/cards/{cardId}",
GetCard,
},
Route{
"GetCardDetail",
strings.ToUpper("Get"),
@ -348,6 +418,13 @@ var routes = Routes{
RemoveCard,
},
Route{
"SetArticleRevision",
strings.ToUpper("Put"),
"/contact/article/revision",
SetArticleRevision,
},
Route{
"SetCardGroup",
strings.ToUpper("Put"),
@ -376,6 +453,13 @@ var routes = Routes{
SetCardStatus,
},
Route{
"SetChannelRevision",
strings.ToUpper("Put"),
"/contact/channel/revision",
SetChannelRevision,
},
Route{
"SetCloseMessage",
strings.ToUpper("Put"),
@ -383,20 +467,6 @@ var routes = Routes{
SetCloseMessage,
},
Route{
"SetContentRevision",
strings.ToUpper("Put"),
"/contact/content/revision",
SetContentRevision,
},
Route{
"SetLabelRevision",
strings.ToUpper("Put"),
"/contact/label/revision",
SetLabelRevision,
},
Route{
"SetOpenMessage",
strings.ToUpper("Put"),
@ -419,430 +489,185 @@ var routes = Routes{
},
Route{
"AddArticle",
"AddChannel",
strings.ToUpper("Post"),
"/content/articles",
AddArticle,
"/content/channels",
AddChannel,
},
Route{
"AddArticleAsset",
"AddChannelAsset",
strings.ToUpper("Post"),
"/content/articles/{articleId}/assets",
AddArticleAsset,
"/content/channels/{channelId}/topics/{topicId}/assets",
AddChannelAsset,
},
Route{
"AddArticleTag",
"AddChannelTopic",
strings.ToUpper("Post"),
"/content/articles/{articleId}/tags",
AddArticleTag,
"/content/channels/{channelId}/topics",
AddChannelTopic,
},
Route{
"AddLabel",
"AddChannelTopicTag",
strings.ToUpper("Post"),
"/content/labels",
AddLabel,
"/content/channels/{channelId}/topics/{topicId}/tags",
AddChannelTopicTag,
},
Route{
"ClearArticleGroup",
"ClearChannelGroup",
strings.ToUpper("Delete"),
"/content/articles/{articleId}/groups/{groupId}",
ClearArticleGroup,
"/content/channels/{channelId}/groups/{groupId}",
ClearChannelGroup,
},
Route{
"ClearArticleLabel",
"GetChannelAsset",
strings.ToUpper("Get"),
"/content/channels/{channelId}/topics/{topicId}/assets/{assetId}",
GetChannelAsset,
},
Route{
"GetChannelAssets",
strings.ToUpper("Get"),
"/content/channels/{channelId}/topics/{topicId}/assets",
GetChannelAssets,
},
Route{
"GetChannelDetail",
strings.ToUpper("Get"),
"/content/channels/{channelId}/detail",
GetChannelDetail,
},
Route{
"GetChannelSize",
strings.ToUpper("Get"),
"/content/channels/{channelId}/size",
GetChannelSize,
},
Route{
"GetChannelSubjectField",
strings.ToUpper("Get"),
"/content/channels/{channelId}/subject/{field}",
GetChannelSubjectField,
},
Route{
"GetChannelTopicDetail",
strings.ToUpper("Get"),
"/content/channels/{channelId}/topics/{topicId}/detail",
GetChannelTopicDetail,
},
Route{
"GetChannelTopicSize",
strings.ToUpper("Get"),
"/content/channels/{channelId}/topics/{topicId}/size",
GetChannelTopicSize,
},
Route{
"GetChannelTopicSubjectField",
strings.ToUpper("Get"),
"/content/channels/{channelId}/topics/{topicId}/subject/{field}",
GetChannelTopicSubjectField,
},
Route{
"GetChannelTopicTagSubjectField",
strings.ToUpper("Get"),
"/content/channels/{channelId}/topics/{topicId}/tags/{tagId}/subject/{field}",
GetChannelTopicTagSubjectField,
},
Route{
"GetChannelTopicTags",
strings.ToUpper("Get"),
"/content/channels/{channelId}/topics/{topicId}/tags",
GetChannelTopicTags,
},
Route{
"GetChannelTopics",
strings.ToUpper("Get"),
"/content/channels/{channelId}/topics",
GetChannelTopics,
},
Route{
"GetChannels",
strings.ToUpper("Get"),
"/content/channels",
GetChannels,
},
Route{
"RemoveChannel",
strings.ToUpper("Delete"),
"/content/articles/{articleId}/labels/{labelId}",
ClearArticleLabel,
"/content/channels/{channelId}",
RemoveChannel,
},
Route{
"ClearLabelGroup",
"RemoveChannelAsset",
strings.ToUpper("Delete"),
"/content/labels/{labelId}/groups/{groupId}",
ClearLabelGroup,
"/content/channels/{channelId}/topics/{topicId}/assets/{assetId}",
RemoveChannelAsset,
},
Route{
"GetArticle",
strings.ToUpper("Get"),
"/content/articles/{articleId}",
GetArticle,
},
Route{
"GetArticleAsset",
strings.ToUpper("Get"),
"/content/articles/{articleId}/assets/{assetId}",
GetArticleAsset,
},
Route{
"GetArticleAssets",
strings.ToUpper("Get"),
"/content/articles/{articleId}/assets",
GetArticleAssets,
},
Route{
"GetArticleSubjectField",
strings.ToUpper("Get"),
"/content/articles/{articleId}/subject/{field}",
GetArticleSubjectField,
},
Route{
"GetArticleTag",
strings.ToUpper("Get"),
"/content/articles/{articleId}/tags/{tagId}",
GetArticleTag,
},
Route{
"GetArticleTagBlockView",
strings.ToUpper("Get"),
"/content/articles/{articleId}/tagBlocks/view",
GetArticleTagBlockView,
},
Route{
"GetArticleTagSubjectField",
strings.ToUpper("Get"),
"/content/articles/{articleId}/tags/{tagId}/subject/{field}",
GetArticleTagSubjectField,
},
Route{
"GetArticleTagView",
strings.ToUpper("Get"),
"/content/articles/{articleId}/tagBlocks/{blockId}/view",
GetArticleTagView,
},
Route{
"GetArticleTags",
strings.ToUpper("Get"),
"/content/articles/{articleId}/tagBlocks/{blockId}",
GetArticleTags,
},
Route{
"GetArticles",
strings.ToUpper("Get"),
"/content/articles",
GetArticles,
},
Route{
"GetLabels",
strings.ToUpper("Get"),
"/content/labels",
GetLabels,
},
Route{
"RemoveArticle",
"RemoveChannelTopic",
strings.ToUpper("Delete"),
"/content/articles/{articleId}",
RemoveArticle,
"/content/channels/{channelId}/topics/{topicId}",
RemoveChannelTopic,
},
Route{
"RemoveArticleAsset",
"RemoveChannelTopicTag",
strings.ToUpper("Delete"),
"/content/articles/{articleId}/assets/{assetId}",
RemoveArticleAsset,
"/content/channels/{channelId}/topics/{topicId}/tags/{tagId}",
RemoveChannelTopicTag,
},
Route{
"RemoveArticleTag",
strings.ToUpper("Delete"),
"/content/articles/{articleId}/tags/{tagId}",
RemoveArticleTag,
},
Route{
"RemoveLabel",
strings.ToUpper("Delete"),
"/content/labels/{labelId}",
RemoveLabel,
},
Route{
"SetArticleConfirmed",
"SetChannelConfirmed",
strings.ToUpper("Put"),
"/content/articles/{articleId}/confirmed",
SetArticleConfirmed,
"/content/channels/{channelId}/topics/{topicId}/confirmed",
SetChannelConfirmed,
},
Route{
"SetArticleExpiration",
"SetChannelGroup",
strings.ToUpper("Put"),
"/content/articles/{articleId}/expiration",
SetArticleExpiration,
"/content/channels/{channelId}/groups/{groupId}",
SetChannelGroup,
},
Route{
"SetArticleGroup",
strings.ToUpper("Post"),
"/content/articles/{articleId}/groups/{groupId}",
SetArticleGroup,
},
Route{
"SetArticleLabel",
strings.ToUpper("Post"),
"/content/articles/{articleId}/labels/{labelId}",
SetArticleLabel,
},
Route{
"SetArticleSubject",
"SetChannelSubject",
strings.ToUpper("Put"),
"/content/articles/{articleId}/subject",
SetArticleSubject,
"/content/channels/{channelId}/subject",
SetChannelSubject,
},
Route{
"SetLabelGroup",
strings.ToUpper("Post"),
"/content/labels/{labelId}/groups/{groupId}",
SetLabelGroup,
},
Route{
"UpdateLabel",
"SetChannelTopicSubject",
strings.ToUpper("Put"),
"/content/labels/{labelId}",
UpdateLabel,
"/content/channels/{channelId}/topics/{topicId}/subject",
SetChannelTopicSubject,
},
Route{
"AddDialogue",
strings.ToUpper("Post"),
"/conversation/dialogues",
AddDialogue,
},
Route{
"AddDialogueInsight",
"SetChannelTopicTagSubject",
strings.ToUpper("Put"),
"/conversation/dialogues/{dialogueId}/cards/{cardId}",
AddDialogueInsight,
},
Route{
"AddDialogueTopic",
strings.ToUpper("Post"),
"/conversation/dialogues/{dialogueId}/topics",
AddDialogueTopic,
},
Route{
"AddInsightDialogue",
strings.ToUpper("Post"),
"/conversation/insights/{dialogueId}",
AddInsightDialogue,
},
Route{
"AddTopicAsset",
strings.ToUpper("Post"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}/assets",
AddTopicAsset,
},
Route{
"AddTopicTag",
strings.ToUpper("Post"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}/tags",
AddTopicTag,
},
Route{
"ConversationDialoguesDialogueIdTopicsTopicIdConfirmedPut",
strings.ToUpper("Put"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}/confirmed",
ConversationDialoguesDialogueIdTopicsTopicIdConfirmedPut,
},
Route{
"GetDialogueTopic",
strings.ToUpper("Get"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}",
GetDialogueTopic,
},
Route{
"GetDialogueTopicSubjectField",
strings.ToUpper("Get"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}/subject/{field}",
GetDialogueTopicSubjectField,
},
Route{
"GetDialogues",
strings.ToUpper("Get"),
"/conversation/dialogues",
GetDialogues,
},
Route{
"GetInsights",
strings.ToUpper("Get"),
"/conversation/insights",
GetInsights,
},
Route{
"GetTopicAsset",
strings.ToUpper("Get"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}/assets/{assetId}",
GetTopicAsset,
},
Route{
"GetTopicAssets",
strings.ToUpper("Get"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}/assets",
GetTopicAssets,
},
Route{
"GetTopicBlock",
strings.ToUpper("Get"),
"/conversation/dialogues/{dialogueId}/topicBlocks/{blockId}",
GetTopicBlock,
},
Route{
"GetTopicBlockView",
strings.ToUpper("Get"),
"/conversation/dialogues/{dialogueId}/topicBlocks/view",
GetTopicBlockView,
},
Route{
"GetTopicTag",
strings.ToUpper("Get"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}/tags/{tagId}",
GetTopicTag,
},
Route{
"GetTopicTagBlockView",
strings.ToUpper("Get"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}/tagBlocks/view",
GetTopicTagBlockView,
},
Route{
"GetTopicTagSubjectField",
strings.ToUpper("Get"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}/tags/{tagId}/subject/{field}",
GetTopicTagSubjectField,
},
Route{
"GetTopicTagView",
strings.ToUpper("Get"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}/tagBlocks/{blockId}/view",
GetTopicTagView,
},
Route{
"GetTopicTags",
strings.ToUpper("Get"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}/tagBlocks/{blockId}",
GetTopicTags,
},
Route{
"GetTopicViews",
strings.ToUpper("Get"),
"/conversation/dialogues/{dialogueId}/topicBlocks/{blockId}/view",
GetTopicViews,
},
Route{
"RemoveDialogue",
strings.ToUpper("Delete"),
"/conversation/dialogues/{dialogueId}",
RemoveDialogue,
},
Route{
"RemoveDialogueInsight",
strings.ToUpper("Delete"),
"/conversation/dialogues/{dialogueId}/cards/{cardId}",
RemoveDialogueInsight,
},
Route{
"RemoveDialogueTopic",
strings.ToUpper("Delete"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}",
RemoveDialogueTopic,
},
Route{
"RemoveTopicAsset",
strings.ToUpper("Delete"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}/assets/{assetId}",
RemoveTopicAsset,
},
Route{
"RemoveTopicTag",
strings.ToUpper("Delete"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}/tags/{tagId}",
RemoveTopicTag,
},
Route{
"SetDialogueActive",
strings.ToUpper("Put"),
"/conversation/dialogues/{dialogueId}/active",
SetDialogueActive,
},
Route{
"SetDialogueInsightStatus",
strings.ToUpper("Put"),
"/conversation/dialogues/{dialogueId}/status",
SetDialogueInsightStatus,
},
Route{
"SetDialogueSubject",
strings.ToUpper("Put"),
"/conversation/dialogues/{dialogueId}/subject",
SetDialogueSubject,
},
Route{
"SetInsightDialogue",
strings.ToUpper("Delete"),
"/conversation/insights/{dialogueId}",
SetInsightDialogue,
},
Route{
"SetInsightStatus",
strings.ToUpper("Put"),
"/conversation/insights/{insightId}/status",
SetInsightStatus,
},
Route{
"SetTopicSubject",
strings.ToUpper("Put"),
"/conversation/dialogues/{dialogueId}/topics/{topicId}/subject",
SetTopicSubject,
"/content/channels/{channelId}/topics/{topicId}/tags/{tagId}/subject",
SetChannelTopicTagSubject,
},
Route{
@ -880,34 +705,6 @@ var routes = Routes{
SetProfileImage,
},
Route{
"AddGroup",
strings.ToUpper("Post"),
"/share/groups",
AddGroup,
},
Route{
"GetGroups",
strings.ToUpper("Get"),
"/share/groups",
GetGroups,
},
Route{
"RemoveGroup",
strings.ToUpper("Delete"),
"/share/groups/{groupId}",
RemoveGroup,
},
Route{
"UpdateGroup",
strings.ToUpper("Put"),
"/share/groups/{groupId}",
UpdateGroup,
},
Route{
"Status",
strings.ToUpper("Get"),

View File

@ -65,12 +65,10 @@ type Account struct {
Username string `gorm:"not null;uniqueIndex"`
Password []byte `gorm:"not null"`
ProfileRevision int64 `gorm:"not null;default:1"`
ContentRevision int64 `gorm:"not null;default:1"`
ArticleRevision int64 `gorm:"not null;default:1"`
GroupRevision int64 `gorm:"not null;default:1"`
LabelRevision int64 `gorm:"not null;default:1"`
ChannelRevision int64 `gorm:"not null;default:1"`
CardRevision int64 `gorm:"not null;default:1"`
DialogueRevision int64 `gorm:"not null;default:1"`
InsightRevision int64 `gorm:"not null;default:1"`
Created int64 `gorm:"autoCreateTime"`
Disabled bool `gorm:"not null;default:false"`
AccountDetail AccountDetail
@ -183,8 +181,8 @@ type Card struct {
Updated int64 `gorm:"autoUpdateTime"`
ViewRevision int64 `gorm:"not null;default:1"`
NotifiedView int64
NotifiedContent int64
NotifiedLabel int64
NotifiedArticle int64
NotifiedChannel int64
NotifiedProfile int64
Account Account `gorm:"references:Guid"`
Groups []Group `gorm:"many2many:card_groups"`

View File

@ -112,8 +112,6 @@ func SendEndpointTest(
//
func AddTestGroup(prefix string) (*TestGroup, error) {
var err error
var rev *Revision
var ws *websocket.Conn
// allocate contacts
g := &TestGroup{}
@ -130,134 +128,12 @@ func AddTestGroup(prefix string) (*TestGroup, error) {
return g, err
}
// setup A
if g.A.B.CardId, err = AddTestCard(g.A.Token, g.B.Token); err != nil {
return g, err
}
if err = OpenTestCard(g.A.Token, g.A.B.CardId); err != nil {
return g, err
}
if g.A.B.GroupId, err = GroupTestCard(g.A.Token, g.A.B.CardId); err != nil {
return g, err
}
if g.A.C.CardId, err = AddTestCard(g.A.Token, g.C.Token); err != nil {
return g, err
}
if err = OpenTestCard(g.A.Token, g.A.C.CardId); err != nil {
return g, err
}
if g.A.C.GroupId, err = GroupTestCard(g.A.Token, g.A.C.CardId); err != nil {
return g, err
}
if g.A.D.CardId, err = AddTestCard(g.A.Token, g.D.Token); err != nil {
return g, err
}
if err = OpenTestCard(g.A.Token, g.A.D.CardId); err != nil {
return g, err
}
// setup B
if g.B.A.CardId, err = AddTestCard(g.B.Token, g.A.Token); err != nil {
return g, err
}
if err = OpenTestCard(g.B.Token, g.B.A.CardId); err != nil {
return g, err
}
if g.B.A.GroupId, err = GroupTestCard(g.B.Token, g.B.A.CardId); err != nil {
return g, err
}
if g.B.C.CardId, err = AddTestCard(g.B.Token, g.C.Token); err != nil {
return g, err
}
if g.B.C.GroupId, err = GroupTestCard(g.B.Token, g.B.C.CardId); err != nil {
return g, err
}
// setup C
if g.C.D.CardId, err = AddTestCard(g.C.Token, g.D.Token); err != nil {
return g, err
}
if err = OpenTestCard(g.C.Token, g.C.D.CardId); err != nil {
return g, err
}
if g.C.D.GroupId, err = GroupTestCard(g.C.Token, g.C.D.CardId); err != nil {
return g, err
}
if g.C.A.CardId, err = AddTestCard(g.C.Token, g.A.Token); err != nil {
return g, err
}
if err = OpenTestCard(g.C.Token, g.C.A.CardId); err != nil {
return g, err
}
if g.C.A.GroupId, err = GroupTestCard(g.C.Token, g.C.A.CardId); err != nil {
return g, err
}
if g.C.B.CardId, err = AddTestCard(g.C.Token, g.B.Token); err != nil {
return g, err
}
// setup D
if g.D.C.CardId, err = AddTestCard(g.D.Token, g.C.Token); err != nil {
return g, err
}
if err = OpenTestCard(g.D.Token, g.D.C.CardId); err != nil {
return g, err
}
if g.D.C.GroupId, err = GroupTestCard(g.D.Token, g.D.C.CardId); err != nil {
return g, err
}
// get contact tokens
if g.A.B.Token, err = GetCardToken(g.A.Token, g.A.B.CardId); err != nil {
return g, err
}
if g.B.A.Token, err = GetCardToken(g.B.Token, g.B.A.CardId); err != nil {
return g, err
}
if g.C.A.Token, err = GetCardToken(g.C.Token, g.C.A.CardId); err != nil {
return g, err
}
if g.C.D.Token, err = GetCardToken(g.C.Token, g.C.D.CardId); err != nil {
return g, err
}
if g.D.C.Token, err = GetCardToken(g.D.Token, g.D.C.CardId); err != nil {
return g, err
}
// connect websockets
rev = &Revision{}
if ws, err = StatusConnection(g.A.Token, rev); err != nil {
return g, err
}
g.A.Revisions = make(chan *Revision, 64)
g.A.Revisions <- rev
go MonitorStatus(ws, &g.A);
rev = &Revision{}
if ws, err = StatusConnection(g.B.Token, rev); err != nil {
return g, err
}
g.B.Revisions = make(chan *Revision, 64)
g.B.Revisions <- rev
go MonitorStatus(ws, &g.B);
rev = &Revision{}
if ws, err = StatusConnection(g.C.Token, rev); err != nil {
return g, err
}
g.C.Revisions = make(chan *Revision, 64)
g.C.Revisions <- rev
go MonitorStatus(ws, &g.C);
rev = &Revision{}
if ws, err = StatusConnection(g.D.Token, rev); err != nil {
return g, err
}
g.D.Revisions = make(chan *Revision, 64)
g.D.Revisions <- rev
go MonitorStatus(ws, &g.D);
return g, nil
}
func MonitorStatus(ws *websocket.Conn, contact *TestContact) {
var data []byte
var dataType int
@ -288,24 +164,36 @@ func MonitorStatus(ws *websocket.Conn, contact *TestContact) {
func GetCardToken(account string, cardId string) (token string, err error) {
var r *http.Request
var w *httptest.ResponseRecorder
var card Card
var cardDetail CardDetail
var cardProfile CardProfile
vars := make(map[string]string)
vars["cardId"] = cardId
if r, w, err = NewRequest("GET", "/contact/cards/{cardId}", nil); err != nil {
if r, w, err = NewRequest("GET", "/contact/cards/{cardId}/detail", nil); err != nil {
return
}
vars["cardId"] = cardId
r = mux.SetURLVars(r, vars)
SetBearerAuth(r, account)
GetCard(w, r)
if err = ReadResponse(w, &card); err != nil {
GetCardDetail(w, r)
if err = ReadResponse(w, &cardDetail); err != nil {
return
}
if card.CardData.Status != APP_CARDCONNECTED {
if cardDetail.Status != APP_CARDCONNECTED {
err = errors.New("card not connected")
return
}
token = card.CardData.Guid + "." + card.CardData.Token
if r, w, err = NewRequest("GET", "/contact/cards/{cardId}/profile", nil); err != nil {
return
}
r = mux.SetURLVars(r, vars)
SetBearerAuth(r, account)
GetCardProfile(w, r)
if err = ReadResponse(w, &cardProfile); err != nil {
return
}
token = cardProfile.Guid + "." + cardDetail.Token
return
}
@ -330,13 +218,13 @@ func GroupTestCard(account string, cardId string) (groupId string, err error) {
if err = ReadResponse(w, &group); err != nil {
return
}
groupId = group.GroupId
groupId = group.Id
// set contact group
if r, w, err = NewRequest("PUT", "/contact/cards/{cardId}/groups/{groupId}", nil); err != nil {
return
}
vars["groupId"] = group.GroupId
vars["groupId"] = group.Id
vars["cardId"] = cardId
r = mux.SetURLVars(r, vars)
SetBearerAuth(r, account)
@ -389,10 +277,10 @@ func OpenTestCard(account string, cardId string) (err error) {
// update status if connected
if contactStatus.Status == APP_CARDCONNECTED {
view := "viewRevision=" + strconv.FormatInt(contactStatus.ViewRevision, 10)
content := "contentRevision=" + strconv.FormatInt(contactStatus.ContentRevision, 10)
label := "labelRevision=" + strconv.FormatInt(contactStatus.LabelRevision, 10)
article := "articleRevision=" + strconv.FormatInt(contactStatus.ArticleRevision, 10)
channel := "channelRevision=" + strconv.FormatInt(contactStatus.ChannelRevision, 10)
profile := "profileRevision=" + strconv.FormatInt(contactStatus.ProfileRevision, 10)
if r, w, err = NewRequest("PUT", "/contact/cards/{cardId}/status?token=" + contactStatus.Token + "&" + view + "&" + content + "&" + label + "&" + profile, APP_CARDCONNECTED); err != nil {
if r, w, err = NewRequest("PUT", "/contact/cards/{cardId}/status?token=" + contactStatus.Token + "&" + view + "&" + article + "&" + channel + "&" + profile, APP_CARDCONNECTED); err != nil {
return
}
r = mux.SetURLVars(r, vars)
@ -431,7 +319,7 @@ func AddTestCard(account string, contact string) (cardId string, err error) {
if err = ReadResponse(w, &card); err != nil {
return
}
cardId = card.CardId
cardId = card.Id
return
}

View File

@ -1,165 +0,0 @@
package databag
import (
"testing"
"strconv"
"github.com/stretchr/testify/assert"
)
func TestAddArticle(t *testing.T) {
var set *TestGroup
var err error
var rev *Revision
var ver *Revision
var article *Article
var articles *[]Article
var articleAccess *ArticleAccess
var cards []Card
var label *Label
var subject *Subject
var vars *map[string]string
var contentRevision int64
var viewRevision int64
var labelRevision int64
var labels *[]Label
var view int64
var header map[string][]string
// setup testing group
set, err = AddTestGroup("addarticle")
assert.NoError(t, err)
// initial revision
rev = GetTestRevision(set.B.Revisions)
// create article
articleAccess = &ArticleAccess{ Groups: []string{set.A.B.GroupId} }
article = &Article{}
assert.NoError(t, SendEndpointTest(AddArticle, "POST", "/content/articles", nil, articleAccess, APP_TOKENAPP, set.A.Token, article, nil))
article = &Article{}
assert.NoError(t, SendEndpointTest(AddArticle, "POST", "/content/articles", nil, articleAccess, APP_TOKENAPP, set.A.Token, article, nil))
assert.NoError(t, SendEndpointTest(RemoveArticle, "DELETE", "/content/articls/" + article.ArticleId, &map[string]string{"articleId": article.ArticleId }, nil, APP_TOKENAPP, set.A.Token, nil, nil))
ver = GetTestRevision(set.B.Revisions)
assert.NoError(t, SendEndpointTest(GetCards, "GET", "/contact/cards?cardRevision=" + strconv.FormatInt(rev.Card, 10), nil, nil, APP_TOKENAPP, set.B.Token, &cards, nil))
assert.NotEqual(t, ver.Card, rev.Card)
assert.Equal(t, 1, len(cards))
rev = ver
articles = &[]Article{}
assert.NoError(t, SendEndpointTest(GetArticles, "GET", "/content/articles", nil, nil, APP_TOKENAPP, set.A.Token, articles, nil))
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, &header))
assert.Equal(t, 1, len(*articles))
assert.True(t, (*articles)[0].ArticleData != nil)
view, err = strconv.ParseInt(header["View-Revision"][0], 10, 64)
assert.NoError(t, err)
assert.Equal(t, view, cards[0].CardData.NotifiedView)
articles = &[]Article{}
assert.NoError(t, SendEndpointTest(GetArticles, "GET", "/content/articles", nil, nil, APP_TOKENCONTACT, set.C.A.Token, articles, nil))
assert.Equal(t, 0, len(*articles))
articles = &[]Article{}
assert.NoError(t, SendEndpointTest(GetArticles, "GET", "/content/articles?contentRevision=0&viewRevision=" + strconv.FormatInt(cards[0].CardData.NotifiedView, 10), nil, nil, APP_TOKENCONTACT, set.B.A.Token, articles, nil))
assert.Equal(t, 2, len(*articles))
ver = GetTestRevision(set.C.Revisions)
// add another article
article = &Article{}
articleAccess = &ArticleAccess{}
assert.NoError(t, SendEndpointTest(AddArticle, "POST", "/content/articles", nil, articleAccess, APP_TOKENAPP, set.A.Token, article, nil))
// capture updated card on new article
rev = GetTestRevision(set.C.Revisions)
assert.NoError(t, SendEndpointTest(GetCards, "GET", "/contact/cards?cardRevision=" + strconv.FormatInt(ver.Card, 10), nil, nil, APP_TOKENAPP, set.C.Token, &cards, nil))
assert.Equal(t, 1, len(cards))
viewRevision = cards[0].CardData.NotifiedView
contentRevision = cards[0].CardData.NotifiedContent
labelRevision = cards[0].CardData.NotifiedLabel
ver = rev
// create new label
label = &Label{}
subject = &Subject{ DataType: "labeltype", Data: "labeldata" }
assert.NoError(t, SendEndpointTest(AddLabel, "POST", "/content/labels", nil, subject, APP_TOKENAPP, set.A.Token, label, nil))
vars = &map[string]string{
"labelId": label.LabelId,
"groupId": set.A.C.GroupId,
}
label = &Label{}
assert.NoError(t, SendEndpointTest(SetLabelGroup, "POST", "/content/labels/{labelId}/groups/{groupId}", vars, nil, APP_TOKENAPP, set.A.Token, label, nil))
// capture updated card on new assigned label
rev = GetTestRevision(set.C.Revisions)
assert.NoError(t, SendEndpointTest(GetCards, "GET", "/contact/cards?cardRevision=" + strconv.FormatInt(ver.Card, 10), nil, nil, APP_TOKENAPP, set.C.Token, &cards, nil))
assert.Equal(t, 1, len(cards))
assert.NotEqual(t, viewRevision, cards[0].CardData.NotifiedView)
assert.NotEqual(t, labelRevision, cards[0].CardData.NotifiedLabel)
viewRevision = cards[0].CardData.NotifiedView
contentRevision = cards[0].CardData.NotifiedContent
labelRevision = cards[0].CardData.NotifiedLabel
ver = rev
// assign label to article
vars = &map[string]string{
"labelId": label.LabelId,
"articleId": article.ArticleId,
}
article = &Article{}
assert.NoError(t, SendEndpointTest(SetArticleLabel, "POST", "/content/articles/{articleId}/labels/{labelId}", vars, nil, APP_TOKENAPP, set.A.Token, article, nil))
// capture updated card on assigned article
rev = GetTestRevision(set.C.Revisions)
assert.NoError(t, SendEndpointTest(GetCards, "GET", "/contact/cards?cardRevision=" + strconv.FormatInt(ver.Card, 10), nil, nil, APP_TOKENAPP, set.C.Token, &cards, nil))
assert.Equal(t, 1, len(cards))
assert.NotEqual(t, contentRevision, cards[0].CardData.NotifiedContent)
ver = rev
// confirm c can see new article
articles = &[]Article{}
assert.NoError(t, SendEndpointTest(GetArticles, "GET", "/content/articles", nil, nil, APP_TOKENCONTACT, set.C.A.Token, articles, nil))
assert.Equal(t, 1, len(*articles))
assert.Equal(t, (*articles)[0].ArticleId, article.ArticleId)
assert.Equal(t, 1, len((*articles)[0].ArticleData.Labels))
assert.Equal(t, (*articles)[0].ArticleData.Labels[0], label.LabelId)
// confirm b cannot see new article
articles = &[]Article{}
assert.NoError(t, SendEndpointTest(GetArticles, "GET", "/content/articles", nil, nil, APP_TOKENCONTACT, set.B.A.Token, articles, nil))
assert.Equal(t, 1, len(*articles))
assert.NotEqual(t, article.ArticleId, (*articles)[0].ArticleId)
labels = &[]Label{}
assert.NoError(t, SendEndpointTest(GetLabels, "GET", "/content/labels", nil, nil, APP_TOKENAPP, set.A.Token, labels, nil))
assert.Equal(t, 1, len(*labels))
labels = &[]Label{}
assert.NoError(t, SendEndpointTest(GetLabels, "GET", "/content/labels", nil, nil, APP_TOKENCONTACT, set.B.A.Token, labels, nil))
assert.Equal(t, 0, len(*labels))
labels = &[]Label{}
assert.NoError(t, SendEndpointTest(GetLabels, "GET", "/content/labels", nil, nil, APP_TOKENCONTACT, set.C.A.Token, labels, &header))
assert.Equal(t, 1, len(*labels))
view, err = strconv.ParseInt(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, nil))
labels = &[]Label{}
assert.NoError(t, SendEndpointTest(GetLabels, "GET", "/content/labels", nil, nil, APP_TOKENCONTACT, set.C.A.Token, labels, nil))
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, nil))
assert.Equal(t, 0, len(*articles))
}

View File

@ -2,81 +2,11 @@ package databag
import (
"testing"
"strconv"
"github.com/stretchr/testify/assert"
)
func TestUpdateContact(t *testing.T) {
var err error
var set *TestGroup
var rev *Revision
var r *Revision
var msg DataMessage
var cards []Card
var detail int64
var profile int64
var cardDetail *CardDetail
var cardProfile *CardProfile
// setup testing group
set, err = AddTestGroup("updatecontact")
_, err := AddTestGroup("updatecontact")
assert.NoError(t, err)
// setup testing group
_, err = AddTestGroup("updatecontact")
assert.Error(t, err)
rev = GetTestRevision(set.B.Revisions)
assert.NoError(t, SendEndpointTest(GetCards, "PUT", "/contact/cards", nil, nil, APP_TOKENAPP, set.B.Token, &cards, nil))
// update B profile
profileData := ProfileData{
Name: "Namer",
Location: "San Francisco",
Description: "databaggerr",
};
assert.NoError(t, SendEndpointTest(SetProfile, "PUT", "/profile/data", nil, &profileData, APP_TOKENAPP, set.A.Token, nil, nil))
r = GetTestRevision(set.B.Revisions)
assert.NotEqual(t, rev.Card, r.Card)
assert.NoError(t, SendEndpointTest(GetCards, "GET", "/contact/cards?cardRevision=" + strconv.FormatInt(rev.Card, 10), nil, nil, APP_TOKENAPP, set.B.Token, &cards, nil))
assert.Equal(t, 1, len(cards))
assert.Equal(t, set.A.Guid, cards[0].CardData.Guid)
profile = cards[0].CardData.ProfileRevision
rev = r
cardProfile = &CardProfile{}
assert.NoError(t, SendEndpointTest(GetProfileMessage, "GET", "/profile/message", nil, nil, APP_TOKENCONTACT, set.B.A.Token, &msg, nil))
assert.NoError(t, SendEndpointTest(SetCardProfile, "PUT", "/contact/cards/{cardId}/profile", &map[string]string{"cardId":cards[0].CardId}, msg, APP_TOKENAPP, set.B.Token, cardProfile, nil))
assert.Equal(t, "Namer", cardProfile.Name)
r = GetTestRevision(set.B.Revisions)
assert.NotEqual(t, rev.Card, r.Card)
assert.NoError(t, SendEndpointTest(GetCards, "GET", "/contact/cards?cardRevision=" + strconv.FormatInt(rev.Card, 10), nil, nil, APP_TOKENAPP, set.B.Token, &cards, nil))
assert.Equal(t, 1, len(cards))
assert.Equal(t, set.A.Guid, cards[0].CardData.Guid)
assert.NotEqual(t, profile, cards[0].CardData.ProfileRevision)
detail = cards[0].CardData.DetailRevision
rev = r
cardDetail = &CardDetail{}
assert.NoError(t, SendEndpointTest(SetCardNotes, "PUT", "/contact/cards/{cardId}/notes", &map[string]string{"cardId":cards[0].CardId}, "some interesting notes", APP_TOKENAPP, set.B.Token, cardDetail, nil))
assert.Equal(t, "some interesting notes", cardDetail.Notes)
r = GetTestRevision(set.B.Revisions)
assert.NotEqual(t, rev.Card, r.Card)
rev = r
cardDetail = &CardDetail{}
assert.NoError(t, SendEndpointTest(ClearCardNotes, "DELETE", "/contact/cards/{cardId}/notes", &map[string]string{"cardId":cards[0].CardId}, nil, APP_TOKENAPP, set.B.Token, cardDetail, nil))
assert.Equal(t, "", cardDetail.Notes)
r = GetTestRevision(set.B.Revisions)
assert.NotEqual(t, rev.Card, r.Card)
assert.NoError(t, SendEndpointTest(GetCards, "GET", "/contact/cards?cardRevision=" + strconv.FormatInt(rev.Card, 10), nil, nil, APP_TOKENAPP, set.B.Token, &cards, nil))
assert.Equal(t, 1, len(cards))
assert.Equal(t, set.A.Guid, cards[0].CardData.Guid)
assert.NotEqual(t, detail, cards[0].CardData.DetailRevision)
}