diff --git a/lib/controllers/v1/computervision_controller.js b/lib/controllers/v1/computervision_controller.js index 3faa95f8..5f23d2a6 100644 --- a/lib/controllers/v1/computervision_controller.js +++ b/lib/controllers/v1/computervision_controller.js @@ -57,6 +57,9 @@ const ComputervisionController = class ComputervisionController { if ( !req.userSession && !req.applicationSession ) { throw util.httpError( 401, "Unauthorized" ); } + if ( req.query.photo_id && Number.isNaN( req.query.photo_id ) ) { + throw util.httpError( 422, "photo_id is not a number" ); + } const obsID = Number( req.params.id ); if ( !obsID ) { throw util.httpError( 422, "Missing observation ID or UUID" ); @@ -79,14 +82,17 @@ const ComputervisionController = class ComputervisionController { let photoURL; _.each( observation.photos, p => { if ( photoURL ) { return; } + if ( req.query.photo_id && p.id !== Number( req.query.photo_id ) ) { return; } if ( !p.url ) { return; } photoURL = p.url; if ( photoURL.match( /\/square\./i ) ) { photoURL = p.url.replace( "/square.", "/medium." ); } } ); - if ( !photoURL ) { + if ( !photoURL && !req.query.photo_id ) { throw util.httpError( 422, "Observation has no scorable photos" ); + } else if ( !photoURL ) { + throw util.httpError( 422, "Observation has no scorable photos or no photo with the provided id" ); } req.query.image_url = photoURL; return ComputervisionController.scoreImageURL( req, { observation } ); diff --git a/openapi/paths/v2/computervision/score_observation/{uuid}.js b/openapi/paths/v2/computervision/score_observation/{uuid}.js index c70681bc..68243908 100644 --- a/openapi/paths/v2/computervision/score_observation/{uuid}.js +++ b/openapi/paths/v2/computervision/score_observation/{uuid}.js @@ -24,6 +24,12 @@ module.exports = sendWrapper => { .required( ) .description( "A single observation UUID" ) ), + transform( + Joi.number( ).integer( ) + .label( "photo_id" ) + .meta( { in: "query" } ) + .description( "The photo id associated with the observation to use for suggestions." ) + ), transform( Joi.string( ).label( "fields" ).meta( { in: "query" } ) .description( ` diff --git a/test/integration/v2/computervision.js b/test/integration/v2/computervision.js index 963b6dc5..d38203bb 100644 --- a/test/integration/v2/computervision.js +++ b/test/integration/v2/computervision.js @@ -89,6 +89,30 @@ describe( "Computervision", ( ) => { .set( "Authorization", token ) .expect( 401, done ); } ); + it( "filters for photo id if provided", function ( done ) { + const token = jwt.sign( + { application: "whatever" }, + config.jwtApplicationSecret || "application_secret", + { algorithm: "HS512" } + ); + request( this.app ).get( `${url}?photo_id=1` ) + .set( "Authorization", token ) + .expect( 200 ) + .expect( res => { + expect( res.body.results.length ).to.be.above( 0 ); + } ) + .expect( 200, done ); + } ); + it( "should fail when given a photo id not attributed to the observation", function ( done ) { + const token = jwt.sign( + { application: "whatever" }, + config.jwtApplicationSecret || "application_secret", + { algorithm: "HS512" } + ); + request( this.app ).get( `${url}?photo_id=2020101601` ) + .set( "Authorization", token ) + .expect( 422, done ); + } ); } ); describe( "score_image", ( ) => { const token = jwt.sign(