Skip to content

Commit

Permalink
Merge pull request #17 from sigmacomputing/embed_link_sharing
Browse files Browse the repository at this point in the history
Add embed link sharing
  • Loading branch information
pballai authored Sep 4, 2024
2 parents f814a85 + 06a2c66 commit 3fb4a72
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 0 deletions.
Binary file added embedding/sigma_embed_link_sharing/.DS_Store
Binary file not shown.
15 changes: 15 additions & 0 deletions embedding/sigma_embed_link_sharing/.env
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
93 changes: 93 additions & 0 deletions embedding/sigma_embed_link_sharing/embed-api.js
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}`);
});
147 changes: 147 additions & 0 deletions embedding/sigma_embed_link_sharing/index.html
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>
6 changes: 6 additions & 0 deletions embedding/sigma_embed_link_sharing/nodemon.json
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"
}
11 changes: 11 additions & 0 deletions embedding/sigma_embed_link_sharing/package.json
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": ""
}

0 comments on commit 3fb4a72

Please sign in to comment.