1+ import { r } from "../../models" ;
2+
3+ // TODO: Add OPTINS_SHARE_ALL_ORGS to env doc
4+
5+ const orgCacheKey = orgId =>
6+ ! ! process . env . OPTINS_SHARE_ALL_ORGS
7+ ? `${ process . env . CAHCE_PREFIX || "" } :optins`
8+ : `${ process . env . CACHE_PREFIS || "" } :optins-${ orgId } ` ;
9+
10+ const sharingOptIns = ! ! process . env . OPTINS_SHARE_ALL_ORGS
11+
12+ // Probably not needed, but good to offload stress from
13+ // db.
14+ const loadMany = async organizationId => {
15+ if ( r . redis ) {
16+ let dbQuery = r
17+ . knex ( "opt_in" )
18+ . select ( "cell" )
19+ . orderBy ( "id" , "desc" )
20+ . limit ( process . env . OPTINS_CACHE_MAX || 1000000 ) ;
21+
22+ if ( ! sharingOptIns ) {
23+ dbQuery = dbQuery . where ( "organization_id" , organizationId ) ;
24+ }
25+ const dbResult = await dbQuery ;
26+ const cellOptIns = dbResult . map ( rec => rec . cell ) ;
27+ const hashKey = orgCacheKey ( organizationId ) ;
28+
29+ await r . redis . SADD ( hashKey , [ "0" ] ) ;
30+ await r . redis . expire ( hashKey , 43200 ) ;
31+
32+ for (
33+ let i100 = 0 , l100 = Math . ceil ( cellOptOuts . length / 100 ) ;
34+ i100 < l100 ;
35+ i100 ++
36+ ) {
37+ await r . redis . SADD (
38+ hashKey ,
39+ cellOptIns . slice ( 100 * i100 , 100 * i100 + 100 )
40+ ) ;
41+ }
42+ return cellOptIns . length ;
43+ }
44+ }
45+
46+ const updateIsOptedIn = async queryModifier => {
47+ // update all organization/instance's active campaigns
48+ const optInContactQuery = r
49+ . knex ( "campaign_contact" )
50+ . join ( "campaign" , "campaign_contact.id" , "campaign.id" )
51+ . where ( "campaign.is_archived" , false )
52+ . select ( "campaign_contact.id" ) ;
53+
54+ return await r
55+ . knex ( "campaign_contact" )
56+ . whereIn (
57+ "id" ,
58+ queryModifier ? queryModifier ( optInContactQuery ) : optInContactQuery
59+ )
60+ . update ( "is_opted_in" , true )
61+ . update ( {
62+ is_opted_in : true
63+ } )
64+ }
65+
66+ const optInCache = {
67+ clearQuery : async ( { cell, organizationId } ) => {
68+ if ( r . redis ) {
69+ if ( cell ) {
70+ await r . redis . sdel ( orgCacheKey ( organizationId ) , cell ) ;
71+ } else {
72+ await r . redis . DEL ( orgCacheKey ( organizationId ) ) ;
73+ }
74+ }
75+ } ,
76+ query : async ( { cell, organizationId } ) => {
77+ const accountingForOrgSharing = ! sharingOptIns
78+ ? { cell, organization_id : organizationId }
79+ : { cell } ;
80+
81+ if ( r . redis ) {
82+ const hashKey = orgCacheKey ( organizationId ) ;
83+ const [ exists , isMember ] = await r . redis
84+ . MULTI ( )
85+ . EXISTS ( hashKey )
86+ . SISMEMBER ( hashKey , cell )
87+ . exec ( ) ;
88+ if ( exists ) {
89+ return isMember ;
90+ }
91+
92+ loadMany ( organizationId )
93+ . then ( optInCount => {
94+ if ( ! global . TEST_ENVIRONMENT ) {
95+ console . log (
96+ "optInCache loaded for organization" ,
97+ organizationId ,
98+ optInCount
99+ ) ;
100+ }
101+ } )
102+ . catch ( err => {
103+ console . log (
104+ "optInCache Error for organization" ,
105+ organizationId ,
106+ err
107+ ) ;
108+ } ) ;
109+ }
110+ const dbResult = await r
111+ . knex ( "opt_in" )
112+ . select ( "cell" )
113+ . where ( accountingForOrgSharing )
114+ . limit ( 1 ) ;
115+ return dbResult . length > 0
116+ } ,
117+ save : async ( {
118+ cell,
119+ campaign,
120+ assignmentId,
121+ reason
122+ } ) => {
123+ const organizationId = campaign . organization_id ;
124+ if ( r . redis ) {
125+ const hashKey = orgCacheKey ( organizationId ) ;
126+ const exists = await r . redis . exists ( hashKey ) ;
127+ if ( exists ) {
128+ await r . redis . SADD ( hashKey , cell ) ;
129+ }
130+ }
131+
132+ // place into db
133+ await r . knex ( "opt_in" ) . insert ( {
134+ assignment_id : assignmentId ,
135+ organization_id : organizationId ,
136+ reason_code : reason ,
137+ cell
138+ } ) ;
139+ } ,
140+ loadMany,
141+ updateIsOptedIn
142+ }
143+
144+ export default optInCache ;
0 commit comments