refactor to prepare for channel peak data

This commit is contained in:
Roland Osborne 2022-05-09 12:53:00 -07:00
parent 8f8cd6eb4d
commit 0416389be0
14 changed files with 86 additions and 193 deletions

View File

@ -2118,7 +2118,7 @@ paths:
tags:
- content
description: Get details of channel.
operationId: get-channel
operationId: get-channel-detail
security:
- bearerAuth: []
parameters:
@ -2134,7 +2134,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/Channel'
$ref: '#/components/schemas/ChannelDetail'
'401':
description: invalid password
'404':
@ -2472,43 +2472,6 @@ paths:
schema:
$ref: '#/components/schemas/Subject'
/content/channels/{channelId}/topics/{topicId}/detail:
get:
tags:
- content
description: Get full object of topic.
operationId: get-channel-topic
security:
- bearerAuth: []
parameters:
- name: channelId
in: path
description: specified channel id
required: true
schema:
type: string
- name: topicId
in: path
description: specified topic id
required: true
schema:
type: string
responses:
'200':
description: success
content:
application/json:
schema:
$ref: '#/components/schemas/Topic'
'401':
description: invalid password
'404':
description: channel not found
'410':
description: account disabled
'500':
description: internal server error
/content/channels/{channelId}/topics/{topicId}:
delete:
tags:
@ -3374,7 +3337,8 @@ components:
node:
type: string
revision:
type: int64
type: integer
format: int64
CardDetail:
type: object
@ -3500,7 +3464,7 @@ components:
$ref: '#/components/schemas/ChannelContacts'
members:
type: array
item:
items:
type: string
ChannelContacts:
@ -3860,7 +3824,3 @@ components:

View File

@ -1,62 +0,0 @@
package databag
import (
"errors"
"net/http"
"gorm.io/gorm"
"github.com/gorilla/mux"
"databag/internal/store"
)
func GetChannel(w http.ResponseWriter, r *http.Request) {
// scan parameters
params := mux.Vars(r)
channelId := params["channelId"]
var guid string
var act *store.Account
tokenType := ParamTokenType(r)
if tokenType == APP_TOKENAGENT {
account, code, err := ParamAgentToken(r, false);
if err != nil {
ErrResponse(w, code, err)
return
}
act = account
} else if tokenType == APP_TOKENCONTACT {
card, code, err := ParamContactToken(r, true)
if err != nil {
ErrResponse(w, code, err)
return
}
act = &card.Account
guid = card.Guid
} else {
ErrResponse(w, http.StatusBadRequest, errors.New("unknown token type"))
return
}
// load channel
var slot store.ChannelSlot
if err := store.DB.Preload("Channel.Cards.CardSlot").Preload("Channel.Groups.Cards").Preload("Channel.Groups.GroupSlot").Where("account_id = ? AND channel_slot_id = ?", act.ID, channelId).First(&slot).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
ErrResponse(w, http.StatusNotFound, err)
} else {
ErrResponse(w, http.StatusInternalServerError, err)
}
return
}
// return model data
if guid != "" {
if isChannelShared(guid, slot.Channel) {
WriteResponse(w, getChannelModel(&slot, true, false))
} else {
WriteResponse(w, getChannelModel(&slot, false, false))
}
} else {
WriteResponse(w, getChannelModel(&slot, true, true))
}
}

View File

