Unable to serve html file using 'http' module of Node.js - javascript

I am trying to serve an html page as a response to '/' request on my http server.
But somehow it's not working.
My index.html is -
<html>
<head>
<title>File Explorer</title>
<link rel='stylesheet' href='/stylesheets/style.css'/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.13/semantic.min.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.js"></script>
</head>
<script>
var fileExplorerApp = angular.module('explorerApp', []);
fileExplorerApp.controller("MyController", function ($scope, $http) {
var currentPath = '';
$scope.reload = function (newPath, back) {
if (back) {
currentPath = newPath;
} else {
if (currentPath === '') {
currentPath = newPath;
} else {
currentPath = currentPath + '/' + newPath;
}
}
console.log('Newpath- ' + currentPath);
$http.get('http://localhost:3000/list_dir?path=' + currentPath)
.then(function (response) {
$scope.filesAndFolders = response.data;
$scope.currentPath = currentPath;
}, function (error) {
console.log('Error in $http- ' + error);
});
}
$scope.back = function () {
var prevPath = currentPath.substring(0, currentPath.lastIndexOf('/'));
console.log('Path after substring- ' + prevPath);
console.log('Prevpath when back clicked- ' + prevPath);
$scope.reload(prevPath, true);
}
$scope.reload('F:/', false);
});
</script>
<body ng-app="explorerApp" ng-controller="MyController">
<div class="ui container">
<h1 id="currentPath">Current Directory- {{ currentPath }}</h1>
<button ng-if="currentPath !== 'F:/'"
ng-click="back()"
class="ui left labeled icon button">
<i class="left arrow icon"></i>
Back
</button>
<div class="ui list">
<a class="item"
ng-repeat="item in filesAndFolders"
ng-click="reload(item.name, false)"
ng-href="{{item.type === 'file' ? '/get_file?path='+currentPath+'/'+item.name : ''}}">
<i ng-if="item.type === 'folder'" class="folder icon"></i>
<i ng-if="item.type === 'file'" class="file icon"></i>
{{ item.name }}</a>
</div>
</div>
</body>
</html>
Via angular i'm accessing another route '/list_dir' and handling the request using 'http' module of Node.js(Not Express).
if(parsedUrl.pathname === '/list_dir') {
console.log('I\'m here');
var file_path = parsedUrl.query['path'];
list_dir.listDir(file_path, function (err, data) {
if(err){
res.writeHeader(400, {'Content-Type':'text/json'});
res.write(err);
} else {
console.log('in list_dir, no errors- response is- '+data);
res.writeHeader(200,{'Contenttype':'application/json'});
res.write(JSON.stringify(data));
}
});
res.end();
break;
}
The route '/list_dir' then accesses a function in another script which is this-
module.exports = {
listDir: function (path, myCallback) {
var resultObj = [];
fs.readdir(path, function (err, data) {
console.log('In listDir');
if (err) {
switch(err.code){
case 'EACCES':
return myCallback({errno: err.errno, description: 'An attempt was made to access a file in a way forbidden by its file access permissions.'}, null);
case 'ENOENT':
return myCallback({errno: err.errno, description: 'The specified path does not exist.'});
case 'EPERM':
return myCallback({errno: err.errno, description: 'An attempt was made to perform an operation that requires elevated privileges.'})
case 'ENOTDIR':
return myCallback({errno: err.errno, description: 'The specified path is not a directory.'})
}
return myCallback(err, null);
}
var itemsCompleted = 0;
data.forEach(function (value) {
fs.lstat(path + '/' + value, function (err, stats) {
itemsCompleted++;
if (err) {
console.log(err);
} else {
if (stats.isFile()) {
resultObj.push({
type: 'file',
name: value,
size: stats['size']
});
//resultObj.push(value);
//console.log(resultObj + '\n');
} else if (stats.isDirectory()) {
resultObj.push({
type: 'folder',
name: value,
size: stats['size']
});
}
}
if (itemsCompleted >= data.length) {
//console.log(resultObj);
return myCallback(null, resultObj)
}
});
});
});
}
};
This function return a json object of all the files/folders inside the given path, which will be provided to the '/list_dir' route. But i'm not getting the correct response from the route.
I want this route to respond with the same json that is returned by the listDir function. I'm new to the http module of Node.js, maybe ive written the header wrong or i'm consuming the data in a wrong way. Please help. Thanks!
UPDATE:
Chirags answer was correct and now '/list_dir' route is returning the correct json response. However, i'm still not able to serve the index.html file where i'm using AngularJS to consume this route.
This is how i'm handling the route-
if (parsedUrl.pathname === '/') {
fs.readFile('./index.html', 'utf-8', function (err, fileResponse) {
if (err) {
console.log('Error');
res.writeHeader(404, {
"Content-Type": "text/html"
});
res.write('There was an error!');
} else {
console.log('No error');
res.writeHeader(200, {
"Content-Type": "text/html"
});
res.write(fileResponse);
}
res.end();
});
}
Whats wrong with this?

