How to embed an Apache Superset dashboard in a webpage? - apache-superset

I am trying to implement the Apache superset dashboard in a webpage.
Anyone have any idea how to implement this?

Keep the iframe tag line as you mentioned.
<iframe src="linkToYourDashBoard?standalone=true"></iframe>
and check the superset_config.py file.
HTTP_HEADERS = {'X-Frame-Options': 'SAMEORIGIN'}
Change the line to
HTTP_HEADERS = {'X-Frame-Options': 'ALLOWALL'}
or
HTTP_HEADERS = {}
Don't forget to add superset_config.py file to your python path.

First, you need to update the public roles with these options.
Security/List Roles:
can explore json on Superset,
can dashboard on Superset,
all database access on all_database_access
Second, embed your dashboard in your HTML
<iframe src="localhost:8088/superset/dashboard/5/?standalone=true"></iframe>

Superset Embedded SDK allows you to embed
dashboards from Superset into your own app, using your app's authentication.
superset backend server: update superset_config.py or config.py
FEATURE_FLAGS = {
"EMBEDDED_SUPERSET": True, # requirement
}
"GUEST_ROLE_NAME": "Public", # you might need to edit role permissions when 403 error
"GUEST_TOKEN_JWT_EXP_SECONDS": 300 # 5 minutes, or you could set it longer
your app's backend server
fetch access_token
http://localhost:8088/api/v1/security/login
fetch guest_token
http://localhost:8088/api/v1/security/guest_token/
your app's frontend, for example:
<script src="https://unpkg.com/#superset-ui/embedded-sdk"></script>
<script>
supersetEmbeddedSdk.embedDashboard({
id: 'd3918020-0349-435d-9277-xxxxxx', // given by the Superset embedding UI
supersetDomain: 'http://localhost:9000',
mountPoint: document.getElementById('container'), // any html element that can contain an iframe
fetchGuestToken: () =>
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.xxxxxx.1RExnlLfdDI6P4vG3gB0otLL7XR_3OE2OZ0WhCKyTyE', // guest_token
dashboardUiConfig: {} // dashboard UI config: hideTitle, hideTab, hideChartControls (optional)
})
</script>
Please refer to: Embedding Superset dashboards in your React application

Superset now provides the Superset Embedded SDK, an NPM package for inserting an iframe that will embed your Superset dashboard. I'm using it at the moment and it is relatively straightforward; this is the current implementation example provided in the docs:
import { embedDashboard } from "#superset-ui/embedded-sdk";
embedDashboard({
id: "abc123", // given by the Superset embedding UI
supersetDomain: "https://superset.example.com",
mountPoint: document.getElementById("my-superset-container"), // any html element that can contain an iframe
fetchGuestToken: () => fetchGuestTokenFromBackend(),
dashboardUiConfig: { hideTitle: true }, // dashboard UI config: hideTitle, hideTab, hideChartControls (optional)
});
Obviously the end result could still be achieved by adding the iframe "manually," but using the official abstraction might provide simplicity and future functionality in subsequent versions.

Related

How to get PayPal client-side info to Django?

