From 49499569f750c3cc7369b1caa25d7031d8235531 Mon Sep 17 00:00:00 2001 From: Patrick Leary Date: Thu, 19 Oct 2023 09:53:22 -0400 Subject: [PATCH] add platform parameter to announcements endpoint --- .../v1/announcements_controller.js | 11 ++++++++- .../schema/request/announcements_search.js | 6 +++++ openapi/schema/response/announcement.js | 1 + schema/database.sql | 3 ++- schema/fixtures.js | 24 +++++++++++++++---- test/integration/v2/announcements.js | 22 +++++++++++++++++ 6 files changed, 61 insertions(+), 6 deletions(-) diff --git a/lib/controllers/v1/announcements_controller.js b/lib/controllers/v1/announcements_controller.js index 8cff39bc..3b229e14 100644 --- a/lib/controllers/v1/announcements_controller.js +++ b/lib/controllers/v1/announcements_controller.js @@ -8,7 +8,7 @@ const Site = require( "../../models/site" ); const AnnouncementsController = class AnnouncementsController { static async search( req ) { let query = squel.select( ) - .field( "announcements.id, body, placement, dismissible, locales, start, \"end\"" ) + .field( "announcements.id, body, placement, dismissible, locales, platforms, start, \"end\"" ) .from( "announcements" ) .where( "NOW() at time zone 'utc' between start and \"end\"" ) .order( "announcements.id" ); @@ -29,6 +29,15 @@ const AnnouncementsController = class AnnouncementsController { query = query.where( placementClause ); } + if ( req.query.platform ) { + // given a platform parameter, return only announcements that include that platform, + // or announcements with no platform specified + query = query.where( "? = ANY( platforms ) OR platforms IS NULL OR platforms = '{}'", req.query.platform ); + } else { + // if there is no platform parameter, return only announcements with no platform specified + query = query.where( "platforms IS NULL OR platforms = '{}'" ); + } + // site_id filter if ( req.userSession ) { // authenticated requests include announcements targeted at the users site, diff --git a/openapi/schema/request/announcements_search.js b/openapi/schema/request/announcements_search.js index c3de620f..b8ce8935 100644 --- a/openapi/schema/request/announcements_search.js +++ b/openapi/schema/request/announcements_search.js @@ -8,6 +8,12 @@ module.exports = Joi.object( ).keys( { "mobile/home", "mobile" ), + platform: Joi.string( ).valid( + "inat-ios", + "inat-android", + "seek", + "inatrn" + ), locale: Joi.string( ), fields: Joi.any( ) } ).unknown( false ); diff --git a/openapi/schema/response/announcement.js b/openapi/schema/response/announcement.js index 8dde9cd1..f9e8f8e4 100644 --- a/openapi/schema/response/announcement.js +++ b/openapi/schema/response/announcement.js @@ -4,6 +4,7 @@ module.exports = Joi.object( ).keys( { id: Joi.number( ).integer( ).required( ), body: Joi.string( ), placement: Joi.string( ), + platforms: Joi.array( ).items( Joi.string( ) ), dismissible: Joi.boolean( ), locales: Joi.array( ).items( Joi.string( ) ), start: Joi.date( ), diff --git a/schema/database.sql b/schema/database.sql index bd2d6bc8..0cd3df9e 100644 --- a/schema/database.sql +++ b/schema/database.sql @@ -322,7 +322,8 @@ CREATE TABLE public.announcements ( updated_at timestamp without time zone, locales text[] DEFAULT '{}'::text[], dismiss_user_ids integer[] DEFAULT '{}'::integer[], - dismissible boolean DEFAULT false + dismissible boolean DEFAULT false, + platforms text[] DEFAULT '{}'::text[] ); diff --git a/schema/fixtures.js b/schema/fixtures.js index f2ef08ec..5a278458 100644 --- a/schema/fixtures.js +++ b/schema/fixtures.js @@ -1851,7 +1851,8 @@ "updated_at": "2023-01-01 00:00:00", "placement": "mobile/home", "locales": "{}", - "dismissible": true + "dismissible": true, + "platforms": "{}" }, { "id": 2, @@ -1862,7 +1863,8 @@ "updated_at": "2023-01-01 00:00:00", "placement": "mobile/home", "locales": "{}", - "dismissible": true + "dismissible": true, + "platforms": "{}" }, { "id": 3, @@ -1873,7 +1875,8 @@ "updated_at": "2023-01-01 00:00:00", "placement": "mobile/home", "locales": "{en-US,fr}", - "dismissible": true + "dismissible": true, + "platforms": "{}" }, { "id": 4, @@ -1884,7 +1887,20 @@ "updated_at": "2023-01-01 00:00:00", "placement": "mobile/home", "locales": "{en}", - "dismissible": true + "dismissible": true, + "platforms": "{}" + }, + { + "id": 5, + "body": "Active announcement for inat-ios and inat-android", + "start": "2023-01-01 00:00:00", + "end": "2100-01-01 00:00:00", + "created_at": "2023-01-01 00:00:00", + "updated_at": "2023-01-01 00:00:00", + "placement": "mobile/home", + "locales": "{}", + "dismissible": true, + "platforms": "{inat-ios,inat-android}" } ], "comments": [ diff --git a/test/integration/v2/announcements.js b/test/integration/v2/announcements.js index 2a23dcd6..2ad4d50d 100644 --- a/test/integration/v2/announcements.js +++ b/test/integration/v2/announcements.js @@ -69,6 +69,28 @@ describe( "Announcements", ( ) => { } ).expect( "Content-Type", /json/ ) .expect( 200, done ); } ); + + it( "returns announcements based on platform", function ( done ) { + const inatiOSAnnouncement = _.find( + fixtures.postgresql.announcements, a => a.platforms.match( /inat-ios/ ) + ); + request( this.app ).get( "/v2/announcements?fields=all&platform=inat-ios" ).expect( res => { + expect( res.body.results ).to.not.be.empty; + expect( _.every( res.body.results, r => ( + r.platforms.includes( "inat-ios" ) || _.isEmpty( r.platforms ) + ) ) ).to.be.true; + expect( _.map( res.body.results, "id" ) ).to.include( inatiOSAnnouncement.id ); + } ).expect( "Content-Type", /json/ ) + .expect( 200, done ); + } ); + + it( "does not return announcements with a platform not matching parameter", function ( done ) { + request( this.app ).get( "/v2/announcements?fields=all&platform=seek" ).expect( res => { + expect( res.body.results ).to.not.be.empty; + expect( _.every( res.body.results, r => _.isEmpty( r.platforms ) ) ).to.be.true; + } ).expect( "Content-Type", /json/ ) + .expect( 200, done ); + } ); } ); describe( "dismiss", ( ) => {