agora-appbuilder-core 4.1.3 → 4.1.4-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/customization-api/utils.ts +1 -0
- package/template/defaultConfig.js +2 -2
- package/template/src/SDKAppWrapper.tsx +2 -0
- package/template/src/components/EventsConfigure.tsx +7 -2
- package/template/src/components/SdkApiContext.tsx +1 -0
- package/template/src/components/participants/UserActionMenuOptions.tsx +14 -9
- package/template/src/components/room-info/useRoomInfo.tsx +1 -0
- package/template/src/language/default-labels/videoCallScreenLabels.ts +2 -2
- package/template/src/logger/AppBuilderLogger.tsx +2 -1
- package/template/src/utils/SdkEvents.ts +1 -0
- package/template/src/utils/SdkMethodEvents.ts +1 -0
- package/template/src/utils/useJoinRoom.ts +1 -0
- package/template/src/utils/useRemoteEndCall.ts +4 -1
- package/template/src/utils/useUserBan.ts +113 -0
package/package.json
CHANGED
|
@@ -55,3 +55,4 @@ export {useActionSheet} from '../src/utils/useActionSheet';
|
|
|
55
55
|
export {default as PlatformWrapper} from '../src/utils/PlatformWrapper';
|
|
56
56
|
export {useSpotlight} from '../src/utils/useSpotlight';
|
|
57
57
|
export {useActiveUids} from '../src/utils/useActiveUids';
|
|
58
|
+
export {default as useUserBan} from '../src/utils/useUserBan';
|
|
@@ -76,8 +76,8 @@ const DefaultConfig = {
|
|
|
76
76
|
CHAT_ORG_NAME: '',
|
|
77
77
|
CHAT_APP_NAME: '',
|
|
78
78
|
CHAT_URL: '',
|
|
79
|
-
CLI_VERSION: '3.1.
|
|
80
|
-
CORE_VERSION: '4.1.
|
|
79
|
+
CLI_VERSION: '3.1.4-beta.1',
|
|
80
|
+
CORE_VERSION: '4.1.4-beta.1',
|
|
81
81
|
DISABLE_LANDSCAPE_MODE: false,
|
|
82
82
|
STT_AUTO_START: false,
|
|
83
83
|
CLOUD_RECORDING_AUTO_START: false,
|
|
@@ -24,6 +24,7 @@ export interface AppBuilderSdkApiInterface {
|
|
|
24
24
|
preference?: {
|
|
25
25
|
disableShareTile: boolean;
|
|
26
26
|
disableVideoProcessors: boolean;
|
|
27
|
+
userRemovalTimeout: number;
|
|
27
28
|
},
|
|
28
29
|
) => Promise<meetingData>;
|
|
29
30
|
joinPrecall: (
|
|
@@ -33,6 +34,7 @@ export interface AppBuilderSdkApiInterface {
|
|
|
33
34
|
preference?: {
|
|
34
35
|
disableShareTile: boolean;
|
|
35
36
|
disableVideoProcessors: boolean;
|
|
37
|
+
userRemovalTimeout: number;
|
|
36
38
|
},
|
|
37
39
|
) => Promise<
|
|
38
40
|
[
|
|
@@ -244,6 +244,7 @@ const EventsConfigure: React.FC<Props> = ({
|
|
|
244
244
|
}, [defaultContent]);
|
|
245
245
|
const {
|
|
246
246
|
data: {isHost, roomId},
|
|
247
|
+
roomPreference: {userRemovalTimeout},
|
|
247
248
|
} = useRoomInfo();
|
|
248
249
|
const {setRoomInfo} = useSetRoomInfo();
|
|
249
250
|
const isHostRef = React.useRef(isHost);
|
|
@@ -402,9 +403,13 @@ const EventsConfigure: React.FC<Props> = ({
|
|
|
402
403
|
primaryBtn: null,
|
|
403
404
|
secondaryBtn: null,
|
|
404
405
|
});
|
|
405
|
-
|
|
406
|
+
if (userRemovalTimeout > 0) {
|
|
407
|
+
setTimeout(() => {
|
|
408
|
+
executeEndCall();
|
|
409
|
+
}, userRemovalTimeout);
|
|
410
|
+
} else {
|
|
406
411
|
executeEndCall();
|
|
407
|
-
}
|
|
412
|
+
}
|
|
408
413
|
});
|
|
409
414
|
|
|
410
415
|
events.on(controlMessageEnum.requestAudio, () => {
|
|
@@ -100,6 +100,7 @@ export default function UserActionMenuOptionsOptions(
|
|
|
100
100
|
const {hostUids, audienceUids} = useLiveStreamDataContext();
|
|
101
101
|
const {
|
|
102
102
|
data: {isHost},
|
|
103
|
+
roomPreference: {userRemovalTimeout},
|
|
103
104
|
} = useRoomInfo();
|
|
104
105
|
const remoteRequest = useRemoteRequest();
|
|
105
106
|
const remoteMute = useRemoteMute();
|
|
@@ -516,15 +517,19 @@ export default function UserActionMenuOptionsOptions(
|
|
|
516
517
|
setModalVisible={setRemoveMeetingPopupVisible}
|
|
517
518
|
username={user.name}
|
|
518
519
|
removeUserFromMeeting={() => {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
520
|
+
userRemovalTimeout > 0 &&
|
|
521
|
+
Toast.show({
|
|
522
|
+
leadingIconName: 'info',
|
|
523
|
+
type: 'info',
|
|
524
|
+
text1: toastlabel(
|
|
525
|
+
trimText(user.name),
|
|
526
|
+
userRemovalTimeout / 1000,
|
|
527
|
+
),
|
|
528
|
+
visibilityTime: 5000,
|
|
529
|
+
primaryBtn: null,
|
|
530
|
+
secondaryBtn: null,
|
|
531
|
+
leadingIcon: null,
|
|
532
|
+
});
|
|
528
533
|
endRemoteCall(user.uid);
|
|
529
534
|
}}
|
|
530
535
|
/>
|
|
@@ -1189,8 +1189,8 @@ export const VideoCallScreenLabels: I18nVideoCallScreenLabelsInterface = {
|
|
|
1189
1189
|
[peoplePanelMeText]: 'Me',
|
|
1190
1190
|
[peoplePanelPresenterText]: 'Presenter',
|
|
1191
1191
|
|
|
1192
|
-
[userRemovedFromTheRoomToastHeading]: name =>
|
|
1193
|
-
`The system will remove ${name} from this call after
|
|
1192
|
+
[userRemovedFromTheRoomToastHeading]: (name, time) =>
|
|
1193
|
+
`The system will remove ${name} from this call after ${time} secs.`,
|
|
1194
1194
|
|
|
1195
1195
|
[vbPanelImageUploadErrorToastHeading]: 'Upload Failed',
|
|
1196
1196
|
[vbPanelImageUploadErrorToastSubHeading]:
|
|
@@ -103,7 +103,8 @@ type LogType = {
|
|
|
103
103
|
| 'recording_start'
|
|
104
104
|
| 'recording_stop'
|
|
105
105
|
| 'recordings_get'
|
|
106
|
-
| 'recording_delete'
|
|
106
|
+
| 'recording_delete'
|
|
107
|
+
| 'ban_user';
|
|
107
108
|
[LogSource.Events]: 'CUSTOM_EVENTS' | 'RTM_EVENTS';
|
|
108
109
|
[LogSource.CustomizationAPI]:
|
|
109
110
|
| 'Log'
|
|
@@ -49,6 +49,7 @@ export interface userEventsMapInterface {
|
|
|
49
49
|
'will-token-expire': () => void;
|
|
50
50
|
'did-token-expire': () => void;
|
|
51
51
|
'token-refreshed': () => void;
|
|
52
|
+
'rtc-user-removed': (uid: UidType, channel: string) => void;
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
const SDKEvents = createNanoEvents<userEventsMapInterface>();
|
|
@@ -3,13 +3,14 @@ import {useRoomInfo} from '../components/room-info/useRoomInfo';
|
|
|
3
3
|
import useIsPSTN from './useIsPSTN';
|
|
4
4
|
import {UidType} from '../../agora-rn-uikit';
|
|
5
5
|
import events, {PersistanceLevel} from '../rtm-events-api';
|
|
6
|
+
import SDKEvents from './SdkEvents';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Returns a function to end the call for a remote user with the given uid.
|
|
9
10
|
*/
|
|
10
11
|
const useRemoteEndCall = () => {
|
|
11
12
|
const {
|
|
12
|
-
data: {isHost},
|
|
13
|
+
data: {isHost, channel},
|
|
13
14
|
} = useRoomInfo();
|
|
14
15
|
const isPSTN = useIsPSTN();
|
|
15
16
|
|
|
@@ -22,6 +23,8 @@ const useRemoteEndCall = () => {
|
|
|
22
23
|
PersistanceLevel.None,
|
|
23
24
|
uid,
|
|
24
25
|
);
|
|
26
|
+
// Also Send the SDK event for wrapper app to add extra functinalities like banning user;
|
|
27
|
+
SDKEvents.emit('rtc-user-removed', uid, channel);
|
|
25
28
|
}
|
|
26
29
|
} else {
|
|
27
30
|
console.error('A host can only remove the audience from the call.');
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/*
|
|
2
|
+
********************************************
|
|
3
|
+
Copyright © 2021 Agora Lab, Inc., all rights reserved.
|
|
4
|
+
AppBuilder and all associated components, source code, APIs, services, and documentation
|
|
5
|
+
(the “Materials”) are owned by Agora Lab, Inc. and its licensors. The Materials may not be
|
|
6
|
+
accessed, used, modified, or distributed for any purpose without a license from Agora Lab, Inc.
|
|
7
|
+
Use without a license or in violation of any license terms and conditions (including use for
|
|
8
|
+
any purpose competitive to Agora Lab, Inc.’s business) is strictly prohibited. For more
|
|
9
|
+
information visit https://appbuilder.agora.io.
|
|
10
|
+
*********************************************
|
|
11
|
+
*/
|
|
12
|
+
import React from 'react';
|
|
13
|
+
import {logger, LogSource} from '../logger/AppBuilderLogger';
|
|
14
|
+
import {UidType} from '../../agora-rn-uikit';
|
|
15
|
+
import getUniqueID from './getUniqueID';
|
|
16
|
+
import StorageContext from '../components/StorageContext';
|
|
17
|
+
import {useRoomInfo} from 'customization-api';
|
|
18
|
+
|
|
19
|
+
type BanUserPrivilegesResponse = {
|
|
20
|
+
success: boolean;
|
|
21
|
+
message: string;
|
|
22
|
+
data?: any;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Bans specific user privileges in the channel.
|
|
27
|
+
* @param hostMeetingId - host meeting id.
|
|
28
|
+
* @param channel - channel from which to ban the user.
|
|
29
|
+
* @param uid - user id to ban.
|
|
30
|
+
* @param duration - how long to ban user in minutes - min 1 max 1440
|
|
31
|
+
* @param privileges - list of privileges to ban. default is ['join_channel', 'publish_audio', 'publish_video']
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
function useUserBan() {
|
|
35
|
+
const {store} = React.useContext(StorageContext);
|
|
36
|
+
const {
|
|
37
|
+
data: {roomId},
|
|
38
|
+
} = useRoomInfo();
|
|
39
|
+
const BAN_API_URL = `${$config.BACKEND_ENDPOINT}/v1/channel/user/ban`;
|
|
40
|
+
|
|
41
|
+
// duration - how long to ban user in minutes - min 1 max 1440
|
|
42
|
+
const banUserPrivileges = async (
|
|
43
|
+
hostMeetingID: string,
|
|
44
|
+
channel: string,
|
|
45
|
+
uid: UidType,
|
|
46
|
+
duration: number,
|
|
47
|
+
privileges: string[] = ['join_channel', 'publish_audio', 'publish_video'],
|
|
48
|
+
): Promise<BanUserPrivilegesResponse> => {
|
|
49
|
+
if (!uid || !duration || duration < 1 || duration > 1440) {
|
|
50
|
+
logger.error(
|
|
51
|
+
LogSource.NetworkRest,
|
|
52
|
+
'ban_user',
|
|
53
|
+
`Invalid parameters: uid=${uid}, duration=${duration}`,
|
|
54
|
+
);
|
|
55
|
+
return {success: false, message: 'Invalid user ID or duration'};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const requestId = getUniqueID();
|
|
59
|
+
logger.log(
|
|
60
|
+
LogSource.NetworkRest,
|
|
61
|
+
'ban_user',
|
|
62
|
+
`Trying to ban user with id ${uid} in channel : ${channel}`,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const payload = {
|
|
66
|
+
passphrase: hostMeetingID || roomId?.host,
|
|
67
|
+
uid: uid,
|
|
68
|
+
channel_name: channel,
|
|
69
|
+
duration: duration,
|
|
70
|
+
privileges: privileges,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const response = await fetch(BAN_API_URL, {
|
|
75
|
+
method: 'POST',
|
|
76
|
+
headers: {
|
|
77
|
+
'Content-Type': 'application/json',
|
|
78
|
+
authorization: store?.token ? `Bearer ${store.token}` : '',
|
|
79
|
+
'X-Request-Id': requestId,
|
|
80
|
+
'X-Session-Id': logger.getSessionId(),
|
|
81
|
+
},
|
|
82
|
+
body: JSON.stringify(payload),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
if (!response.ok && response.status != 200) {
|
|
86
|
+
const errorText = await response.text();
|
|
87
|
+
logger.error(
|
|
88
|
+
LogSource.NetworkRest,
|
|
89
|
+
'ban_user',
|
|
90
|
+
`Failed to ban user with id ${uid}`,
|
|
91
|
+
errorText,
|
|
92
|
+
);
|
|
93
|
+
return {success: false, message: errorText};
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
success: true,
|
|
97
|
+
message: 'User privileges banned successfully',
|
|
98
|
+
};
|
|
99
|
+
} catch (error) {
|
|
100
|
+
logger.error(
|
|
101
|
+
LogSource.NetworkRest,
|
|
102
|
+
'ban_user',
|
|
103
|
+
`Error while trying to ban user with id ${uid}`,
|
|
104
|
+
error,
|
|
105
|
+
);
|
|
106
|
+
return {success: false, message: 'Error while banning the user'};
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return banUserPrivileges;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export default useUserBan;
|