i deeply need help with this audio file upload to cloudinary issue I have had for several days now. I tried many times to make it work, but i am still struggling. I am a beginner backend developer, so please any help is appreciated.
It is an mp3 player App. When i upload a song, the title gets saved in DB, but the Audio isn't. This is the MP3 PLAYER page screenshot. It shows the title being saved and rendered from DB but not the audio file.
Audio upload form
<form class="ui form" action="/albums/<%= album._id %>/songs" method="POST" enctype="multipart/form-data">
<div class="field">
<label>Song Title:</label>
<input type="text" id="title" name="song[title]" placeholder="song title...." required>
</div>
<div class="field">
<label>Song file:</label>
<input type="file" id="song" name="audio" accept="audio/*" required>
</div>
<div class="field">
<input class="fluid ui green button" type="submit" id="submit" value="Enter">
</div>
Exit
</form>
Song model
var mongoose = require("mongoose");
//Album Schema
var audioSchema = new mongoose.Schema({
title: String,
audio: String,
date: {type: Date, default: Date.now()}
});
//exporting the Schema
module.exports = mongoose.model("Audio", audioSchema);
Backend code/ROUTE
var express = require("express"),
router = express.Router({mergeParams: true}),
middleware = require("../middleware"),
Album = require("../models/album"),
Song = require("../models/songs"),
multer = require("multer")
var storage = multer.diskStorage({
filename: function(req, file, callback) {
callback(null, Date.now() + file.originalname);
}
});
//uploader
var upload = multer({ storage: storage});
var cloudinary = require('cloudinary');
cloudinary.config({
cloud_name: 'proccess.env.CLOUDINARY_NAME',
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET
});
//Songs new Route
router.get("/albums/:id/songs/new", middleware.isLoggedIn, function(req, res) {
//find Album by id
Album.findById(req.params.id, function(err, album) {
if(err) {
console.log(err);
} else {
res.render("songs/new", {album: album});
}
});
});
//Song POST route
router.post("/albums/:id/songs", middleware.isLoggedIn, upload.single("audio"), function(req, res) {
cloudinary.uploader.upload(req.file.path, function(result) {
// add cloudinary url for the mp3 to the album object under audio property
req.body.song.audio = result.secure_url;
//find Album by ID
Album.findById(req.params.id, function(err, album) {
if(err) {
console.log(err);
res.redirect("/albums/" + req.params.id);
} else {
//Creating Album and saving it to DB
Song.create(req.body.song, function(err, song) {
if(err) {
console.log("Opps something went wrong!" + err);
res.redirect("back");
} else {
//save the song to DB
song.save();
//this saves the songs object inside
album.songs.push(song);
//save album
album.save();
res.redirect("/albums/" + album._id);
}
});
}
});
});
});
module.exports = router;
cloudinary.uploader.upload(req.file.path, resource_type: "video", function(result)
That's because you will need to use GridFS from MongoDB to store data from a file.
https://docs.mongodb.com/manual/core/gridfs/#use-gridfs
As you are using Mongoose, please check this module : https://www.npmjs.com/package/mongoose-gridfs
The mongoose-gridfs module wrap the gridfs-stream module, and seems to fit to binary data upload. If you want, you can still do it yourself, by following this tutorial : http://niralar.com/mongodb-gridfs-using-mongoose-on-nodejs/
Related
To begin with, I'm making a simple social media application. I'm trying to submit a form which has text, images, and videos. My frontend where the form is submitted is made with React and server is ran with node.js mounted on nginx. I was trying to append the inputted files into FormData with code below:
handleSubmit = function (e) {
e.preventDefault();
const formData = new FormData();
formData.append("textBody", this.state.textBody)
for (let i = 0; i < this.state.imgInput.length; i++) {
formData.append("imgInput", this.state.imgInput.files[i], "img"+i.toString())
fetch("mywebsite.com/api/submitArticle", {
body: formData,
method: "POST",
credentials: 'include',
}).then((response) => console.log(response))
return false;
}.bind(this)
handleChange = function (e) {
e.preventDefault();
if (e.target.name === 'imgInput') {
this.setState({
imgInput: e.target.files,
showSpan: false
})
}
}.bind(this)
<form onSubmit={this.handleSubmit}>
<textarea id='textBody' name='textBody' onFocus={removeSpan} onBlur={checkSpanOn} onChange={this.handleChange}/>
<input type="file" id="imgInput" name="imgInput" accept="image/*" ref={this.imgRef} multiple={true} onChange={this.handleChange}/>
<input type="submit" id="submitButton" name="submitButton" formEncType="multipart/form-data" />
</form>
But React gave me this error upon submitting the form:
TypeError: Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'.
at "formData.append("imgInput", this.state.imgInput.files[i], "img"+i.toString())".
So when I console logged what e.target.files before setState in handleChange, I got normal FileList with all the image files listed. But when I console loggedd this.state.imgInput after setState in handleChange, I got String of C://fakepath/filename, not fileList. (Initially state.imgInput was null. When I saw other examples and codes, e.target.files was fileList so I'm puzzled elsewhere I made mistake.
I was spending half my day on this problem and I'm 5 sec before fainting so any advice would be appreciated :) Thank you for reading.
yes this happening because the event is gone you need to store the event.target in variable + the files will be in imgInput not imgInput.files so here it is:
handleSubmit = e => {
e.preventDefault();
const formData = new FormData();
formData.append("textBody", this.state.textBody);
for (let i = 0; i < this.state.imgInput.length; i++) {
formData.append("imgInput", this.state.imgInput[i], "img" + i.toString());
fetch("mywebsite.com/api/submitArticle", {
body: formData,
method: "POST",
credentials: "include"
}).then(response => console.log(response));
}
};
handleChange = e => {
e.preventDefault();
const target = e.target;
if (target.name === "imgInput") {
this.setState(current => ({
...current,
imgInput: target.files,
showSpan: false
}));
}
};
I want to send data about shopping cart from mongoDB to front-end page, use I use Koa and EJS engine, and I sure I have successfully get data from database. But in web page, it shown undefined
router.get('/cart', loadCart)
async function loadCart(ctx){
let userid = ctx.session.userID
let c_data = await C.getCart(userid)
console.log(typeof(c_data))
await ctx.render('cart',{
userid, c_data
})
}
code in html
<input type="hidden" value="<%= c_data %>" id="data">
function loadCart(){
let content = ""
let c_data = document.getElementById('data').value
c_data.forEach(element => {
console.log(element.name)
});
}
Did you add render settings like bellow?
render(app, {
root: templatesPath,
layout: 'template',
viewExt: 'html',
cache: false,
debug: false,
async: true
})
I think two properties here are important: root and layout.
My Html file is -
<form method="post" [formGroup]="orderForm" enctype="multipart/form-data" (ngSubmit)="OnSubmit(orderForm.value)" >
<div class="form-group">
<label for="image">Select Branch Image</label>
<input type="file" formControlName="branchImg" (change)="onFileChange($event)" class="form-control-file" id="image">
</div>
</form>
and my .ts file is -
public orderForm: FormGroup;
onFileChange(event) {
const reader = new FileReader();
if (event.target.files && event.target.files.length) {
const [file] = event.target.files;
reader.readAsDataURL(file);
reader.onload = () => {
this.orderForm.patchValue({
branchImg: reader.result
});
};
}
}
ngOnInit() {
this.orderForm = this.formBuilder.group({
branchImg: [null, Validators.required]
});
}
and then submit the form.
I am supposed to get the image address and the upload that address in cloudinary
But when I am consoling the body in my nodejs app
it gives something like this-
branchImg: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/7QCEUGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAGccAigAYkZCTUQwMTAwMGE4MjBkMDAwMD and so on.
I don't think that it is the images address. Can anyone tell me that what is this? and how to get that image's address which I will upload to cloudinary
As the Eric suggest -
my app.js code is
router.post('/branch',(req,res) =>{
const body = req.body;
const base64Data = body.branchImg.replace(/^data:image\/png;base64,/, "");
console.log(base64Data);
fs.writeFile("out.jpg", base64Data, 'base64', function(err,result) {
console.log(result);
});
});
it gives result as undefined
That basically is a base64 encoding of the image data. What you need to do after you get that is write that to a file, and then upload it to cloudinary
//this will write the base64 data as a jpg file to your local disk
require("fs").writeFile("out.jpg", base64Data, 'base64', function(err) {
//after you write it to disk, use the callback space here to upload said file
//to your cloudinary endpoint
});
I'm trying to build a web platform that where you can register and adapt your profile. However, I'm struggling with the editing part. Registration and Login are fine, but the rest gives an HTTP 500.
So here's what I did:
User Scheme for Mongoose:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');
//enhanced userSchema
var UserSchema = new Schema({
user_id: Schema.ObjectId,
username: {type :String, required : true, unique : true}, //serves as unique identifier
password: {type : String, required: true},
name: {type : String, required : true},
surname: String,
created_at : Date,
updated_at : Date,
skills: [{type : String}],
lectures: [{type : String}],
groups: [{type : String}] //todo: Change for later cross referencing with group schemes
});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model('User', UserSchema);
Followed by the Routing:
var express = require('express');
var router = express.Router();
var auth = require("../controllers/AuthController.js");
var profile = require ("../controllers/ProfileController");
// restrict index for logged in user only
router.get('/', auth.home);
// route to register page
router.get('/register.html', auth.register);
// route for register action
router.post('/register.html', auth.doRegister);
// route to login page
router.get('/login.html', auth.login);
// route for login action
router.post('/login.html', auth.doLogin);
// route for logout action
router.get('/logout.html', auth.logout);
//route to profile
router.get('/profile.html', profile.goToProfile);
//route for changing profile
router.post('/profile.html', profile.changeProfile);
module.exports = router;
And the profileController
/**
* Controller for editing the profile
*/
var mongoose = require("mongoose");
var passport = require("passport");
var User = require("../models/User");
var path = require('path');
//Change Name
var profileController = {};
//go to Profile
profileController.goToProfile = function (req, res){
res.sendFile(path.resolve('login.html')), {user : req.user};
}
profileController.changeProfile= function (req, res){
console.log("REQUEST: " + req.body.toString());
if (req.body.surname.isEmpty()){
}
else {
User.findByIdAndUpdate(req.user._id, { $set: { surname: req.body.surname }}, { new: true }, function (err, User) {
if (err) {
console.log(err.toString());}
res.alert('Changed surname');
console.log('changed surname')
});
};
if (req.body.name.isEmpty()){}
else {
User.findByIdAndUpdate(req.user._id, { $set: { name: req.body.name }}, { new: true }, function (err, User) {
if (err) {
console.log(err.toString());}
res.alert('Changed name');
console.log('changed name')
});
};
if (req.body.skills.length === 0){}
else {
User.findByIdAndUpdate(req.user._id, { $set: { skills: req.body.skills }}, { new: true }, function (err, User) {
console.log("Old Skills: " + User.skills.toString());
if (err) {
console.log(err.toString());}
console.log("New skills: " + User.skills.toString());
console.log('changed skills')
});
}
};
module.exports = profileController;
Which gets its data from this HTML form:
<!-- register container -->
<div class="container">
<form role="form" action="profile.html" method="post" style="max-width: 300px;">
<h2 class="form-heading">Your Profile</h2>
<input type="text" name="name" placeholder="Name" class="form-control" />
<input type="text" name="username" placeholder="Username" class="form-control" />
<input type="text" name="surname" placeholder="Last Name" class="form-control"/>
<input type="text" name="skills[]" placeholder="Your skills" class="form-control"/>
<button type="submit" class="btn btn-lg btn-primary btn-block">Save</button>
</form>
</div>
I'm very sorry for my bad code quality. This resulted from a very long day of working on it, but I simply couldn't figure out (even with tutorials and stack overflow) what went wrong.
The result is a 500 Internal Server Error.
Where is your PUT request? To update data, you need to use a PUT request. POST is for adding new entries.
I'm trying to learn some stuff with Knockout by following the examples.
I've followed the loading and saving data tutorial and read the docs on Loading and Saving JSON Data.
Using the code in these examples, I can't seem to overwrite the JSON file. I tried setting permissions to 777 to make sure that wasn't the problem.
On "success," it just seems to return the data in the file. I confirmed this by loading the HTML file, manually editing the JSON file, deleting tasks, and clicking save. The result I saw in my console was the data from the manual edit of the JSON file.
I have this hosted on my server right now: index.html, test.json.
For the sake of posterity, here is that code:
HTML
<!doctype html>
<html>
<body>
<h3>Tasks</h3>
<form data-bind="submit: addTask">
Add task: <input data-bind="value: newTaskText" placeholder="What needs to be done?" />
<button type="submit">Add</button>
</form>
<ul data-bind="foreach: tasks, visible: tasks().length > 0">
<li>
<input type="checkbox" data-bind="checked: isDone" />
<input data-bind="value: title, disable: isDone" />
Delete
</li>
</ul>
You have <b data-bind="text: incompleteTasks().length"> </b> incomplete task(s)
<span data-bind="visible: incompleteTasks().length == 0"> - it's beer time!</span>
<button data-bind="click: save">Save</button>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js"></script>
<script src="//code.jquery.com/jquery-1.10.2.min.js"></script>
<script>
function Task(data) {
this.title = ko.observable(data.title);
this.isDone = ko.observable(data.isDone);
}
function TaskListViewModel() {
// Data
var self = this;
self.tasks = ko.observableArray([]);
self.newTaskText = ko.observable();
self.incompleteTasks = ko.computed(function() {
return ko.utils.arrayFilter(self.tasks(), function(task) { return !task.isDone() && !task._destroy });
});
// Operations
self.addTask = function() {
self.tasks.push(new Task({ title: this.newTaskText() }));
self.newTaskText("");
};
self.removeTask = function(task) { self.tasks.destroy(task) };
self.save = function() {
var data = ko.toJSON({ tasks: self.tasks });
$.post('test.json', data, function(returnedData) {
console.info(returnedData);
});
/*
$.ajax("test.json", {
data: ko.toJSON({ tasks: self.tasks }),
type: "post", contentType: "application/json",
success: function(result) { console.info(result) }
});
*/
};
// Load initial state from server, convert it to Task instances, then populate self.tasks
$.getJSON("test.json", function(allData) {
var mappedTasks = $.map(allData, function(item) { return new Task(item) });
self.tasks(mappedTasks);
});
}
ko.applyBindings(new TaskListViewModel());
</script>
</body>
</html>
JSON
[{"title":"Wire the money to Panama","isDone":true},{"title":"Get hair dye, beard trimmer, dark glasses and \"passport\"","isDone":false},{"title":"Book taxi to airport","isDone":false},{"title":"Arrange for someone to look after the cat","isDone":false}]
The form is working properly, it's posting the correct JSON to the server (you can see this in the browser's dev tools). But because it's just a JSON file on the server, you're not able to overwrite it by simply posting to it. Instead, you'll need to create a web service endpoint on the server that you can post the data to, and the service will then save the file on the server's file system.