How can I store Code Snippet in mongo db? - javascript

I want to create A post route So I Can store the User Typed code snippets into the collection in MongoDB.
the schema would look like this:-
const newSnippetSchema= new mongoose.Schema({
title:String,
snippet:String
})
to be brief I am working on creating a web app like codeSandbox or code-pen where I can save the code user has saved or typed....
I want to send data in Json format when Post Route is triggered

Create a http post web api.
const express = require('express')
const mongoose = require('mongoose')
const NewSnippetSchema = require('./models/newSnippetSchema')
const app = express()
mongoose.connect('mongodb://localhost/mydb', {
useNewUrlParser: true, useUnifiedTopology: true
})
app.set('view engine', 'ejs')
app.use(express.urlencoded({ extended:false }))
app.post('/newSnippet', async (req, res) => {
await NewSnippetSchema.create({ title: req.body.title, snippet: req.body.snippet })
res.redirect('/')
})
app.listen(process.env.PORT || 5000);

catchAsync Code:
const catchAsync = (fn) =>
function asyncUtilWrap(...args) {
const fnReturn = fn(...args);
const next = args[args.length - 1];
return Promise.resolve(fnReturn).catch(next);
};
export default catchAsync;
AppError Code:
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
export default AppError;
Controller Code:
const snippetController = catchAsync(async (req, res, next) => {
const { title, snippet } = req.body;
if (!title || !snippt) {
return next(new AppError('All fields are required', 400));
}
const snippetDoc = await Snippet.create(req.body);
return res.status(201).json({
status: 'success',
snippetDoc
});
});
export default snippetController;
Router Code:
router.route('/snippet').post(snippetController);

The database has nothing to do with this. It doesn't matter how you store it, what matters is how render it in your HTML representation on the UI.
Just use the built-in HTML encoding function to encode the code snippet before storing it in the database.(eg - encode all & as & something like this).
After fetching the data, decode it back before rendering it on the UI.

Related

req.body undefined in custom middleware express

So I'm doing a simple NodeJS app with MongoDB/Express/Mongoose. In my mongoose schema I have a field (pictureURL) with a default value, the problem is that if pictureURL is an empty string the default value does not get applied. To solve this I though about using a custom middleware when doing the POST request either when creating or updating the model.
But the issue I'm having is that from within the middleware req.body is undefined. It is fine when in the router.post method but not in the middleware. Here is the code I have.
middleware (pictureU.js)
const app = require('../app');
const bookPictureUrl = (res, req, next) => {
console.log({ body: req.body });
if (!req.body.pictureUrl)
req.body.pictureUrl = 'images/default';
next();
};
module.exports = { bookPictureUrl };
book.routes.js
const app = require('../app');
const router = require('express').Router();
const Book = require('../models/Book.model');
const { bookPictureUrl } = require('../middleware/pictureUrl');
router.post('/update/:id', bookPictureUrl, async (req, res, next) => {
try {
req.body.authors = req.body.authors.split(',');
const data = await Book.findByIdAndUpdate(req.params.id, req.body);
res.redirect('/books');
} catch (err) {
next(err);
}
});
Any help trying to fix this so that I can use req.body within the middleware would be greatly appreciate.
Thanks
You mixed up your argument order. req should come before res.
const bookPictureUrl = (req, res, next) => {
console.log({ body: req.body });
if (!req.body.pictureUrl)
req.body.pictureUrl = 'images/default';
next();
};

CastError: Cast to ObjectId failed for value "(contains mongodb id)" (type string) at path "_id" for model "User"