I am using PayPal standard IPN payment solution in client side in my Django web app.
<body>
<!-- Set up a container element for the button -->
<div id="paypal-button-container"></div>
<!-- Include the PayPal JavaScript SDK -->
<script src="https://www.paypal.com/sdk/js?client-id=test&currency=USD"></script>
<script>
// Render the PayPal button into #paypal-button-container
paypal.Buttons({
// Set up the transaction
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
value: '88.44'
}
}]
});
},
// Finalize the transaction
onApprove: function(data, actions) {
return actions.order.capture().then(function(orderData) {
// Successful capture! For demo purposes:
console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
});
}
}).render('#paypal-button-container');
</script>
</body>
everything works fine and I can access all the data through the details variable in the js code.
Now, i need to insert the details into django db, no api, simple model.
Tried many things, none worked.
I prefer not to use django-paypal because it doesn't have smart buttons (as far as i saw) and there is only option for "buy now button" and no credit / debit card.
how can it be done? or is there smart buttons for django-paypal package?
Thanks for the help!
How to get PayPal client-side info to Django?
Don't.
An integration that creates and captures payments with client-side JS functions is for very simple use cases. It should never be used if you need to do anything automated with the result, such as writing transaction results to a database.
Instead, API-based integrations exist for precisely this use case. Use the v2/checkout/orders API and make two routes (url paths) on your server, one for 'Create Order' and one for 'Capture Order'. You could use the Checkout-PHP-SDK for the routes' API calls to PayPal, or your own HTTPS implementation of first getting an access token and then doing the call. Both of these routes should return/output only JSON data (no HTML or text). Inside the 2nd route, when the capture API is successful you should verify the amount was correct and store its resulting payment details in your database (particularly purchase_units[0].payments.captures[0].id, which is the PayPal transaction ID) and perform any necessary business logic (such as reserving product or sending an email) immediately before forwarding return JSON to the frontend caller. In the event of an error forward the JSON details of it as well, since the frontend must handle such cases.
Pair those 2 routes with this frontend approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server . (If you need to send any additional data from the client to the server, such as an items array or selected options, add a body parameter to the fetch with a value that is a JSON string or object)

How do I embed Superset in an iframe?

I'm trying to embed Superset (version 1.3) in an iframe and I'm getting a DOMException 18. The installation of Superset itself works fine since I can access it normally at its URL. Ultimately, my need is to allow website X of a completely different origin to embed a view of my superset instance.
I've found a number of github issues and articles online suggesting changes to superset_config.py to allow embedding superset in an iframe and I've made a few of them. In particular, I've made the following changes to config.py (rather than superset_config.py as a temporary measure to be sure that the config changes were indeed being registered):
from .mysecurity import CustomSecurityManager
CUSTOM_SECURITY_MANAGER = CustomSecurityManager
ENABLE_PROXY_FIX = True
HTTP_HEADERS: Dict[str, Any] = {'X-Frame-Options': 'ALLOWALL'}
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_SAMESITE = "None"
I'm using a this as a base for custom security manager (the only changes are that I'm checking a token against another service before logging in the user and I'm providing a redirect in the URL).
This instance of superset is behind NGINX which is setting Access-Control-Allow-Origin * and running with gunicorn.
The following screenshots are from my local host with a basic website that has the following bit of relevant JS logging in a user with role Gamma:
let analytics_div = document.getElementById('analytics');
let report = document.createElement("iframe")
const report_url = new URL("/superset/dashboard/123/?standalone=true", superset_url);
const start_url = new URL(`/login?auth_code=${superset_auth_token}&redirect=${report_url}`, superset_url)
report.src = start_url;
report.width = "100%"
report.height = 700
analytics_div.appendChild(report)
Error I'm getting in the iframe
What I see in the dev tools

In wagtail how do I setup the v2 api to attach the full base url ( e.g. http://localhost:8000" ) to steamfield images and richtext embeds?

I am currently using nuxt.js as a frontend for my wagtail headless cms. When I load a richtext field or an image block within a streamfield I am unable, or don't know how to, attach the full base url of the wagtail server so when it gets rendered on the nuxtjs site it resolves to src="/media/images/image.png which in the end tries to find the image on the nuxtjs site http://localhost:3000 and it needs to find it on the wagtail server side http://localhost:8000. For standard images I can intercept and prepend the server base url, but not when it comes to anything inside a streamfield.
[EDIT: Better answer below]
I'm not 100% certain this is the "proper" way to do it, but I managed to get what I needed by adding a server middleware that detects anything that starts with the directory /media and prepends the server base url.
// in nuxt.config.js
export default {
serverMiddleware:[
'~/serverMiddleware/redirects'
],
}
then in `serverMiddleware/redirects.js
export default function(req, res, next) {
if (req.url.startsWith('/media')) {
res.writeHead(301, {Location: `http://localhost:8000${req.url}`})
res.end()
} else {
next()
}
}
This is a quick workaround for now I'll see if there is anything better.
Ok, I believe this is the proper solution. It just seemed to evade me :P
Instead of using a redirect simply add a proxy to nuxt.config.js
modules: [
'#nuxtjs/axios',
],
axios: {proxy: true},
proxy: {
'/api/v2/': 'http://localhost:8000',
'/media/': 'http://localhost:8000'
}

