-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from sigmacomputing/embed_link_sharing
Add embed link sharing
- Loading branch information
Showing
6 changed files
with
272 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Sigma Embed Configuration | ||
EMBED_PATH={url path to embed} | ||
CLIENT_ID={your client id} | ||
EMBED_SECRET={your embed secret} | ||
|
||
# Required Parameters | ||
EMAIL={your embed test user email address} | ||
EXTERNAL_USER_ID=123 | ||
EXTERNAL_USER_TEAM=Sales_People | ||
ACCOUNT_TYPE=Pro | ||
MODE=userbacked | ||
SESSION_LENGTH=600 | ||
|
||
# Server Configuration | ||
PORT=3000 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// SIGMA EMBED LINK SHARING QUICKSTART | ||
// embed-api.js | ||
|
||
// 1: Require necessary Node.js modules | ||
const express = require("express"); | ||
const crypto = require("crypto"); | ||
require("dotenv").config(); // Load environment variables from .env file | ||
|
||
// 2: Initialize an Express application | ||
const app = express(); | ||
|
||
// 3: Fetch configuration variables from .env file | ||
const EMBED_PATH = process.env.EMBED_PATH; // Base URL for Sigma embedding | ||
const EXPLORE_EMBED_PATH = process.env.EXPLORE_EMBED_PATH; // Base URL for exploration embedding | ||
const EMBED_SECRET = process.env.EMBED_SECRET; // Secret key for signing the embed URL | ||
const CLIENT_ID = process.env.CLIENT_ID; // Client ID for Sigma API | ||
const EMAIL = process.env.EMAIL; // Email associated with the Sigma user | ||
const EXTERNAL_USER_ID = process.env.EXTERNAL_USER_ID; // External user ID | ||
const EXTERNAL_USER_TEAM = process.env.EXTERNAL_USER_TEAM; // Team associated with the external user | ||
const ACCOUNT_TYPE = process.env.ACCOUNT_TYPE; // Account type (e.g., viewer, creator) | ||
const MODE = process.env.MODE; // Mode (e.g., userbacked) | ||
const SESSION_LENGTH = process.env.SESSION_LENGTH; // Session length in seconds | ||
const PORT = process.env.PORT || 3000; // Default port is 3000 | ||
|
||
// 4: Serve static files from the root directory | ||
app.use(express.static(__dirname)); // Serve index.html and other static files | ||
|
||
// 5: Define a route handler for generating Sigma embed URLs | ||
app.get("/api/generate-embed-url", (req, res) => { | ||
try { | ||
// Generate a unique nonce using crypto's UUID | ||
const nonce = crypto.randomUUID(); | ||
let searchParams = `?:nonce=${nonce}`; | ||
|
||
// Add required search parameters using .env variables | ||
searchParams += `&:client_id=${CLIENT_ID}`; | ||
searchParams += `&:email=${EMAIL}`; | ||
searchParams += `&:external_user_id=${EXTERNAL_USER_ID}`; | ||
searchParams += `&:external_user_team=${EXTERNAL_USER_TEAM}`; | ||
searchParams += `&:account_type=${ACCOUNT_TYPE}`; | ||
searchParams += `&:mode=${MODE}`; | ||
searchParams += `&:session_length=${SESSION_LENGTH}`; | ||
searchParams += `&:time=${Math.floor(new Date().getTime() / 1000)}`; // Current time in seconds | ||
|
||
// Handle exploreKey if present in the query parameters | ||
const exploreKey = req.query.exploreKey; | ||
|
||
// Append exploreKey to the URL if present | ||
if (exploreKey) { | ||
searchParams += `&:explore=${exploreKey}`; | ||
} | ||
|
||
// Handle bookmarkId if present in the query parameters | ||
const bookmarkId = req.query.bookmarkId; | ||
|
||
// Append bookmarkId to the URL if present | ||
if (bookmarkId) { | ||
searchParams += `&:bookmark=${bookmarkId}`; | ||
} | ||
|
||
// Construct the URL with search parameters and generate a signature | ||
const URL_WITH_SEARCH_PARAMS = EMBED_PATH + searchParams; | ||
const SIGNATURE = crypto | ||
.createHmac("sha256", Buffer.from(EMBED_SECRET, "utf8")) | ||
.update(Buffer.from(URL_WITH_SEARCH_PARAMS, "utf8")) | ||
.digest("hex"); | ||
const URL_TO_SEND = `${URL_WITH_SEARCH_PARAMS}&:signature=${SIGNATURE}`; | ||
|
||
// Send the final URL to the requester | ||
res.status(200).json({ url: URL_TO_SEND }); | ||
} catch (error) { | ||
// Log and send error if URL generation fails | ||
console.error("Error generating embed URL:", error.message); | ||
res.status(500).send("Internal Server Error"); | ||
} | ||
}); | ||
|
||
// 6: Define a route to serve the exploration embed URL from .env | ||
app.get("/api/get-explore-embed-url", (req, res) => { | ||
try { | ||
const exploreEmbedUrl = EXPLORE_EMBED_PATH; | ||
res.status(200).json({ url: exploreEmbedUrl }); | ||
} catch (error) { | ||
// Log and send error if retrieval fails | ||
console.error("Error retrieving explore embed URL:", error.message); | ||
res.status(500).send("Internal Server Error"); | ||
} | ||
}); | ||
|
||
// 7: Start the server | ||
app.listen(PORT, () => { | ||
console.log(`Node Express Server listening on port ${PORT}`); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
<!DOCTYPE html> | ||
<html lang="en" style="height: 100%; margin: 0; padding: 0;"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Sigma - Embed Link Sharing Sample</title> | ||
<style> | ||
body, html { | ||
height: 100%; | ||
margin: 0; | ||
padding: 0; | ||
display: flex; | ||
flex-direction: column; | ||
} | ||
h2 { | ||
margin: 0; | ||
padding: 10px; | ||
text-align: center; | ||
background: #f0f0f0; | ||
} | ||
iframe { | ||
flex-grow: 1; | ||
width: 100%; | ||
border: none; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<h2>Sigma - Embed Link Sharing Sample</h2> | ||
<iframe id="sigmaDashboard" frameborder="0"></iframe> | ||
|
||
<script> | ||
// Base URL for API requests | ||
const API_BASE_URL = window.location.origin; | ||
|
||
// Reference to the Sigma iframe | ||
const iframe = document.getElementById("sigmaDashboard"); | ||
|
||
// Variables to store current exploreKey and bookmarkId | ||
let currentExploreKey = null; | ||
let currentBookmarkId = null; | ||
|
||
// Parse query parameters from the current URL | ||
const urlParams = new URLSearchParams(window.location.search); | ||
const exploreKey = urlParams.get("exploreKey"); | ||
const bookmarkId = urlParams.get("bookmarkId"); | ||
|
||
// Function to generate the fetch URL for the server request | ||
function generateFetchUrl(exploreKey, bookmarkId) { | ||
let url = `${API_BASE_URL}/api/generate-embed-url?`; // Base API URL | ||
if (exploreKey) url += `exploreKey=${exploreKey}`; | ||
if (bookmarkId) url += `&bookmarkId=${bookmarkId}`; | ||
console.log("Generated fetch URL:", url); // Log the generated URL for debugging | ||
return url; // Return the constructed URL | ||
} | ||
|
||
// Function to fetch the signed embed URL from the server | ||
async function fetchEmbedUrl(exploreKey, bookmarkId) { | ||
try { | ||
// Generate the URL with the correct parameters | ||
const newUrl = generateFetchUrl(exploreKey, bookmarkId); | ||
console.log("Fetching new URL:", newUrl); // Log the URL being fetched | ||
const response = await fetch(newUrl); | ||
const data = await response.json(); | ||
|
||
if (response.ok) { | ||
// Set the iframe src to the retrieved embed URL | ||
iframe.src = data.url; | ||
console.log("Updated iframe src to:", data.url); | ||
} else { | ||
console.error("Error fetching embed URL:", data.error); | ||
} | ||
} catch (error) { | ||
console.error("Error fetching embed URL:", error); | ||
} | ||
} | ||
|
||
// Function to update the browser URL without reloading the page | ||
function updateBrowserUrl(exploreKey, bookmarkId) { | ||
const params = new URLSearchParams(); | ||
if (exploreKey) params.append("exploreKey", exploreKey); | ||
if (bookmarkId) params.append("bookmarkId", bookmarkId); | ||
|
||
const newUrl = `${window.location.origin}${window.location.pathname}?${params.toString()}`; | ||
window.history.pushState({}, '', newUrl); | ||
} | ||
|
||
// Function to send sharing links back to Sigma | ||
function sendSharingLinks() { | ||
const baseUrl = window.location.origin + window.location.pathname; | ||
const finalSharingLink = currentExploreKey || currentBookmarkId | ||
? `${baseUrl}?${currentExploreKey ? `exploreKey=${currentExploreKey}` : ''}${currentBookmarkId ? `&bookmarkId=${currentBookmarkId}` : ''}` | ||
: baseUrl; | ||
|
||
const sharingExplorationLink = currentExploreKey | ||
? currentBookmarkId | ||
? `${baseUrl}?exploreKey=${currentExploreKey}&bookmarkId=${currentBookmarkId}` | ||
: `${baseUrl}?exploreKey=${currentExploreKey}` | ||
: null; | ||
|
||
console.log("Sending sharing links to Sigma:"); | ||
console.log("Final Sharing Link:", finalSharingLink); | ||
console.log("Sharing Exploration Link:", sharingExplorationLink); | ||
|
||
iframe.contentWindow.postMessage( | ||
{ | ||
type: "workbook:sharinglink:update", | ||
sharingLink: finalSharingLink, | ||
sharingExplorationLink: sharingExplorationLink, | ||
}, | ||
"https://app.sigmacomputing.com" | ||
); | ||
} | ||
|
||
// Event listener for messages from the Sigma iframe | ||
window.addEventListener("message", (event) => { | ||
if (event.source === iframe.contentWindow && event.origin === "https://app.sigmacomputing.com") { | ||
const eventData = event.data; | ||
|
||
// Handle exploreKey changes | ||
if (eventData.type === "workbook:exploreKey:onchange") { | ||
currentExploreKey = eventData.exploreKey; | ||
console.log("Explore Key Updated:", currentExploreKey); // Log the exploreKey update | ||
updateBrowserUrl(currentExploreKey, currentBookmarkId); // Update the browser URL | ||
sendSharingLinks(); // Send the sharing link back to Sigma | ||
} | ||
|
||
// Handle bookmarkId changes | ||
if (eventData.type === "workbook:bookmark:onchange") { | ||
currentBookmarkId = eventData.bookmarkId; | ||
console.log("Bookmark ID Updated:", currentBookmarkId); // Log the bookmarkId update | ||
updateBrowserUrl(currentExploreKey, currentBookmarkId); // Update the browser URL | ||
sendSharingLinks(); // Send the sharing link back to Sigma | ||
} | ||
|
||
// Handle workbook loaded events | ||
if (eventData.type === "workbook:loaded" || eventData.type === "workbook:dataloaded") { | ||
sendSharingLinks(); // Send the sharing link back to Sigma | ||
} | ||
} | ||
}); | ||
|
||
// Initial fetch of the embed URL and setting the iframe src | ||
fetchEmbedUrl(exploreKey, bookmarkId); | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"watch": [".env", ".js", "html"], | ||
"ext": "js, env, html", | ||
"ignore": ["node_modules"], | ||
"exec": "node embed-api.js" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"name": "sigma_embed_link_sharing", | ||
"version": "1.0.0", | ||
"main": "embed-api.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"author": "", | ||
"license": "ISC", | ||
"description": "" | ||
} |