You are closing your response stream too early. Basically, res.end() gets executed before your asynchronous function to read the directory gets executed and the callback is invoked. Try:
if (parsedUrl.pathname === '/list_dir') {
console.log('I\'m here');
var file_path = parsedUrl.query['path'];
list_dir.listDir(file_path, function (err, data) {
if (err) {
res.writeHeader(400, {
'Content-Type': 'text/json'
});
res.write(err);
} else {
console.log('in list_dir, no errors- response is- ' + data);
res.writeHeader(200, {
'Contenttype': 'application/json'
});
res.write(JSON.stringify(data));
}
res.end();
});
break;
}

Related

refresh page on function call javascript

I have a script where I am uploading a file to cloudinary, and then when it uploads, call my nodejs function (through js on front-end) and then update the file in my db. its working, but when I call the function, it does not render the page again. Instead nothing happens, but my db updates:
front-end script:
<script src="https://widget.cloudinary.com/v2.0/global/all.js" type="text/javascript"></script>
<script type="text/javascript">
var myWidget = cloudinary.createUploadWidget({
cloudName: 'ps',
uploadPreset: 'ld3l7evv'}, (error, result) => {
if (!error && result && result.event === "success") {
console.log('Done! Here is the image info: ', result.info);
console.log(result.info.secure_url)
var result_url = result.info.secure_url;
console.log("result url is " + result_url)
document.getElementById("url").value = result_url;
var employee_num = document.getElementById('employee_num').value
fetch('/changeProfileImage', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
result_url,
employee_num
})
})
}
}
)
backend (node.js):
app.post('/changeProfileImage', (req, res) => {
var employee_num = req.body.employee_num;
var url = req.body.result_url;
console.log("e " + employee_num)
console.log("u " + url)
var changeProfileImage = "update EMPLOYEES set (PROFILE_IMAGE)= '" + url + "' where EMPLOYEE_NUM = '" + employee_num + "'";
ibmdb.open(ibmdbconnMaster, function (err, conn) {
if (err) return console.log(err);
conn.query(changeProfileImage, function (err, rows) {
if (err) {
console.log(err);
}
console.log("succes")
conn.close(function () {
// console.log("closed the function /index");
});
})
})
})
but it is not actually refreshing / reloading the page after it updates the db. any idea?

How to FORK a repository inside aws codecommit using javascript from lambda?

