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? - django

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'
}

Related

next.js export static - S3 - routing fails on page reload

I'm deploying a next.js app as a static export, to an s3 bucket configured for static website hosting.
I use next's build and export commands to generate the out/ directory and then copy that into my s3 bucket
The bucket then contains some files, for simplicity lets say there's just index.html and about.html
The problem is when a user hits index.html via www.website.com then navigates to www.website.com/about everything works, but reloading www.website.com/about fails of course.
www.website.com/about.html finds the correct asset to render the site however
Is there a way to export a static next.js app, host on s3, and have requests to /about proxy /about.html ?
As always, thanks for looking, and thanks even more for participating.
On your next.config.js file at the root of the project.
module.exports = {
trailingSlash: true,
}
Now you can create your pages (e.g. about.jsx) inside the pages directory and Next will create a folder with the file name with an index.html file inside of it when you run the export command.
Give it a try, worked fine here.
The best solution I've arrived at so far, inspired by this gist:
https://gist.github.com/rbalicki2/30e8ee5fb5bc2018923a06c5ea5e3ea5
Basically when deploying the build to the s3 bucket, you can simply rename the .html files to have no .html suffix, ex: www.bucket.com/about.html -> www.bucket.com/about and now both SSR & CSR routing work as expected.
The resulting files have Content-Type: text/html despite not having the suffix, I don't know if this is problematic or not.
RewriteRule ^([^.]+)$ $1.html [NC,L]
worked fine (y)
Here's how Guy Hudash did it:
Assuming you already have a react.js website hosted on s3, you need to first change the S3 Routing Rules in S3 bucket -> Properties -> Static website hosting -> Redirection rules.
The new s3 console changes the routing rules format to JSON, so you’ll need to add this (don’t forget to replace myhost.com):
[
{
"Condition": {
"HttpErrorCodeReturnedEquals": "404"
},
"Redirect": {
"HostName": "myhost.com",
"ReplaceKeyPrefixWith": "#!/"
}
},
{
"Condition": {
"HttpErrorCodeReturnedEquals": "403"
},
"Redirect": {
"HostName": "myhost.com",
"ReplaceKeyPrefixWith": "#!/"
}
}
]
These rules add #!/ as the prefix to the URL in the case of a 403 or 404 error. This solves the react-router issue and now it will load the right page.
Now we would like to remove this prefix from the url for a cleaner solution. You’ll need to edit you _app.js and add:
import {useRouter} from 'next/router';
const MyApp = ({ Component, pageProps }) => {
const router = useRouter();
const path = (/#!(\/.*)$/.exec(router.asPath) || [])[1];
if (path) {
router.replace(path);
}
return (
<Component {...pageProps} />
);
};
export default MyApp;
You may refer to the blog-post itself... or if you are using any other routing solution than NextJS for you application, or looking for more detailed explanation then look at: Mark Biek blog

Why my angular HTTP request can't GET on local Django server?

I made an Angular application able use an online api to get a json and do stuff.
But, although the json is the same, if I try to change only the url of the json by setting a local url of a server written in django, angular would seem not to connect anymore ...
My question is, why if with an online cloud server works, with a local one wouldn't?
I tried making this server "on cloud" opening the router's port, also setting up a ddns, and using postman or a browser it seems to work, but when i try to connect with angular it still doesn't get the data...
I am sure 100% that the server answer, with the right json data, because django prints on console that he received a HTTP GET request :
http://i.imgur.com/TIQnIcR.png
I remind you that the HTTP angular request worked with another api, but i will still show up some code :
export class ProdottoService {
private prodotti: Array<ProdottoModel>;
constructor(private httpClient: HttpClient) {
this.prodotti = new Array<ProdottoModel>();
var url:string = "https://gist.githubusercontent.com/saniyusuf/406b843afdfb9c6a86e25753fe2761f4/raw/523c324c7fcc36efab8224f9ebb7556c09b69a14/Film.JSON";
var local_url:string = "http://127.0.0.1:8000/films/?format=json";
httpClient.get(local_url)
.subscribe((films : Array<Object> ) => {
films.forEach((film => {
this.prodotti.push(new ProdottoModel(film));
}));
}
);
}
getProdotti(): Array<ProdottoModel> {
return this.prodotti;
}
}
Result using external api :
http://i.imgur.com/MT7xD9c.png
Thanks in advace for any help :3
-- EDIT -- IS A CORS ISSUE
In django settings.py file :
CORS_ORIGIN_WHITELIST = (
'localhost:8000',
'127.0.0.1:4200'
)
INSTALLED_APPS = (
...
'corsheaders',
...
)
MIDDLEWARE = [ # Or MIDDLEWARE_CLASSES on Django < 1.10
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
]
But i don't know if there's a way to set-up CORS settings in Angular
Based on feedback, this is a CORS issue. Your Django server is getting the requests and responding because localhost is an implicitly trusted domain in Django's dev environment, but it isn't configured properly to set the cross origin header, so the browser is not allowing your app to see the response because the server hasn't authorized the domain explicitly.
The problem here is that you've set CORS white list like this:
CORS_ORIGIN_WHITELIST = ( 'localhost:8000', '127.0.0.1:4200' )
it needs to be like this:
CORS_ORIGIN_WHITELIST = ( 'localhost:4200' )
angular runs on localhost, not 127.0.0.1, even though that's what localhost is an alias for, your browser still differentiates them for CORS. Also, you do not need to whitelist the domain your serving off of, that's not crossing any origin as it's the same origin.
In your screenshot, it looks like the response is type "document..." something. The simplest fix, with only the code here, is to convert the string to JSON.
JSON.parse(films)
This is the wrong answer, because it's being set to that because of the CORS issue in the other answers.

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,
}
}
}
};

How to embed an Apache Superset dashboard in a webpage?

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.

Strongloop / Loopback Getting started missing root.js

I'm following the getting started documentation from Loopback, and I have an issue when I want to add static files Strongloop getting started Step 3: the file /server/boot/root.js doesn't exists, in addition /server/server.js does not have the 2 lines that were supposed to be there :
// var path = require('path');
// app.use(loopback.static(path.resolve(__dirname, '../client')));
Instead, the /server/middleware.json shows :
"routes": {
"loopback#status": {
"paths": "/"
}
},
Could someone please let me know how to perform this step ? Note : the git repository for Step 3 is good, but not the scaffolded project running slc loopback.
The /server/middleware.json file is where middleware is registered now. The following excerpt is resolving to a file in module's server/middleware directory (loopback-getting-started/node_modules/loopback/server/middleware).
"routes": {
"loopback#status": {
"paths": "/"
}
},
Change this to:
"routes": {
},
Restart the Loopback server and visiting localhost:3000 results in an Express error 404, which would be expected since you no longer have a route defined for /.
You now need to specify in the middleware.json file how to serve static content. You do this in the "files" phase:
"files": {
"loopback#static": {
"params": "$!../client"
}
}
You can now add the following to an index.html file in your /client directory as the original documentation states.
<head><title>LoopBack</title></head>
<body>
<h1>LoopBack Rocks!</h1>
<p>Hello World... </p>
</body>
Restarting the Loopback server and visiting localhost:3000 now serves the index.html page.
More details about how to specify middleware via the new way is located at http://docs.strongloop.com/display/public/LB/Defining+middleware#Definingmiddleware-Registeringmiddlewareinmiddleware.json
Also see https://github.com/strongloop/loopback-faq-middleware
The latest version of LoopBack removed the root.js file. You do not need it anymore, the docs need to be updated to reflect this.