Skip to content

Commit

Permalink
added metabse embedding feature on php
Browse files Browse the repository at this point in the history
  • Loading branch information
MIKEINTOSHSYSTEMS committed Aug 23, 2024
1 parent 7f82c07 commit 44ba5f1
Show file tree
Hide file tree
Showing 96 changed files with 4,016 additions and 18 deletions.
72 changes: 72 additions & 0 deletions analytics/meta/dashboard.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php
require '../../vendor/autoload.php';

use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;

// Metabase parameters
$metabaseSiteUrl = 'https://viz.hispmd.merqconsultancy.org';
$metabaseSecretKey = '25893c16e94ac3c193ad2bfa3b2dbdba5ea0e663de266dc7649ffc9216e09865'; // Replace with your Metabase secret key
$dashboardId = 2; // Replace with your dashboard ID

// Create JWT configuration with HMAC SHA-256 signer
$config = Configuration::forSymmetricSigner(
new Sha256(),
InMemory::plainText($metabaseSecretKey)
);

// Create the token
$now = new DateTimeImmutable();
$exp = $now->add(new DateInterval('PT10M')); // Token expires in 10 minutes

// You can add parameters if needed for filtering or other purposes
$params = (object)[
// Add any parameters required by your dashboard or charts here
// For example: 'region' => 'North', 'date' => '2024-01-01'
// Leave this as an empty object if there are no params
];

$token = $config->builder()
->issuedBy($metabaseSiteUrl) // Configures the issuer (iss claim)
->issuedAt($now) // Configures the time that the token was issued (iat claim)
->expiresAt($exp) // Configures the expiration time of the token (exp claim)
->withClaim('resource', ['dashboard' => $dashboardId]) // Add resource claim
->withClaim('params', $params) // Add params claim as an object
->getToken($config->signer(), $config->signingKey()); // Retrieves the generated token

// Generate iframe URL
$iframeUrl = $metabaseSiteUrl . "/embed/dashboard/" . $token->toString() . "#theme=transparent&bordered=false&titled=true";
?>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Embedded Metabase Dashboard</title>
<style>
/* Make sure the body and html elements take up full height */
html, body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
}
/* Style the iframe to cover the entire viewport */
iframe {
border: none;
width: 100%;
height: 100vh; /* Full viewport height */
position: absolute;
top: 0;
left: 0;
}
</style>
</head>
<body>
<iframe
src="<?= htmlspecialchars($iframeUrl, ENT_QUOTES, 'UTF-8') ?>"
allowtransparency></iframe>
</body>
</html>
16 changes: 16 additions & 0 deletions analytics/meta/embed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php
include '../../vendor/autoload.php';

// The url of the metabase installation
$metabaseUrl = '[https://viz.hispmd.merqconsultancy.org]';
// The secret embed key from the admin settings screen
$metabaseKey = '[c7242586ae89ceb5c0dd2ecab564b09c9b4f2b6e78b1491c7e8271f3ba2aa6cd]';
// The id of the dashboard (from the url)
$dashboardId = 2;
// Any parameters to pass to the dashboard
//$params = ['date' => 'past26weeks'];

$metabase = new \Metabase\Embed($metabaseUrl, $metabaseKey);
// Generate the HTML to create an iframe with the embedded dashboard
echo $metabase->dashboardIframe($dashboardId, $params);
?>
188 changes: 188 additions & 0 deletions analytics/meta/metabase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
<?php

namespace Metabase;

use DateInterval;
use DateTimeImmutable;
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Token;