How to have Google Form submit event trigger be caught by a Flask website to update that website?

I have a website written on Flask, and I would like to update it when answers to a Google Form has been submitted.
More precisely, I have already associated the form to a Google spreadsheet and I can read that spreadsheet from Flask, but the key component missing is how to trigger the website to update its content when new answers have been submitted to the form.
What would be the best way to do this?
Webhook solution:
Google Forms:
Enter the Google Forms editor
Click 3 vertical dots next to profile picture, and select 'script editor'
Customize this snippet to your WebHook url and set a custom token (this is not really secure, but better than nothing ).
function onFormSubmit(e) {
const url = "https://example.com/webhook";
var options = {
"method": "post",
"headers": {
"Content-Type": "application/json"
},
"payload": JSON.stringify({"token": "sometokenheretocheckonbackend"})
};
UrlFetchApp.fetch(url, options);
}
( Dialog may popup where you have to approve that you connect to an unauthorized service )
Handling on the Flask side:
from http import HTTPStatus
from flask import (
abort,
request
)
#blueprint.route('/webhook', methods=['POST'])
def handle_webhook():
payload = request.get_json()
if payload.get('token') != "sometokenheretocheckonbackend":
abort(HTTPStatus.UNAUTHORIZED)
# Update your content
return jsonify({'success': True}), HTTPStatus.OK
Periodic updates (Alternative solution):
I would consider launching a daemon Thread that periodically updates this content. This is obviously not as elegant, but should work quite stable and wouldn't be much more demanding for the server if the content update procedure is reasonably lightweight.
You could create an Form Submit trigger to trigger a Google Apps Script function that calls out to your Flask site and triggers the update.
https://developers.google.com/apps-script/guides/triggers/installable

JWT authentication between Django and Vue.js

I wish to create a public area on a website containing standard Django and templates. When a user logs in to the members area, they are logged in to a SPA (using Vue.js) and Django Rest Framework. I will be using JWT's to handle authentication between the SPA and backend once the user has logged in to the members area.
This is the user journey:
User browses around the public areas of the site (served by normal Django and templates).
User decides to signup / login to the members area.
Django Rest Framework generates a JWT for the user and returns the token along with the index.html of the SPA
The user continues to use the SPA with the JWT
Is the above possible and how would it be done? More specifically, the issue is that the user is not logging in to the SPA and requesting a JWT. They are logging in to regular Django and getting returned a JWT along with the SPA. That JWT would then be used from that point onwards.
This is something that I've used with laravel, but the principle should be the same.
I've placed vue-cli generated code into the subfolder frontend.
This is trimmed content of the file vue.config.js, which you need to add manually to the vue-cli project root.
const path = require('path')
/*
vue-cli is initialized in project subfolder `frontend`
and I run `npm run build` in that sub folder
*/
module.exports = {
outputDir: path.resolve(__dirname, '../public/'),
/*
https://cli.vuejs.org/config/#outputdir
!!! WARNING !!! target directory content will be removed before building
where js, css and the rest will be placed
*/
assetsDir: 'assets/',
/*
Where `public/index.html` should be written
- this is example for the laravel, but you can change as needed
- .blade.php is laravel template that's served trough laravel.
So you could inject JWT into `index.html`
- Check https://cli.vuejs.org/guide/html-and-static-assets.html
for the syntax before adding values
*/
indexPath: path.resolve(__dirname, '../resources/views/index.blade.php'),
devServer: {
host: '0.0.0.0',
port: 8021,
proxy: {
/*
Proxy calls from
localhost:8021/api (frontend)
localhost:8020/api (backend)
*/
'/api': {
target: 'http://localhost:8020',
changeOrigin: true,
}
}
}
};