2022-01-27 17:06:29 +03:00
const _ = require ( 'lodash' ) ;
2021-07-19 13:46:38 +03:00
const errors = require ( '@tryghost/errors' ) ;
const tpl = require ( '@tryghost/tpl' ) ;
2021-05-12 15:02:27 +03:00
const MembersSSR = require ( '@tryghost/members-ssr' ) ;
const db = require ( '../../data/db' ) ;
const MembersConfigProvider = require ( './config' ) ;
2021-07-21 18:34:11 +03:00
const MembersCSVImporter = require ( '@tryghost/members-importer' ) ;
2021-08-18 10:48:07 +03:00
const MembersStats = require ( './stats/members-stats' ) ;
2021-05-12 15:02:27 +03:00
const createMembersSettingsInstance = require ( './settings' ) ;
2021-06-15 17:36:27 +03:00
const logging = require ( '@tryghost/logging' ) ;
2021-05-12 15:02:27 +03:00
const urlUtils = require ( '../../../shared/url-utils' ) ;
2021-07-20 17:42:57 +03:00
const labsService = require ( '../../../shared/labs' ) ;
2021-06-30 16:56:57 +03:00
const settingsCache = require ( '../../../shared/settings-cache' ) ;
2021-05-12 15:02:27 +03:00
const config = require ( '../../../shared/config' ) ;
2021-07-27 12:27:59 +03:00
const models = require ( '../../models' ) ;
2021-07-20 17:42:26 +03:00
const { GhostMailer } = require ( '../mail' ) ;
2021-07-20 18:21:59 +03:00
const jobsService = require ( '../jobs' ) ;
2022-01-27 17:06:29 +03:00
const VerificationTrigger = require ( '@tryghost/verification-trigger' ) ;
2022-01-30 18:05:09 +03:00
const events = require ( '../../lib/common/events' ) ;
2021-05-12 15:02:27 +03:00
2021-07-19 13:46:38 +03:00
const messages = {
noLiveKeysInDevelopment : 'Cannot use live stripe keys in development. Please restart in production mode.' ,
sslRequiredForStripe : 'Cannot run Ghost without SSL when Stripe is connected. Please update your url config to use "https://".' ,
2021-07-23 19:37:29 +03:00
remoteWebhooksInDevelopment : 'Cannot use remote webhooks in development. See https://ghost.org/docs/webhooks/#stripe-webhooks for developing with Stripe.' ,
2021-08-20 17:07:20 +03:00
emailVerificationNeeded : ` We're hard at work processing your import. To make sure you get great deliverability on a list of that size, we'll need to enable some extra features for your account. A member of our team will be in touch with you by email to review your account make sure everything is configured correctly so you're ready to go. ` ,
2021-07-28 18:28:13 +03:00
emailVerificationEmailMessage : ` Email verification needed for site: {siteUrl}, just imported: {importedNumber} members. `
2021-07-19 13:46:38 +03:00
} ;
2021-07-20 17:42:26 +03:00
const ghostMailer = new GhostMailer ( ) ;
2021-05-12 15:02:27 +03:00
const membersConfig = new MembersConfigProvider ( {
config ,
settingsCache ,
2021-12-14 18:18:46 +03:00
urlUtils
2021-05-12 15:02:27 +03:00
} ) ;
2022-01-27 17:06:29 +03:00
const membersStats = new MembersStats ( {
db : db ,
settingsCache : settingsCache ,
isSQLite : config . get ( 'database:client' ) === 'sqlite3'
} ) ;
2021-05-12 15:02:27 +03:00
let membersApi ;
let membersSettings ;
2022-01-27 17:06:29 +03:00
let verificationTrigger ;
2021-07-23 19:37:29 +03:00
2021-07-23 15:58:35 +03:00
const membersImporter = new MembersCSVImporter ( {
storagePath : config . getContentPath ( 'data' ) ,
getTimezone : ( ) => settingsCache . get ( 'timezone' ) ,
2022-01-18 18:56:47 +03:00
getMembersApi : ( ) => module . exports . api ,
2021-07-23 15:58:35 +03:00
sendEmail : ghostMailer . send . bind ( ghostMailer ) ,
isSet : labsService . isSet . bind ( labsService ) ,
addJob : jobsService . addJob . bind ( jobsService ) ,
knex : db . knex ,
2022-01-27 17:06:29 +03:00
urlFor : urlUtils . urlFor . bind ( urlUtils )
2021-07-23 15:58:35 +03:00
} ) ;
2021-07-28 15:36:20 +03:00
const processImport = async ( options ) => {
const result = await membersImporter . process ( options ) ;
2021-07-28 18:28:13 +03:00
const importSize = result . meta . originalImportSize ;
delete result . meta . originalImportSize ;
2021-07-28 15:36:20 +03:00
2022-01-27 17:06:29 +03:00
const importThreshold = await verificationTrigger . getImportThreshold ( ) ;
if ( importThreshold > importSize ) {
await verificationTrigger . startVerificationProcess ( {
amountImported : importSize ,
throwOnTrigger : true
} ) ;
2021-07-28 15:36:20 +03:00
}
2021-07-23 19:37:29 +03:00
return result ;
2021-07-23 15:58:35 +03:00
} ;
2021-05-12 15:02:27 +03:00
2022-01-18 18:56:47 +03:00
module . exports = {
2021-05-12 15:46:05 +03:00
async init ( ) {
2022-01-18 18:56:47 +03:00
const stripeService = require ( '../stripe' ) ;
const createMembersApiInstance = require ( './api' ) ;
2021-05-12 15:46:05 +03:00
const env = config . get ( 'env' ) ;
2022-01-30 18:05:09 +03:00
events . on ( 'settings.edited' , async function ( settingModel ) {
if ( labsService . isSet ( 'multipleProducts' ) ) {
return ;
}
const key = settingModel . get ( 'key' ) ;
const value = settingModel . get ( 'value' ) ;
if ( key === 'members_free_signup_redirect' ) {
try {
await models . Product . forge ( ) . query ( ) . update ( 'welcome_page_url' , value ) . where ( 'type' , 'free' ) ;
} catch ( err ) {
logging . error ( err ) ;
}
return ;
}
if ( key === 'members_paid_signup_redirect' ) {
try {
await models . Product . forge ( ) . query ( ) . update ( 'welcome_page_url' , value ) . where ( 'type' , 'paid' ) ;
} catch ( err ) {
logging . error ( err ) ;
}
return ;
}
} ) ;
2022-01-18 18:56:47 +03:00
// @TODO Move to stripe service
2021-05-12 15:46:05 +03:00
if ( env !== 'production' ) {
2021-10-04 14:18:22 +03:00
if ( stripeService . api . configured && stripeService . api . mode === 'live' ) {
2021-12-01 14:22:14 +03:00
throw new errors . IncorrectUsageError ( {
message : tpl ( messages . noLiveKeysInDevelopment )
} ) ;
2021-05-12 15:46:05 +03:00
}
} else {
const siteUrl = urlUtils . getSiteUrl ( ) ;
2021-10-04 14:18:22 +03:00
if ( ! /^https/ . test ( siteUrl ) && stripeService . api . configured ) {
2021-12-01 14:22:14 +03:00
throw new errors . IncorrectUsageError ( {
message : tpl ( messages . sslRequiredForStripe )
} ) ;
2021-05-12 15:46:05 +03:00
}
}
2021-05-12 15:02:27 +03:00
if ( ! membersApi ) {
membersApi = createMembersApiInstance ( membersConfig ) ;
membersApi . bus . on ( 'error' , function ( err ) {
logging . error ( err ) ;
} ) ;
}
2022-01-04 12:21:36 +03:00
2022-01-27 17:06:29 +03:00
verificationTrigger = new VerificationTrigger ( {
configThreshold : _ . get ( config . get ( 'hostSettings' ) , 'emailVerification.importThreshold' ) ,
isVerified : ( ) => config . get ( 'hostSettings:emailVerification:verified' ) === true ,
isVerificationRequired : ( ) => settingsCache . get ( 'email_verification_required' ) === true ,
sendVerificationEmail : ( { subject , message , amountImported } ) => {
const escalationAddress = config . get ( 'hostSettings:emailVerification:escalationAddress' ) ;
const fromAddress = config . get ( 'user_email' ) ;
if ( escalationAddress ) {
2022-02-01 15:00:01 +03:00
ghostMailer . send ( {
2022-01-27 17:06:29 +03:00
subject ,
html : tpl ( message , {
amountImported ,
siteUrl : this . _urlUtils . getSiteUrl ( )
} ) ,
forceTextContent : true ,
from : fromAddress ,
to : escalationAddress
} ) ;
}
} ,
membersStats ,
Settings : models . Settings ,
eventRepository : membersApi . events
} ) ;
2022-01-04 12:21:36 +03:00
( async ( ) => {
try {
const collection = await models . SingleUseToken . fetchAll ( ) ;
await collection . invokeThen ( 'destroy' ) ;
} catch ( err ) {
logging . error ( err ) ;
}
} ) ( ) ;
2022-01-18 18:56:47 +03:00
2022-01-24 17:38:16 +03:00
try {
await stripeService . migrations . execute ( ) ;
} catch ( err ) {
logging . error ( err ) ;
}
2021-10-04 14:18:22 +03:00
} ,
contentGating : require ( './content-gating' ) ,
config : membersConfig ,
get api ( ) {
2021-05-12 15:02:27 +03:00
return membersApi ;
} ,
get settings ( ) {
if ( ! membersSettings ) {
membersSettings = createMembersSettingsInstance ( membersConfig ) ;
}
return membersSettings ;
} ,
ssr : MembersSSR ( {
cookieSecure : urlUtils . isSSL ( urlUtils . getSiteUrl ( ) ) ,
cookieKeys : [ settingsCache . get ( 'theme_session_secret' ) ] ,
cookieName : 'ghost-members-ssr' ,
cookieCacheName : 'ghost-members-ssr-cache' ,
2022-01-18 18:56:47 +03:00
getMembersApi : ( ) => module . exports . api
2021-05-12 15:02:27 +03:00
} ) ,
stripeConnect : require ( './stripe-connect' ) ,
2021-07-23 15:58:35 +03:00
processImport : processImport ,
2021-05-12 15:02:27 +03:00
2022-01-27 17:06:29 +03:00
stats : membersStats
2021-05-12 15:02:27 +03:00
2022-01-18 18:56:47 +03:00
} ;
2021-05-12 15:02:27 +03:00
module . exports . middleware = require ( './middleware' ) ;