i am making a zip file of PDFs and then download it in browser.. i have used ajax and want to receivce file in response so that i can download it.
return response()->download(public_path().'/documents/'.$zipName , $zipName, $headers);
this is the response i m getting
i have also tried this method but it didn't worked idont know what i am missing.
Laravel Response:
$downloadData = [
'zipFile' => $zipName,
'headers' => $headers,
'url' => public_path('documents/').$zipName
];
return response()->json(['status'=>1,'data'=> $downloadData]);
AJAX success:
var a = document.getElementById('zipDownload');
a.href = data.data.url;
a.target = '_blank';
a.download = data.data.zipFile;
setTimeout(function() {
a.click();
}, 200);
the anchor is showing correct path for the file and downloads when i paste that in a new tab.. but when i trigger the anchor tag it shows
Not allowed to load local resource: file:///C:/xampp/htdocs/ems/public/documents/records-20200512002210.zip
Try using this in the Laravel response (if you are accessing the web app using http://localhost:8000 or something similar, where the laravel app's public directory is set as the document root):
$downloadData = [
'zipFile' => $zipName,
'headers' => $headers,
'url' => '/documents/'.$zipName
];
return response()->json(['status'=>1,'data'=> $downloadData]);
Here you may even use the url('/documents/'.$zipName) or route() functions depending on the configurations/environment variables that have been set.
file:///C:/xampp/htdocs/ems/public/documents/records-20200512002210.zip is a file resource that is on the webserver, and the front-end (JS) should not see it.
So, the zip file that you are going to download should be accessed relative to the web application's URI.
In your case, if the browser is able to access something like http://localhost:8000/documents/<zip file name>.zip or http://localhost/ems/documents/<zip file name>.zip, then you're good to proceed further.
Related
I recently tried to intercept all image requests following the example in their documentation:
await page.route('**/*.{png,jpg,jpeg}', route => route.abort());
// Abort based on the request type
await page.route('**/*', route => {
return route.request().resourceType() === 'image' ?
route.abort() : route.continue();
});
But it was not working at all.
How can I make it work?
There is a missing string in the types (or they are outdated in v1.15.1):
When logging route.request().resourceType() into console, I noticed there is a "images" resource type. So you can easily intercept any images including "images" to your check.
For instance you could do like this:
await page.route('**/*', route => {
return route.request().resourceType().match(/(image)s?/) ?
route.abort() : route.continue();
});
I am using minio to manage the files
const getMinioClient = () => {
const minioClient = new Minio.Client({
endPoint: '127.0.0.1',
port: 9000,
useSSL: false,
accessKey: 'minioadmin',
secretKey: 'minioadmin'
});
return minioClient;
};
uploadFile(bucketName, newFileName, localFileLocation,metadata={}) {
return new Promise((resolve, reject) => {
const minioClient = getMinioClient();
//'application/octet-stream'
minioClient.fPutObject(bucketName, newFileName, localFileLocation, metadata , (err, etag) => {
if (err) return reject(err);
return resolve(etag);
});
});
}
with the following code I can upload the file, after successfully uploading it returns me only with etag, but I want to get the download link, how would I get it directly without searching the filename again.
You won't be able to get something like Public URL/Link for accessing images unless you ask for it to manually generate a time limited download URL using something like:
https://min.io/docs/minio/linux/reference/minio-mc/mc-share-download.html#generate-a-url-to-download-object-s
One workaround is to let nginx directly access the location you are uploading your files to:
https://gist.github.com/harshavardhana/f05b60fe6f96803743f38bea4b565bbf
After you have successfully written your file with your code above, you can use presignedUrl method to generate the link to your image.
An example for Javascript is here: https://min.io/docs/minio/linux/developers/javascript/API.html#presignedUrl:~:text=//%20presigned%20url%20for%20%27getObject%27%20method.%0A//%20expires%20in%20a%20day.%0AminioClient.presignedUrl(%27GET%27%2C%20%27mybucket%27%2C%20%27hello.txt%27%2C%2024*60*60%2C%20function(err%2C%20presignedUrl)%20%7B%0A%20%20if%20(err)%20return%20console.log(err)%0A%20%20console.log(presignedUrl)%0A%7D)
In any case you have to set an expiration time. Here or you set a very long time, which is suitable to your app or if you have a backend, require the images from Frontend through the backend with the getObject method: getObject(bucketName, objectName, getOpts[, callback]).
https://min.io/docs/minio/linux/developers/javascript/API.html#presignedUrl:~:text=getObject(bucketName%2C%20objectName%2C%20getOpts%5B%2C%20callback%5D)
If you have only a few number of static images to show in your app, (which are not uploaded by your app), you can also create the links manually with tme minio client or from the Minio-UI.
:) I chose for automated testing a tool Cypress.io.
I need some tests for my sitemap.xml document and I dont know how to do that :(
I have tried install an npm package libxmljs
npm install libxmljs --save
and load it as plugin in cypress/plugins/index.js
const libxmljs = require('libxmljs');
But there is a problem with this. It shows an error
The plugins file is missing or invalid.
Your pluginsFile is set to /home/my-app/cypress/plugins/index.js, but
either the file is missing,
it contains a syntax error, or threw an error when required.
The pluginsFile must be a .js or .coffee file.
Please fix this, or set pluginsFile to false if a plugins file is not
necessary for your project.
Error: The module '/home/my-app/node_modules/libxmljs/build/Release/xmljs.node'
Please help me, how can I use libxmljs in Cypress.io or how i should write tests for Sitemap.xml in this end-to-end testing tool.
Thanks for your time! :)
Although #NoriSte's answer is correct, I found a simpler alternative without the need for any 3rd party code.
Cypress API exposes all the necessary methods to:
load a file (the sitemap.xml in your case): cy.request.
parse XML file (it exposes the jQuery API): Cypress.$
check if a page successfully loads (with a 200 status code): cy.visit
This is the following test that I use to test if all of the pages declared in the sitemap are loading (and make sure it doesn't point to any 404):
describe('Sitemap', () => {
// initialize the url array
let urls = []
// be sure to get the url list before executing any tests
before(async () => {
// getch the sitemap content
const response = await cy.request('sitemap.xml')
// convert sitemap xml body to an array of urls
urls = Cypress.$(response.body)
// according to the sitemap.xml spec,
// the url value should reside in a <loc /> node
// https://www.google.com/sitemaps/protocol.html
.find('loc')
// map to a js array
.toArray()
// get the text of the <loc /> node
.map(el => el.innerText)
})
it('should succesfully load each url in the sitemap', () => {
urls.forEach(cy.visit)
})
})
If you want to use libxmljs to parse your sitemap you should
read the sitemap itself with cy.request
add a custom task to Cypress (because libxmljs is a node library, cy.task is the only way to consume Node.js scripts from your Cypress tests)
returns the parsed data from your task
assert about it in a Cypress test
Those are the high-level steps you need to do 😉
To add to a great answer by gion_13, here’s his solution refactored to utilize Cypress promise-like-commands instead of async calls.
describe('Sitemap', () => {
let urls = [];
before(() => {
cy.request('sitemap.xml')
.as('sitemap')
.then((response) => {
urls = Cypress.$(response.body)
.find('loc')
.toArray()
.map(el => el.innerText);
});
});
it('should succesfully load each url in the sitemap', () => {
urls.forEach(cy.visit);
});
});
Using async in Cypress may raise error ‘Cypress detected that you returned a promise in a test, but also invoked one or more cy commands inside of that promise’.
describe('Sitemap', () => {
let urls = [];
before(() => {
const parser = new DOMParser();
cy.request('/sitemap.xml').then((response) => {
const document = parser.parseFromString(response.body, 'application/xml');
const parsedUrls = document.getElementsByTagName('loc');
urls = Array.from(parsedUrls).map((item) => item.innerHTML);
});
});
it('Should load each url from the sitemap', () => {
urls.forEach(cy.visit);
});
});
I have a multi-step form in Vue, I am posting the results once I collect all of the information, to a Laravel controller. This is an authenticated area of the site. I am using Passport. So essentially I have a Vue SPA that is the admin area of a website built within the Laravel 5.7 framework.
Vue file:
axios.post('/api/quotes/finalize', this.wizardModel)
.then(response => {
if (response.data.success) {
//
}
})
.catch(err => {
if (err.response.status == 401) {
window.location.href = '/login';
}
swal.showValidationError(
`Request failed: ${error}`
)
})
The controller gets data and makes a pdf. All of that is working. It then has three actions to look at - email the PDF, email the PDF with CC, and download the PDF.
public function finalizeQuote(Request $request)
{
$data = $request->all();
$data['phone'] = $this->formatTelephone($data['phone']);
$dateStamp = date('Ymdhis', strtotime('now'));
$fileName = 'quote-' . $dateStamp . '.pdf';
$html = View::make('quotes.quote', compact('data'))->render();
$conv = new Converter();
$conv->addPage($html)
->save('storage/' . $fileName);
if ($data['actions']['emailPDF']) {
$message = (new Proposal('storage/' . $fileName))
->onConnection('redis')
->onQueue('emails');
if ($data['actions']['carbonCopy']) {
Mail::to($data['emailAddress'])
->cc(Auth::user()->email)
->queue($message);
} else {
Mail::to($data['emailAddress'])->queue($message);
}
}
if ($data['actions']['downloadPDF']) {
return response()->download(public_path('storage/' . $fileName));
}
}
So in dev tools I see the pdf file in the response. No download occurs in the browser. I am sure I am just missing something fundamental here.
Ajax requests alone cannot invoke a download. You could have a hidden form that posts your data to your api endpoint, probably the quickest solution.
Axios has a built in way to do this easily
axios({
method: 'post',
url: '/api/quotes/finalize',
data: wizardModelFormData,
config: { headers: {'Content-Type': 'multipart/form-data' }}
})
Instead of sending json in the request, you would have to send form data. It is pretty easy to setup a form data object, and a quick google on FormData should be enough.
Another way is to do something like this. Have the endpoint return a download url for your file,
if ($data['actions']['downloadPDF']) {
return response()->json(["download_url" => "/api/download/" . $fileName]);
}
and on the client side, use window.location to set the browser location to this api endpoint that only returns files (in this case /api/download/{fileName}). The browser would then download any file returned from that location you set (if you have the headers setup correctly).
This would mean you would have to implement the /api/download/{fileName} route, but that is where you would put something like this.
return response()->download(public_path('storage/' . $fileName));
Obviously that is just a simple explanation and it doesn't need to be implemented exactly the same way, but it gets the idea across.
Now you would want to make sure that you don't put any sensitive files in storage/ and have some permissions setup.
Axios is used for XHR requests. Typically, downloading files is done through normal GET requests but here you have an XHR post request to download files.
To download files over AJAX, some folks use libraries and some create
a blob link from the response, append it to DOM and then, trigger a
click on the link.
You can refer this gist and SO post for further details.
Personally, I prefer simple non-XHR get requests for file downloads.
I'm getting the following error when trying to access one of my routes on Twilio using Laravel.
error on line 2 at column 6: XML declaration allowed only at the start of the document
The cause seems to be that there is an empty 1st line in the XML document rendered by the library because I've tested it on a different installation and it didn't have the same error. However, I do not know how to go about removing it. I've looked elsewhere online and the've suggested removing any spaces preceding the php tag, which I've tried, but it hasn't worked.
How do I remove the first line in the XML file generated?
Route::get('/outbound', function()
{
$sayMessage = "Hello";
$twiml = new Services_Twilio_Twiml();
$twiml->say($sayMessage, array(
'voice' => 'alice',
'language' => 'en-GB'
));
$twiml->gather(array(
'action' => '/goodbye',
'method' => 'GET',
));
$response = Response::make($twiml, 200);
$response->header('Content-Type', 'text/xml');
return $response;
});
Service_Twilio_Twiml() already sets the response header to XML, so no need to do it again. Remove this line and try again $response->header('Content-Type', 'text/xml');