-
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.
added metabse embedding feature on php
- Loading branch information
1 parent
7f82c07
commit 44ba5f1
Showing
96 changed files
with
4,016 additions
and
18 deletions.
There are no files selected for viewing
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,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> |
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,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); | ||
?> |
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,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>'; | ||
} | ||
} |
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 @@ | ||
<html> | ||
|
||
|
||
<iframe | ||
src="https://viz.hispmd.merqconsultancy.org/public/dashboard/d918846e-4cd4-4909-837e-73c99e8f85d8" | ||
frameborder="0" | ||
width="100%" | ||
height="100%" | ||
allowtransparency | ||
></iframe> | ||
</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 |
---|---|---|
@@ -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" | ||
} | ||
} | ||
} |
Oops, something went wrong.