Uploading images using a vue comonent and DRF - vue.js

I am trying to upload an image using a vue component and django rest framework. Here is a snippet of the html
<div class="mb-3 mx-5">
<label for="image" class="form-label">Upload an image that best describes the survey</label>
<input class="form-control" type="file" ref="file" name="image" id="image" #change="onFileSelected()">
</div>
And here are my vue methods that am using to send data to the backend
methods: {
onFileSelected() {
this.image = this.$refs.file.files.item(0)
},
sendData (file) {
const formData = new FormData()
formData.append('image', file)
axios.post('/api/v1/surveys/', this.SurveyList, formData, {
headers: {
"Content-Type": "multipart/form-data",
"X-CSRFToken": "{{ csrf_token }}"
}
})
.then(response => {
this.SurveyList = response.data
})
.catch(error => {
console.log(error)
})
}
}
I was getting the following error The submitted data was not a file and then tried implementing the changes discussed here Django REST Framework upload image: "The submitted data was not a file" But now I get this error This field may not be null.
Here is my serializer.py
class SurveySerializer(serializers.ModelSerializer):
image = Base64ImageField(
max_length=None, use_url=True,
)
class Meta:
model = Survey
fields = (
"id",
"category",
"description",
"location",
"image",
"question1",
"questiontype1",
"choice1a",
"choice2a",
"choice3a",
"choice4a",
)
And here is my views.py
def post(self, request, format=None):
serializer = SurveySerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
What could be the issue?

Related

profilePic.move is not a function [AdonisJS]

