Skip to content

Commit 43a1016

Browse files
committed
refactor: pass announcements/search requests through to the Rails app
1 parent a6b10db commit 43a1016

4 files changed

Lines changed: 51 additions & 571 deletions

File tree

lib/controllers/v1/announcements_controller.js

Lines changed: 4 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1,161 +1,14 @@
1-
const _ = require( "lodash" );
2-
const squel = require( "safe-squel" );
31
const { announcements } = require( "inaturalistjs" );
42
const InaturalistAPI = require( "../../inaturalist_api" );
5-
const pgClient = require( "../../pg_client" );
6-
const Announcement = require( "../../models/announcement" );
7-
const AnnouncementImpression = require( "../../models/announcement_impression" );
8-
const Site = require( "../../models/site" );
9-
const util = require( "../../util" );
103

114
const AnnouncementsController = class AnnouncementsController {
125
static async search( req ) {
13-
let query = squel.select( )
14-
.field( "announcements.id" )
15-
.field( "body" )
16-
.field( "placement" )
17-
.field( "dismissible" )
18-
.field( "locales" )
19-
.field( "clients" )
20-
.field( "start" )
21-
.field( "\"end\"" )
22-
.field( "target_group_type" )
23-
.field( "target_group_partition" )
24-
.field( "to_char( include_donor_start_date, 'YYYY-MM-DD') AS include_donor_start_date" )
25-
.field( "to_char( include_donor_end_date, 'YYYY-MM-DD') AS include_donor_end_date" )
26-
.field( "to_char( exclude_donor_start_date, 'YYYY-MM-DD') AS exclude_donor_start_date" )
27-
.field( "to_char( exclude_donor_end_date, 'YYYY-MM-DD') AS exclude_donor_end_date" )
28-
.from( "announcements" )
29-
.where( "NOW() at time zone 'utc' between start and \"end\"" )
30-
.order( "announcements.id" );
31-
32-
// placement filter
33-
if ( req.query.placement ) {
34-
let placementClause = squel.expr( );
35-
_.each( req.query.placement.split( "," ), placement => {
36-
switch ( placement ) {
37-
case "mobile":
38-
placementClause = placementClause.or( "placement LIKE 'mobile%'" );
39-
break;
40-
default:
41-
placementClause = placementClause.or( "placement = ?", placement );
42-
break;
43-
}
44-
} );
45-
query = query.where( placementClause );
46-
}
47-
48-
const userAgentClient = util.userAgentClient( req );
49-
if ( req.query.client || userAgentClient ) {
50-
// given a client parameter, return only announcements that include that client,
51-
// or announcements with no client specified
52-
query = query.where( "? = ANY( clients ) OR clients IS NULL OR clients = '{}'",
53-
req.query.client || userAgentClient );
54-
} else {
55-
// if there is no client parameter, return only announcements with no client specified
56-
query = query.where( "clients IS NULL OR clients = '{}'" );
57-
}
58-
59-
// site_id filter
60-
if ( req.userSession ) {
61-
// authenticated requests include announcements targeted at the users site,
62-
// or that have no site affiliation
63-
query = query.left_join( "announcements_sites", null, "announcements.id = announcements_sites.announcement_id" )
64-
.where( "announcements_sites.site_id IS NULL OR announcements_sites.site_id = ?",
65-
req.userSession?.site_id || Site.defaultID );
66-
} else {
67-
// unauthenticated requests exclude announcements associated with sites
68-
query = query.left_join( "announcements_sites", null, "announcements.id = announcements_sites.announcement_id" )
69-
.where( "announcements_sites.site_id IS NULL" );
70-
}
71-
72-
// exclude announcements the authenticated user has dismissed
73-
if ( req.userSession ) {
74-
query = query.where( "NOT ( ? = ANY( dismiss_user_ids ) )", req.userSession.user_id );
75-
}
76-
77-
// when request is unauthenticated, or authenticated user has confirmed their email,
78-
// exclude announcements that are targeting users with unconfirmed emails
79-
if ( !req.userSession || ( req.userSession && req.userSession.emailConfirmed ) ) {
80-
query = query.left_join( "preferences prefs_unconfirmed", null, "announcements.id = prefs_unconfirmed.owner_id AND"
81-
+ " prefs_unconfirmed.owner_type = 'Announcement' AND prefs_unconfirmed.name = 'target_unconfirmed_users'"
82-
+ " AND prefs_unconfirmed.value='t'" )
83-
.where( "prefs_unconfirmed.id IS NULL" );
84-
}
85-
86-
// when request is unauthenticated, or authenticated is not staff,
87-
// exclude announcements that are targeting staff
88-
if ( !req.userSession || ( req.userSession && !req.userSession.isAdmin ) ) {
89-
query = query.left_join( "preferences prefs_staff", null, "announcements.id = prefs_staff.owner_id AND"
90-
+ " prefs_staff.owner_type = 'Announcement' AND prefs_staff.name = 'target_staff'"
91-
+ " AND prefs_staff.value='t'" )
92-
.where( "prefs_staff.id IS NULL" );
93-
}
94-
95-
// when request is authenticated and the authenticated user is a montly supporter,
96-
// exclude announcements that prefer to exclude monthly supporters
97-
if ( req.userSession?.isMonthlySupporter ) {
98-
query = query.left_join(
99-
"preferences prefs_exclude_supporters",
100-
null,
101-
"announcements.id = prefs_exclude_supporters.owner_id AND"
102-
+ " prefs_exclude_supporters.owner_type = 'Announcement' AND"
103-
+ " prefs_exclude_supporters.name = 'exclude_monthly_supporters' AND"
104-
+ " prefs_exclude_supporters.value='t'"
105-
).where( "prefs_exclude_supporters.id IS NULL" );
106-
}
107-
108-
let announcementRows;
109-
const queryLocale = req.query.locale || req.userSession?.locale;
110-
// locale filter
111-
if ( queryLocale ) {
112-
// first attempt to fetch announcements with an exact match for locale
113-
const exactLocaleQuery = query.clone( ).where( "? = ANY( locales )", queryLocale );
114-
( { rows: announcementRows } = await pgClient.replica.query( exactLocaleQuery.toString( ) ) );
115-
// if none exist and the locale is hyphenated, fetch announcements with the base locale
116-
if ( _.isEmpty( announcementRows ) && queryLocale.match( "-" ) ) {
117-
const baseLocaleQuery = query.clone( ).where( "? = ANY( locales )", queryLocale.split( "-" )[0] );
118-
( { rows: announcementRows } = await pgClient.replica.query(
119-
baseLocaleQuery.toString( )
120-
) );
121-
}
122-
// if none exist for either version of the locale, fetch announcements with no locale
123-
if ( _.isEmpty( announcementRows ) ) {
124-
const noLocaleQuery = query.clone( ).where( "locales IS NULL OR locales = '{}'" );
125-
( { rows: announcementRows } = await pgClient.replica.query( noLocaleQuery.toString( ) ) );
126-
}
127-
} else {
128-
// if no locale filter was requested, fetch announcements with the already applied filters
129-
( { rows: announcementRows } = await pgClient.replica.query( query.toString( ) ) );
130-
}
131-
132-
// filter announcements using async functions
133-
const filterPromises = _.map( announcementRows, async announcement => (
134-
Announcement.targetedToRequestor( announcement, req )
135-
&& Announcement.requestorMatchesDonationRequirements( announcement, req )
136-
) );
137-
const filterPromiseResults = await Promise.all( filterPromises );
138-
announcementRows = _.filter( announcementRows,
139-
( announcement, index ) => filterPromiseResults[index] );
140-
141-
// remove columns fetched for filtering that should not be in the final response
142-
announcementRows = _.map( announcementRows, announcement => (
143-
_.omit( announcement, [
144-
"target_group_type",
145-
"target_group_partition",
146-
"include_donor_start_date",
147-
"include_donor_end_date",
148-
"exclude_donor_start_date",
149-
"exclude_donor_end_date"
150-
] )
151-
) );
152-
153-
await AnnouncementImpression.createAnnouncementImpressions( req, announcementRows );
6+
const anncs = await InaturalistAPI.iNatJSWrap( announcements.search, req );
1547
return {
155-
total_results: announcementRows.length,
8+
total_results: anncs.length,
1569
page: 1,
157-
per_page: announcementRows.length,
158-
results: announcementRows
10+
per_page: anncs.length,
11+
results: anncs
15912
};
16013
}
16114

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
"flat": "^5.0.2",
3838
"geoip-lite": "^1.4.10",
3939
"h3-js": "^4.1.0",
40-
"inaturalistjs": "github:inaturalist/inaturalistjs",
40+
"inaturalistjs": "github:inaturalist/inaturalistjs#web-622-add-high-priority-filters-for-targeting-announcements",
4141
"joi": "^17.13.3",
4242
"joi-to-swagger": "^6.2.0",
4343
"jsonwebtoken": "^9.0.2",

0 commit comments

Comments
 (0)