Merge pull request #801 from sharelatex/ho-mailchimp

Add non checked checkbox for newsletter subscription on signup and use mailchimp as newsletter provider.
This commit is contained in:
Henry Oswald 2018-08-16 11:40:39 +01:00 committed by GitHub
commit 5ed95694da
7 changed files with 104 additions and 39 deletions

View file

@ -1,37 +1,68 @@
async = require('async')
Request = require('request')
logger = require 'logger-sharelatex'
Settings = require 'settings-sharelatex'
crypto = require('crypto')
Mailchimp = require('mailchimp-api-v3')
if !Settings.mailchimp?.api_key?
logger.info "Using newsletter provider: none"
mailchimp =
request: (opts, cb)-> cb()
else
logger.info "Using newsletter provider: mailchimp"
mailchimp = new Mailchimp(Settings.mailchimp?.api_key)
module.exports =
subscribe: (user, callback = () ->)->
if !Settings.markdownmail?
logger.warn "No newsletter provider configured so not subscribing user"
return callback()
logger.log user:user, email:user.email, "trying to subscribe user to the mailing list"
options = buildOptions(user, true)
Request.post options, (err, response, body)->
logger.log body:body, user:user, "finished attempting to subscribe the user to the news letter"
logger.log options:options, user:user, email:user.email, "trying to subscribe user to the mailing list"
mailchimp.request options, (err)->
if err?
logger.err err:err, "error subscribing person to newsletter"
else
logger.log user:user, "finished subscribing user to the newsletter"
callback(err)
unsubscribe: (user, callback = () ->)->
if !Settings.markdownmail?
logger.warn "No newsletter provider configured so not unsubscribing user"
return callback()
logger.log user:user, email:user.email, "trying to unsubscribe user to the mailing list"
options = buildOptions(user, false)
Request.post options, (err, response, body)->
logger.log err:err, body:body, email:user.email, "compled newsletter unsubscribe attempt"
mailchimp.request options, (err)->
if err?
logger.err err:err, "error unsubscribing person to newsletter"
else
logger.log user:user, "finished unsubscribing user to the newsletter"
callback(err)
changeEmail: (oldEmail, newEmail, callback = ()->)->
options = buildOptions({email:oldEmail})
delete options.body.status
options.body.email_address = newEmail
mailchimp.request options, (err)->
# if the user has unsubscribed mailchimp will error on email address change
if err? and err?.message.indexOf("could not be validated") == -1
logger.err err:err, "error changing email in newsletter"
return callback(err)
else
logger.log "finished changing email in the newsletter"
return callback()
hashEmail = (email)->
crypto.createHash('md5').update(email.toLowerCase()).digest("hex")
buildOptions = (user, is_subscribed)->
options =
json:
secret_token: Settings.markdownmail.secret
name: "#{user.first_name} #{user.last_name}"
email: user.email
subscriber_list_id: Settings.markdownmail.list_id
is_subscribed: is_subscribed
url: "https://www.markdownmail.io/lists/subscribe"
timeout: 30 * 1000
return options
status = if is_subscribed then "subscribed" else "unsubscribed"
subscriber_hash = hashEmail(user.email)
opts =
method: "PUT"
path: "/lists/#{Settings.mailchimp?.list_id}/members/#{subscriber_hash}"
body:
status_if_new: status
status: status
email_address:user.email
merge_fields:
FNAME: user.first_name
LNAME: user.last_name
MONGO_ID:user._id
return opts

View file

@ -1,4 +1,3 @@
sanitize = require('sanitizer')
User = require("../../models/User").User
UserCreator = require("./UserCreator")
UserGetter = require("./UserGetter")
@ -54,7 +53,8 @@ module.exports = UserRegistrationHandler =
(cb)-> User.update {_id: user._id}, {"$set":{holdingAccount:false}}, cb
(cb)-> AuthenticationManager.setUserPassword user._id, userDetails.password, cb
(cb)->
NewsLetterManager.subscribe user, ->
if userDetails.subscribeToNewsletter == "true"
NewsLetterManager.subscribe user, ->
cb() #this can be slow, just fire it off
], (err)->
logger.log user: user, "registered"

View file