I am facing the error while trying to upload a file(image) via the form on AdonisJS (I referred to the official docs #AdonisJS4.1 File Uploads)
await profilePic.move(Helpers.tmpPath('uploads'), {
name: 'custom.jpg',
overwrite: true
})
if (!profilePic.moved()) {
console.log('file not moved')
}
Official Docs Here
HTML
<form method="POST" action="upload" enctype="multipart/form-data">
<input type="file" name="profile_pic" />
<button type="submit"> Submit </button>
</form>
JS
const Helpers = use('Helpers')
Route.post('upload', async ({ request }) => {
const profilePic = request.file('profile_pic', {
types: ['image'],
size: '2mb'
})
await profilePic.move(Helpers.tmpPath('uploads'), {
name: 'custom-name.jpg',
overwrite: true
})
if (!profilePic.moved()) {
return profilePic.error()
}
return 'File moved'
})

axios sending null when uploading files to laravel api. Error Message: "Call to a member function store() on null"

I have a form with file upload. I am using vue, axios and laravel 7 at the moment.
My form is as given below:
<form v-on:submit.prevent="createTask" enctype="multipart/form-data" method="post">
<div class="form-group">
<label for="title">Title</label>
<input type="text" class="form-control" name="title" id="title" v-model="task.title" />
<label for="content">Content</label>
<textarea v-model="task.content" class="form-control" id="content" name="content" rows="4" ></textarea>
<button type="submit" class="btn btn-sm btn-primary
pull-right" style="margin:10px; padding:5 15 5 15; background-color:#4267b2">Save Task</button>
<span>
<button #click="removeImage" class="btn btn-sm btn-outline-danger" style="margin:10px; padding:5 15 5 15; ">Remove File</button>
</span>
<input type="file" id="image" name="image" />
</div>
</form>
Axios submission
createTask() {
console.log(document.getElementById('image').files[0])
axios({
headers: { 'Content-Type': 'multipart/form-data' },
method: 'post',
url: '/api/tasks',
data: {
task_id : this.task.id,
title : this.task.title,
content : this.task.content,
created_by : this.$userId,
image : document.getElementById('image').files[0],
}
})
.then(res => {
// check if the request is successful
this.$emit("task-created");
this.task = {}
})
.catch(function (error){
console.log(error)
});
}
My controller code
public function store(Request $request)
{
$task = $request->isMethod('put') ? Task::findOrFail($request->task_id) : New Task;
$task->id = $request->input('task_id');
$task->title = $request->input('title');
$task->content = $request->input('content');
$task->views = $request->input('views');
$task->created_by = $request->input('created_by');
$task->image = $request->image->store('images');
//$task->image = $request->file('image')->store('images');
if($task->save()) {
return new TaskResource($task);
}
}
The request payload
{task_id: "", title: "test", content: "test content", created_by: "1", image: {}}
We can see the image attribute is empty
The response error message
"Call to a member function store() on null"
The output of console.log(document.getElementById('image').files[0])
File {name: "test.jpg", lastModified: 1590920737890, lastModifiedDate: Sun May 31 2020 11:25:37 GMT+0100 (British Summer Time), webkitRelativePath: "", size: 436632, …}
lastModified: 1590920737890
lastModifiedDate: Sun May 31 2020 11:25:37 GMT+0100 (British Summer Time) {}
name: "test.jpg"
size: 436632
type: "image/jpeg"
webkitRelativePath: ""
proto: File
I solved this problem by changing the axios post request as follows. I used FormData to append and send data to server
createTask() {
let data = new FormData;
data.append('image', document.getElementById('image').files[0]);
data.append('task_id', this.task.id);
data.append('title', this.task.title);
data.append('content', this.task.content);
data.append('created_by', this.$userId);
axios({
headers: { 'Content-Type': 'multipart/form-data' },
method: 'post',
url: '/api/tasks',
data: data
})
.then(res => {
// check if the request is successful
this.$emit("task-created");
this.image = '';
this.task = {}
})
.catch(function (error){
console.log(error)
});
}
Assuming the image column has the right structure, you could try with somenthing like this:
<?php
public function store(Request $request)
{
$task = $request->isMethod('put') ? Task::findOrFail($request->task_id) : New Task;
$task->id = $request->input('task_id');
$task->title = $request->input('title');
$task->content = $request->input('content');
$task->views = $request->input('views');
$task->created_by = $request->input('created_by');
$task->image = $request->hasFile('images')
? $request->file('images')
: null;
if($task->save()) {
return new TaskResource($task);
}
}
laravel 5.4 upload image read here for more information

Uploading files to Google Cloud Buckets using Rest API POST

I searched around but I couldn't find anything useful about this.
I'm trying to upload a file to a google cloud bucket in my project using REST APIs, but all i am obtaining is a binary file in the bucket, and not the actual file.
Uploading using curl as explained in the Documentation works fine and, e.g., i can upload a png to my bucket.
I am using Vue.js and axios to make the request.
This is the code for the form:
<template>
<div>
<div id="form">
<form #submit.prevent="postFiles" enctype="multipart/form-data">
<input type="file" #change="previewFiles" multiple />
<input type="submit" value="Send file" />
</form>
</div>
</div>
</template>
<script>
export default {
name: "InsertFile",
data() {
return {
file: "",
};
},
methods: {
previewFiles(event) { //I use this just for the debug
console.log(event.target.files);
this.file = event.target.files;
},
postFiles(){
this.$emit('insert-file',this.file);
}
},
};
</script>
This is the code for the view
<template>
<div class="upload">
<h1>Here you can upload your files</h1>
<InsertFile #insert-file="postFile" />
</div>
</template>
<script>
import InsertFile from "../components/InsertFile";
import axios from "axios";
let token='exampletoken'
let config = {
headers: {
'content-type': 'multipart/form-data',
Authorization: "Bearer " + token,
},
};
let url =
"https://storage.googleapis.com/upload/storage/v1/b/bucketURL/o?uploadType=media&name=foo.png";
export default {
components: {
InsertFile,
},
methods: {
postFile(path) {
let bodyFormData = new FormData();
bodyFormData.append("image", path[0]);
console.log(bodyFormData);
axios
.post(url, bodyFormData, config)
.then((response) => {
console.log("Response", response.data);
})
.catch((e) => {
console.log("Error: ", e.response.data);
});
},
},
};
</script>
From this code i obtain a file of type multipart/form-data in the bucket, how can i upload it as a png (or any kind of file)?
[EDIT]
This is the form right now
<template>
<div>
<div id="form">
<form #submit.prevent="postFiles" enctype="multipart/form-data">
<input type="file" #change="previewFiles" multiple />
<input type="hidden" name="Content-Type" value="image/png">
<input type="submit" value="Send file" />
</form>
</div>
</div>
</template>
This is the method
<script>
import InsertFile from "../components/InsertFile";
import axios from "axios";
let url =
"https://storage.googleapis.com/upload/storage/v1/b/myBucket/o?uploadType=media&name=prova.png";
export default {
components: {
InsertFile,
},
methods: {
postFile(path) {
console.log(path);
let bodyFormData = new FormData();
bodyFormData.append("file", path[0]);
bodyFormData.append("content-type", "image/png");
console.log(bodyFormData);
let token ='mytoken'
let config = {
headers: {
Authorization: "Bearer " + token,
},
};
axios
.put(url, bodyFormData, config)
.then((response) => {
console.log("Response", response.data);
})
.catch((e) => {
console.log("Error: ", e.response.data);
});
},
},
};
</script>
Within the multipart data you need to send the mime type as a content-type.
For example, with a JPEG you would send Content-Type: image/jpeg
Without this, the upload assumes that the file type is the default of being binary data not an image.
In your link to the docs you provided, take a look at this OBJECT_CONTENT_TYPE part.
To quote their documentation:
The MIME type of the file you are uploading via the form. If you do not specify a content type, the Cloud Storage system defaults to application/octet-stream when it serves the content.
If you are able to, I'd recommend installing and using the storage part of the official NodeJS SDK and following this example here: https://cloud.google.com/storage/docs/uploading-objects#storage-upload-object-nodejs
This should be a lot more robust and provide an immediately functioning example.
It will also make it a lot easier to utilise other functions of the API such as list or delete operations.

How can I upload image to server using axios

I am trying to send a form along with an image. Note: I don't want to save the image in a database, I want to save it in a folder which I created on the server and just add a link of the image to the database.
From the server side I know how to handle this, but I don't know how to do this from font-end. With other words, how can I send the image using axios to the server.
<template>
<input type="text" class="form-control" id="specdesc" v-model="product.specdesc" name="specdesc" placeholder="Enter your name">
<input type="file" name="image" id="image" accept="image/*" >
<button type="submit" class="btn btn-sm btn-primary"#click.prevent="Submit()"> Submit</button>
</template>
<script>
export default {
name: 'Addproduct',
data(){
return{
image: '',
product:{
specdesc:'',
},
}
},
methods:{
Submit(){
var _this=this
// console.log(this.image)
console.log(this.selectedCategory.category_name)
var product = {
specification:this.product.specdesc,
imagename:this.image
}
this.$http.post('http://localhost:3000/api/companyproducts',product)
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.log("error.response");
});
}
},
}
</script>
Now my question is how can I upload a image as well as the input name using axios. Moreover I want to use the same method i.e var product to send.
A standard (mostly) approach will be to split the logic in two, if you want to save the image path on your product, you firstly need to upload the photo to the server and return their path.
pseudo example:
component's data
{
imagePath: '',
productSpect: ''
}
``
``html
<input type="text" v-model="productSpect" />
<input type="file" #change="uploadImage" name="image" id="image" accept="image/*" >
<button type="submit" #click.prevent="submit"> Submit</button>`
``
**uploadImage method**
uploadImage (e) {
let img = e.target.files[0]
let fd= new FormData()
fd.append('image', img)
axios.post('/upload-image', fd)
.then(resp => {
this.imagePath = resp.data.path
})
}
**submit method**
submit () {
let data = {
imagePath: this.imagePath,
productSpect: this.productSpect
}
axios.post('/path/to/save', data)
}
**edited method to handle just only 1 image on the server**
Change the input `#change` to just save the img on a property under data():
<input type="file" #change="image = e.target.file[0]" name="image" id="image" accept="image/*" >
submit() {
let fd= new FormData()
fd.append('image', this.image)
axios.post('/upload-image', fd)
.then(resp => {
this.imagePath = resp.data.path
let data = {
imagePath: this.imagePath,
productSpect: this.productSpect
}
axios.post('/path/to/save', data)
})
}
There is nothing specific to Vue in this question. To send a POST request with axios, the easiest thing to do is to grab the formData of the html form and pass it as the data argument to Axios. To do this in Vue, just give your form tag a ref, then create a formData from the form.
<form ref="myForm">
// then in your method...
var myFormData = new FormData(this.$refs.myForm)
axios({
method: 'post',
url: 'myurl',
data: myFormData,
config: { headers: {'Content-Type': 'multipart/form-data' }}
})
for upload file I've used vuetify https://vuetifyjs.com/en/components/file-inputs/
<v-file-input
accept="image/png, image/jpeg, image/bmp"
placeholder="Pick an avatar"
prepend-icon="mdi-camera"
v-model="imageData"
></v-file-input>
<v-btn color="primary" #click="onUpload">Upload</v-btn>
in my vue method I have
onUpload() {
let formData = new FormData();
formData.append('file', this.imageData);
axios.post(
"/images/v1/upload"
,formData
,{headers: {"Content-Type": "multipart/form-data"}}
)
.then(response => {
//...
})
.catch(e => {
//...
})
}
Best regards!

