Converting JS file upload with fetch() to python - javascript

I have to convert js code to python.
The js code performs a file upload via a POST request, using fetch().
This is the js code:
<input type="file" />
<button onclick="upload()">Upload data</button>
<script>
upload = async() =>
{
const fileField = document.querySelector('input[type="file"]');
await uploadDoc(fileField.files[0] );
};
uploadDoc = async( file ) =>
{
let fd = new FormData();
fd.append( 'file', file );
fd.append( 'descr', 'demo_upload' );
fd.append( 'title', name );
fd.append( 'contentType', 'text' );
fd.append( 'editor', user );
let resp = await fetch( url, { method: 'POST', mode: 'cors', body: fd });
};
</script>
The code works and complies with the fetch() docs, provided here:
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#uploading_a_file
Now when i try to recreate this in python, i get a 500 HTTP Status Code
This is the python code:
from urllib import request
from urllib.parse import urlencode
import json
with open('README.md', 'rb') as f:
upload_credentials = {
"file": f,
"descr": "testing",
"title": "READMEE.md",
"contentType": "text",
"editor": username,
}
url_for_upload = "" #here you place the upload URL
req = request.Request(url_for_upload, method="POST")
form_data = urlencode(upload_credentials)
form_data = form_data.encode()
response = request.urlopen(req, data=form_data)
http_status_code = response.getcode()
content = response.read()
print(http_status_code)
print(content)
This doesn't work however and i get this error:
raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 500:
Someone with both js and python experience might be able to see what is wrong in the python side, or how to convert the fetch() function to python.

I think the problem is that you're reading the file in binary mode (rb). You need just r:
with open('README.md', 'r') as f: # r instead of rb
However, I still reccomend the requests module, which is more widely used, and is easier in this case.
import requests # pip install requests
url = "https://www.example.com/upload_file"
headers = {
"content-type": "text/plain" # force text file content type
}
files = {
"my_file": ("FILE_NAME.md", open("README.md","r")) # tuple containing file name, and io.BytesIO file buffer
}
data = { # in case you want to send a request payload too
"foo": "bar"
}
r = requests.post(url, headers=headers, files=files, data=data)
if r.status_code == 200:
print(r.text) # print response as a string (r.content for bytes, if response is binary like an image)

Related

How can I enable the user to download a file from a server using Django?

I am using Django 3.1.2 to build a website, and I want the user of my website to be able to download a .zip file created on the backend when they click a button on the webpage.
However, when testing, I found that the download would not start when the button is clicked. No error was thrown either, and I just could not work out where I went wrong.
JavaScript:
document.querySelector("#download").onclick = function() {
// #download is the button I am talking about; it is in reality a div element
var formData = new FormData();
for (let i = 2; i < formElementsNumber; i++) {
let element = formElements[i];
formData.append(element.name, element.value);
}
formData.append("txtFile", formElements[1].files[0]);
formData.append("token", token);
// Up to here, everything works fine
$.ajax({
url: "/download/",
type: 'post',
data: formData,
// Essential; otherwise will receive an "illegal invocation" error
contentType: false,
processData: false,
success: function(data) {
// What should I add here to make the downloading start?
}
})
}
urls.py:
urlpatterns = [
path('', views.index),
path('process/', views.process),
path('download/', views.download)
]
views.py:
def download(request):
// Creates an .zip file
property_list = ['imageWidth', 'imageHeight', 'fontFamily', 'fontSize', 'rotationDirection', 'rotationAngle', 'foregroundColor', 'backgroundColor', 'token']
image_info = {}
for item in property_list:
image_info[item] = request.POST.get(item)
image_info['txtFile'] = request.FILES.get('txtFile').read().decode('gbk').split('\r\n')
// zip_name is the absolute path to the newly created .zip file
zip_name = w2p.make_zip(image_info, image_info['token'])
// Everything above works fine; the .zip file is successfully created
// What modification should I make here to make the downloading start properly
with open(zip_name, 'rb') as f:
response = HttpResponse(f.read())
response['content_type'] = "application/octet-stream"
response['Content-Disposition'] = 'attachment; filename=word2pic.zip'
return response
A thousand thanks in advance for your time.
import os
from django.conf import settings
from django.http import HttpResponse, Http404
def download(request, path):
file_path = os.path.join(settings.MEDIA_ROOT, path)
if os.path.exists(file_path):
with open(file_path, 'rb') as fh:
response = HttpResponse(fh.read(), content_type="application/filename")
response['Content-Disposition'] = 'inline; filename=' + os.path.basename(file_path)
return response
raise Http404

How to reconstruct file from base64 to pdf in javascript?

In Nodejs, I'm getting response from an api
{
"file": "PHN0eWxlPnRlRrU3VRbUNDJyAvPjwvcD4K",
"mime_type": "text/html",
"document_type": "shippingLabel"
}
To reconstruct the file, the data from the node needs to be base64 decoded, and interpreted according to the mime_type.
Help me to get the file in .pdf and save to directory.
Using fs.writeFileSync(file, data[, options]):
const fs = require('fs');
// get your response somehow...
const response = {
file: 'PHN0eWxlPnRlRrU3VRbUNDJyAvPjwvcD4K',
mime_type: 'text/html',
document_type: 'shippingLabel'
};
// LUT for MIME type to extension
const ext = {
'text/html': 'html',
// ...
}
// save to shippingLabel.html
fs.writeFileSync(`${response.document_type}.${ext[response.mime_type]}`, response.file, 'base64');

Vue-Resource upload file to PHP

