From 0beabeb713939dd8ddd747bc497ab55c7be5961a Mon Sep 17 00:00:00 2001 From: Roland Osborne Date: Tue, 8 Feb 2022 23:54:09 -0800 Subject: [PATCH] restoring profile update test --- doc/api.oa3 | 174 ++++++++++---------- net/server/internal/api_addCard.go | 4 +- net/server/internal/api_getCard.go | 32 ++++ net/server/internal/api_getProfile.go | 29 ++++ net/server/internal/api_profile.go | 10 -- net/server/internal/api_setProfile.go | 49 ++++++ net/server/internal/routers.go | 7 + net/server/internal/ucUpdateProfile_test.go | 80 ++++++++- 8 files changed, 285 insertions(+), 100 deletions(-) create mode 100644 net/server/internal/api_getCard.go create mode 100644 net/server/internal/api_getProfile.go create mode 100644 net/server/internal/api_setProfile.go diff --git a/doc/api.oa3 b/doc/api.oa3 index 165d599b..6e709d66 100644 --- a/doc/api.oa3 +++ b/doc/api.oa3 @@ -43,12 +43,12 @@ paths: '200': description: Awaiting announce - /admin/status: + /admin/available: get: tags: - admin description: Check if portal params have been set - operationId: get-node-status + operationId: get-node-available responses: '200': description: success @@ -58,11 +58,13 @@ paths: type: boolean '500': description: internal server error - put: + + /admin/claim: + post: tags: - admin description: Set admin password and node domain - operationId: set-node-status + operationId: set-node-claim security: - basicCredentials: [] parameters: @@ -267,12 +269,12 @@ paths: type: string format: binary - /account/public/status: + /account/public/available: get: tags: - account description: Check if a public account can be created. - operationId: get-public-status + operationId: get-public-available responses: '200': description: success @@ -981,7 +983,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/DataMessage' + $ref: '#/components/schemas/Card' '400': description: invalid data message '401': @@ -990,8 +992,42 @@ paths: description: account disabled '500': description: internal server error - + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DataMessage' + /contact/cards/{cardId}: + get: + tags: + - contact + description: get card entry. Access granted to app tokens of account holder. + operationId: get-card + security: + - bearerAuth: [] + parameters: + - name: cardId + in: path + description: specified card id + required: true + schema: + type: string + responses: + '200': + description: success + content: + application/json: + schema: + $ref: '#/components/schemas/Card' + '401': + description: permission denied + '404': + description: card not found + '410': + description: account disabled + '500': + description: internal server error delete: tags: - contact @@ -1039,30 +1075,6 @@ 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 @@ -1181,6 +1193,18 @@ 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': @@ -1484,36 +1508,12 @@ paths: type: integer format: int64 - /contact/article/revision: + /contact/content/revision: put: tags: - contact - 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 + 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 security: - bearerAuth: [] responses: @@ -1726,7 +1726,15 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Subject' + type: object + required: + - type + - data + properties: + type: + type: string + data: + type: string /attribute/articles/{articleId}/groups/{groupId}: put: @@ -2367,7 +2375,15 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Subject' + type: object + required: + - type + - data + properties: + type: + type: string + data: + type: string /content/channels/{channelId}/topics/{topicId}/assets: get: @@ -2822,7 +2838,7 @@ components: type: object required: - profile - - article + - attribute - group - channel - card @@ -2973,7 +2989,7 @@ components: id: type: string revision: - type: integer + type: number format: int64 data: $ref: '#/components/schemas/CardData' @@ -2984,7 +3000,7 @@ components: - detailRevision - profileRevision - notifiedProfile - - notifiedArticle + - notifiedContent - notifiedChannel - notifiedView properties: @@ -2997,7 +3013,7 @@ components: notifiedProfile: type: integer format: int64 - notifiedArticle: + notifiedContent: type: integer format: int64 notifiedChannel: @@ -3056,7 +3072,7 @@ components: required: - id - revision - - data + - ata properties: id: type: string @@ -3180,8 +3196,7 @@ components: id: type: string revision: - type: integer - format: int64 + type: string data: $ref: '#/components/schemas/TopicData' @@ -3251,8 +3266,7 @@ components: id: type: string revision: - type: integer - format: int64 + type: string data: $ref: '#/components/schemas/TagData' @@ -3288,8 +3302,7 @@ components: id: type: string revision: - type: integer - format: int64 + type: string data: $ref: '#/components/schemas/ArticleData' @@ -3399,15 +3412,12 @@ components: viewRevision: type: integer format: int64 - articleRevision: + contentRevision: type: integer format: int64 profileRevision: type: integer format: int64 - channelRevision: - type: integer - format: int64 handle: type: string name: @@ -3459,18 +3469,6 @@ 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 ] diff --git a/net/server/internal/api_addCard.go b/net/server/internal/api_addCard.go index 3e8cb5d8..856aa5e5 100644 --- a/net/server/internal/api_addCard.go +++ b/net/server/internal/api_addCard.go @@ -110,6 +110,7 @@ func AddCard(w http.ResponseWriter, r *http.Request) { } } } else { + if identity.Revision > card.ProfileRevision { // update card data @@ -125,10 +126,10 @@ func AddCard(w http.ResponseWriter, r *http.Request) { // save contact card err = store.DB.Transaction(func(tx *gorm.DB) error { - slot = &card.CardSlot if res := tx.Save(&card).Error; res != nil { return res } + slot = &card.CardSlot if slot == nil { slot = &store.CardSlot{ CardSlotId: uuid.New().String(), @@ -146,6 +147,7 @@ func AddCard(w http.ResponseWriter, r *http.Request) { if res := tx.Model(&account).Update("card_revision", account.CardRevision + 1).Error; res != nil { return res } + slot.Card = &card return nil }) } diff --git a/net/server/internal/api_getCard.go b/net/server/internal/api_getCard.go new file mode 100644 index 00000000..2a122b23 --- /dev/null +++ b/net/server/internal/api_getCard.go @@ -0,0 +1,32 @@ +package databag + +import ( + "errors" + "net/http" + "gorm.io/gorm" + "github.com/gorilla/mux" + "databag/internal/store" +) + +func GetCard(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 + } + + WriteResponse(w, getCardModel(&slot)) +} + diff --git a/net/server/internal/api_getProfile.go b/net/server/internal/api_getProfile.go new file mode 100644 index 00000000..c2ecaed6 --- /dev/null +++ b/net/server/internal/api_getProfile.go @@ -0,0 +1,29 @@ +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 + + profile := &Profile{ + Guid: account.Guid, + Handle: account.Username, + Description: detail.Description, + Location: detail.Location, + Image: detail.Image, + Revision: account.ProfileRevision, + Version: APP_VERSION, + Node: "https://" + getStrConfigValue(CONFIG_DOMAIN, "") + "/", + } + + WriteResponse(w, profile) +} + diff --git a/net/server/internal/api_profile.go b/net/server/internal/api_profile.go index 193dece4..8e04ef7e 100644 --- a/net/server/internal/api_profile.go +++ b/net/server/internal/api_profile.go @@ -13,21 +13,11 @@ 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) diff --git a/net/server/internal/api_setProfile.go b/net/server/internal/api_setProfile.go new file mode 100644 index 00000000..46f80f49 --- /dev/null +++ b/net/server/internal/api_setProfile.go @@ -0,0 +1,49 @@ +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) +} + diff --git a/net/server/internal/routers.go b/net/server/internal/routers.go index 0b58cf3d..970380ff 100644 --- a/net/server/internal/routers.go +++ b/net/server/internal/routers.go @@ -145,6 +145,13 @@ var routes = Routes{ GetAccountUsername, }, + Route{ + "GetCard", + strings.ToUpper("Get"), + "/contact/cards/{cardId}", + GetCard, + }, + Route{ "GetPublicStatus", strings.ToUpper("Get"), diff --git a/net/server/internal/ucUpdateProfile_test.go b/net/server/internal/ucUpdateProfile_test.go index d5176968..5bea0d5e 100644 --- a/net/server/internal/ucUpdateProfile_test.go +++ b/net/server/internal/ucUpdateProfile_test.go @@ -6,9 +6,87 @@ import ( ) func TestUpdateProfile(t *testing.T) { + param := map[string]string{} + var msg DataMessage + var card Card + var bProfileRev int64 + var bCardRev int64 + var cProfileRev int64 + var cCardRev int64 + // setup testing group set, err := AddTestGroup("updateprofile") assert.NoError(t, err) - PrintMsg(set) + // setup testing group + _, ret := AddTestGroup("updateprofile") + assert.Error(t, ret) + + // reset revision + bCardRev = GetTestRevision(set.B.Revisions).Card + cCardRev = GetTestRevision(set.C.Revisions).Card + + param["cardId"] = set.B.A.CardId + assert.NoError(t, SendEndpointTest(GetCard, "GET", "/contact/cards/{cardId}", + ¶m, nil, + APP_TOKENAPP, set.B.Token, &card, nil)) + bProfileRev = card.Data.NotifiedProfile + + param["cardId"] = set.C.A.CardId + assert.NoError(t, SendEndpointTest(GetCard, "GET", "/contact/cards/{cardId}", + ¶m, nil, + APP_TOKENAPP, set.C.Token, &card, nil)) + cProfileRev = card.Data.NotifiedProfile + + // update A 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)) + + assert.NotEqual(t, bCardRev, GetTestRevision(set.B.Revisions).Card) + assert.NotEqual(t, cCardRev, GetTestRevision(set.C.Revisions).Card) + + param["cardId"] = set.B.A.CardId + assert.NoError(t, SendEndpointTest(GetCard, "GET", "/contact/cards/{cardId}", + ¶m, nil, + APP_TOKENAPP, set.B.Token, &card, nil)) + assert.NotEqual(t, bProfileRev, card.Data.NotifiedProfile) + assert.NotEqual(t, card.Data.ProfileRevision, card.Data.NotifiedProfile) + + param["cardId"] = set.C.A.CardId + assert.NoError(t, SendEndpointTest(GetCard, "GET", "/contact/cards/{cardId}", + ¶m, nil, + APP_TOKENAPP, set.C.Token, &card, nil)) + assert.NotEqual(t, cProfileRev, card.Data.NotifiedProfile) + assert.NotEqual(t, card.Data.ProfileRevision, card.Data.NotifiedProfile) + + // update profile + assert.NoError(t, SendEndpointTest(GetProfileMessage, "GET", "/profile/message", + nil, nil, + APP_TOKENCONTACT, set.B.A.Token, &msg, nil)) + assert.NoError(t, SendEndpointTest(AddCard, "POST", "/contact/cards", + nil, &msg, + APP_TOKENAPP, set.B.Token, &card, nil)) + assert.Equal(t, card.Id, set.B.A.CardId) + assert.Equal(t, card.Data.ProfileRevision, card.Data.NotifiedProfile) + assert.Equal(t, card.Data.CardProfile.Name, "Namer") + + // update profile + assert.NoError(t, SendEndpointTest(GetProfileMessage, "GET", "/profile/message", + nil, nil, + APP_TOKENCONTACT, set.C.A.Token, &msg, nil)) + assert.NoError(t, SendEndpointTest(AddCard, "POST", "/contact/cards", + nil, &msg, + APP_TOKENAPP, set.C.Token, &card, nil)) + assert.Equal(t, card.Id, set.C.A.CardId) + assert.Equal(t, card.Data.ProfileRevision, card.Data.NotifiedProfile) + assert.Equal(t, card.Data.CardProfile.Name, "Namer") + + + }