Switching Google reCaptcha Version 1 from 2

I have successfully designed and implemented Google reCaptcha Version 2 but now my Manager wants that to be of version 1 with numbers to be entered and validated. Is there a way to switch from later to former i.e.- from 2 to 1. I am using following library for reCaptcha:
<script src='https://www.google.com/recaptcha/api.js'></script>
Update..
To implement Captcha inside form i am using following HTML..
<form class="contact_form" action="#" method="post" name="contact_form">
<div class="frm_row">
<label id="lblmsg" />
<div class="clear">
</div>
</div>
<div class="g-recaptcha" data-sitekey="6Lduiw8TAAAAAOZRYAWFUHgFw9_ny5K4-Ti94cY9"></div>
<div class="login-b">
<span class="button-l">
<input type="button" id="Captcha" name="Submit" value="Submit" />
</span>
<div class="clear"> </div>
</div>
</form>
As i need to get the Captcha inside the above form to Validate and get the response on button click but as now i am using <script src="http://www.google.com/recaptcha/api/challenge?k=6Lduiw8TAAAAAOZRYAWFUHgFw9_ny5K4-Ti94cY9"></script> , so not getting the Captcha inside the form ..Please help me to get that ..Also here is the Jquery Ajax code to send the request on Server side code..
$(document).ready(function () {
alert("hii1");
$('#Captcha').click(function () {
alert("Hii2");
if ($("#g-recaptcha-response").val()) {
alert("Hii3");
var responseValue = $("#g-recaptcha-response").val();
alert(responseValue);
$.ajax({
type: 'POST',
url: 'http://localhost:64132/ValidateCaptcha',
data: JSON.stringify({ "CaptchaResponse": responseValue }),
contentType: "application/json; charset=utf-8",
dataType: 'json', // Set response datatype as JSON
success: function (data) {
console.log(data);
if (data = true) {
$("#lblmsg").text("Validation Success!!");
} else {
$("#lblmsg").text("Oops!! Validation Failed!! Please Try Again");
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("Error");
}
});
}
});
});
Please help me ..Thanks..
You have to verify the reCaptcha at "http://www.google.com/recaptcha/api/verify" on Server side.
The parameters of this are:
privatekey: Your Private Key
remoteip: User's IP Address
challenge: Value of input[name=recaptcha_response_field]
response: Value of input[name=recaptcha_challenge_field]
Therefore, you have to post them on your server-side method like this:
cshtml file:
var recaptchaResponseField=$("input[name=recaptcha_response_field]").val();
var recaptchaChallengeField=$("input[name=recaptcha_challenge_field]").val();
// ajax block
$.ajax({
url: '/api/VerifyReCaptcha/', // your Server-side method
type: 'POST',
data: {
ipAddress: '#Request.ServerVariables["REMOTE_ADDR"]',
challengeField: recaptchaChallengeField,
responseField: recaptchaResponseField
},
dataType: 'text',
success: function (data) {
// Do something
},
Since you are using .NET so an example of C# code is as follows:
cs file:
using System.Net;
using System.Collections.Specialized;
[HttpPost]
public bool VerifyReCaptcha(string ipAddress, string challengeField, string responseField)
{
string result = "";
using (WebClient client = new WebClient())
{
byte[] response =
client.UploadValues("http://www.google.com/recaptcha/api/verify", new NameValueCollection()
{
{ "privatekey", "{Your private key}" },
{ "remoteip", ipAddress },
{ "challenge", challengeField },
{ "response", responseField },
});
result = System.Text.Encoding.UTF8.GetString(response);
}
return result.StartsWith("true");
}