@ -5,6 +5,7 @@ import (
"errors"
"strconv"
"net/http"
"gorm.io/gorm"
"encoding/json"
"databag/internal/store"
)
@ -101,7 +102,9 @@ func GetChannels(w http.ResponseWriter, r *http.Request) {
account := &card.Account
var slots []store.ChannelSlot
if channelRevisionSet {
if err := store.DB.Preload("Channel.Cards").Preload("Channel.Groups.Cards").Where("account_id = ? AND revision > ?", account.ID, channelRevision).Find(&slots).Error; err != nil {
if err := store.DB.Preload("Channel.Topics", func(db *gorm.DB) *gorm.DB {
return store.DB.Order("topics.id DESC").Limit(1)
}).Preload("Channel.Cards").Preload("Channel.Groups.Cards").Where("account_id = ? AND revision > ?", account.ID, channelRevision).Find(&slots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}

View File

@ -165,13 +165,10 @@ func getChannelRevisionModel(slot *store.ChannelSlot, showData bool) *Channel {
}
}
func getChannelModel(slot *store.ChannelSlot, showData bool, showList bool) *Channel {
func getChannelDetailModel(slot *store.ChannelSlot, showList bool) *ChannelDetail {
if !showData || slot.Channel == nil {
return &Channel{
Id: slot.ChannelSlotId,
Revision: slot.Revision,
}
if slot.Channel == nil {
return nil
}
var contacts *ChannelContacts
@ -192,20 +189,32 @@ func getChannelModel(slot *store.ChannelSlot, showData bool, showList bool) *Cha
members = append(members, card.Guid)
}
return &Channel{
Id: slot.ChannelSlotId,
Revision: slot.Revision,
Data: &ChannelData {
DetailRevision: slot.Channel.DetailRevision,
TopicRevision: slot.Channel.TopicRevision,
ChannelDetail: &ChannelDetail{
return &ChannelDetail{
DataType: slot.Channel.DataType,
Data: slot.Channel.Data,
Created: slot.Channel.Created,
Updated: slot.Channel.Updated,
Contacts: contacts,
Members: members,
},
}
}
func getChannelModel(slot *store.ChannelSlot, showData bool, showList bool) *Channel {
if !showData || slot.Channel == nil {
return &Channel{
Id: slot.ChannelSlotId,
Revision: slot.Revision,
}
}
return &Channel{
Id: slot.ChannelSlotId,
Revision: slot.Revision,
Data: &ChannelData {
DetailRevision: slot.Channel.DetailRevision,
TopicRevision: slot.Channel.TopicRevision,
ChannelDetail: getChannelDetailModel(slot, showList),
},
}
}

View File

@ -539,10 +539,10 @@ var routes = Routes{
},
Route{
"GetChannel",
"GetChannelDetail",
strings.ToUpper("Get"),
"/content/channels/{channelId}/detail",
GetChannel,
GetChannelDetail,
},
Route{

View File

@ -215,16 +215,16 @@ func (c *TestContactData) UpdateContactChannel(storeChannel *TestChannel, channe
token := c.card.Data.CardProfile.Guid + "." + c.card.Data.CardDetail.Token
params := &TestApiParams{ query: "/channel/{channelId}", path: map[string]string{ "channelId": channel.Id },
tokenType: APP_TOKENCONTACT, token: token }
channel := Channel{}
response := &TestApiResponse{ data: &channel }
if err = TestApiRequest(GetChannel, params, response); err != nil {
detail := &ChannelDetail{}
response := &TestApiResponse{ data: &detail }
if err = TestApiRequest(GetChannelDetail, params, response); err != nil {
return
}
if channel.Data == nil {
err = errors.New("channel removed during update")
return
}
storeChannel.channel.Data.ChannelDetail = channel.Data.ChannelDetail
storeChannel.channel.Data.ChannelDetail = detail
storeChannel.channel.Data.DetailRevision = channel.Data.DetailRevision
}
}
@ -507,16 +507,16 @@ func (a *TestApp) UpdateChannel(storeChannel *TestChannel, channel *Channel) (er
} else if storeChannel.channel.Data.DetailRevision != channel.Data.DetailRevision {
params := &TestApiParams{ query: "/channel/{channelId}", path: map[string]string{ "channelId": channel.Id },
tokenType: APP_TOKENAGENT, token: a.token }
channel := Channel{}
response := &TestApiResponse{ data: &channel }
if err = TestApiRequest(GetChannel, params, response); err != nil {
detail := &ChannelDetail{}
response := &TestApiResponse{ data: &detail }
if err = TestApiRequest(GetChannelDetail, params, response); err != nil {
return
}
if channel.Data == nil {
err = errors.New("channel removed during update")
return
}
storeChannel.channel.Data.ChannelDetail = channel.Data.ChannelDetail
storeChannel.channel.Data.ChannelDetail = detail
storeChannel.channel.Data.DetailRevision = channel.Data.DetailRevision
}
}

View File

@ -9,6 +9,7 @@ import (
func TestChannelShare(t *testing.T) {
var subject *Subject
var channel *Channel
var detail *ChannelDetail
var channels *[]Channel
var cards *[]Card
aRevision := make(map[string][]string)
@ -79,13 +80,13 @@ func TestChannelShare(t *testing.T) {
assert.Nil(t, (*channels)[0].Data)
// get discovered channel
channel = &Channel{}
assert.NoError(t, ApiTestMsg(GetChannel, "GET", "/content/channels/{channelId}",
&params, nil, APP_TOKENCONTACT, set.B.A.Token, channel, nil))
assert.Equal(t, "channeldatatype", channel.Data.ChannelDetail.DataType)
assert.Equal(t, 1, len(channel.Data.ChannelDetail.Members))
assert.Equal(t, set.B.Guid, channel.Data.ChannelDetail.Members[0])
assert.Nil(t, channel.Data.ChannelDetail.Contacts)
detail = &ChannelDetail{}
assert.NoError(t, ApiTestMsg(GetChannelDetail, "GET", "/content/channels/{channelId}/detail",
&params, nil, APP_TOKENCONTACT, set.B.A.Token, detail, nil))
assert.Equal(t, "channeldatatype", detail.DataType)
assert.Equal(t, 1, len(detail.Members))
assert.Equal(t, set.B.Guid, detail.Members[0])
assert.Nil(t, detail.Contacts)
// get revision
aRev = GetTestRevision(set.A.Revisions)
@ -150,12 +151,12 @@ func TestChannelShare(t *testing.T) {
assert.Equal(t, 1, len(*channels))
// get discovered channel
channel = &Channel{}
assert.NoError(t, ApiTestMsg(GetChannel, "GET", "/content/channels/{channelId}",
&params, nil, APP_TOKENCONTACT, set.C.A.Token, channel, nil))
assert.Equal(t, "channeldatatype", channel.Data.ChannelDetail.DataType)
assert.Equal(t, 2, len(channel.Data.ChannelDetail.Members))
assert.Nil(t, channel.Data.ChannelDetail.Contacts)
detail = &ChannelDetail{}
assert.NoError(t, ApiTestMsg(GetChannelDetail, "GET", "/content/channels/{channelId}/detail",
&params, nil, APP_TOKENCONTACT, set.C.A.Token, detail, nil))
assert.Equal(t, "channeldatatype", detail.DataType)
assert.Equal(t, 2, len(detail.Members))
assert.Nil(t, detail.Contacts)
// reset notification
GetTestRevision(set.B.Revisions)

View File

@ -12,6 +12,7 @@ import (
func TestTopicShare(t *testing.T) {
var topic *Topic
var channel *Channel
var detail *ChannelDetail
var subject *Subject
params := make(map[string]string)
header := make(map[string][]string)
@ -43,17 +44,17 @@ func TestTopicShare(t *testing.T) {
&params, nil, APP_TOKENAGENT, set.A.Token, nil, nil))
// view channel
channel = &Channel{}
assert.NoError(t, ApiTestMsg(GetChannel, "GET", "/content/channels/{channelId}",
&params, nil, APP_TOKENAGENT, set.A.Token, channel, nil))
detail = &ChannelDetail{}
assert.NoError(t, ApiTestMsg(GetChannelDetail, "GET", "/content/channels/{channelId}/detail",
&params, nil, APP_TOKENAGENT, set.A.Token, detail, nil))
assert.NotNil(t, detail);
detail = &ChannelDetail{}
assert.NoError(t, ApiTestMsg(GetChannelDetail, "GET", "/content/channels/{channelId}/detail",
&params, nil, APP_TOKENCONTACT, set.B.A.Token, detail, nil))
assert.NotNil(t, channel.Data.ChannelDetail);
channel = &Channel{}
assert.NoError(t, ApiTestMsg(GetChannel, "GET", "/content/channels/{channelId}",
&params, nil, APP_TOKENCONTACT, set.B.A.Token, channel, nil))
assert.NotNil(t, channel.Data.ChannelDetail);
channel = &Channel{}
assert.NoError(t, ApiTestMsg(GetChannel, "GET", "/content/channels/{channelId}",
&params, nil, APP_TOKENCONTACT, set.B.A.Token, channel, nil))
detail = &ChannelDetail{}
assert.NoError(t, ApiTestMsg(GetChannelDetail, "GET", "/content/channels/{channelId}/detail",
&params, nil, APP_TOKENCONTACT, set.B.A.Token, detail, nil))
assert.NotNil(t, channel.Data.ChannelDetail);
params["field"] = "nested.image"
data, header, err = ApiTestData(GetChannelSubjectField, "GET", "/content/channels/{channelId}/subject/{field}",

View File

@ -18,13 +18,13 @@ export function VideoAsset({ thumbUrl, lqUrl, hdUrl }) {
}, [thumbUrl, hdUrl, lqUrl]);
const onFullScreen = () => {
updateState({ fullscreen: true, modalUrl: hdUrl, playing: false, url: null });
updateState({ inline: false, popout: true, popoutUrl: hdUrl, playing: false, inlineUrl: null });
}
const CenterButton = () => {
if (!state.loaded) {
if (!state.inline) {
return (
<div onClick={() => updateState({ loaded: true, url: lqUrl, controls: false, paused: true, playing: false })}>
<div onClick={() => updateState({ inline: true, inlineUrl: lqUrl, playing: false })}>
<SelectOutlined style={{ fontSize: 48, color: '#eeeeee', cursor: 'pointer' }} />
</div>
)
@ -46,15 +46,12 @@ export function VideoAsset({ thumbUrl, lqUrl, hdUrl }) {
}
const Controls = () => {
if (state.controls) {
return <></>;
}
return (
<div>
<div class="control">
<CenterButton />
</div>
<div class="fullscreen" onClick={() => onFullScreen()}>
<div class="expand" onClick={() => onFullScreen()}>
<ExpandOutlined style={{ fontSize: 24, color: '#eeeeee', cursor: 'pointer' }} />
</div>
</div>
@ -72,12 +69,12 @@ export function VideoAsset({ thumbUrl, lqUrl, hdUrl }) {
}}
</ReactResizeDetector>
<div class="player" style={{ width: state.width, height: state.height }}>
<ReactPlayer ref={player} controls={state.controls} playing={state.playing}
height="100%" width="100%" url={state.url} />
<ReactPlayer ref={player} controls={false} playing={state.playing}
height="100%" width="100%" url={state.inlineUrl} />
<Controls />
</div>
<Modal visible={state.fullscreen} width={'60%'} bodyStyle={{ paddingBottom: 0, paddingTop: 6, paddingLeft: 6, paddingRight: 6, backgroundColor: '#dddddd' }} footer={null} destroyOnClose={true} closable={false} onCancel={() => { updateState({ fullscreen: false, modalUrl: null })}}>
<ReactPlayer controls={true} height="100%" width="100%" url={state.modalUrl} />
<Modal visible={state.popout} width={'60%'} bodyStyle={{ paddingBottom: 0, paddingTop: 6, paddingLeft: 6, paddingRight: 6, backgroundColor: '#dddddd' }} footer={null} destroyOnClose={true} closable={false} onCancel={() => { updateState({ popout: false })}}>
<ReactPlayer controls={true} height="100%" width="100%" url={state.popoutUrl} />
</Modal>
</VideoAssetWrapper>
)

View File

@ -16,7 +16,7 @@ export const VideoAssetWrapper = styled.div`
visibility: visible;
}
.player:hover .fullscreen {
.player:hover .expand {
visibility: visible;
}
@ -38,7 +38,7 @@ export const VideoAssetWrapper = styled.div`
opacity: 0.5;
}
.fullscreen {
.expand {
padding-right: 2px;
visibility: hidden;
position: absolute;

View File

@ -1,8 +0,0 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getChannel(token, channelId) {
let channel = await fetchWithTimeout(`/content/channels/${channelId}/detail?agent=${token}`, { method: 'GET' });
checkResponse(channel)
return await channel.json()
}

View File

@ -1,8 +0,0 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getContactChannel(token, channelId) {
let channel = await fetchWithTimeout(`/content/channels/${channelId}/detail?contact=${token}`, { method: 'GET' });
checkResponse(channel)
return await channel.json()
}

View File

@ -1,6 +1,6 @@
import { useEffect, useState, useRef } from 'react';
import { getContactChannels } from 'api/getContactChannels';
import { getContactChannel } from 'api/getContactChannel';
import { getContactChannelDetail } from 'api/getContactChannelDetail';
import { getContactProfile } from 'api/getContactProfile';
import { setCardProfile } from 'api/setCardProfile';
import { getCards } from 'api/getCards';
@ -119,9 +119,9 @@ export function useCardContext() {
cur.data.detailRevision = channel.data.detailRevision;
}
else {
let slot = await getContactChannel(guid + "." + token, channel.id);
cur.data.channelDetail = slot.data.channelDetail;
cur.data.detailRevision = slot.data.detailRevision;
let detail = await getContactChannelDetail(guid + "." + token, channel.id);
cur.data.channelDetail = detail;
cur.data.detailRevision = channel.data.detailRevision;
}
}
cur.data.topicRevision = channel.data.topicRevision;

View File

@ -1,6 +1,6 @@
import { useEffect, useState, useRef } from 'react';
import { getChannels } from 'api/getChannels';
import { getChannel } from 'api/getChannel';
import { getChannelDetail } from 'api/getChannelDetail';
import { addChannel } from 'api/addChannel';
import { addChannelTopic } from 'api/addChannelTopic';
import { getChannelTopics } from 'api/getChannelTopics';
@ -35,9 +35,9 @@ export function useChannelContext() {
cur.data.detailRevision = channel.data.detailRevision;
}
else {
let slot = await getChannel(access.current, channel.id);
cur.data.channelDetail = slot.data.channelDetail;
cur.data.detailRevision = slot.data.detailRevision;
let detail = await getChannelDetail(access.current, channel.id);
cur.data.channelDetail = detail;
cur.data.detailRevision = channel.data.detailRevision;
}
}
cur.data.topicRevision = channel.data.topicRevision;