Installed API infrastructure, getText works already
parent
39b5f57d4e
commit
f45b7ce9ea
|
@ -1,3 +1,4 @@
|
|||
node_modules
|
||||
settings.json
|
||||
static/js/jquery.min.js
|
||||
APIKEY.txt
|
||||
|
|
|
@ -0,0 +1,457 @@
|
|||
/**
|
||||
* This module provides all API functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* 2011 Peter 'Pita' Martischka
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var padManager = require("./PadManager");
|
||||
var async = require("async");
|
||||
|
||||
/**********************/
|
||||
/**GROUP FUNCTIONS*****/
|
||||
/**********************/
|
||||
|
||||
/**
|
||||
createGroup() creates a new group
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: {groupID: 5}}
|
||||
*/
|
||||
exports.createGroup = function (callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
getMappedGroup4(groupMapper) this functions helps you to map your application group ids to etherpad lite group ids
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: {groupID: 7}}
|
||||
*/
|
||||
exports.getMappedGroup4 = function (groupMapper, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
deleteGroup(groupID) deletes a group
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"There is no group for this groupID", data: null}
|
||||
*/
|
||||
exports.deleteGroup = function(groupID, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
listPads(groupID) returns all pads of this group
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: {padIDs : ["3$test", "3$test2"]}
|
||||
{code: 1, message:"There is no group for this groupID", data: null}
|
||||
*/
|
||||
exports.listPads = function(groupID, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
createPad(groupID, padName [, text]) creates a new pad in this group
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"pad does already exist", data: null}
|
||||
{code: 1, message:"There is no group for this groupID", data: null}
|
||||
*/
|
||||
exports.createPad = function(groupID, padName, text, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**********************/
|
||||
/**AUTHOR FUNCTIONS****/
|
||||
/**********************/
|
||||
|
||||
|
||||
/**
|
||||
createAuthor([name]) creates a new author
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: {authorID: 5}}
|
||||
*/
|
||||
exports.createAuthor = function(name, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
getMappedAuthor4(authorMapper [, name]) this functions helps you to map your application author ids to etherpad lite author ids
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: {authorID: 5}}
|
||||
*/
|
||||
exports.getMappedAuthor4 = function(authorMapper ,name, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**********************/
|
||||
/**SESSION FUNCTIONS***/
|
||||
/**********************/
|
||||
|
||||
/**
|
||||
createSession(groupID, authorID, validUntil) creates a new session
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: {sessionID: 5}}
|
||||
{code: 1, message:"groupID doesn't exist", data: null}
|
||||
{code: 1, message:"authorID doesn't exist", data: null}
|
||||
{code: 1, message:"validUntil is in the past", data: null}
|
||||
*/
|
||||
exports.createSession = function(groupID, authorID, validUntil, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
deleteSession(sessionID) deletes a session
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 1, message:"ok", data: null}
|
||||
{code: 1, message:"sessionID does not exist", data: null}
|
||||
*/
|
||||
exports.deleteSession = function(sessionID, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
getSessionInfo(sessionID) returns informations about a session
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: {authorID: 5, groupID: 7, validUntil: 1312201246}}
|
||||
{code: 1, message:"sessionID does not exist", data: null}
|
||||
*/
|
||||
exports.getSessionInfo = function(sessionID, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
listSessionsOfGroup(groupID) returns all sessions of a group
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: {32: {authorID: 5, groupID: 7, validUntil: 1312201246}, 53: {authorID: 3, groupID: 2, validUntil: 1312201216}}}
|
||||
{code: 1, message:"groupID does not exist", data: null}
|
||||
*/
|
||||
exports.listSessionsOfGroup = function(groupID, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
listSessionsOfAuthor(authorID) returns all sessions of an author
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: {32: {authorID: 5, groupID: 7, validUntil: 1312201246}, 53: {authorID: 3, groupID: 2, validUntil: 1312201216}}}
|
||||
{code: 1, message:"authorID does not exist", data: null}
|
||||
*/
|
||||
exports.listSessionsOfAuthor = function(authorID, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
deleteAllSessionsOfGroup(groupID) deletes all sessions of a group
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"groupID does not exist", data: null}
|
||||
*/
|
||||
exports.deleteAllSessionsOfGroup = function(groupID, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
deleteAllSessionsOfAuthor(authorID) deletes all sessions of an author
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"authorID does not exist", data: null}
|
||||
*/
|
||||
exports.deleteAllSessionsOfAuthor = function(authorID, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/************************/
|
||||
/**PAD CONTENT FUNCTIONS*/
|
||||
/************************/
|
||||
|
||||
/**
|
||||
getText(padID, [rev]) returns the text of a pad
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: {text:"Welcome Text"}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.getText = function(padID, rev, callback)
|
||||
{
|
||||
//check if rev is set
|
||||
if(typeof rev == "function")
|
||||
{
|
||||
callback = rev;
|
||||
rev = undefined;
|
||||
}
|
||||
|
||||
//check if padID is a string
|
||||
if(typeof padID != "string")
|
||||
{
|
||||
callback({stop: "padID is not a string"});
|
||||
return;
|
||||
}
|
||||
|
||||
//check if rev is a number
|
||||
if(rev !== undefined && typeof rev != "number")
|
||||
{
|
||||
//try to parse the number
|
||||
if(!isNaN(parseInt(rev)))
|
||||
{
|
||||
rev = parseInt(rev);
|
||||
}
|
||||
else
|
||||
{
|
||||
callback({stop: "rev is not a number"});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//ensure this is not a negativ number
|
||||
if(rev !== undefined && rev < 0)
|
||||
{
|
||||
callback({stop: "rev is a negativ number"});
|
||||
return;
|
||||
}
|
||||
|
||||
//ensure this is not a float value
|
||||
if(rev !== undefined && !is_int(rev))
|
||||
{
|
||||
callback({stop: "rev is a float value"});
|
||||
return;
|
||||
}
|
||||
|
||||
var pad;
|
||||
var data;
|
||||
|
||||
async.series([
|
||||
//check if pad exists
|
||||
function(callback)
|
||||
{
|
||||
padManager.doesPadExists(padID, function(err, exists)
|
||||
{
|
||||
if(err)
|
||||
{
|
||||
callback(err);
|
||||
}
|
||||
else
|
||||
{
|
||||
callback(exists == false ? {stop: "padID does not exist"} : null)
|
||||
}
|
||||
});
|
||||
},
|
||||
//get the pad object
|
||||
function(callback)
|
||||
{
|
||||
padManager.getPad(padID, function(err, _pad)
|
||||
{
|
||||
pad=_pad;
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
//return the text
|
||||
function(callback)
|
||||
{
|
||||
//the client asked for a special revision
|
||||
if(rev !== undefined)
|
||||
{
|
||||
//check if this is a valid revision
|
||||
if(rev > pad.getHeadRevisionNumber())
|
||||
{
|
||||
callback({stop: "rev is higher than the head revision of the pad"});
|
||||
return;
|
||||
}
|
||||
|
||||
//get the text of this revision
|
||||
pad.getInternalRevisionAText(rev, function(err, atext)
|
||||
{
|
||||
if(!err)
|
||||
{
|
||||
data = {text: atext.text};
|
||||
}
|
||||
|
||||
callback(err);
|
||||
})
|
||||
}
|
||||
//the client wants the latest text, lets return it to him
|
||||
else
|
||||
{
|
||||
data = {"text": pad.text()};
|
||||
callback();
|
||||
}
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
callback(err, data)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
setText(padID, text) sets the text of a pad
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
{code: 1, message:"text too long", data: null}
|
||||
*/
|
||||
exports.setText = function(padID, text, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*****************/
|
||||
/**PAD FUNCTIONS */
|
||||
/*****************/
|
||||
|
||||
/**
|
||||
getRevisionsCount(padID) returns the number of revisions of this pad
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: {revisions: 56}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.getRevisionsCount = function(padID, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
deletePad(padID) deletes a pad
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.deletePad = function(padID, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
getReadOnlyLink(padID) returns the read only link of a pad
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.getReadOnlyLink = function(padID, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
setPublicStatus(padID, publicStatus) sets a boolean for the public status of a pad
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.setPublicStatus = function(padID, publicStatus, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
getPublicStatus(padID) return true of false
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: {publicStatus: true}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.getPublicStatus = function(padID, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
setPassword(padID, password) returns ok or a error message
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.setPassword = function(padID, password, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
isPasswordProtected(padID) returns true or false
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: {passwordProtection: true}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.isPasswordProtected = function(padID, callback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/******************************/
|
||||
/** INTERNAL HELPER FUNCTIONS */
|
||||
/******************************/
|
||||
|
||||
//checks if a number is an int
|
||||
function is_int(value)
|
||||
{
|
||||
return (parseFloat(value) == parseInt(value)) && !isNaN(value)
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* The Group Manager provides functions to manage groups in the database
|
||||
*/
|
||||
|
||||
/*
|
||||
* 2011 Peter 'Pita' Martischka
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
require("../db/Pad");
|
||||
var db = require("./DB").db;
|
||||
|
||||
/**
|
||||
* A Array with all known Pads
|
||||
|
@ -58,6 +59,13 @@ exports.getPad = function(id, callback)
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
//globalPads[id].timestamp = new Date().getTime();
|
||||
}
|
||||
|
||||
//checks if a pad exists
|
||||
exports.doesPadExists = function(padId, callback)
|
||||
{
|
||||
db.get("pad:"+padId, function(err, value)
|
||||
{
|
||||
callback(err, value != null);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* The Session Manager provides functions to manage session in the database
|
||||
*/
|
||||
|
||||
/*
|
||||
* 2011 Peter 'Pita' Martischka
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
|
@ -0,0 +1,139 @@
|
|||
/**
|
||||
* The API Handler handles all API http requests
|
||||
*/
|
||||
|
||||
/*
|
||||
* 2011 Peter 'Pita' Martischka
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var fs = require("fs");
|
||||
var api = require("../db/API");
|
||||
|
||||
//ensure we have an apikey
|
||||
var apikey = null;
|
||||
try
|
||||
{
|
||||
apikey = fs.readFileSync("../APIKEY.txt","utf8");
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
apikey = randomString(32);
|
||||
fs.writeFileSync("../APIKEY.txt",apikey,"utf8");
|
||||
}
|
||||
|
||||
//a list of all functions
|
||||
var functions = {
|
||||
// "createGroup" : [],
|
||||
// "getMappedGroup4" : ["groupMapper"],
|
||||
// "deleteGroup" : ["groupID"],
|
||||
// "listPads" : ["groupID"],
|
||||
// "createPad" : ["groupID", "padName", "text"],
|
||||
// "createAuthor" : ["name"],
|
||||
// "getMappedAuthor4" : ["authorMapper" , "name"],
|
||||
// "createSession" : ["groupID", "authorID", "validUntil"],
|
||||
// "deleteSession" : ["sessionID"],
|
||||
// "getSessionInfo" : ["sessionID"],
|
||||
// "listSessionsOfGroup" : ["groupID"],
|
||||
// "listSessionsOfAuthor" : ["authorID"],
|
||||
// "deleteAllSessionsOfGroup" : ["groupID"],
|
||||
// "deleteAllSessionsOfAuthor" : ["authorID"],
|
||||
"getText" : ["padID", "rev"]
|
||||
// "setText" : ["padID", "text"]
|
||||
// "getRevisionsCount" : ["padID"],
|
||||
// "deletePad" : ["padID"],
|
||||
// "getReadOnlyLink" : ["padID"],
|
||||
// "setPublicStatus" : ["padID", "publicStatus"],
|
||||
// "getPublicStatus" : ["padID"],
|
||||
// "setPassword" : ["padID", "password"],
|
||||
// "isPasswordProtected" : ["padID"]
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a HTTP API call
|
||||
* @param functionName the name of the called function
|
||||
* @param fields the params of the called function
|
||||
* @req express request object
|
||||
* @res express response object
|
||||
*/
|
||||
exports.handle = function(functionName, fields, req, res)
|
||||
{
|
||||
//check the api key!
|
||||
if(fields["apikey"] != apikey)
|
||||
{
|
||||
res.send({code: 4, message: "no or wrong API Key", data: null});
|
||||
return;
|
||||
}
|
||||
|
||||
//check if this is a valid function name
|
||||
var isKnownFunctionname = false;
|
||||
for(var knownFunctionname in functions)
|
||||
{
|
||||
if(knownFunctionname == functionName)
|
||||
{
|
||||
isKnownFunctionname = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//say goodbye if this is a unkown function
|
||||
if(!isKnownFunctionname)
|
||||
{
|
||||
res.send({code: 3, message: "no such function", data: null});
|
||||
return;
|
||||
}
|
||||
|
||||
//put the function parameters in an array
|
||||
var functionParams = [];
|
||||
for(var i=0;i<functions[functionName].length;i++)
|
||||
{
|
||||
functionParams.push(fields[functions[functionName][i]]);
|
||||
}
|
||||
|
||||
//add a callback function to handle the response
|
||||
functionParams.push(function(err, data)
|
||||
{
|
||||
// no error happend, everything is fine
|
||||
if(err == null)
|
||||
{
|
||||
res.send({code: 0, message: null, data: data});
|
||||
}
|
||||
// parameters were wrong and the api stopped execution, pass the error
|
||||
else if(err.stop)
|
||||
{
|
||||
res.send({code: 1, message: err.stop, data: null});
|
||||
}
|
||||
//an unkown error happend
|
||||
else
|
||||
{
|
||||
res.send({code: 2, message: "internal error", data: null});
|
||||
throw (err);
|
||||
}
|
||||
});
|
||||
|
||||
//call the api function
|
||||
api[functionName](functionParams[0],functionParams[1],functionParams[2],functionParams[3],functionParams[4]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random String with the given length. Is needed to generate the Author Ids
|
||||
*/
|
||||
function randomString(len) {
|
||||
// use only numbers and lowercase letters
|
||||
var pieces = [];
|
||||
for(var i=0;i<len;i++) {
|
||||
pieces.push(Math.floor(Math.random()*36).toString(36).slice(-1));
|
||||
}
|
||||
return pieces.join('');
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
require('joose');
|
||||
|
||||
var log4js = require('log4js');
|
||||
var socketio = require('socket.io');
|
||||
var fs = require('fs');
|
||||
var settings = require('./utils/Settings');
|
||||
|
@ -32,7 +33,7 @@ var express = require('express');
|
|||
var path = require('path');
|
||||
var minify = require('./utils/Minify');
|
||||
var formidable = require('formidable');
|
||||
var log4js = require('log4js');
|
||||
var apiHandler;
|
||||
var exportHandler;
|
||||
var importHandler;
|
||||
var exporthtml;
|
||||
|
@ -74,6 +75,7 @@ async.waterfall([
|
|||
exporthtml = require("./utils/ExportHtml");
|
||||
exportHandler = require('./handler/ExportHandler');
|
||||
importHandler = require('./handler/ImportHandler');
|
||||
apiHandler = require('./handler/APIHandler');
|
||||
|
||||
//install logging
|
||||
var httpLogger = log4js.getLogger("http");
|
||||
|
@ -222,8 +224,28 @@ async.waterfall([
|
|||
importHandler.doImport(req, res, req.params.pad);
|
||||
});
|
||||
|
||||
//This is a api call, collect all post informations and pass it to the apiHandler
|
||||
app.all('/api/1/:func', function(req, res)
|
||||
{
|
||||
//check if this is a post request
|
||||
if(req.method == "POST")
|
||||
{
|
||||
new formidable.IncomingForm().parse(req, function(err, fields, files)
|
||||
{
|
||||
if(err) throw err;
|
||||
|
||||
//call the api handler
|
||||
apiHandler.handle(req.params.func, fields, req, res);
|
||||
});
|
||||
}
|
||||
//say goodbye if this is not a post request
|
||||
else
|
||||
{
|
||||
res.send({code: 5, message: "no POST request", data: null});
|
||||
}
|
||||
});
|
||||
|
||||
//The Etherpad client side sends information about how a disconnect happen
|
||||
//I don't know how to use them, but maybe there usefull, so we should print them out to the log
|
||||
app.post('/ep/pad/connection-diagnostic-info', function(req, res)
|
||||
{
|
||||
new formidable.IncomingForm().parse(req, function(err, fields, files)
|
||||
|
|
Loading…
Reference in New Issue