mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
refactor to prepare for channel peak data
This commit is contained in:
parent
8f8cd6eb4d
commit
0416389be0
52
doc/api.oa3
52
doc/api.oa3
@ -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':
|
||||
@ -2144,7 +2144,7 @@ paths:
|
||||
'500':
|
||||
description: internal server error
|
||||
|
||||
/content/channels/{channelId}:
|
||||
/content/channels/{channelId}:
|
||||
delete:
|
||||
tags:
|
||||
- content
|
||||
@ -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:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 &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: &ChannelDetail{
|
||||
DataType: slot.Channel.DataType,
|
||||
Data: slot.Channel.Data,
|
||||
Created: slot.Channel.Created,
|
||||
Updated: slot.Channel.Updated,
|
||||
Contacts: contacts,
|
||||
Members: members,
|
||||
},
|
||||
ChannelDetail: getChannelDetailModel(slot, showList),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -539,10 +539,10 @@ var routes = Routes{
|
||||
},
|
||||
|
||||
Route{
|
||||
"GetChannel",
|
||||
"GetChannelDetail",
|
||||
strings.ToUpper("Get"),
|
||||
"/content/channels/{channelId}/detail",
|
||||
GetChannel,
|
||||
GetChannelDetail,
|
||||
},
|
||||
|
||||
Route{
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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}",
|
||||
¶ms, 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",
|
||||
¶ms, 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}",
|
||||
¶ms, 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",
|
||||
¶ms, 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)
|
||||
|
@ -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) {
|
||||
¶ms, nil, APP_TOKENAGENT, set.A.Token, nil, nil))
|
||||
|
||||
// view channel
|
||||
channel = &Channel{}
|
||||
assert.NoError(t, ApiTestMsg(GetChannel, "GET", "/content/channels/{channelId}",
|
||||
¶ms, nil, APP_TOKENAGENT, set.A.Token, channel, nil))
|
||||
detail = &ChannelDetail{}
|
||||
assert.NoError(t, ApiTestMsg(GetChannelDetail, "GET", "/content/channels/{channelId}/detail",
|
||||
¶ms, nil, APP_TOKENAGENT, set.A.Token, detail, nil))
|
||||
assert.NotNil(t, detail);
|
||||
detail = &ChannelDetail{}
|
||||
assert.NoError(t, ApiTestMsg(GetChannelDetail, "GET", "/content/channels/{channelId}/detail",
|
||||
¶ms, 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}",
|
||||
¶ms, 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}",
|
||||
¶ms, nil, APP_TOKENCONTACT, set.B.A.Token, channel, nil))
|
||||
detail = &ChannelDetail{}
|
||||
assert.NoError(t, ApiTestMsg(GetChannelDetail, "GET", "/content/channels/{channelId}/detail",
|
||||
¶ms, 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}",
|
||||
|
@ -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>
|
||||
)
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user