I am trying to write a user blocking/unblocking script but having some troubles with mongodb's CastError : "https://prnt.sc/5pIESnJ8Jmqe"
So, these are my codes related to this error. If you can check them out and give me a second opinion about the error, i would be very pleased. Don't hesitate to ask for more information.
Admin.JS of routers
const express = require('express');
const {getAccessToRoute, getAdminAccess} = require("../middlewares/authorization/auth");
const {checkUserExist} = require("../middlewares/database/databaseErrorHelpers")
const {blockUser} = require("../controllers/admin")
const router = express.Router()
router.use([getAccessToRoute,getAdminAccess])
router.get("/block/:id",checkUserExist, blockUser)
module.exports = router
Admin.JS of controllers
const User = require("../models/User")
const asyncErrorWrapper = require("express-async-handler")
const CustomError = require("../helpers/error/CustomError")
const blockUser = asyncErrorWrapper(async (req, res, next) => {
const {id} = req.params
const user = await User.findById(id)
user.blocked = !user.blocked
await user.save()
return res.status(200)
.json({
success : true,
message : "Block - Unblock Successfull"
})
})
module.exports = {
blockUser
}
My model file doesn't contain "_id", mongodb generates the id of the registered user as a default parameter.

How come fetch only works here when I add an alert to the end of the line? Express + NodeJS + Fetch. What's a good fix here