@ -11,6 +11,7 @@ EmailHelper = require "../Helpers/EmailHelper"
Errors = require "../Errors/Errors"
Settings = require "settings-sharelatex"
request = require 'request'
NewsletterManager = require "../Newsletter/NewsletterManager"
module.exports = UserUpdater =
updateUser: (query, update, callback = (error) ->) ->
@ -99,15 +100,21 @@ module.exports = UserUpdater =
setDefaultEmailAddress: (userId, email, callback) ->
email = EmailHelper.parseEmail(email)
return callback(new Error('invalid email')) if !email?
query = _id: userId, 'emails.email': email
update = $set: email: email
@updateUser query, update, (error, res) ->
if error?
logger.err error:error, 'problem setting default emails'
UserGetter.getUserEmail userId, (error, oldEmail) =>
if err?
return callback(error)
if res.n == 0 # TODO: Check n or nMatched?
return callback(new Error('Default email does not belong to user'))
callback()
query = _id: userId, 'emails.email': email
update = $set: email: email
@updateUser query, update, (error, res) ->
if error?
logger.err error:error, 'problem setting default emails'
return callback(error)
else if res.n == 0 # TODO: Check n or nMatched?
return callback(new Error('Default email does not belong to user'))
else
NewsletterManager.changeEmail oldEmail, email, callback
updateV1AndSetDefaultEmailAddress: (userId, email, callback) ->
@updateEmailAddressInV1 userId, email, (error) =>

View file

@ -278,10 +278,10 @@ module.exports = settings =
# Third party services
# --------------------
#
# ShareLaTeX's regular newsletter is managed by Markdown mail. Add your
# ShareLaTeX's regular newsletter is managed by mailchimp. Add your
# credentials here to integrate with this.
# markdownmail:
# secret: ""
# mailchimp:
# api_key: ""
# list_id: ""
#
# Fill in your unique token from various analytics services to enable

View file

@ -59,6 +59,7 @@
"lodash": "^4.13.1",
"logger-sharelatex": "git+https://github.com/sharelatex/logger-sharelatex.git#master",
"lynx": "0.1.1",
"mailchimp-api-v3": "^1.12.0",
"marked": "^0.3.5",
"method-override": "^2.3.3",
"metrics-sharelatex": "git+https://github.com/sharelatex/metrics-sharelatex.git#v1.7.1",

View file

@ -132,11 +132,17 @@ describe "UserRegistrationHandler", ->
@AuthenticationManager.setUserPassword.calledWith(@user._id, @passingRequest.password).should.equal true
done()
it "should add the user to the news letter manager", (done)->
it "should add the user to the newsletter if accepted terms", (done)->
@passingRequest.subscribeToNewsletter = "true"
@handler.registerNewUser @passingRequest, (err)=>
@NewsLetterManager.subscribe.calledWith(@user).should.equal true
done()
it "should not add the user to the newsletter if not accepted terms", (done)->
@handler.registerNewUser @passingRequest, (err)=>
@NewsLetterManager.subscribe.calledWith(@user).should.equal false
done()
it "should track the registration event", (done)->
@handler.registerNewUser @passingRequest, (err)=>
@AnalyticsManager.recordEvent

View file

@ -18,21 +18,27 @@ describe "UserUpdater", ->
getUserEmail: sinon.stub()
getUserByAnyEmail: sinon.stub()
ensureUniqueEmailAddress: sinon.stub()
@logger = err: sinon.stub(), log: ->
@logger =
err: sinon.stub()
log: ->
warn: ->
@addAffiliation = sinon.stub().yields()
@removeAffiliation = sinon.stub().callsArgWith(2, null)
@refreshFeatures = sinon.stub().yields()
@NewsletterManager =
changeEmail:sinon.stub()
@UserUpdater = SandboxedModule.require modulePath, requires:
"logger-sharelatex": @logger
"../../infrastructure/mongojs":@mongojs
"metrics-sharelatex": timeAsyncMethod: sinon.stub()
"./UserGetter": @UserGetter
'../Institutions/InstitutionsAPI':
addAffiliation: @addAffiliation
removeAffiliation: @removeAffiliation
'../Subscription/FeaturesUpdater': refreshFeatures: @refreshFeatures
"../../infrastructure/mongojs":@mongojs
"metrics-sharelatex": timeAsyncMethod: sinon.stub()
"settings-sharelatex": @settings = {}
"request": @request = {}
"../Newsletter/NewsletterManager": @NewsletterManager
@stubbedUser =
_id: "3131231"
@ -174,6 +180,10 @@ describe "UserUpdater", ->
done()
describe 'setDefaultEmailAddress', ->
beforeEach ->
@UserGetter.getUserEmail.callsArgWith(1, null, @stubbedUser.email)
@NewsletterManager.changeEmail.callsArgWith(2, null)
it 'set default', (done)->
@UserUpdater.updateUser = sinon.stub().callsArgWith(2, null, n: 1)
@ -185,6 +195,16 @@ describe "UserUpdater", ->
).should.equal true
done()
it 'set changed the email in newsletter', (done)->
@UserUpdater.updateUser = sinon.stub().callsArgWith(2, null, n: 1)
@UserUpdater.setDefaultEmailAddress @stubbedUser._id, @newEmail, (err)=>
should.not.exist(err)
@NewsletterManager.changeEmail.calledWith(
@stubbedUser.email, @newEmail
).should.equal true
done()
it 'handle error', (done)->
@UserUpdater.updateUser = sinon.stub().callsArgWith(2, new Error('nope'))