kopia lustrzana https://github.com/OpenDroneMap/NodeODM
Added swagger docs, scripts to generate API doc
rodzic
3958b8a543
commit
f51a77d995
|
@ -107,7 +107,7 @@ Make a pull request to the dev branch for small contributions. For big contribut
|
|||
- [X] GPC List support
|
||||
- [ ] Autoremove Abandoned Tasks
|
||||
- [ ] Continuous Integration Setup
|
||||
- [ ] Documentation
|
||||
- [X] Documentation
|
||||
- [ ] Unit Testing
|
||||
|
||||
## API Docs
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
node generateSwaggerAPI.js
|
||||
java -jar swagger2markup-cli-1.0.1.jar convert -i swagger.json -f index
|
|
@ -19,19 +19,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
let swaggerJSDoc = require('swagger-jsdoc');
|
||||
let fs = require('fs');
|
||||
|
||||
let packageJson = JSON.parse(fs.readFileSync('../package.json'));
|
||||
|
||||
let options = {
|
||||
swaggerDefinition: {
|
||||
info: {
|
||||
title: 'Node-OpenDroneMap',
|
||||
version: '0.1.0',
|
||||
title: packageJson.name,
|
||||
version: packageJson.version,
|
||||
description: packageJson.description,
|
||||
license: {
|
||||
name: 'GPLv3',
|
||||
url: 'http://www.gnu.org/licenses/'
|
||||
name: packageJson.license
|
||||
},
|
||||
contact: {
|
||||
name: 'Piero Toffanin',
|
||||
url: 'https://www.masseranolabs.com',
|
||||
email: 'pt@masseranolabs.com'
|
||||
name: packageJson.author,
|
||||
email: packageJson.authorEmail
|
||||
}
|
||||
},
|
||||
consumes: ["application/json"],
|
||||
|
|
|
@ -0,0 +1,355 @@
|
|||
= node-opendronemap
|
||||
|
||||
|
||||
[[_overview]]
|
||||
== Overview
|
||||
REST API to access OpenDroneMap
|
||||
|
||||
|
||||
=== Version information
|
||||
[%hardbreaks]
|
||||
_Version_ : 1.0
|
||||
|
||||
|
||||
=== Contact information
|
||||
[%hardbreaks]
|
||||
_Contact_ : Piero Toffanin
|
||||
_Contact Email_ : pt@masseranolabs.com
|
||||
|
||||
|
||||
=== License information
|
||||
[%hardbreaks]
|
||||
_License_ : GPL-3.0
|
||||
|
||||
|
||||
=== URI scheme
|
||||
[%hardbreaks]
|
||||
_BasePath_ : /
|
||||
_Schemes_ : HTTP
|
||||
|
||||
|
||||
=== Consumes
|
||||
|
||||
* `application/json`
|
||||
|
||||
|
||||
=== Produces
|
||||
|
||||
* `application/json`
|
||||
* `application/zip`
|
||||
|
||||
|
||||
|
||||
|
||||
[[_paths]]
|
||||
== Paths
|
||||
|
||||
[[_getoptions_get]]
|
||||
=== GET /getOptions
|
||||
|
||||
==== Description
|
||||
Retrieves the command line options that can be passed to process a task
|
||||
|
||||
|
||||
==== Responses
|
||||
|
||||
[options="header", cols=".^2,.^14,.^4"]
|
||||
|===
|
||||
|HTTP Code|Description|Schema
|
||||
|*200*|Options|< <<_getoptions_get_response_200,Response 200>> > array
|
||||
|===
|
||||
|
||||
[[_getoptions_get_response_200]]
|
||||
*Response 200*
|
||||
|
||||
[options="header", cols=".^3,.^11,.^4"]
|
||||
|===
|
||||
|Name|Description|Schema
|
||||
|*domain* +
|
||||
_optional_|Valid range of values (for example, "positive integer" or "float > 0.0")|string
|
||||
|*help* +
|
||||
_optional_|Description of what this option does|string
|
||||
|*name* +
|
||||
_optional_|Command line option (exactly as it is passed to the OpenDroneMap process, minus the leading '–')|string
|
||||
|*type* +
|
||||
_optional_|Datatype of the value of this option|enum (int, float, string, bool)
|
||||
|*value* +
|
||||
_optional_|Default value of this option|string
|
||||
|===
|
||||
|
||||
|
||||
[[_task_cancel_post]]
|
||||
=== POST /task/cancel
|
||||
|
||||
==== Description
|
||||
Cancels a task (stops its execution, or prevents it from being executed)
|
||||
|
||||
|
||||
==== Parameters
|
||||
|
||||
[options="header", cols=".^2,.^3,.^9,.^4,.^2"]
|
||||
|===
|
||||
|Type|Name|Description|Schema|Default
|
||||
|*Body*|*uuid* +
|
||||
_required_|UUID of the task|string|
|
||||
|===
|
||||
|
||||
|
||||
==== Responses
|
||||
|
||||
[options="header", cols=".^2,.^14,.^4"]
|
||||
|===
|
||||
|HTTP Code|Description|Schema
|
||||
|*200*|Command Received|<<_response,Response>>
|
||||
|===
|
||||
|
||||
|
||||
[[_task_new_post]]
|
||||
=== POST /task/new
|
||||
|
||||
==== Description
|
||||
Creates a new task and places it at the end of the processing queue
|
||||
|
||||
|
||||
==== Parameters
|
||||
|
||||
[options="header", cols=".^2,.^3,.^9,.^4,.^2"]
|
||||
|===
|
||||
|Type|Name|Description|Schema|Default
|
||||
|*FormData*|*images* +
|
||||
_required_|Images to process, plus an optional GPC file. If included, the GPC file should have .txt extension|file|
|
||||
|*FormData*|*name* +
|
||||
_optional_|An optional name to be associated with the task|string|
|
||||
|*FormData*|*options* +
|
||||
_optional_|Serialized JSON string of the options to use for processing, as an array of the format: [{name: option1, value: value1}, {name: option2, value: value2}, …]. For example, [{"name":"cmvs-maxImages","value":"500"},{"name":"time","value":true}]. For a list of all options, call /getOptions|string|
|
||||
|===
|
||||
|
||||
|
||||
==== Responses
|
||||
|
||||
[options="header", cols=".^2,.^14,.^4"]
|
||||
|===
|
||||
|HTTP Code|Description|Schema
|
||||
|*200*|Success|<<_task_new_post_response_200,Response 200>>
|
||||
|*default*|Error|<<_error,Error>>
|
||||
|===
|
||||
|
||||
[[_task_new_post_response_200]]
|
||||
*Response 200*
|
||||
|
||||
[options="header", cols=".^3,.^11,.^4"]
|
||||
|===
|
||||
|Name|Description|Schema
|
||||
|*uuid* +
|
||||
_required_|UUID of the newly created task|string
|
||||
|===
|
||||
|
||||
|
||||
==== Consumes
|
||||
|
||||
* `multipart/form-data`
|
||||
|
||||
|
||||
[[_task_remove_post]]
|
||||
=== POST /task/remove
|
||||
|
||||
==== Description
|
||||
Removes a task and deletes all of its assets
|
||||
|
||||
|
||||
==== Parameters
|
||||
|
||||
[options="header", cols=".^2,.^3,.^9,.^4,.^2"]
|
||||
|===
|
||||
|Type|Name|Description|Schema|Default
|
||||
|*Body*|*uuid* +
|
||||
_required_|UUID of the task|string|
|
||||
|===
|
||||
|
||||
|
||||
==== Responses
|
||||
|
||||
[options="header", cols=".^2,.^14,.^4"]
|
||||
|===
|
||||
|HTTP Code|Description|Schema
|
||||
|*200*|Command Received|<<_response,Response>>
|
||||
|===
|
||||
|
||||
|
||||
[[_task_restart_post]]
|
||||
=== POST /task/restart
|
||||
|
||||
==== Description
|
||||
Restarts a task that was previously canceled or that had failed to process
|
||||
|
||||
|
||||
==== Parameters
|
||||
|
||||
[options="header", cols=".^2,.^3,.^9,.^4,.^2"]
|
||||
|===
|
||||
|Type|Name|Description|Schema|Default
|
||||
|*Body*|*uuid* +
|
||||
_required_|UUID of the task|string|
|
||||
|===
|
||||
|
||||
|
||||
==== Responses
|
||||
|
||||
[options="header", cols=".^2,.^14,.^4"]
|
||||
|===
|
||||
|HTTP Code|Description|Schema
|
||||
|*200*|Command Received|<<_response,Response>>
|
||||
|===
|
||||
|
||||
|
||||
[[_task_uuid_download_asset_get]]
|
||||
=== GET /task/{uuid}/download/{asset}
|
||||
|
||||
==== Description
|
||||
Retrieves an asset (the output of OpenDroneMap's processing) associated with a task
|
||||
|
||||
|
||||
==== Parameters
|
||||
|
||||
[options="header", cols=".^2,.^3,.^9,.^4,.^2"]
|
||||
|===
|
||||
|Type|Name|Description|Schema|Default
|
||||
|*Path*|*asset* +
|
||||
_required_|Type of asset to download. Use "all" for zip file containing all assets. Other options are not yet available|enum (all)|
|
||||
|*Path*|*uuid* +
|
||||
_required_|UUID of the task|string|
|
||||
|===
|
||||
|
||||
|
||||
==== Responses
|
||||
|
||||
[options="header", cols=".^2,.^14,.^4"]
|
||||
|===
|
||||
|HTTP Code|Description|Schema
|
||||
|*200*|Asset File|file
|
||||
|*default*|Error message|<<_error,Error>>
|
||||
|===
|
||||
|
||||
|
||||
[[_task_uuid_info_get]]
|
||||
=== GET /task/{uuid}/info
|
||||
|
||||
==== Description
|
||||
Gets information about this task, such as name, creation date, processing time, status, command line options and number of images being processed. See schema definition for a full list.
|
||||
|
||||
|
||||
==== Parameters
|
||||
|
||||
[options="header", cols=".^2,.^3,.^9,.^4,.^2"]
|
||||
|===
|
||||
|Type|Name|Description|Schema|Default
|
||||
|*Path*|*uuid* +
|
||||
_required_|UUID of the task|string|
|
||||
|===
|
||||
|
||||
|
||||
==== Responses
|
||||
|
||||
[options="header", cols=".^2,.^14,.^4"]
|
||||
|===
|
||||
|HTTP Code|Description|Schema
|
||||
|*200*|Task Information|<<_task_uuid_info_get_response_200,Response 200>>
|
||||
|*default*|Error|<<_error,Error>>
|
||||
|===
|
||||
|
||||
[[_task_uuid_info_get_response_200]]
|
||||
*Response 200*
|
||||
|
||||
[options="header", cols=".^3,.^11,.^4"]
|
||||
|===
|
||||
|Name|Description|Schema
|
||||
|*dateCreated* +
|
||||
_optional_|Timestamp|integer
|
||||
|*imagesCount* +
|
||||
_optional_|Number of images|integer
|
||||
|*name* +
|
||||
_optional_|Name|string
|
||||
|*options* +
|
||||
_optional_|List of options used to process this task|< <<_task_uuid_info_get_options,options>> > array
|
||||
|*processingTime* +
|
||||
_optional_|Milliseconds that have elapsed since the task started being processed.|integer
|
||||
|*status* +
|
||||
_optional_|Status code (10 = QUEUED, 20 = RUNNING, 30 = FAILED, 40 = COMPLETED, 50 = CANCELED)|integer
|
||||
|*uuid* +
|
||||
_optional_|UUID|string
|
||||
|===
|
||||
|
||||
[[_task_uuid_info_get_options]]
|
||||
*options*
|
||||
|
||||
[options="header", cols=".^3,.^11,.^4"]
|
||||
|===
|
||||
|Name|Description|Schema
|
||||
|*name* +
|
||||
_optional_|Option name (example: "odm_meshing-octreeDepth")|string
|
||||
|*value* +
|
||||
_optional_|Value (example: 9)|string
|
||||
|===
|
||||
|
||||
|
||||
[[_task_uuid_output_get]]
|
||||
=== GET /task/{uuid}/output
|
||||
|
||||
==== Description
|
||||
Retrieves the console output of the OpenDroneMap's process. Useful for monitoring execution and to provide updates to the user.
|
||||
|
||||
|
||||
==== Parameters
|
||||
|
||||
[options="header", cols=".^2,.^3,.^9,.^4,.^2"]
|
||||
|===
|
||||
|Type|Name|Description|Schema|Default
|
||||
|*Path*|*uuid* +
|
||||
_required_|UUID of the task|string|
|
||||
|*Query*|*line* +
|
||||
_optional_|Optional line number that the console output should be truncated from. For example, passing a value of 100 will retrieve the console output starting from line 100. Defaults to 0 (retrieve all console output).|integer|
|
||||
|===
|
||||
|
||||
|
||||
==== Responses
|
||||
|
||||
[options="header", cols=".^2,.^14,.^4"]
|
||||
|===
|
||||
|HTTP Code|Description|Schema
|
||||
|*200*|Console Output|string
|
||||
|*default*|Error|<<_error,Error>>
|
||||
|===
|
||||
|
||||
|
||||
|
||||
|
||||
[[_definitions]]
|
||||
== Definitions
|
||||
|
||||
[[_error]]
|
||||
=== Error
|
||||
|
||||
[options="header", cols=".^3,.^11,.^4"]
|
||||
|===
|
||||
|Name|Description|Schema
|
||||
|*error* +
|
||||
_required_|Description of the error|string
|
||||
|===
|
||||
|
||||
|
||||
[[_response]]
|
||||
=== Response
|
||||
|
||||
[options="header", cols=".^3,.^11,.^4"]
|
||||
|===
|
||||
|Name|Description|Schema
|
||||
|*error* +
|
||||
_optional_|Error message if an error occured|string
|
||||
|*success* +
|
||||
_required_|true if the command succeeded, false otherwise.|boolean
|
||||
|===
|
||||
|
||||
|
||||
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
Plik binarny nie jest wyświetlany.
208
index.js
208
index.js
|
@ -69,6 +69,46 @@ let upload = multer({
|
|||
let taskManager;
|
||||
let server;
|
||||
|
||||
/** @swagger
|
||||
* /task/new:
|
||||
* post:
|
||||
* description: Creates a new task and places it at the end of the processing queue
|
||||
* consumes:
|
||||
* - multipart/form-data
|
||||
* parameters:
|
||||
* -
|
||||
* name: images
|
||||
* in: formData
|
||||
* description: Images to process, plus an optional GPC file. If included, the GPC file should have .txt extension
|
||||
* required: true
|
||||
* type: file
|
||||
* -
|
||||
* name: name
|
||||
* in: formData
|
||||
* description: An optional name to be associated with the task
|
||||
* required: false
|
||||
* type: string
|
||||
* -
|
||||
* name: options
|
||||
* in: formData
|
||||
* description: 'Serialized JSON string of the options to use for processing, as an array of the format: [{name: option1, value: value1}, {name: option2, value: value2}, ...]. For example, [{"name":"cmvs-maxImages","value":"500"},{"name":"time","value":true}]. For a list of all options, call /getOptions'
|
||||
* required: false
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Success
|
||||
* schema:
|
||||
* type: object
|
||||
* required: [uuid]
|
||||
* properties:
|
||||
* uuid:
|
||||
* type: string
|
||||
* description: UUID of the newly created task
|
||||
* default:
|
||||
* description: Error
|
||||
* schema:
|
||||
* $ref: '#/definitions/Error'
|
||||
*/
|
||||
app.post('/task/new', addRequestId, upload.array('images'), (req, res) => {
|
||||
if (req.files.length === 0) res.json({error: "Need at least 1 file."});
|
||||
else{
|
||||
|
@ -118,7 +158,7 @@ app.post('/task/new', addRequestId, upload.array('images'), (req, res) => {
|
|||
if (err) cb(err);
|
||||
else{
|
||||
taskManager.addNew(task);
|
||||
res.json({uuid: req.id, success: true});
|
||||
res.json({uuid: req.id});
|
||||
cb();
|
||||
}
|
||||
}, req.body.options);
|
||||
|
@ -137,12 +177,121 @@ let getTaskFromUuid = (req, res, next) => {
|
|||
}else res.json({error: `${req.params.uuid} not found`});
|
||||
};
|
||||
|
||||
/** @swagger
|
||||
* /task/{uuid}/info:
|
||||
* get:
|
||||
* description: Gets information about this task, such as name, creation date, processing time, status, command line options and number of images being processed. See schema definition for a full list.
|
||||
* parameters:
|
||||
* -
|
||||
* name: uuid
|
||||
* in: path
|
||||
* description: UUID of the task
|
||||
* required: true
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Task Information
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* uuid:
|
||||
* type: string
|
||||
* description: UUID
|
||||
* name:
|
||||
* type: string
|
||||
* description: Name
|
||||
* dateCreated:
|
||||
* type: integer
|
||||
* description: Timestamp
|
||||
* processingTime:
|
||||
* type: integer
|
||||
* description: Milliseconds that have elapsed since the task started being processed.
|
||||
* status:
|
||||
* type: integer
|
||||
* description: Status code (10 = QUEUED, 20 = RUNNING, 30 = FAILED, 40 = COMPLETED, 50 = CANCELED)
|
||||
* enum: [10, 20, 30, 40, 50]
|
||||
* options:
|
||||
* type: array
|
||||
* description: List of options used to process this task
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* description: 'Option name (example: "odm_meshing-octreeDepth")'
|
||||
* value:
|
||||
* type: string
|
||||
* description: 'Value (example: 9)'
|
||||
* imagesCount:
|
||||
* type: integer
|
||||
* description: Number of images
|
||||
* default:
|
||||
* description: Error
|
||||
* schema:
|
||||
* $ref: '#/definitions/Error'
|
||||
*/
|
||||
app.get('/task/:uuid/info', getTaskFromUuid, (req, res) => {
|
||||
res.json(req.task.getInfo());
|
||||
});
|
||||
|
||||
/** @swagger
|
||||
* /task/{uuid}/output:
|
||||
* get:
|
||||
* description: Retrieves the console output of the OpenDroneMap's process. Useful for monitoring execution and to provide updates to the user.
|
||||
* parameters:
|
||||
* -
|
||||
* name: uuid
|
||||
* in: path
|
||||
* description: UUID of the task
|
||||
* required: true
|
||||
* type: string
|
||||
* -
|
||||
* name: line
|
||||
* in: query
|
||||
* description: Optional line number that the console output should be truncated from. For example, passing a value of 100 will retrieve the console output starting from line 100. Defaults to 0 (retrieve all console output).
|
||||
* required: false
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Console Output
|
||||
* schema:
|
||||
* type: string
|
||||
* default:
|
||||
* description: Error
|
||||
* schema:
|
||||
* $ref: '#/definitions/Error'
|
||||
*/
|
||||
app.get('/task/:uuid/output', getTaskFromUuid, (req, res) => {
|
||||
res.json(req.task.getOutput(req.query.line));
|
||||
});
|
||||
|
||||
/** @swagger
|
||||
* /task/{uuid}/download/{asset}:
|
||||
* get:
|
||||
* description: Retrieves an asset (the output of OpenDroneMap's processing) associated with a task
|
||||
* parameters:
|
||||
* - name: uuid
|
||||
* in: path
|
||||
* type: string
|
||||
* description: UUID of the task
|
||||
* required: true
|
||||
* - name: asset
|
||||
* in: path
|
||||
* type: string
|
||||
* description: Type of asset to download. Use "all" for zip file containing all assets. Other options are not yet available
|
||||
* required: true
|
||||
* enum:
|
||||
* - all
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Asset File
|
||||
* schema:
|
||||
* type: file
|
||||
* default:
|
||||
* description: Error message
|
||||
* schema:
|
||||
* $ref: '#/definitions/Error'
|
||||
*/
|
||||
app.get('/task/:uuid/download/:asset', getTaskFromUuid, (req, res) => {
|
||||
if (!req.params.asset || req.params.asset === "all"){
|
||||
res.download(req.task.getAssetsArchivePath(), "all.zip", err => {
|
||||
|
@ -153,13 +302,16 @@ app.get('/task/:uuid/download/:asset', getTaskFromUuid, (req, res) => {
|
|||
}
|
||||
});
|
||||
|
||||
let uuidCheck = (req, res, next) => {
|
||||
if (!req.body.uuid) res.json({error: "uuid param missing."});
|
||||
else next();
|
||||
};
|
||||
|
||||
/** @swagger
|
||||
* definition:
|
||||
* Error:
|
||||
* type: object
|
||||
* required:
|
||||
* - error
|
||||
* properties:
|
||||
* error:
|
||||
* type: string
|
||||
* description: Description of the error
|
||||
* Response:
|
||||
* type: object
|
||||
* required:
|
||||
|
@ -167,10 +319,15 @@ let uuidCheck = (req, res, next) => {
|
|||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* description: true if the command succeeded, false otherwise.
|
||||
* error:
|
||||
* type: string
|
||||
* description: Error message if an error occured
|
||||
*/
|
||||
let uuidCheck = (req, res, next) => {
|
||||
if (!req.body.uuid) res.json({error: "uuid param missing."});
|
||||
else next();
|
||||
};
|
||||
|
||||
let successHandler = res => {
|
||||
return err => {
|
||||
|
@ -187,7 +344,7 @@ let successHandler = res => {
|
|||
* -
|
||||
* name: uuid
|
||||
* in: body
|
||||
* description: UUID of the task to cancel
|
||||
* description: UUID of the task
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
|
@ -209,7 +366,7 @@ app.post('/task/cancel', uuidCheck, (req, res) => {
|
|||
* -
|
||||
* name: uuid
|
||||
* in: body
|
||||
* description: UUID of the task to cancel
|
||||
* description: UUID of the task
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
|
@ -231,7 +388,7 @@ app.post('/task/remove', uuidCheck, (req, res) => {
|
|||
* -
|
||||
* name: uuid
|
||||
* in: body
|
||||
* description: UUID of the task to cancel
|
||||
* description: UUID of the task
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
|
@ -245,6 +402,39 @@ app.post('/task/restart', uuidCheck, (req, res) => {
|
|||
taskManager.restart(req.body.uuid, successHandler(res));
|
||||
});
|
||||
|
||||
/** @swagger
|
||||
* /getOptions:
|
||||
* get:
|
||||
* description: Retrieves the command line options that can be passed to process a task
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Options
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* description: Command line option (exactly as it is passed to the OpenDroneMap process, minus the leading '--')
|
||||
* type:
|
||||
* type: string
|
||||
* description: Datatype of the value of this option
|
||||
* enum:
|
||||
* - int
|
||||
* - float
|
||||
* - string
|
||||
* - bool
|
||||
* value:
|
||||
* type: string
|
||||
* description: Default value of this option
|
||||
* domain:
|
||||
* type: string
|
||||
* description: Valid range of values (for example, "positive integer" or "float > 0.0")
|
||||
* help:
|
||||
* type: string
|
||||
* description: Description of what this option does
|
||||
*/
|
||||
app.get('/getOptions', (req, res) => {
|
||||
odmOptions.getOptions((err, options) => {
|
||||
if (err) res.json({error: err.message});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "node-opendronemap",
|
||||
"version": "0.1.0",
|
||||
"description": "Node.js API to access OpenDroneMap",
|
||||
"version": "1.0",
|
||||
"description": "REST API to access OpenDroneMap",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
|
@ -14,6 +14,7 @@
|
|||
"opendronemap"
|
||||
],
|
||||
"author": "Piero Toffanin",
|
||||
"authorEmail": "pt@masseranolabs.com",
|
||||
"license": "GPL-3.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/pierotofy/node-OpenDroneMap/issues"
|
||||
|
|
|
@ -294,7 +294,7 @@ $(function(){
|
|||
.on('filebatchuploadsuccess', function(e, params){
|
||||
$("#images").fileinput('reset');
|
||||
|
||||
if (params.response.success && params.response.uuid){
|
||||
if (params.response && params.response.uuid){
|
||||
taskList.add(new Task(params.response.uuid));
|
||||
}
|
||||
})
|
||||
|
|
Ładowanie…
Reference in New Issue