I am trying to send an image through a resource and recovery in a php file but I have not succeeded, this is my JS file:
//* AJAX *//
startAsyncNews: function(){
if(this.sendimage){
var formdata = new FormData();
formdata.append("file",this.contentnew.imageFile );
console.log(this.contentnew.imageFile);
}
// POST /someUrl
this.$http.post('controllers/newsController.php', {
data:{action : this.accion_new, data_new: this.contentnew , imgf : formdata}
}).then(response => {
}, response => {
console.log("error");
});
},
imageSelect: function($event){
this.sendimage=true;
this.contentnew.imageFile =$event.target.files[0];
}
When I use the console.log = console.log (this.contentnew.imageFile), it shows me the properties of the image correctly, that is, it is sending the file well, but when I receive it in php and I do vardump I get this object ( stdclass) # 3 (0) no properties no properties and with json_decode / encode I get it empty, also try
headers: {
'content-type': 'multipart/form-data'
}
But it generates the following error:
Missing boundary in multipart/form-data POST
You need to add all your data in formdata Object using formdata.append(key,value) function.
Then you simply send formdata
formdata.append('action ',this.accion_new);
formdata.append('data_new',this.contentnew);
this.$http.post('controllers/newsController.php', {
data:formdata
});
// or just if i'm not mistaken
this.$http.post('controllers/newsController.php',formdata);
object in http request data.
I don't know what this.accion_new and this.contentnew are, but this line:
this.$http.post('controllers/newsController.php', {
data:{action : this.accion_new, data_new: this.contentnew , imgf : formdata}
})
should simply be be:
this.$http.post('controllers/newsController.php', formdata)

Triggering a Jenkins build using node js

I have a jenkins job that takes a file as an input. The job reads the input file and then processes the job.
I am trying to run a jenkins job from node js script. I am able to run the particular job using the jenkins api for npm.
My problem is that I am not able to run the job by passing the file required.
In Jenkins, I have to find the particular job and then migrate to it and then click "Build with parameters" and then select the file and build.
I am trying to uncomplicate this by having a react UI that takes a file as input and submits it to the node js script. Now that script has to upload the file to Jenkins and then build the job.
Node js code is,
var file0 = '/Users/m0a00pf/Documents/react-js/asda/src/files/APA.csv';
exports.buildJenkinsJob = function buildJenkinsJob(){
jenkins.job.build({"name":"Create a job",
"parameters":
{
"name": "\\src\\main\\resources\\com\\asda\\qa\\data\\APA\\APA.csv", "file": file0
}
}
,function(err, data){
if(err)
throw err;
else
console.log(data);
});
}
The parameters part is not working. when I run.
jenkins.job.build({"Create a job"});
this works fine.
Changed the options as,
var options = {
method: 'POST',
url: 'http://localhost/job/JobName/buildWithParameters?delay=0sec&Jenkins-Crumb=asdf345672das',
auth : {
username : jenkins.username,
password : jenkins.password
},
headers:
{
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
},
body:
{
'fileParameterName' :
{ value: fs.createReadStream(absoluteFilePath), options: { filename: FileName, contentType: null } },
'param': 'value'
}
};
There is a plain JS way of doing this, with just popular libraries such as Axios and form-data
var axios = require('axios');
var FormData = require('form-data');
var fs = require('fs');
var data = new FormData();
const jenkinsUrl = 'http://example_jenkins_server_url.com/job/<JOB_NAME>/build';
// notice the URL has build not buildWithParameters if the job has file parameters. ^
const userName = 'example_user';
const password = 'example_pass'
const params = {"parameter": [
// file0 here is the field name we are appending to data object,
// this informs Jenkins which file maps to which job parameter, so even multiple file uploads can be done using this approach!
{"name":"<Name Of file parameter in Job>", "file":"file0"}
// incase you have additional string parameters you need to pass add it here.
{"name": "StringParam1", "value": "value"}
]}
data.append('file0', fs.createReadStream(<full file path>));
data.append('json', JSON.stringify(params));
var config = {
method: 'post',
url: jenkinsUrl,
headers: {
Authorization: `Basic ${Buffer.from(`${userName}:${password}`).toString('base64')}`,
...data.getHeaders()
},
data : data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})

POST request take too long time with fetch api

I have developed http server in python3 with http.server.
I have encountered problem that the does not done sending post response, so browser keep loading too much time.
Which side (server or browser) causes this problem?
and How do I fix it?
Python3.6.3
macOS 10.13
import http.server
class MyHandler(http.server.BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def do_POST(self):
# Now this method just print path and content-type.
print("POSTED")
content_type = self.headers["Content-Type"]
print(content_type)
print(self.path)
if "multipart/form-data" in content_type:
raw_data = self.rfile.read()
self.send_response(200, self.responses[200][0])
self.send_header("access-control-allow-origin", "*")
self.send_header("connection", "close")
self.end_headers()
# WIP: do something...
def do_GET(self):
if self.path[0] == "/":
self.path = self.path[1:]
try:
with open(self.path, "rb") as f:
file_data = f.read()
except FileNotFoundError:
self.send_response(404, self.responses[404][0])
self.end_headers()
return
content_length = len(file_data)
self.send_response(200, self.responses[200][0])
self.send_header("content-length", content_length)
self.end_headers()
self.wfile.write(file_data)
def parse_post():
# WIP
pass
httpd = http.server.HTTPServer(("", 6788), MyHandler)
print("Address:", "", "Port:", 6788)
httpd.serve_forever()
browser js:
let formdata = new FormData();
formdata.append("Hello", "World");
fetch("http://localhost:6788/nk", {
method: "post",
mode: "cors",
body: formdata,
})

Categories

Resources