Merge pull request #4604 from totten/master-civimail-addrs
[civicrm-core.git] / js / angular-crmMailing2-services.js
1 (function (angular, $, _) {
2 var partialUrl = function (relPath) {
3 return CRM.resourceUrls['civicrm'] + '/partials/crmMailing2/' + relPath;
4 };
5
6 var crmMailing2 = angular.module('crmMailing2');
7
8 // The representation of from/reply-to addresses is inconsistent in the mailing data-model,
9 // so the UI must do some adaptation. The crmFromAddresses provides a richer way to slice/dice
10 // the available "From:" addrs. Records are like the underlying OptionValues -- but add "email"
11 // and "author".
12 crmMailing2.factory('crmFromAddresses', function($q, crmApi) {
13 var emailRegex = /^"(.*)" \<([^@\>]*@[^@\>]*)\>$/;
14 var addrs = _.map(CRM.crmMailing.fromAddress, function(addr){
15 var match = emailRegex.exec(addr.label);
16 return _.extend({}, addr, {
17 email: match ? match[2] : '(INVALID)',
18 author: match ? match[1] : '(INVALID)'
19 });
20 });
21 function first(array) {
22 return (array.length == 0) ? null : array[0];
23 };
24
25 return {
26 getAll: function getAll() {
27 return addrs;
28 },
29 getByAuthorEmail: function getByAuthorEmail(author, email, autocreate) {
30 var result = null;
31 _.each(addrs, function(addr){
32 if (addr.author == author && addr.email == email) {
33 result = addr;
34 }
35 });
36 if (!result && autocreate) {
37 result = {
38 label: '(INVALID) "' + author + '" <' + email + '>',
39 author: author,
40 email: email
41 };
42 addrs.push(result);
43 }
44 return result;
45 },
46 getByEmail: function getByEmail(email) {
47 return first(_.where(addrs, {email: email}));
48 },
49 getByLabel: function(label) {
50 return first(_.where(addrs, {label: label}));
51 },
52 getDefault: function getDefault() {
53 return first(_.where(addrs, {is_default: "1"}));
54 }
55 };
56 });
57
58 // The crmMailingMgr service provides business logic for loading, saving, previewing, etc
59 crmMailing2.factory('crmMailingMgr', function($q, crmApi, crmFromAddresses) {
60 window.f = crmFromAddresses; // REVERT
61 var pickDefaultMailComponent = function pickDefaultMailComponent(type) {
62 var mcs = _.where(CRM.crmMailing.headerfooterList, {
63 component_type:type,
64 is_default: "1"
65 });
66 return (mcs.length >= 1) ? mcs[0].id : null;
67 };
68
69 return {
70 // @param scalar idExpr a number or the literal string 'new'
71 // @return Promise|Object Mailing (per APIv3)
72 getOrCreate: function getOrCreate(idExpr) {
73 return (idExpr == 'new') ? this.create() : this.get(idExpr);
74 },
75 // @return Promise Mailing (per APIv3)
76 get: function get(id) {
77 return crmApi('Mailing', 'getsingle', {id: id}).then(function(mailing){
78 return crmApi('MailingGroup', 'get', {mailing_id: id}).then(function(groupResult){
79 mailing.groups = {include: [], exclude: []};
80 mailing.mailings = {include: [], exclude: []};
81 _.each(groupResult.values, function(mailingGroup) {
82 var bucket = (mailingGroup.entity_table == 'civicrm_group') ? 'groups' : 'mailings';
83 var entityId = parseInt(mailingGroup.entity_id);
84 mailing[bucket][mailingGroup.group_type].push(entityId);
85 });
86 return mailing;
87 });
88 });
89 },
90 // @return Object Mailing (per APIv3)
91 create: function create() {
92 return {
93 name: "revert this", // fixme
94 campaign_id: null,
95 from_name: crmFromAddresses.getDefault().author,
96 from_email: crmFromAddresses.getDefault().email,
97 replyto_email: "",
98 subject: "For {contact.display_name}", // fixme
99 dedupe_email: "1",
100 groups: {include: [2], exclude: [4]}, // fixme
101 mailings: {include: [], exclude: []},
102 body_html: "<b>Hello</b> {contact.display_name}", // fixme
103 body_text: "Hello {contact.display_name}", // fixme
104 footer_id: null, // pickDefaultMailComponent('Footer'),
105 header_id: null, // pickDefaultMailComponent('Header'),
106 visibility: "Public Pages",
107 url_tracking: "1",
108 dedupe_email: "1",
109 forward_replies: "0",
110 auto_responder: "0",
111 open_tracking: "1",
112 override_verp: "1",
113 optout_id: pickDefaultMailComponent('OptOut'),
114 reply_id: pickDefaultMailComponent('Reply'),
115 resubscribe_id: pickDefaultMailComponent('Resubscribe'),
116 unsubscribe_id: pickDefaultMailComponent('Unsubscribe')
117 };
118 },
119
120 // @param mailing Object (per APIv3)
121 // @return Promise
122 'delete': function(mailing) {
123 if (mailing.id) {
124 return crmApi('Mailing', 'delete', {id: mailing.id});
125 } else {
126 var d = $q.defer();
127 d.resolve();
128 return d.promise;
129 }
130 },
131
132 // @param mailing Object (per APIv3)
133 // @return Promise an object with "subject", "body_text", "body_html"
134 preview: function preview(mailing) {
135 var params = _.extend({}, mailing, {
136 options: {force_rollback: 1},
137 'api.Mailing.preview': {
138 id: '$value.id',
139 }
140 });
141 return crmApi('Mailing', 'create', params).then(function(result){
142 // changes rolled back, so we don't care about updating mailing
143 return result.values[result.id]['api.Mailing.preview'].values;
144 });
145 },
146
147 // @param mailing Object (per APIv3)
148 // @param int previewLimit
149 // @return Promise for a list of recipients (mailing_id, contact_id, api.contact.getvalue, api.email.getvalue)
150 previewRecipients: function previewRecipients(mailing, previewLimit) {
151 // To get list of recipients, we tentatively save the mailing and
152 // get the resulting recipients -- then rollback any changes.
153 var params = _.extend({}, mailing, {
154 options: {force_rollback: 1},
155 'api.mailing_job.create': 1, // note: exact match to API default
156 'api.MailingRecipients.get': {
157 mailing_id: '$value.id',
158 options: { limit: previewLimit },
159 'api.contact.getvalue': {'return': 'display_name'},
160 'api.email.getvalue': {'return': 'email'}
161 }
162 });
163 return crmApi('Mailing', 'create', params).then(function(recipResult){
164 // changes rolled back, so we don't care about updating mailing
165 return recipResult.values[recipResult.id]['api.MailingRecipients.get'].values;
166 });
167 },
168
169 // @param mailing Object (per APIv3)
170 // @return Promise
171 save: function(mailing) {
172 var params = _.extend({}, mailing, {
173 'api.mailing_job.create': 0 // note: exact match to API default
174 });
175 return crmApi('Mailing', 'create', params).then(function(result){
176 if (result.id && !mailing.id) mailing.id = result.id; // no rollback, so update mailing.id
177 return result.values[result.id];
178 });
179 },
180
181 // Schedule/send the mailing
182 // @param mailing Object (per APIv3)
183 // @return Promise
184 submit: function(mailing) {
185 throw 'Not implemented: crmMailingMgr.submit';
186 // var params = _.extend({}, mailing, {
187 // 'api.mailing_job.create': 1 // note: exact match to API default
188 // });
189 // return crmApi('Mailing', 'create', params).then(function(result){
190 // if (result.id && !mailing.id) mailing.id = result.id; // no rollback, so update mailing.id
191 // return result.values[result.id];
192 // });
193 },
194
195 // Immediately send a test message
196 // @param mailing Object (per APIv3)
197 // @param testEmail string
198 // @param testGroup int (id#)
199 // @return Promise for a list of delivery reports
200 sendTest: function(mailing, testEmail, testGroup) {
201 var params = _.extend({}, mailing, {
202 // options: {force_rollback: 1},
203 'api.Mailing.send_test': {
204 mailing_id: '$value.id',
205 test_email: testEmail,
206 test_group: testGroup
207 }
208 });
209 return crmApi('Mailing', 'create', params).then(function(result){
210 if (result.id && !mailing.id) mailing.id = result.id; // no rollback, so update mailing.id
211 return result.values[result.id]['api.Mailing.send_test'].values;
212 });
213 }
214 };
215 });
216
217 })(angular, CRM.$, CRM._);