I'm doing a implementation, and I need to fork a git repository into a codecommit repository using lambda and javascript. Create or update a file in the repository I can do.
What I need to know to fork a github repository (or a codecommit repository) for another repository inside codecommit?
I am showing the full code, because it is needed to undestand what I already do.
'use strict';
var AWS = require("aws-sdk");
var codecommit = new AWS.CodeCommit({ apiVersion: '2015-04-13' });
exports.handler = (event, context, callback) => {
event.Records.forEach((record) => {
console.log('Stream record: ', JSON.stringify(record, null, 2));
if (record.eventName == 'INSERT') {
var name = JSON.stringify(record.dynamodb.NewImage.name.S).replace(/[^a-z0-9áéíóúñü \.,_-]/gim,"");
var version = JSON.stringify(record.dynamodb.NewImage.version.S);
var data = JSON.stringify(record.dynamodb.NewImage.data.S);
var params = { repositoryName: name };
codecommit.getRepository(params, function(err, response) {
if (err) {
console.log(err, err.stack);
if(err.code == 'RepositoryDoesNotExistException') {
params.repositoryDescription='Repository ' + name;
codecommit.createRepository(params, function(err, response) {
if (err) {
console.log(err, err.stack);
} else {
console.log(response);
prepareCommit(name,version, data);
}
});
}
} else {
console.log('response repository: ', response);
prepareCommit(name, version, data);
}
});
}
});
callback(null, `Successfully processed ${event.Records.length} records.`);
};
function prepareCommit(name, version, data) {
var params = {
branchName: 'master',
repositoryName: name
};
codecommit.getBranch(params, function(err, response) {
if (err) {
console.log(err);
if (err.code='BranchDoesNotExistException') {
doCommit(name, version, '' + data, '');
}
} else {
console.log('response branch: ', response);
doCommit(name, version, '' + data, '' + response.branch.commitId);
}
});
}
function doCommit(name, version, data, parentCommitId) {
var params = {
branchName: 'master',
fileContent: Buffer.from(JSON.parse(data)) || '',
filePath: 'data/structure.json',
repositoryName: name,
commitMessage: 'generated by lambda stream ' + version,
email: '<email here>',
fileMode: 'NORMAL',
name: '<name here>'
};
if (parentCommitId != '') {
params.parentCommitId = parentCommitId;
}
codecommit.putFile(params, function(err, response) {
if (err) {
console.log(err, err.stack);
} else {
console.log(response);
}
});
}
This code receive a data from STREAM/DynamoDB and check if the repository exist, if not, a new is created and put a json file structure.json inside data/ folder.
I need fork a github or a codecommit repository on create inside a new repository.

sending formData using $http.post returns an empty body for larger files

