Instantly share code, notes, and snippets.
Created
August 15, 2013 22:07
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save MichaelAstreiko/6245417 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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