/**
* Convenience class to embed Metabase dashboards and questions
*/
class Embed
{
private $url;
private $key;

public $border;
public $title;
public $theme;

public $width;
public $height;

private $jwtConfig;

private $expirationSeconds;

/**
* Default constructor
*
* @param string $url Base url for the Metabase installation
* @param string $key Secret Metabase key
* @param bool $title Show dashboard/question title (default = false)
* @param string $width Set css width of dashboard/question (default = 100%)
* @param string $height Set css height of dashboard/question (default = 800)
* @param bool $border Show dashboard/question border (default = true)
* @param int $expirationSeconds Set jwt token expiration in seconds (default = null)
*/
public function __construct($url, $key, $title = false, $width = '100%', $height = '800', $border = true, $expirationSeconds = null)
{
$this->url = $url;
$this->key = $key;
$this->border = $border;
$this->title = $title;
$this->width = $width;
$this->height = $height;
$this->expirationSeconds = $expirationSeconds;

$this->jwtConfig = Configuration::forSymmetricSigner(new Sha256(), InMemory::plainText($this->key));
}

/**
* Get the embed URL for a Metabase question
*
* @param int $questionId The id of the question to embed
* @param array $params An associate array with variables to be passed to the question
*
* @return string Embed URL
*/
public function questionUrl($questionId, $params = [])
{
return $this->url('question', $questionId, $params);
}

/**
* Get the embed URL for a Metabase dashboard
*
* @param int $dashboardId The id of the dashboard to embed
* @param array $params An associate array with variables to be passed to the dashboard
*
* @return string Embed URL
*/
public function dashboardUrl($dashboardId, $params = [])
{
return $this->url('dashboard', $dashboardId, $params);
}

/**
* Use JWT to encode tokens
*
* @param array $resource Resource to encode (question or dashboard)
* @param array $params An associate array with variables to be passed to the dashboard
*
* @return string Token
*/
private function encode($resource, $params)
{
$jwt = $this->jwtConfig->builder();
$jwt->withClaim('resource', $resource);
if (empty($params)) {
$jwt->withClaim('params', (object)[]);
} else {
$jwt->withClaim('params', $params);
}
if (!is_null($this->expirationSeconds)) {
$jwt->expiresAt((new DateTimeImmutable())->modify('+' . $this->expirationSeconds . ' seconds'));
}

return $jwt->getToken($this->jwtConfig->signer(), $this->jwtConfig->signingKey());
}

protected function url($resource, $id, $params)
{
// Generate auth token, using JWT
$token = $this->encode([$resource => $id], $params);

// Generate embed URL
$url = $this->url . '/embed/' . $resource . '/' . $token->toString() . '#';

// Should border be included
if ($this->border) {
$url .= 'bordered=true&';
} else {
$url .= 'bordered=false&';
}

// Should title be included
if ($this->title) {
$url .= 'titled=true&';
} else {
$url .= 'titled=false&';
}

// Set selected theme (if any)
if (!empty($this->theme)) {
$url .= 'theme=' . $this->theme . '&';
}

// Remove trailing &
$url = rtrim($url, '&');

return $url;
}

/**
* Generate the HTML to embed a question iframe with a given question id.
* It assumes no iframe border. Size can be manipulated via
* class $width/$height
*
* @param int $questionId The id of the question to embed
* @param array $params An associate array with variables to be passed to the question
*
* @return string Code to embed
*/
public function questionIFrame($questionId, $params = [])
{
$url = $this->questionUrl($questionId, $params);
return $this->iframe($url);
}

/**
* Generate the HTML to embed a dashboard iframe with a given dashboard id.
* It assumes no iframe border. Size can be manipulated via
* class $width/$height
*
* @param int $dashboardId The id of the dashboard to embed
* @param array $params An associate array with variables to be passed to the dashboard
*
* @return string Code to embed
*/
public function dashboardIFrame($dashboardId, $params = [])
{
$url = $this->dashboardUrl($dashboardId, $params);
return $this->iframe($url);
}

/**
* Generate the HTML to embed an iframe with a given URL.
* It assumes no iframe border. Size can be manipulated via
* class $width/$height
*
* @param string $iframeUrl The URL to create an iframe for
*
* @return string Code to embed
*/
protected function iframe($iframeUrl)
{
return '<iframe
src="' . $iframeUrl . '"
frameborder="0"
width="' . $this->width . '"
height="' . $this->height . '"
allowtransparency></iframe>';
}
}
11 changes: 11 additions & 0 deletions analytics/tests/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<html>


<iframe
src="https://viz.hispmd.merqconsultancy.org/public/dashboard/d918846e-4cd4-4909-837e-73c99e8f85d8"
frameborder="0"
width="100%"
height="100%"
allowtransparency
></iframe>
</html>
24 changes: 22 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
{
"name": "mikeintoshsystems/hispmd",
"type": "library",
"description": "HISPMD",
"keywords": ["metabase, HISPMD"],
"homepage": "https://github.com/mikeintoshsystems/hispmd",
"license": "MIT",
"authors": [
{
"name": "Michael Kifle Teferra",
"email": "[email protected]",
"homepage": "https://mikeintoshsys.com",
"role": "Developer"
}
],
"require": {
"vlucas/phpdotenv": "^5.6"
}
"vlucas/phpdotenv": "^5.6",
"lcobucci/jwt": "^5.3"
},
"autoload": {
"psr-4": {
"Metabase\\": "analytics"
}
}
}
Loading

0 comments on commit 44ba5f1

Please sign in to comment.