diff --git a/doc/api.oa3 b/doc/api.oa3 index 06814f86..808e5dc2 100644 --- a/doc/api.oa3 +++ b/doc/api.oa3 @@ -1019,8 +1019,6 @@ paths: - contact description: Get list of cards. Access granted to app tokens of account holder. operationId: get-cards - security: - - bearerAuth: [] parameters: - name: revision in: query @@ -1028,6 +1026,12 @@ paths: required: false schema: type: string + - name: agent + in: query + description: agent token + required: false + schema: + type: string responses: '200': description: successful operation @@ -1054,8 +1058,13 @@ paths: - contact description: Add a contact card. Access granted to app tokens of account holder. operationId: add-card - security: - - bearerAuth: [] + parameters: + - name: agent + in: query + description: agent token + required: false + schema: + type: string responses: '200': description: success @@ -1078,8 +1087,6 @@ paths: - contact description: Remove card entry. Access granted to app tokens of account holder. operationId: remove-card - security: - - bearerAuth: [] parameters: - name: cardId in: path @@ -1087,6 +1094,12 @@ paths: required: true schema: type: string + - name: agent + in: query + description: agent token + required: false + schema: + type: string responses: '200': description: success @@ -1105,8 +1118,6 @@ paths: - contact description: Updated connected status of contact. Access granted to app tokens of account holder. operationId: set-card-status - security: - - bearerAuth: [] parameters: - name: cardId in: path @@ -1114,6 +1125,12 @@ paths: required: true schema: type: string + - name: agent + in: query + description: agent token + required: false + schema: + type: string - name: token in: query description: token for accessing card @@ -1172,8 +1189,6 @@ paths: - contact description: Get message for connecting to other contacts. Access granted to app tokens for account holder. operationId: get-open-message - security: - - bearerAuth: [] parameters: - name: cardId in: path @@ -1181,6 +1196,12 @@ paths: required: true schema: type: string + - name: agent + in: query + description: agent token + required: false + schema: + type: string responses: '200': description: success @@ -1228,8 +1249,6 @@ paths: - contact description: Get message for closing connection with contact. Access granted to app tokens for account holder. operationId: get-close-message - security: - - bearerAuth: [] parameters: - name: cardId in: path @@ -1237,6 +1256,12 @@ paths: required: true schema: type: string + - name: agent + in: query + description: agent token + required: false + schema: + type: string responses: '200': description: successful operation @@ -1280,8 +1305,6 @@ paths: - contact description: Get profile of card entry. Access granted to app tokens of account holder. operationId: get-card-profile - security: - - bearerAuth: [] parameters: - name: cardId in: path @@ -1289,6 +1312,12 @@ paths: required: true schema: type: string + - name: agent + in: query + description: agent token + required: false + schema: + type: string responses: '200': description: successful operation @@ -1309,8 +1338,6 @@ paths: - contact description: Set profile of card entry. Access granted to app tokens of account holder. operationId: set-card-profile - security: - - bearerAuth: [] parameters: - name: cardId in: path @@ -1318,6 +1345,12 @@ paths: required: true schema: type: string + - name: agent + in: query + description: agent token + required: false + schema: + type: string responses: '200': description: success @@ -1345,8 +1378,6 @@ paths: - contact description: Get image of card profile. Access granted to app tokens of account holder. operationId: get-card-profile-image - security: - - bearerAuth: [] parameters: - name: cardId in: path @@ -1354,6 +1385,12 @@ paths: required: true schema: type: string + - name: agent + in: query + description: agent token + required: false + schema: + type: string responses: '200': description: success @@ -1379,8 +1416,6 @@ paths: - contact description: Get specified card detail. Access granted to app tokens for account holder. operationId: get-card-detail - security: - - bearerAuth: [] parameters: - name: cardId in: path @@ -1388,6 +1423,12 @@ paths: required: true schema: type: string + - name: agent + in: query + description: agent token + required: false + schema: + type: string responses: '200': description: success @@ -1410,8 +1451,6 @@ paths: - contact description: Update card notes for specified card. Access granted to app tokens for account holder. operationId: set-card-notes - security: - - bearerAuth: [] parameters: - name: cardId in: path @@ -1419,6 +1458,12 @@ paths: required: true schema: type: string + - name: agent + in: query + description: agent token + required: false + schema: + type: string responses: '200': description: success @@ -1444,8 +1489,6 @@ paths: - contact description: Clear notes for specified card. Access granted to app tokens of account holder. operationId: clear-card-notes - security: - - bearerAuth: [] parameters: - name: cardId in: path @@ -1453,6 +1496,12 @@ paths: required: true schema: type: string + - name: agent + in: query + description: agent token + required: false + schema: + type: string responses: '200': description: success @@ -1475,8 +1524,6 @@ paths: - contact description: Set sharing group for contact. Access granted to app tokens for account holder. operationId: set-card-group - security: - - bearerAuth: [] parameters: - name: cardId in: path @@ -1490,6 +1537,12 @@ paths: required: true schema: type: string + - name: agent + in: query + description: agent token + required: false + schema: + type: string responses: '200': description: success @@ -1510,8 +1563,6 @@ paths: - contact description: Clear sharing group for card. Access granted to app tokens for account holder. operationId: clear-card-group - security: - - bearerAuth: [] parameters: - name: cardId in: path @@ -1525,6 +1576,12 @@ paths: required: true schema: type: string + - name: agent + in: query + description: agent token + required: false + schema: + type: string responses: '200': description: success @@ -1547,8 +1604,13 @@ paths: - contact description: Set profile revision for contact. This is intend to be invoked automatically anytime a contact updates their profile. Access granted to contact tokens. operationId: set-profile-revision - security: - - bearerAuth: [] + parameters: + - name: contact + in: query + description: contact token + required: false + schema: + type: string responses: '200': description: revision set @@ -1571,8 +1633,13 @@ paths: - 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: [] + parameters: + - name: contact + in: query + description: contact token + required: false + schema: + type: string responses: '200': description: revision set @@ -1595,8 +1662,13 @@ paths: - 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: [] + parameters: + - name: contact + in: query + description: contact token + required: false + schema: + type: string responses: '200': description: revision set @@ -1619,8 +1691,13 @@ paths: - contact description: Set view 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-view-revision - security: - - bearerAuth: [] + parameters: + - name: contact + in: query + description: contact token + required: false + schema: + type: string responses: '200': description: revision set @@ -3749,3 +3826,4 @@ components: + diff --git a/net/server/internal/api_getCardDetail.go b/net/server/internal/api_getCardDetail.go index 76b35051..e8f5f1d7 100644 --- a/net/server/internal/api_getCardDetail.go +++ b/net/server/internal/api_getCardDetail.go @@ -10,7 +10,7 @@ import ( func GetCardDetail(w http.ResponseWriter, r *http.Request) { - account, code, err := BearerAppToken(r, false); + account, code, err := ParamAgentToken(r, false); if err != nil { ErrResponse(w, code, err) return diff --git a/net/server/internal/api_getCardProfile.go b/net/server/internal/api_getCardProfile.go index ee30369e..b24bf097 100644 --- a/net/server/internal/api_getCardProfile.go +++ b/net/server/internal/api_getCardProfile.go @@ -10,7 +10,7 @@ import ( func GetCardProfile(w http.ResponseWriter, r *http.Request) { - account, code, err := BearerAppToken(r, false); + account, code, err := ParamAgentToken(r, false); if err != nil { ErrResponse(w, code, err) return diff --git a/net/server/internal/api_getCards.go b/net/server/internal/api_getCards.go index 797a572c..f9fff2c6 100644 --- a/net/server/internal/api_getCards.go +++ b/net/server/internal/api_getCards.go @@ -10,7 +10,7 @@ func GetCards(w http.ResponseWriter, r *http.Request) { var cardRevisionSet bool var cardRevision int64 - account, code, err := BearerAppToken(r, false); + account, code, err := ParamAgentToken(r, false); if err != nil { ErrResponse(w, code, err) return diff --git a/net/server/internal/testUtil.go b/net/server/internal/testUtil.go index ccb72235..57b98201 100644 --- a/net/server/internal/testUtil.go +++ b/net/server/internal/testUtil.go @@ -426,11 +426,10 @@ func GetCardToken(account string, cardId string) (token string, err error) { vars := make(map[string]string) vars["cardId"] = cardId - if r, w, err = NewRequest("GET", "/contact/cards/{cardId}/detail", nil); err != nil { + if r, w, err = NewRequest("GET", "/contact/cards/{cardId}/detail?agent=" + account, nil); err != nil { return } r = mux.SetURLVars(r, vars) - SetBearerAuth(r, account) GetCardDetail(w, r) if err = ReadResponse(w, &cardDetail); err != nil { return @@ -440,11 +439,10 @@ func GetCardToken(account string, cardId string) (token string, err error) { return } - if r, w, err = NewRequest("GET", "/contact/cards/{cardId}/profile", nil); err != nil { + if r, w, err = NewRequest("GET", "/contact/cards/{cardId}/profile?agent=" + account, nil); err != nil { return } r = mux.SetURLVars(r, vars) - SetBearerAuth(r, account) GetCardProfile(w, r) if err = ReadResponse(w, &cardProfile); err != nil { return @@ -459,10 +457,9 @@ func GetCardId(account string, guid string) (cardId string, err error) { var w *httptest.ResponseRecorder var cards []Card - if r, w, err = NewRequest("GET", "/contact/cards", nil); err != nil { + if r, w, err = NewRequest("GET", "/contact/cards?agent=" + account, nil); err != nil { return } - SetBearerAuth(r, account) GetCards(w, r) if err = ReadResponse(w, &cards); err != nil { return diff --git a/net/web/src/AppContext/fetchUtil.js b/net/web/src/AppContext/fetchUtil.js index f71f430c..f8d1c9c2 100644 --- a/net/web/src/AppContext/fetchUtil.js +++ b/net/web/src/AppContext/fetchUtil.js @@ -98,3 +98,27 @@ export async function getListing(server) { return await listing.json(); } +export async function getCards(token, revision) { + let param = "?agent=" + token + if (revision != null) { + param += '&revision=' + revision + } + let cards = await fetchWithTimeout('/contact/cards' + param, { method: 'GET', timeout: FETCH_TIMEOUT }); + checkResponse(cards) + return await cards.json() +} + +export async function getCardProfile(token, cardId) { + let param = "?agent=" + token + let profile = await fetchWithTimeout(`/contact/cards/${cardId}/profile${param}`, { method: 'GET', timeout: FETCH_TIMEOUT }); + checkResponse(profile); + return await profile.json() +} + +export async function getCardDetail(token, cardId) { + let param = "?agent=" + token + let detail = await fetchWithTimeout(`/contact/cards/${cardId}/detail${param}`, { method: 'GET', timeout: FETCH_TIMEOUT }); + checkResponse(detail); + return await detail.json() +} + diff --git a/net/web/src/AppContext/useAppContext.hook.js b/net/web/src/AppContext/useAppContext.hook.js index da3e6d04..1180c206 100644 --- a/net/web/src/AppContext/useAppContext.hook.js +++ b/net/web/src/AppContext/useAppContext.hook.js @@ -1,5 +1,5 @@ import { useEffect, useState, useRef } from 'react'; -import { getListingImageUrl, getListing, setProfileImage, setProfileData, getProfileImageUrl, getAccountStatus, setAccountSearchable, getProfile, getGroups, getAvailable, getUsername, setLogin, createAccount } from './fetchUtil'; +import { getCards, getCardProfile, getCardDetail, getListingImageUrl, getListing, setProfileImage, setProfileData, getProfileImageUrl, getAccountStatus, setAccountSearchable, getProfile, getGroups, getAvailable, getUsername, setLogin, createAccount } from './fetchUtil'; async function updateAccount(token, updateData) { let status = await getAccountStatus(token); @@ -19,6 +19,53 @@ async function updateGroups(token, revision, groupMap, updateData) { updateData({ groups: Array.from(groupMap.values()) }); } +async function updateCards(token, revision, cardMap, updateData) { + let cards = await getCards(token, revision); + for (let card of cards) { + let cur = cardMap.get(card.id); + if (cur == null) { + cur = { id: card.id, data: {} } + } + if (cur.data.DetailRevision != card.data.DetailRevision) { + if (card.data.CardDetail != null) { + cur.data.CardDetail = card.data.CardDetail; + } + else { + cur.data.CardDetail = await getCardDetail(token, card.id); + } + cur.data.DetailRevision = card.data.DetailRevision; + } + if (cur.data.ProfileRevision != card.data.ProfileRevision) { + if (cur.data.CardProfile != null) { + cur.data.CardProfile = card.data.CardProfile; + } + else { + cur.data.CardProfile = await getCardProfile(token, card.id); + } + cur.data.ProfileRevision = card.data.ProfileRevision; + } + if (cur.data.NotifiedProfile != card.data.NotifiedProfile) { + // update remote profile + cur.data.NotifiedProfile = card.data.NotifiedProfile; + } + if (cur.data.NotifiedView != card.data.NotifiedView) { + // update remote articles and channels + cur.data.NotifiedArticle = card.data.NotifiedArticle; + cur.data.NotifiedChannel = card.data.NotifiedChannel; + cur.data.NotifiedView = card.data.NotifiedView; + } + if (cur.data.NotifiedArticle != card.data.NotifiedArticle) { + // update remote articles + cur.data.NotifiedArticle = card.data.NotifiedArticle; + } + if (cur.data.NotifiedChannel != card.data.NotifiedChannel) { + // update remote channels + cur.data.NotifiedChannel = card.data.NotifiedChannel; + } + cur.revision = card.revision; + } +} + async function appCreate(username, password, updateState, setWebsocket) { await createAccount(username, password); let access = await setLogin(username, password) @@ -48,7 +95,9 @@ export function useAppContext() { const groupRevision = useRef(null); const accountRevision = useRef(null); const profileRevision = useRef(null); + const cardRevision = useRef(null); + const cards = useRef(new Map()); const groups = useRef(new Map()); const delay = useRef(2); @@ -68,6 +117,8 @@ export function useAppContext() { revision.current = null; profileRevision.current = null; groupRevision.current = null; + cardRevision.current = null; + cards.current = new Map(); groups.current = new Map(); setState({}); } @@ -125,6 +176,12 @@ export function useAppContext() { groupRevision.current = rev.group } + // update card status if revision changed + if (rev.card != cardRevision.current) { + await updateCards(token, cardRevision.current, cards.current, updateData); + cardRevision.current = rev.card + } + // update account status if revision changed if (rev.account != accountRevision.current) { await updateAccount(token, updateData)