Skip to content

Instantly share code, notes, and snippets.

@MichaelAstreiko
Created August 15, 2013 22:07
Show Gist options
  • Select an option

  • Save MichaelAstreiko/6245417 to your computer and use it in GitHub Desktop.

Select an option

Save MichaelAstreiko/6245417 to your computer and use it in GitHub Desktop.
import static groovyx.net.http.Method.GET
import static groovyx.net.http.Method.POST
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.ContentType
import org.apache.commons.lang.BooleanUtils
import org.apache.commons.httpclient.methods.multipart.Part
import org.apache.commons.httpclient.methods.multipart.StringPart
import com.nearme.portal.http.MultipartEntityWrapper
import grails.converters.JSON
import com.nearme.portal.domain.authentication.User
import org.springframework.web.context.request.RequestAttributes
import org.springframework.web.context.request.RequestContextHolder
import org.springframework.context.i18n.LocaleContextHolder
/**
* @author Michael Astreiko
*/
class NewsletterService implements Serializable {
static transactional = false
def countryService
def grailsApplication
def groovyPagesTemplateEngine
def springSecurityService
def messageSource
/**
*
* @param searchParams
* @param pagingParams
* @return
*/
def listCampaigns(Map searchParams, Map pagingParams) {
def gchimpConfig = grailsApplication.config.gchimp
def query = [apikey: gchimpConfig.apiKey, method: 'campaigns']
searchParams?.each {
query["filters[${it.key}]"] = it.value
}
query["filters[list_id]"] = "${gchimpConfig.defaultListId},${gchimpConfig.salesListId}"
query += pagingParams
return executeSimpleHTTPCall(query, {text -> JSON.parse(text)})
}
Long getSubscribersForSegments(Map segmentation) {
def query = [apikey: grailsApplication.config.gchimp.apiKey, list_id: grailsApplication.config.gchimp.defaultListId,
method: 'campaignSegmentTest']
query += getSegmentationParams(segmentation, 'options')
return executeSimpleHTTPCall(query) as Long
}
boolean createTemplateAndCampaign(String pathToGenerateTemplate, Map binding, String emailSubject,
Map segmentation, List userPhones, boolean sendCampaign, boolean skipEmail = false) {
def htmlStringWriter = new StringWriter()
groovyPagesTemplateEngine.createTemplate(pathToGenerateTemplate).make(binding).writeTo(htmlStringWriter)
String campaignId = createCampaignWithoutTemplate(htmlStringWriter.toString(), emailSubject, segmentation)
if (sendCampaign) {
return BooleanUtils.toBoolean(sendCampaignNow(campaignId, userPhones, skipEmail))
} else {
return campaignId != null
}
}
boolean subscribeUsersAndCreateCampaign(String pathToGenerateTemplate, Map binding, String emailSubject,
List userData, List userPhones, String groupName, boolean sendCampaign) {
def htmlStringWriter = new StringWriter()
groovyPagesTemplateEngine.createTemplate(pathToGenerateTemplate).make(binding).writeTo(htmlStringWriter)
def subscriptionResult = bulkRecipientsSubscribe(userData, groupName)
if (log.isInfoEnabled()) {
log.info("Bulk subscription result: ${subscriptionResult}")
}
if (subscriptionResult && (subscriptionResult.add_count > 0 || subscriptionResult.update_count > 0)) {
def createCampaignQuery = [apikey: grailsApplication.config.gchimp.apiKey, method: 'campaignCreate',
type: 'regular']
def formParams = [:]
def options = [
from_email: '[email protected]',
from_name: 'Test',
generate_text: 'true',
auto_footer: 'false',
list_id: grailsApplication.config.gchimp.salesListId,
subject: emailSubject
]
formParams['content[html]'] = htmlStringWriter.toString()
options.each {
formParams["options[$it.key]"] = it.value
}
User user = User.read(springSecurityService.currentUser.id)
def segments = [[field: 'GROUPNAME', value: groupName, op: 'eq']]
if (user.salesReprRoleDefinition) {
segments << [field: 'SALESCODE', value: user.salesReprRoleDefinition.salesCode, op: 'eq']
}
formParams += getSegmentationParams([conditions: segments, match: 'all'])
String campaignId = createCampaign(createCampaignQuery, formParams)
if (sendCampaign) {
return BooleanUtils.toBoolean(sendCampaignNow(campaignId, userPhones))
} else {
return campaignId != null
}
} else {
log.error "Users were not subscribed due to: ${subscriptionResult}"
return false
}
}
def deleteCampaign(String campaignId) {
def query = [apikey: grailsApplication.config.gchimp.apiKey, cid: campaignId, method: 'campaignDelete']
def hTTPCallResult = executeSimpleHTTPCall(query)
def isCampaignDeleted = BooleanUtils.toBoolean(hTTPCallResult)
if (!isCampaignDeleted) {
return JSON.parse(hTTPCallResult).error
}
return isCampaignDeleted
}
private def bulkRecipientsSubscribe(List userData, String groupName) {
def query = [apikey: grailsApplication.config.gchimp.apiKey, id: grailsApplication.config.gchimp.salesListId,
method: 'listBatchSubscribe', double_optin: 'false', update_existing: 'true']
def formParams = [:]
User user = User.read(springSecurityService.currentUser.id)
userData?.eachWithIndex {data, ind ->
formParams["batch[$ind][FNAME]"] = data.firstName
formParams["batch[$ind][LNAME]"] = data.lastName
formParams["batch[$ind][EMAIL]"] = data.email
formParams["batch[$ind][GROUPNAME]"] = groupName
if (user.salesReprRoleDefinition) {
formParams["batch[$ind][SALESCODE]"] = user.salesReprRoleDefinition.salesCode
}
}
return executeSimpleHTTPCall(query, {text -> JSON.parse(text)}, formParams)
}
boolean unsubscribe(String email) {
def query = [apikey: grailsApplication.config.gchimp.apiKey, id: grailsApplication.config.gchimp.defaultListId,
method: 'listUnsubscribe ', email_address: email, send_goodbye: 'false', send_notify: 'false']
return BooleanUtils.toBoolean(executeSimpleHTTPCall(query))
}
def memberInfo(String email) {
def query = [apikey: grailsApplication.config.gchimp.apiKey, id: grailsApplication.config.gchimp.defaultListId,
method: 'listMemberInfo', email_address: email]
return executeSimpleHTTPCall(query, {text -> JSON.parse(text)?.data})[0]
}
/**
* Subscribe or update Member
*
* @param user
* @param newEmail - - if updateExisting is true and value is present, then it will be used for new EMAIL
* @param ipAddress
* @return true if member successfully subscribed/updated
*/
boolean subscribeUser(User user, String newEmail = null, String ipAddress = null) {
boolean updateExisting = false
if (memberInfo(user.email)?.status == 'subscribed') {
updateExisting = true
}
def query = [apikey: grailsApplication.config.gchimp.apiKey, id: grailsApplication.config.gchimp.defaultListId,
method: 'listSubscribe', email_address: user.email,
double_optin: 'false', update_existing: updateExisting]
def mergeVars = [:]
mergeVars["FNAME"] = user.firstName
mergeVars["LNAME"] = user.lastName
if (updateExisting && newEmail) {
mergeVars["EMAIL"] = newEmail
}
if (user.birthday) {
mergeVars["BIRTHDAY"] = user.birthday.format("MM/dd")
}
if (!updateExisting) {
mergeVars["REGISTERED"] = user.dateCreated.format("yyyy-MM-dd")
mergeVars["OPTIN_IP"] = ipAddress
mergeVars["OPTIN_TIME"] = new Date().format("yyyy-MM-dd HH:mm:ss")
}
mergeVars.each {key, value ->
query["merge_vars[${key}]"] = value
}
query += retrieveGroupingMergeVars(user)
return BooleanUtils.toBoolean(executeSimpleHTTPCall(query))
}
private LinkedHashMap retrieveGroupingMergeVars(User user) {
def groupingsMergeVars = [:]
int externalIndex = 0
listGroupings().each {group ->
def groupValue = null
if (group?.name == 'Gender') {
groupValue = user.gender
} else if (group?.name == 'Age' && user.birthday) {
groupValue = getUserAgeGroupValue(user)
} else if (group?.name == 'Country' && user.countryCode) {
def userCountry = countryService.getISO3166_2().get(user.countryCode)
groupValue = getGroupValueForMutableGroup(group, userCountry)
} else if (group?.name == 'City' && user.homeCity) {
def userCity = user.homeCity
groupValue = getGroupValueForMutableGroup(group, userCity)
}
if (groupValue) {
groupingsMergeVars["merge_vars[GROUPINGS][$externalIndex][id]"] = group?.id
groupingsMergeVars["merge_vars[GROUPINGS][$externalIndex][groups]"] = groupValue
externalIndex++
}
}
return groupingsMergeVars
}
private String getUserAgeGroupValue(User user) {
String result = ""
def userAge = calculateUserAge(user.birthday)
if (userAge <= 20) {
result = '16 - 20'
} else if (userAge <= 60) {
result = '21 - 60'
} else {
result = '60 +'
}
return result
}
private String getGroupValueForMutableGroup(group, userValue) {
def groupValue = group.groups.find {it.name == userValue}?.name
if (!groupValue) {
boolean groupIsAdded = addGroup(group?.id?.toString(), userValue)
if (groupIsAdded) {
groupValue = userValue
} else {
log.error "Group ${userValue} was not added to grouping ${group?.id} for some reasons."
}
}
return groupValue
}
/**
* Calculate age by birthday
*
* @param birthday
* @return
*/
private int calculateUserAge(Date birthday) {
def now = new Date()
def birthdayThisYear = new Date()
birthdayThisYear.month = birthday.month
birthdayThisYear.date = birthday.date
return now.year - birthday.year - (birthdayThisYear > now ? 1 : 0)
}
/**
*
* @param templateId
* @return campaignId
*/
private String createCampaignWithoutTemplate(String htmlTemplate, String emailSubject, Map segmentation) {
def query = [apikey: grailsApplication.config.gchimp.apiKey, method: 'campaignCreate',
type: 'regular']
def formParams = [:]
def options = [
from_email: '[email protected]',
from_name: 'Test',
generate_text: 'true',
auto_footer: 'false',
list_id: grailsApplication.config.gchimp.defaultListId,
subject: emailSubject
]
formParams['content[html]'] = htmlTemplate
options.each {
formParams["options[$it.key]"] = it.value
}
formParams += getSegmentationParams(segmentation)
return createCampaign(query, formParams)
}
private Map getSegmentationParams(Map segmentation, String optionsName = 'segment_opts') {
def result = [:]
if (segmentation && segmentation.conditions) {
result[optionsName + '[match]'] = segmentation["match"]
segmentation?.conditions?.eachWithIndex {cond, ind ->
result["${optionsName}[conditions][$ind][field]"] = cond.field
result["${optionsName}[conditions][$ind][value]"] = cond.value
result["${optionsName}[conditions][$ind][op]"] = cond.op
}
} else {
//Load all
result[optionsName + '[match]'] = "all"
result["${optionsName}[conditions][0][field]"] = 'date'
result["${optionsName}[conditions][0][op]"] = 'gt'
result["${optionsName}[conditions][0][value]"] = '1900-01-01'
}
return result
}
private def listGroupings() {
def query = [apikey: grailsApplication.config.gchimp.apiKey, id: grailsApplication.config.gchimp.defaultListId,
method: 'listInterestGroupings']
return executeSimpleHTTPCall(query, {text -> JSON.parse(text)})
}
private boolean addGroup(String groupingId, String newGroupName) {
def query = [apikey: grailsApplication.config.gchimp.apiKey, id: grailsApplication.config.gchimp.defaultListId,
method: 'listInterestGroupAdd ', grouping_id: groupingId, group_name: newGroupName]
return BooleanUtils.toBoolean(executeSimpleHTTPCall(query))
}
private String createCampaign(Map query, Map formParams) {
def parts = []
formParams?.each {key, value ->
parts << new StringPart(key, value, "UTF-8")
}
try {
def http = new HTTPBuilder(grailsApplication.config.gchimp.apiUrl)
http.request(POST, ContentType.TEXT) {request ->
uri.query = query
requestContentType = 'multipart/form-data'
request.entity = new MultipartEntityWrapper(parts.toArray() as Part[], request.params)
response.success = { resp, reader ->
return reader.text?.replaceAll('"', "")
}
response.failure = {resp ->
log.error "Error during HTTP call ${resp.statusLine.statusCode} : ${resp.statusLine.reasonPhrase}"
}
}
} catch (ex) {
log.error "Error during HTTP call : ${ex.message}"
return ""
}
}
String sendCampaignNow(String campaignId) {
try {
def http = new HTTPBuilder(grailsApplication.config.gchimp.apiUrl)
http.request(GET, ContentType.TEXT) {
uri.query = [apikey: grailsApplication.config.gchimp.apiKey, method: 'campaignSendNow',
cid: campaignId]
response.success = { resp, reader ->
return reader.text
}
response.failure = {resp ->
log.error "Error during HTTP call ${resp.statusLine.statusCode} : ${resp.statusLine.reasonPhrase}"
}
}
} catch (ex) {
log.error "Error during HTTP call : ${ex.message}"
return ""
}
}
private campaignDetails(String campaignId) {
def gchimpConfig = grailsApplication.config.gchimp
def query = [apikey: gchimpConfig.apiKey, method: 'campaigns']
query["filters[campaign_id]"] = campaignId
return executeSimpleHTTPCall(query, {text -> JSON.parse(text)?.data?.getAt(0)})
}
/**
* Simple HTTP POST to MailChimp API
*
* @param query - Map with URL params
* @return list of elements or empty list if nothing or error
*/
private executeSimpleHTTPCall(query, Closure responseParser = null, Map formParams = [:]) {
def http = new HTTPBuilder(grailsApplication.config.gchimp.apiUrl)
def parts = []
try {
formParams?.each { key, value ->
parts << new StringPart(key, value, "UTF-8")
}
} catch (ex) {
log.error "${ex.message}"
return []
}
try {
http.request(POST, ContentType.TEXT) {request ->
uri.query = query
if (parts) {
requestContentType = 'multipart/form-data'
request.entity = new MultipartEntityWrapper(parts.toArray() as Part[], request.params)
}
response.success = { resp, reader ->
def text = reader.text
log.info "Response from MailChimp: ${text}"
if (responseParser) {
return responseParser(text)
} else {
return text
}
}
response.failure = {resp ->
log.error "Error during HTTP call ${resp.statusLine.statusCode} : ${resp.statusLine.reasonPhrase}"
}
}
} catch (ex) {
log.error "Error during HTTP call : ${ex.message}"
return []
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment