mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
support conversation removal
This commit is contained in:
parent
1dc80fdb95
commit
e31c973963
@ -2179,7 +2179,7 @@ paths:
|
|||||||
delete:
|
delete:
|
||||||
tags:
|
tags:
|
||||||
- content
|
- content
|
||||||
description: Remove specified channel. Access granted to app token of account holder.
|
description: Remove specified channel or membership. When invoked by account holder, channel is removed. When invoked by member, membership is removed.
|
||||||
operationId: remove-channel
|
operationId: remove-channel
|
||||||
security:
|
security:
|
||||||
- bearerAuth: []
|
- bearerAuth: []
|
||||||
@ -3862,4 +3862,3 @@ components:
|
|||||||
scheme: bearer
|
scheme: bearer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,15 +9,33 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func RemoveChannel(w http.ResponseWriter, r *http.Request) {
|
func RemoveChannel(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var err error
|
||||||
|
var code int
|
||||||
|
|
||||||
// scan parameters
|
// scan parameters
|
||||||
params := mux.Vars(r)
|
params := mux.Vars(r)
|
||||||
channelId := params["channelId"]
|
channelId := params["channelId"]
|
||||||
|
|
||||||
// validate contact access
|
// validate contact access
|
||||||
account, code, err := BearerAppToken(r, false)
|
var account *store.Account
|
||||||
if err != nil {
|
var contact *store.Card
|
||||||
ErrResponse(w, code, err)
|
tokenType := ParamTokenType(r);
|
||||||
|
if tokenType == APP_TOKENAGENT {
|
||||||
|
account, code, err = ParamAgentToken(r, false);
|
||||||
|
if err != nil {
|
||||||
|
ErrResponse(w, code, err);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if tokenType == APP_TOKENCONTACT {
|
||||||
|
contact, code, err = ParamContactToken(r, true)
|
||||||
|
if err != nil {
|
||||||
|
ErrResponse(w, code, err);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
account = &contact.Account
|
||||||
|
} else {
|
||||||
|
err = errors.New("unknown token type")
|
||||||
|
code = http.StatusBadRequest
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,50 +65,79 @@ func RemoveChannel(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = store.DB.Transaction(func(tx *gorm.DB) error {
|
if contact == nil {
|
||||||
if res := tx.Model(&slot.Channel).Association("Groups").Clear(); res != nil {
|
err = store.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
return res
|
if res := tx.Model(&slot.Channel).Association("Groups").Clear(); res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
slot.Channel.Groups = []store.Group{}
|
||||||
|
if res := tx.Model(&slot.Channel).Association("Cards").Clear(); res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
slot.Channel.Cards = []store.Card{}
|
||||||
|
if res := tx.Where("channel_id = ?", slot.Channel.ID).Delete(&store.Tag{}).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
if res := tx.Where("channel_id = ?", slot.Channel.ID).Delete(&store.TagSlot{}).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
if res := tx.Where("channel_id = ?", slot.Channel.ID).Delete(&store.Asset{}).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
if res := tx.Where("channel_id = ?", slot.Channel.ID).Delete(&store.Topic{}).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
if res := tx.Where("channel_id = ?", slot.Channel.ID).Delete(&store.TopicSlot{}).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
slot.Channel.Topics = []store.Topic{}
|
||||||
|
if res := tx.Delete(&slot.Channel).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
slot.Channel = nil
|
||||||
|
if res := tx.Model(&slot).Update("channel_id", 0).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
if res := tx.Model(&slot).Update("revision", account.ChannelRevision + 1).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
if res := tx.Model(account).Update("channel_revision", account.ChannelRevision + 1).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ErrResponse(w, http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
slot.Channel.Groups = []store.Group{}
|
|
||||||
if res := tx.Model(&slot.Channel).Association("Cards").Clear(); res != nil {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
slot.Channel.Cards = []store.Card{}
|
|
||||||
if res := tx.Where("channel_id = ?", slot.Channel.ID).Delete(&store.Tag{}).Error; res != nil {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
if res := tx.Where("channel_id = ?", slot.Channel.ID).Delete(&store.TagSlot{}).Error; res != nil {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
if res := tx.Where("channel_id = ?", slot.Channel.ID).Delete(&store.Asset{}).Error; res != nil {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
if res := tx.Where("channel_id = ?", slot.Channel.ID).Delete(&store.Topic{}).Error; res != nil {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
if res := tx.Where("channel_id = ?", slot.Channel.ID).Delete(&store.TopicSlot{}).Error; res != nil {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
slot.Channel.Topics = []store.Topic{}
|
|
||||||
if res := tx.Delete(&slot.Channel).Error; res != nil {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
slot.Channel = nil
|
|
||||||
if res := tx.Model(&slot).Update("revision", account.ChannelRevision + 1).Error; res != nil {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
if res := tx.Model(account).Update("channel_revision", account.ChannelRevision + 1).Error; res != nil {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
ErrResponse(w, http.StatusInternalServerError, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// cleanup file assets
|
// cleanup file assets
|
||||||
go garbageCollect(account)
|
go garbageCollect(account)
|
||||||
|
} else {
|
||||||
|
if _, member := cards[contact.Guid]; !member {
|
||||||
|
ErrResponse(w, http.StatusNotFound, errors.New("member channel not found"));
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = store.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
|
if res := tx.Model(&slot.Channel).Association("Cards").Delete(contact); res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
if res := tx.Model(&slot.Channel).Update("detail_revision", account.ChannelRevision + 1).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
if res := tx.Model(&slot).Update("revision", account.ChannelRevision + 1).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
if res := tx.Model(&account).Update("channel_revision", account.ChannelRevision + 1).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ErrResponse(w, http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SetStatus(account)
|
SetStatus(account)
|
||||||
for _, card := range cards {
|
for _, card := range cards {
|
||||||
|
@ -51,9 +51,6 @@ type AccountToken struct {
|
|||||||
Account *Account
|
Account *Account
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: card & app reference account by guid, all other tables by id
|
|
||||||
// because token lookup uses guid and is most common and wanted to avoid join
|
|
||||||
// int foreign key should be faster, so left other tables with id reference
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
ID uint `gorm:"primaryKey;not null;unique;autoIncrement"`
|
ID uint `gorm:"primaryKey;not null;unique;autoIncrement"`
|
||||||
AccountDetailID uint `gorm:"not null"`
|
AccountDetailID uint `gorm:"not null"`
|
||||||
|
2
net/server/transform/transform_vhd.sh
Executable file
2
net/server/transform/transform_vhd.sh
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
ffmpeg -i $1 -y -f mp4 -map_metadata -1 -vf scale=720:-2 -c:v libx264 -crf 23 -preset veryfast -c:a aac $2
|
3
net/server/transform/transform_vlq.sh
Executable file
3
net/server/transform/transform_vlq.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
ffmpeg -i $1 -y -f mp4 -map_metadata -1 -vf scale=320:-2 -c:v libx264 -crf 32 -preset veryfast -c:a aac $2
|
||||||
|
|
2
net/server/transform/transform_vsd.sh
Executable file
2
net/server/transform/transform_vsd.sh
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
ffmpeg -i $1 -y -f mp4 -map_metadata -1 -vf scale=640:-2 -vcodec libx265 -crf 32 -preset veryfast -tag:v hvc1 -acodec aac $2
|
@ -0,0 +1,63 @@
|
|||||||
|
import React, { useEffect, useState, useRef } from 'react';
|
||||||
|
import ReactPlayer from 'react-player'
|
||||||
|
import ReactResizeDetector from 'react-resize-detector';
|
||||||
|
import { RightOutlined, LeftOutlined } from '@ant-design/icons';
|
||||||
|
import { VideoFileWrapper, LabelInput } from './VideoFile.styled';
|
||||||
|
|
||||||
|
export function VideoFile({ url, onPosition }) {
|
||||||
|
|
||||||
|
const [state, setState] = useState({ width: 0, height: 0 });
|
||||||
|
const [playing, setPlaying] = useState(false);
|
||||||
|
const player = useRef(null);
|
||||||
|
const seek = useRef(0);
|
||||||
|
|
||||||
|
const updateState = (value) => {
|
||||||
|
setState((s) => ({ ...s, ...value }));
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSeek = (offset) => {
|
||||||
|
if (player.current) {
|
||||||
|
let len = player.current.getDuration();
|
||||||
|
seek.current += offset;
|
||||||
|
if (seek.current < 0 || seek.current >= len) {
|
||||||
|
seek.current = 0;
|
||||||
|
}
|
||||||
|
onPosition(seek.current);
|
||||||
|
player.current.seekTo(seek.current, 'seconds');
|
||||||
|
setPlaying(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPause = () => {
|
||||||
|
setPlaying(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<VideoFileWrapper>
|
||||||
|
<ReactResizeDetector handleWidth={true} handleHeight={true}>
|
||||||
|
{({ width, height }) => {
|
||||||
|
if (width != state.width || height != state.height) {
|
||||||
|
updateState({ width, height });
|
||||||
|
}
|
||||||
|
return <ReactPlayer ref={player} playing={playing} playbackRate={0} controls={false} height="100%" width="auto" url={url}
|
||||||
|
onStart={() => onPause()} onPlay={() => onPause()} />
|
||||||
|
}}
|
||||||
|
</ReactResizeDetector>
|
||||||
|
<div class="overlay" style={{ width: state.width, height: state.height }}>
|
||||||
|
<div class="control">
|
||||||
|
<div class="left">
|
||||||
|
<div class="icon" onClick={() => onSeek(-1)}>
|
||||||
|
<LeftOutlined style={{ fontSize: 32, color: '#eeeeee' }} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<div class="icon" onClick={() => onSeek(1)}>
|
||||||
|
<RightOutlined style={{ fontSize: 32, color: '#eeeeee' }} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</VideoFileWrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
export const VideoFileWrapper = styled.div`
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.control {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
width: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
width: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef } from 'react'
|
|||||||
import { CloseOutlined, UserOutlined } from '@ant-design/icons';
|
import { CloseOutlined, UserOutlined } from '@ant-design/icons';
|
||||||
import { useConversation } from './useConversation.hook';
|
import { useConversation } from './useConversation.hook';
|
||||||
import { Button, Checkbox, Modal, Spin } from 'antd'
|
import { Button, Checkbox, Modal, Spin } from 'antd'
|
||||||
import { ConversationWrapper, CloseButton, ListItem, BusySpin } from './Conversation.styled';
|
import { ConversationWrapper, ConversationButton, CloseButton, ListItem, BusySpin } from './Conversation.styled';
|
||||||
import { AutoSizer, CellMeasurer, CellMeasurerCache, List } from 'react-virtualized';
|
import { AutoSizer, CellMeasurer, CellMeasurerCache, List } from 'react-virtualized';
|
||||||
import { AddTopic } from './AddTopic/AddTopic';
|
import { AddTopic } from './AddTopic/AddTopic';
|
||||||
import { VirtualList } from '../../VirtualList/VirtualList';
|
import { VirtualList } from '../../VirtualList/VirtualList';
|
||||||
@ -19,7 +19,10 @@ export function Conversation() {
|
|||||||
return (
|
return (
|
||||||
<ConversationWrapper>
|
<ConversationWrapper>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="title">{ state.handle }</div>
|
<div class="title"></div>
|
||||||
|
<div class="buttons">
|
||||||
|
<ConversationButton ghost onClick={() => actions.remove()}>Remove Conversation</ConversationButton>
|
||||||
|
</div>
|
||||||
<CloseButton type="text" class="close" size={'large'}
|
<CloseButton type="text" class="close" size={'large'}
|
||||||
onClick={() => actions.close()} icon={<CloseOutlined />} />
|
onClick={() => actions.close()} icon={<CloseOutlined />} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,6 +34,13 @@ export const ConversationWrapper = styled.div`
|
|||||||
padding-left: 16px;
|
padding-left: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-right: 32px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.close {
|
.close {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
color: white;
|
color: white;
|
||||||
@ -49,6 +56,12 @@ export const ConversationWrapper = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const ConversationButton = styled(Button)`
|
||||||
|
text-align: center;
|
||||||
|
margin-left: 8px;
|
||||||
|
margin-right: 8px;
|
||||||
|
`
|
||||||
|
|
||||||
export const CloseButton = styled(Button)`
|
export const CloseButton = styled(Button)`
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
color: white;
|
color: white;
|
||||||
|
@ -25,6 +25,10 @@ export function useConversation() {
|
|||||||
close: () => {
|
close: () => {
|
||||||
navigate('/user')
|
navigate('/user')
|
||||||
},
|
},
|
||||||
|
remove: async () => {
|
||||||
|
await conversation.actions.removeConversation();
|
||||||
|
navigate('/user');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -32,8 +32,7 @@ export function ChannelLogo({ item }) {
|
|||||||
}
|
}
|
||||||
setMembers(contacts);
|
setMembers(contacts);
|
||||||
}
|
}
|
||||||
|
}, [item?.data?.channelDetail?.members, state]);
|
||||||
}, [item, state]);
|
|
||||||
|
|
||||||
const Logo = ({card}) => {
|
const Logo = ({card}) => {
|
||||||
if (card?.data?.cardProfile?.imageSet) {
|
if (card?.data?.cardProfile?.imageSet) {
|
||||||
|
8
net/web/src/api/removeChannel.js
Normal file
8
net/web/src/api/removeChannel.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||||
|
|
||||||
|
export async function removeChannel(token, channelId) {
|
||||||
|
|
||||||
|
let channel = await fetchWithTimeout(`/content/channels/${channelId}?agent=${token}`,
|
||||||
|
{ method: 'DELETE' });
|
||||||
|
checkResponse(channel);
|
||||||
|
}
|
8
net/web/src/api/removeContactChannel.js
Normal file
8
net/web/src/api/removeContactChannel.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||||
|
|
||||||
|
export async function removeContactChannel(server, token, channelId) {
|
||||||
|
|
||||||
|
let channel = await fetchWithTimeout(`https://${server}/content/channels/${channelId}?contact=${token}`,
|
||||||
|
{ method: 'DELETE' });
|
||||||
|
checkResponse(channel);
|
||||||
|
}
|
@ -8,6 +8,7 @@ import { getCards } from 'api/getCards';
|
|||||||
import { getCardImageUrl } from 'api/getCardImageUrl';
|
import { getCardImageUrl } from 'api/getCardImageUrl';
|
||||||
import { getCardProfile } from 'api/getCardProfile';
|
import { getCardProfile } from 'api/getCardProfile';
|
||||||
import { getCardDetail } from 'api/getCardDetail';
|
import { getCardDetail } from 'api/getCardDetail';
|
||||||
|
import { removeContactChannel } from 'api/removeContactChannel';
|
||||||
import { addContactChannelTopic } from 'api/addContactChannelTopic';
|
import { addContactChannelTopic } from 'api/addContactChannelTopic';
|
||||||
import { setCardConnecting, setCardConnected, setCardConfirmed } from 'api/setCardStatus';
|
import { setCardConnecting, setCardConnected, setCardConfirmed } from 'api/setCardStatus';
|
||||||
import { getCardOpenMessage } from 'api/getCardOpenMessage';
|
import { getCardOpenMessage } from 'api/getCardOpenMessage';
|
||||||
@ -207,6 +208,12 @@ export function useCardContext() {
|
|||||||
}
|
}
|
||||||
return getCardImageUrl(access.current, cardId, card.data.profileRevision)
|
return getCardImageUrl(access.current, cardId, card.data.profileRevision)
|
||||||
},
|
},
|
||||||
|
removeChannel: async (cardId, channelId) => {
|
||||||
|
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
|
||||||
|
let token = cardProfile.guid + '.' + cardDetail.token;
|
||||||
|
let node = cardProfile.node;
|
||||||
|
await removeContactChannel(node, token, channelId);
|
||||||
|
},
|
||||||
addChannelTopic: async (cardId, channelId, message, assets) => {
|
addChannelTopic: async (cardId, channelId, message, assets) => {
|
||||||
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
|
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
|
||||||
let token = cardProfile.guid + '.' + cardDetail.token;
|
let token = cardProfile.guid + '.' + cardDetail.token;
|
||||||
|
@ -3,6 +3,7 @@ import { getChannels } from 'api/getChannels';
|
|||||||
import { getChannelDetail } from 'api/getChannelDetail';
|
import { getChannelDetail } from 'api/getChannelDetail';
|
||||||
import { getChannelSummary } from 'api/getChannelSummary';
|
import { getChannelSummary } from 'api/getChannelSummary';
|
||||||
import { addChannel } from 'api/addChannel';
|
import { addChannel } from 'api/addChannel';
|
||||||
|
import { removeChannel } from 'api/removeChannel';
|
||||||
import { addChannelTopic } from 'api/addChannelTopic';
|
import { addChannelTopic } from 'api/addChannelTopic';
|
||||||
import { getChannelTopics } from 'api/getChannelTopics';
|
import { getChannelTopics } from 'api/getChannelTopics';
|
||||||
import { getChannelTopic } from 'api/getChannelTopic';
|
import { getChannelTopic } from 'api/getChannelTopic';
|
||||||
@ -88,6 +89,9 @@ export function useChannelContext() {
|
|||||||
addChannel: async (cards, subject, description) => {
|
addChannel: async (cards, subject, description) => {
|
||||||
return await addChannel(access.current, cards, subject, description);
|
return await addChannel(access.current, cards, subject, description);
|
||||||
},
|
},
|
||||||
|
removeChannel: async (channelId) => {
|
||||||
|
return await removeChannel(access.current, channelId);
|
||||||
|
},
|
||||||
addChannelTopic: async (channelId, message, assets) => {
|
addChannelTopic: async (channelId, message, assets) => {
|
||||||
await addChannelTopic(access.current, channelId, message, assets);
|
await addChannelTopic(access.current, channelId, message, assets);
|
||||||
},
|
},
|
||||||
|
@ -30,6 +30,10 @@ export function useConversationContext() {
|
|||||||
|
|
||||||
if (cardId) {
|
if (cardId) {
|
||||||
let deltaRevision = card.actions.getChannelRevision(cardId, channelId);
|
let deltaRevision = card.actions.getChannelRevision(cardId, channelId);
|
||||||
|
if (!deltaRevision) {
|
||||||
|
window.alert("This converstaion has been removed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (curRevision != deltaRevision) {
|
if (curRevision != deltaRevision) {
|
||||||
let delta = await card.actions.getChannelTopics(cardId, channelId, curRevision);
|
let delta = await card.actions.getChannelTopics(cardId, channelId, curRevision);
|
||||||
for (let topic of delta) {
|
for (let topic of delta) {
|
||||||
@ -163,7 +167,16 @@ export function useConversationContext() {
|
|||||||
else {
|
else {
|
||||||
return channel.actions.getChannelTopicAssetUrl(channelId, topicId, assetId);
|
return channel.actions.getChannelTopicAssetUrl(channelId, topicId, assetId);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
removeConversation: async () => {
|
||||||
|
const { cardId, channelId } = conversationId.current;
|
||||||
|
if (cardId) {
|
||||||
|
return await card.actions.removeChannel(cardId, channelId);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return await channel.actions.removeChannel(channelId);
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions }
|
||||||
|
Loading…
Reference in New Issue
Block a user