I'm using NodeJS w/ Express to create a web app that records your audio using the VMSG library and posts the BLOB audio to my file system using HTTP Requests and multer. It also adds that instance of a recording into a MongoDB database.
I'm having an issue with the fetch command. It's not working unless I put an alert right after the fetch. The way I have it set up is that I have my main express app (index.js), and a router to the /recordingsDirectory (recordings.js) which is the endpoint for processing the posts. My main index HTML page uses Handlebars and uses a separate JS script (recorder.js) to 1) use the VMSG library and 2) fetch a POST to the /recordingsDirectory once someone submits the audio file w/ the name and the AudioBlob present. This is where I'm stuck. I can fetch in recorder.js with an alert line after the fetch, but I can't have the fetch on the end of the else if block by itself. I'd like to do it without this since the alert is ugly. A solution I've tried is that I tried to make the onsubmit function async and await fetch since I thought maybe it's waiting for a promise but that didn't work.
Here are the files. I commented CRITICAL and SUPER CRITICAL to the lines of code that you should check out and I think where the issues lie:
index.js
const express = require('express')
const handlebars = require('express-handlebars')
const path = require('path')
const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
const xhr = new XMLHttpRequest()
const db = require('./db')
const app = express()
const PORT = process.env.PORT || 8000
app.set('view engine', 'hbs')
app.engine('hbs', handlebars({
layoutsDir: path.join(__dirname, 'views', 'layouts'),
extname: 'hbs',
defaultLayout: 'index',
partialsDir: path.join(__dirname, 'views', 'partials'),
}))
app.use(express.json())
app.use(express.urlencoded({extended: false}))
app.use((err, req, res, next) => {
if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
return res.status(400).send({ status: 404, message: err.message })
}
next()
})
app.get('/', (req, res) => {
res.render('main', {
title: 'Main Page'
})
})
app.get('/recordings', (req, res) => {
var database = db.get().db('AudioJungle')
database.collection('recordings').find().sort({ "date": -1 }).toArray(function(err, docs) {
res.render('recordings', {
title: 'Recordings',
recordings: docs
})
})
})
// CRITICAL
app.use('/recordingsDirectory', require('./recordings/recordings'))
app.use(express.static('public'))
app.use('/scripts', express.static(path.join(__dirname, 'node_modules', 'vmsg')))
db.connect(function(err) {
if (err) {
console.log('Unable to connect to Mongo.')
process.exit(1)
} else {
app.listen(PORT, () => console.log(`Listening on Port: ${PORT}`))
}
})
process.on('SIGINT', function() {
db.close(function () {
console.log('Disconnected on app termination');
process.exit(0);
});
});
app.use((req, res, next) => {
res.status(404).send({
status: 404,
error: 'Not found'
})
})
recordings.js (Aka the /recordingsDirectory endpoint for a fetch POST)
const express = require('express')
const router = express.Router()
const multer = require('multer')
const fs = require('fs-extra')
const db = require('../db')
const { ObjectId } = require('bson')
const moment = require('moment')
const upload = multer({
storage: multer.diskStorage({
destination: (req, file, callback) => {
let path = './public/uploads'
fs.mkdirsSync(path)
callback(null, path)
},
filename: (req, file, callback) => {
createRecording(req).then((id) => {
var file_name = id + '.mp3'
callback(null, file_name)
})
}
})
})
var type = upload.single('audio-file')
// CRITICAL
router.post('/', type, (req, res) => {
console.log('made it')
res.status(200)
res.send('OK')
})
router.delete('/delete', (req, res) => {
deleteRecording(req.body._id).then((dbResponse) => {
if (dbResponse == null || dbResponse == undefined) {
res.status(400).json({ msg: 'ID already deleted' })
} else {
res.status(200)
}
})
})
router.get('/', (req, res) => {
var database = db.get().db('AudioJungle')
var recordings = database.collection('recordings')
recordings.findOne({"_id": ObjectId(req.query.id)}, function(err, result) {
if (err) throw err
if (result == null || result == undefined) {
return res.status(400).json({
status: 404,
error: 'Recording no longer in the database'
})
}
res.status(200)
res.json({
name: result.name,
date: result.date
})
})
})
async function createRecording(req) {
var database = db.get().db('AudioJungle')
var recordings = database.collection('recordings')
var audioObject = {
name: req.body.name,
date: moment().format('MMMM Do YYYY, h:mm:ss a')
}
var dbResponse = await recordings.insertOne(audioObject)
return dbResponse.insertedId
}
async function deleteRecording(id) {
var database = db.get().db('AudioJungle')
var recordings = database.collection('recordings')
var audioToDelete = {
_id: ObjectId(id)
}
var deleteResult = await recordings.deleteOne(audioToDelete)
return deleteResult
}
module.exports = router
And below is the Script the audio and name and tries to Fetch (where I need the alert for it to actually process into the /recordingsdirectory)
recorder.js
import { record } from "/scripts/vmsg.js";
let recordButton = document.getElementById("record");
var blobObj = null
recordButton.onclick = function() {
record({wasmURL: "/scripts/vmsg.wasm"}).then(blob => {
blobObj = blob
var tag = document.createElement("p")
tag.id="finishedRecording"
var text = document.createTextNode("Audio File Recorded")
tag.appendChild(text)
var element = document.getElementById("box")
element.appendChild(tag)
document.getElementById('box').appendChild(a)
})
}
let form = document.getElementById('mp3Form');
form.addEventListener("submit", submitAudio)
function submitAudio() {
var fileName = form.elements[0].value
if (fileName == "") {
alert('Please enter a name for your file')
} else if (blobObj != null) {
// CRITICAL
// SUPER CRITICAL WHERE FETCH DOESN'T WORK UNLESS I PUT AN ALERT AT THE END
const formData = new FormData()
formData.append('name', fileName)
formData.append('audio-file', blobObj)
const options = {
method: 'POST',
body: formData
}
fetch('/recordingsDirectory', options);
// If I comment an alert here, /recordingsDirectory will process the post since it console.logs 'made it'
} else {
alert('Record some Audio to upload')
}
}
Here's my file system.
Also, I'd like to mention that the fetch works properly on my Windows PC without having to add the alert, but it doesn't work without the alert on my macbook. If any one figures out a fix or an error in how I'm doing things to allow this please let me know. I've been stuck on this problem for a day now. Thanks a bunch!

NeDB not saving into file with Express.JS