I am trying to upload files through my web app. I have the following code:
View:
<div class="row">
<form name="rsdCtrl.viewData.uploadForm" class="form-horizontal col-sm-12">
<div class="row voffset4">
<div class="col-sm-4">
<input type="file" ngf-select ng-model="rsdCtrl.viewData.file" name="file" ngf-max-size="10MB" required/>
<i ng-show="rsdCtrl.viewData.uploadForm.file.$error.maxSize">File too large (max 10MB)</i>
</div>
</div>
<div class="row voffset3">
<div class="col-sm-4">
<button ng-disabled="!rsdCtrl.viewData.file || rsdCtrl.viewData.uploadForm.file.$error.maxSize" class="btn btn-success" type="submit" ng-click="rsdCtrl.uploadFile()">Upload</button>
</div>
</div>
</form>
</div>
Controller:
function uploadFile(){
if (vd.uploadForm.file.$valid && vd.file) {
$('#uploadModal').modal('show');
return uploadService.upload(vd.file, "Convictions Calculator", "PCCS").then(function(response){
vd.documentName = vd.file.name;
vd.uploadedFilePath = response.data;
$('#uploadModal').modal('hide').removeClass("in");
$(".modal-backdrop").remove();
alertService.setAlert('File uploaded', 'success');
}).catch(handleServiceError);
}
}
uploadService:
(function (){
'use strict';
angular.module('cica.common').service('uploadService', ['$http', '$window', '$routeParams', uploadService]);
function uploadService($http, $window, $routeParams) {
this.upload = function (file, name, type) {
const fd = new FormData();
fd.append('document', file);
let jobId = ($routeParams.jobId)? $routeParams.jobId: $routeParams.caseJobId;
fd.append('jobId', jobId);
fd.append('documentRename', name);
fd.append('documentType', type);
console.log(fd);
return $http.post('/document/upload', fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).catch(function(err){
handleHttpError('Unable to upload document.', err);
});
};
function handleHttpError(prefix, response){
throw prefix + ' HTTP Status ' + response.status + ': ' + response.statusText;
};
}
})();
routes.js:
'POST /document/upload': {controller: 'DocumentController', action: 'uploadDocument'},
DocumentController:
"use strict";
const fs = require('fs');
module.exports = {
uploadDocument: function (req, res) {
const params = req.allParams();
const jobId = params.jobId;
const uploadedFileName = params.documentRename;
const uploadedFileType = params.documentType;
const awardsDirectoryKey = this.documentUploadDirectories.ADDITIONAL_AWARDS;
req.file('document').upload({
// don't allow the total upload size to exceed ~100MB
maxBytes: 100000000
}, function whenDone(err, uploadedFiles) {
if (err) {
return res.serverError(err);
}
// If no files were uploaded, respond with an error.
else if (uploadedFiles.length === 0) {
return res.serverError('No file was uploaded');
} else {
const filePath = uploadedFiles[0].fd;
const filename = DocumentService.addDateToDocumentName(uploadedFiles[0].filename);
return fs.readFile(filePath, function (err, data) {
if (err) {
return res.serverError(err);
} else {
const jobId = params.jobId;
const jobVars =
{
filePath: results.filePath,
fileName: uploadedFileName,
fileType: uploadedFileType
};
return DocumentService.uploadConvictions(req.session.sessionId, jobId, jobVars).then(function (response) {
return res.send("Document uploaded.");
}).catch(function (err) {
return res.serverError(err);
});
}
});
}
});
},
If I upload a jpeg with a small picture (around 11kB) the upload works exactly as expected. However, If i try to upload a larger jpeg (around 170kB) it falls over. There is no immediate error thrown/caught though, what happens is the formData object created in the upload service seems to lose its data. If I insert this line into the DocumentController:
console.log(req.allParams());
the result prints the expected variables for the small file, but returns empty for the larger file, which eventually causes an error when the function tries to use these variables further on. Is there some kind of limit set to the size of file you can upload via this method, or have I configured this incorrectly?

.ajax call never returns

I'm using Express and Node. I've got some code that is posting JSON to another service that is adding it in a database.
The logic is doing what it is supposed to do, but the ajax call I am making is never returning, in the 'Network' tab in Chrome Dev tools it always shows as 'Pending' and eventually errors out with net::ERR_EMPTY_RESPONSE.
Can anyone tell me where I am going wrong?
Ajax Call
$.ajax
({
type: "POST",
url: "/order",
contentType: 'application/json',
data: orderDataJson,
success: function () {
alert("success!");
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("Something went wrong checking out!\n" + textStatus + "\n" + errorThrown);
}
});
This above routes to /order, which in turn posts the data to the other service:
app.post("/order", function(req, res, next)
{
var options = {
uri: endpoints.ordersUrl + "order",
method: 'POST',
json: true,
body: req.body
};
request(options, function(error, response, body) {
if (error !== null )
{
return;
}
if (response.statusCode == 200 && body != null && body != "")
{
if (body.error)
{
res.status(500);
res.end();
return;
}
res.end(); // UPDATED AFTER COMMENT
return;
}
console.log(response.statusCode);
});
});
This is the relevant code in the other service (it's correctly adding the content in the database)
if (request.method == 'POST')
{
switch (path)
{
// Add a new order
case "/order":
var body = '';
request.on('data', function (data) {
body += data;
});
request.on('end', function () {
var orderData = JSON.parse(body);
// Insert into orders table
var saleDate = getDate();
var ordersQuery = "INSERT into orders (customerId, saledate)" +
" VALUES (" + orderData.customerId +",'" + saleDate + "')";
db.query(ordersQuery, function(err, result)
{
if (err)
{
throw err;
}
var orderId = result.insertId;
// Insert order details
for (var i=0; i < orderData.order.length; i++)
{
var productId = orderData.order[i].productId;
var quantity = orderData.order[i].quantity;
var orderDetailsQuery = "INSERT into orderdetails (orderID, productID, quantity)" +
"VALUES (" + orderId + "," + productId + "," + quantity +")";
db.query(orderDetailsQuery, function(err, result)
{
if (err)
{
throw err;
}
});
}
});
response.writeHead(200, {
'Access-Control-Allow-Origin': '*'
});
});
break;
Try to add this in your error block:
if (error !== null ) {
res.status(500).send('Internal server error!');
return;
}
I got this fixed. The issue seem to be that express 'middleware' function should have been:
app.post("/order", function(req, res, body)
as opposed to:
app.post("/order", function(req, res, next)
From the expressjs docs:
If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging.

Trying to use prisimic and Node.js with express

I have partially got this starter kit from prismic working, but I am having trouble modifying it. Currently the project outputs everything, and I would like to output different collections in different lists.
I am very new to express, which is what this is using. I am not sure how to use the prismic query in this case to output a separate list for each collection or at least specified collections?
The predicate query according to the prismic api that works is this [:d = at(document.tags, ["ktblog"])]
Here is the EJS template where my list is being outputted
<ul id="list">
<% for(var i=0; i<docs.results.length; i++) { %>
<li>
<a href="<%= ctx.linkResolver(ctx, docs.results[i]) %>">
<%= docs.results[i].slug %>
</a>
</li>
<% } %>
</ul>
There is a index.js file
var prismic = require('../prismic-helpers');
// -- Display all documents
exports.index = prismic.route(function(req, res, ctx) {
ctx.api.form('everything').set("page", req.param('page') || "1").ref(ctx.ref).submit(function(err, docs) {
if (err) { prismic.onPrismicError(err, req, res); return; }
res.render('index', {
docs: docs
});
});
});
// -- Display a given document
exports.detail = prismic.route(function(req, res, ctx) {
var id = req.params['id'],
slug = req.params['slug'];
prismic.getDocument(ctx, id, slug,
function(err, doc) {
if (err) { prismic.onPrismicError(err, req, res); return; }
res.render('detail', {
doc: doc
});
},
function(doc) {
res.redirect(301, ctx.linkResolver(ctx, doc));
},
function(NOT_FOUND) {
res.send(404, 'Sorry, we cannot find that!');
}
);
});
// -- Search in documents
exports.search = prismic.route(function(req, res, ctx) {
var q = req.query['q'];
if(q) {
ctx.api.form('everything').set("page", req.param('page') || "1").ref(ctx.ref)
.query('[[:d = fulltext(document, "' + q + '")]]').submit(function(err, docs) {
if (err) { prismic.onPrismicError(err, req, res); return; }
res.render('search', {
docs: docs,
url: req.url
});
});
} else {
res.render('search', {
docs: null,
url: req.url
});
}
});
and there is a prismic helper file
var Prismic = require('prismic.io').Prismic,
Configuration = require('./prismic-configuration').Configuration,
http = require('http'),
https = require('https'),
url = require('url'),
querystring = require('querystring');
// -- Helpers
exports.getApiHome = function(accessToken, callback) {
Prismic.Api(Configuration.apiEndpoint, callback, accessToken);
};
exports.getDocument = function(ctx, id, slug, onSuccess, onNewSlug, onNotFound) {
ctx.api.forms('everything').ref(ctx.ref).query('[[:d = at(document.id, "' + id + '")]]').submit(function(err, documents) {
var results = documents.results;
var doc = results && results.length ? results[0] : undefined;
if (err) onSuccess(err);
else if(doc && (!slug || doc.slug == slug)) onSuccess(null, doc)
else if(doc && doc.slugs.indexOf(slug) > -1 && onNewSlug) onNewSlug(doc)
else if(onNotFound) onNotFound()
else onSuccess();
});
};
exports.getDocuments = function(ctx, ids, callback) {
if(ids && ids.length) {
ctx.api.forms('everything').ref(ctx.ref).query('[[:d = any(document.id, [' + ids.map(function(id) { return '"' + id + '"';}).join(',') + '])]]').submit(function(err, documents) {
callback(err, documents.results);
});
} else {
callback(null, []);
}
};
exports.getBookmark = function(ctx, bookmark, callback) {
var id = ctx.api.bookmarks[bookmark];
if(id) {
exports.getDocument(ctx, id, undefined, callback);
} else {
callback();
}
};
// -- Exposing as a helper what to do in the event of an error (please edit prismic-configuration.js to change this)
exports.onPrismicError = Configuration.onPrismicError;
// -- Route wrapper that provide a "prismic context" to the underlying function
exports.route = function(callback) {
return function(req, res) {
var accessToken = (req.session && req.session['ACCESS_TOKEN']) || Configuration.accessToken || undefined
exports.getApiHome(accessToken, function(err, Api) {
if (err) { exports.onPrismicError(err, req, res); return; }
var ref = req.query['ref'] || Api.master(),
ctx = {
api: Api,
ref: ref,
maybeRef: ref == Api.master() ? undefined : ref,
oauth: function() {
var token = accessToken;
return {
accessToken: token,
hasPrivilegedAccess: !!token
}
},
linkResolver: function(ctx, doc) {
return Configuration.linkResolver(ctx, doc);
}
};
res.locals.ctx = ctx;
callback(req, res, ctx);
});
};
};
// -- OAuth routes
var redirectUri = function(req) {
return req.protocol + '://' + req.get('Host') + '/auth_callback';
};
exports.signin = function(req, res) {
exports.getApiHome(undefined, function(err, Api) {
if (err) { exports.onPrismicError(err, req, res); return; }
var endpointSpec = url.parse(Api.data.oauthInitiate);
endpointSpec.query = endpointSpec.query || {};
endpointSpec.query['client_id'] = Configuration.clientId;
endpointSpec.query['redirect_uri'] = redirectUri(req);
endpointSpec.query['scope'] = 'master+releases';
res.redirect(301, url.format(endpointSpec));
});
};
exports.authCallback = function(req, res) {
exports.getApiHome(undefined, function(err, Api) {
if (err) { exports.onPrismicError(err, req, res); return; }
var endpointSpec = url.parse(Api.data.oauthToken),
h = endpointSpec.protocol == 'https:' ? https : http,
postData = querystring.stringify({
'grant_type' : 'authorization_code',
'code': req.query['code'],
'redirect_uri': redirectUri(req),
'client_id': Configuration.clientId,
'client_secret': Configuration.clientSecret
});
var postOptions = endpointSpec;
postOptions.method = 'POST';
postOptions.headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
};
var postRequest = h.request(postOptions, function(response) {
var jsonStr = '';
response.setEncoding('utf8');
response.on('data', function (chunk) {
jsonStr += chunk;
});
response.on('end', function () {
var accessToken = JSON.parse(jsonStr)['access_token'];
if(accessToken) {
req.session['ACCESS_TOKEN'] = accessToken;
}
res.redirect(301, '/');
});
});
postRequest.write(postData);
postRequest.end();
});
};
exports.signout = function(req, res) {
delete req.session['ACCESS_TOKEN'];
res.redirect(301, '/');
};
You can specify a collection in the "form" call, instead of 'everything'. Typically if you have a 'foobar' collection, you can restrict any query to this collection this way:
ctx.api.form('foobar')...
You will have to make one call for each collection you want to display.

Categories

Resources