Files
OSIT-AE-App-Svelte/static/jitsi_iframe_api.html

278 lines
15 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OSIT Jitsi Meetings API Example Template Page</title>
</head>
<body>
<!-- IMPORTANT: This HTML page can be used in an iframe or directly as a page to host Jitsi meetings using the Jitsi Meet External API with JWT authentication. -->
<!-- <p>The URL parameters are passed from the Novi page that contains this as an iframe. This will automatically set the attendees name, email address, moderator status, and room name. The moderator status is based on the Novi UUID. This message will be hidden before going live.</p> -->
<div id="jitsi_meet_external_api_container" style="height: 750px; width: 100%"></div>
<script src="https://jitsi.dgrzone.com/external_api.js"></script>
<script lang="ts">
/* BEGIN: IDAA and Novi specific */
// Partial example of the URL params passed to this iframe from the Novi page:
// ?uuid=${novi_customer_uid}&email=${novi_current_user_obj.Email}&full_name=${full_name}&moderator=${is_moderator}&room=${room_name}&iframe=true&key=${idaa_osit_site_key}&incoming_msg_sound=${incoming_msg_sound}&participant_joined_sound=${participant_joined_sound}&participant_left_sound=${participant_left_sound}&reaction_sound=${reaction_sound}`
let novi_api_root_url = 'https://www.idaa.org/api';
// let novi_api_key_for_idaa = 'abc123';
let novi_api_key_for_idaa = 'CmNdWgdPmgluBWjiTd8xsUCk5mio8F1O9DYAh0pVDcg=';
// Get user info from URL parameters. Generated by the Novi page that contains this iframe.
let novi_url_params = new URLSearchParams(document.location.search);
let novi_api_headers = new Headers();
novi_api_headers.append('Authorization', `Basic ${novi_api_key_for_idaa}`);
let requestOptions = {
method: 'GET',
headers: novi_api_headers,
redirect: 'follow'
};
let novi_customer_uid = novi_url_params.get('uuid');
let novi_api_get_customer_endpoint = `${novi_api_root_url}/customers/${novi_customer_uid}`;
console.log(novi_api_get_customer_endpoint);
fetch(novi_api_get_customer_endpoint, requestOptions)
.then((response) => response.json())
.then((result) => {
novi_current_user_obj = result;
// console.log(`Novi's Current User Obj:`, novi_current_user_obj);
console.log(`Novi's Current User Obj (${novi_current_user_obj.Email}):`, novi_current_user_obj);
let full_name = novi_current_user_obj?.Name;
let first_name = novi_current_user_obj?.FirstName;
let last_initial = novi_current_user_obj?.LastName
? novi_current_user_obj.LastName.charAt(0).toUpperCase() + '.'
: '';
if (last_initial) {
full_name = `${first_name} ${last_initial}`;
}
console.log(`Novi's Current User's Full Name: ${full_name}`);
let email = novi_current_user_obj?.Email;
console.log(`Novi's Current User's Email: ${email}`);
// We may need to remove or change a parameter passed here after using it.
// url.searchParams.delete('any_param_you_want_to_remove');
// history.pushState({}, '', url);
})
.catch((error) => console.log('error', error));
let novi_user_id = novi_url_params.get('uuid');
let novi_user_full_name = novi_url_params.get('full_name');
let novi_user_email = novi_url_params.get('email');
// I need to think of a better way to flag moderators if this is being used with Novi in an iframe.
// Temporarily hard coding moderators:
// 5724aad7-6d89-47e7-8943-966fd22911bd = Steven L. Klein - Stevenklein425@gmail.com
// 182d1db3-caa9-41bc-b04a-2facc6859aeb = Melissa Eve Valasky - melissav95@gmail.com
let novi_jitsi_mod_li = [
'2b078deb-b4e7-4203-99da-9f7cd62159a5',
'c9ea07b5-06b0-4a43-a2d0-8d06558c8a82',
'58db22ee-4b0a-49a7-9f34-53d2ba85a84b',
'5724aad7-6d89-47e7-8943-966fd22911bd',
'182d1db3-caa9-41bc-b04a-2facc6859aeb'
];
let novi_user_moderator = novi_url_params.get('moderator');
let novi_is_moderator = false;
if (novi_jitsi_mod_li.includes(novi_user_id)) {
novi_is_moderator = true;
}
// Set variables for Jitsi Meet External API
let user_id = novi_user_id;
let user_full_name = novi_user_full_name;
let user_email = novi_user_email;
let user_moderator = novi_user_moderator;
let url_params = novi_url_params;
let is_moderator = novi_is_moderator
/* END: IDAA and Novi specific */
// These disabled sound options will be used in the disabledSounds array below.
let disabled_sounds = [
url_params.get('incoming_msg_sound') ? 'INCOMING_MSG_SOUND' : null,
url_params.get('participant_joined_sound') ? 'PARTICIPANT_JOINED_SOUND' : null,
url_params.get('participant_left_sound') ? 'PARTICIPANT_LEFT_SOUND' : null,
url_params.get('reaction_sound') ? 'REACTION_SOUND' : null,
url_params.get('raise_hand_sound') ? 'RAISE_HAND_SOUND' : null,
];
// Jitsi Meet External API variables
let domain = url_params.get('domain') ?? 'jitsi.dgrzone.com';
let room_name = url_params.get('room') ?? 'The-Default-Room';
let display_name = user_full_name ?? 'Not My Name';
let email = user_email ?? 'test+unknown@oneskyit.com';
// Replace spaces with plus symbol in email addresses
email = email.replace(/\s+/g, '+');
// let is_moderator = user_moderator === 'true' || user_moderator === true ? true : false;
// 1. Function to fetch the JWT from your backend
async function getJitsiJwt() {
const tokenEndpoint = 'https://api.oneskyit.com/api/jitsi_token';
// This payload now correctly user, separates features, settings, and config overrides.
// The backend will place these into the correct locations in the JWT.
const payload = {
// This is used by the API backend to identify the room and user role. It may override some of the other fields below.
name: display_name, // SPECIAL use: Handled by the backend to set 'name' in the 'users' section. May be truncated or modified. This actual property will be removed by the backend.
email: email, // SPECIAL use: Handled by the backend to set 'email' in the 'users' section. This actual property will be removed by the backend.
is_moderator: is_moderator, // SPECIAL use: Handled by the backend to set 'moderator' in the 'users' section. This actual property will be removed by the backend.
room: room_name, // CHECKED by API: The room the user is joining. Checked by the backend.
// *BEGIN* 'context'
// The 'context' is being built below, but will be adjusted by the backend as needed. It will be put under the 'context' property in the JWT.
// 'users': For adding users to the JWT (if needed)???
// This is partially handled by the backend for now, so no need to send 'users' here. This need to be changed later. Not sure yet... However, if it is sent with the payload, the backend should merge it appropriately. Mainly it will likely overwrite the 'moderator' or 'id' fields.
user: {
// Example user structure:
// id: 'user-id-123',
// name: 'User Name',
// avatar: 'https://example.com/avatar.png',
// email: 'test@example.com',
// moderator: true
id: room_name + '_' + (is_moderator ? 'mod' : 'user') + '_' + Math.floor(Math.random() * 10000),
name: display_name,
// avatar: 'https://example.com/avatar.png', // Not used at this time
email: email,
moderator: true
},
// 'features': For enabling/disabling major Jitsi tools
features: {
livestreaming: false,
recording: false,
transcription: false,
'outbound-call': false,
},
// 'settings': For moderator default checkboxes in the settings panel
settings: {
startMuted: true, // Corresponds to "Everyone starts muted"
startHidden: true, // Corresponds to "Everyone starts hidden"
// followMe: false, // Corresponds to "Everyone follows me"
reactionsMuted: true, // Corresponds to "Mute reaction sounds for everyone"
},
// *END* 'context'
// 'config': For overriding properties from the server's config.js file
config: {
// This disables the reactions feature entirely??? If you want reactions to be
// available but just have the sounds muted by default, set this to 'false'.
// disableReactions: true,
'prejoinConfig.enabled': false,
},
// 'aud': 'my_jitsi_app_id', // For reference only - handled by backend
// 'iss': 'my_jitsi_app_id', // For reference only - handled by backend
// 'sub': 'jitsi.dgrzone.com', // For reference only - handled by backend
// 'room': '*', // For reference only - handled by a mix of frontend and backend
// 'exp': 1672531199, // For reference only - handled by backend
// 'nbf': 1672444800 // For reference only - handled by backend
};
try {
const response = await fetch(tokenEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!response.ok) throw new Error('Failed to fetch JWT token from the server.');
const data = await response.json();
return data.token; // expect { token: "..." }
} catch (err) {
console.error('Error getting JWT:', err);
return null;
}
}
// 2. Main function to initialize the Jitsi API with the JWT
async function initJitsiApi() {
let jwtToken = null;
if (is_moderator) {
jwtToken = await getJitsiJwt();
if (!jwtToken) {
document.getElementById('jitsi_meet_external_api_container').innerHTML =
'<h1>Authentication Failed. Please try again.</h1>';
return;
}
}
const options = {
roomName: room_name,
width: '100%',
height: '100%',
parentNode: document.getElementById('jitsi_meet_external_api_container'),
userInfo: { displayName: display_name, email: email },
// These settings apply to ALL users. Moderator settings are now in the JWT.
configOverwrite: {
prejoinPageEnabled: false,
startWithAudioMuted: true, // Mutes the local user upon joining
startWithVideoMuted: true, // Mutes the local user upon joining
enableLobby: is_moderator,
// OMG THESE disabledSounds ACTUALLY WORK!!!!
// Use the disableSounds array to disable per browser session instance. This should be configurable though. The JWT payload (above in getJitsiJwt()) does not seem to support it?
// Keep this disabledSounds list for reference:
// https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-configuration/#disabledsounds
// disabledSounds: [
// 'ASKED_TO_UNMUTE_SOUND',
// 'E2EE_OFF_SOUND',
// 'E2EE_ON_SOUND',
// 'INCOMING_MSG_SOUND',
// 'KNOCKING_PARTICIPANT_SOUND',
// 'LIVE_STREAMING_OFF_SOUND',
// 'LIVE_STREAMING_ON_SOUND',
// 'NO_AUDIO_SIGNAL_SOUND',
// 'NOISY_AUDIO_INPUT_SOUND',
// 'OUTGOING_CALL_EXPIRED_SOUND',
// 'OUTGOING_CALL_REJECTED_SOUND',
// 'OUTGOING_CALL_RINGING_SOUND',
// 'OUTGOING_CALL_START_SOUND',
// 'PARTICIPANT_JOINED_SOUND',
// 'PARTICIPANT_LEFT_SOUND',
// 'RAISE_HAND_SOUND',
// 'REACTION_SOUND',
// 'RECORDING_OFF_SOUND',
// '_ON_SOUND',
// 'TALK_WHILE_MUTED_SOUND',
//],
disabledSounds: disabled_sounds.filter(sound => sound), // Remove any null/undefined entries
},
interfaceConfigOverwrite: {
DISABLE_JOIN_LEAVE_NOTIFICATIONS: true, // suppress join/leave UI notifications/sounds
// if you want to silence other notification sounds, set any sound URLs to empty:
NOTIFICATION_SOUND_URL: ''
},
jwt: jwtToken // The JWT will correctly override settings for moderators
};
const api = new JitsiMeetExternalAPI(domain, options);
console.log('Jitsi API initialized with options:', options);
}
// 3. Call the initialization function when the page loads
document.addEventListener('DOMContentLoaded', initJitsiApi);
</script>
</body>
</html>