I am writing a bulk import function for a password manager for myself and I have come across an issue.
There is an array of passwords to import and I'm using a forEach() method to iterate through each password to import.
I call the insert function and everything just stops. No error, no callback, no saving to file. Here is my code:
const express = require('express')
const app = express()
const { encrypt, decrypt } = require('./crypto')
const Datastore = require('nedb')
app.post('/bulkimport', checkAuthenticated, (req, res) => {
var passwords = JSON.parse(req.body.passwords)
var dbForUser = new Datastore('./passwords/' + req._passport.session.user + '.db')
passwords.forEach(password => {
function doc(code, link, name, password) {
this.code = code
this.link = link
this.name = name
this.password = password
}
var entry = new doc(password.name, password.url, password.username, password.password)
console.log(entry)
console.log('before insert') // gets logged
dbForUser.insert(entry, function(err, doc) {
console.log('after insert') // doesn't get logged
if (err) return res.status(500).send()
console.log(doc)
})
});
})
Middlewares I'm using:
app.use(bodyParser.json())
app.use(express.urlencoded({ extended: false }))
app.use(flash())
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false
}))
app.use(passport.initialize())
app.use(passport.session())
app.use(methodOverride('_method'))
Thanks for the help!
I see two problems. db.insert according to the nedb docs takes a plain JS object, and you're calling a res.send() in a forEach (which could result in the cannot set headers after they are sent error. You can also skip parsing the body by using a module for that.
const express = require('express')
// added
const bodyParser = require('body-parser')
const app = express()
const { encrypt, decrypt } = require('./crypto')
const Datastore = require('nedb')
// added
app.use(bodyParser.json())
app.post('/bulkimport', checkAuthenticated, (req, res) => {
// changed
var passwords = req.body.passwords
var dbForUser = new Datastore('./passwords/' + req._passport.session.user + '.db')
// changed: forEach would just keep running, potentially causing errors
for (let password of passwords) {
// changed
var entry = {
link: password.url,
password: password.password,
name: password.username,
code: password.name,
}
// changed to remove res.send from callback
let e = false
dbForUser.insert(entry, (err, doc) => {
if (err) {
e = true
}
})
// added to exit from route if an error
if (e) {
res.status(500).send()
return
}
}
res.status(201).send()
})
EDIT:
In the chat we also discovered that nedb doesn't really do anything on disk unless you call it with autoload: true or call loadDatabase, which was happening on one of the databases but not the one in the Express route (docs). Adding that got things working.

My console gives me an error when I put the routes to a controller

I'm setting up a route to register an account, but my VS code gives me an error when I direct the routes to controller.js.
This is for a new website, running javascript, nodejs and react.
My routes.js:
const routes = require('express').Router();
const RegisterController = require('./controllers/RegisterController');
routes.get('/', (req, res) => {
return res.send('Hello, World!')
});
routes.post('/register', RegisterController.store);
module.exports = routes;
My RegisterController.js:
const User = require('../models/UserModel');
class RegisterController {
async store(req, res) {
const email = req.body.email.toLowerCase();
const username = req.body.username.toLowerCase();
const EmailExists = await User.findOne({ email: email });
const UserExists = await User.findOne({ user: username });
if (!EmailExists) {
return res.json({ message: 'This email is already registered! Please, try another.' });
};
if (!UserExists) {
return res.json({ message: 'This user is already registered! Please, try another.' });
}
const { password } = req.body.password;
const user = await User.create({
username,
email,
password
});
return res.json(user)
}
}
I expect to register my MongoDB account.
The error VS Code gives me is:
Error: Route.post() requires a callback function but got a [object Undefined]
RegisterController.store is undefined because store is a instance method instead of a static method.
class RegisterController {
static async store(req, res) {
// ...
}
}
It's a naming problem:
const RegisterController = require('./controllers/RegisterController');
if you have a class with a static function e.g.:
class RegisterController {
static store(req, res) {}
}
Then you would call it like:
RegisterController.store(req, res);
If you make the variable name the same as the class name, then how would you make a distinction between a static call and a normal call?
const RegisterController = require('./controllers/RegisterController');
RegisterController.store(req, res); // this is meant to be a static call
RegisterController.store(req, res); // this is meant to be a normal call
You create your variable name with uppercase, in my opinion it should be lowercase because else how would you make a difference between a class name and a variable name just by looking at it?
Try the following:
const registerController = require('./controllers/RegisterController');
routes.post('/register', registerController.store);
I hope this provides a solution to your problem.

Categories