Commit | Line | Data |
---|---|---|
8dfd5110 TO |
1 | (function (angular, $, _) { |
2 | var partialUrl = function (relPath) { | |
3 | return CRM.resourceUrls['civicrm'] + '/partials/crmMailing2/' + relPath; | |
4 | }; | |
5 | ||
43102e47 TO |
6 | // FIXME: surely there's already some helper which can do this in one line? |
7 | // @return string "YYYY-MM-DD hh:mm:ss" | |
8 | var createNow = function () { | |
9 | var currentdate = new Date(); | |
10 | var yyyy = currentdate.getFullYear(); | |
11 | var mm = currentdate.getMonth() + 1; | |
12 | mm = mm < 10 ? '0' + mm : mm; | |
13 | var dd = currentdate.getDate(); | |
14 | dd = dd < 10 ? '0' + dd : dd; | |
15 | var hh = currentdate.getHours(); | |
16 | hh = hh < 10 ? '0' + hh : hh; | |
17 | var min = currentdate.getMinutes(); | |
18 | min = min < 10 ? '0' + min : min; | |
19 | var sec = currentdate.getSeconds(); | |
20 | sec = sec < 10 ? '0' + sec : sec; | |
21 | return yyyy + "-" + mm + "-" + dd + " " + hh + ":" + min + ":" + sec; | |
22 | }; | |
23 | ||
24 | // FIXME: Load status ids from DB | |
25 | var APPROVAL_STATUSES = { Approved: "1", Rejected: "2", None: "3" }; | |
26 | ||
8dfd5110 TO |
27 | var crmMailing2 = angular.module('crmMailing2'); |
28 | ||
a0214785 TO |
29 | // The representation of from/reply-to addresses is inconsistent in the mailing data-model, |
30 | // so the UI must do some adaptation. The crmFromAddresses provides a richer way to slice/dice | |
31 | // the available "From:" addrs. Records are like the underlying OptionValues -- but add "email" | |
32 | // and "author". | |
33 | crmMailing2.factory('crmFromAddresses', function($q, crmApi) { | |
34 | var emailRegex = /^"(.*)" \<([^@\>]*@[^@\>]*)\>$/; | |
35 | var addrs = _.map(CRM.crmMailing.fromAddress, function(addr){ | |
36 | var match = emailRegex.exec(addr.label); | |
37 | return _.extend({}, addr, { | |
38 | email: match ? match[2] : '(INVALID)', | |
39 | author: match ? match[1] : '(INVALID)' | |
40 | }); | |
41 | }); | |
42 | function first(array) { | |
43 | return (array.length == 0) ? null : array[0]; | |
52f515c6 | 44 | } |
a0214785 TO |
45 | |
46 | return { | |
47 | getAll: function getAll() { | |
48 | return addrs; | |
49 | }, | |
50 | getByAuthorEmail: function getByAuthorEmail(author, email, autocreate) { | |
51 | var result = null; | |
52 | _.each(addrs, function(addr){ | |
53 | if (addr.author == author && addr.email == email) { | |
54 | result = addr; | |
55 | } | |
56 | }); | |
57 | if (!result && autocreate) { | |
58 | result = { | |
59 | label: '(INVALID) "' + author + '" <' + email + '>', | |
60 | author: author, | |
61 | email: email | |
62 | }; | |
63 | addrs.push(result); | |
64 | } | |
65 | return result; | |
66 | }, | |
67 | getByEmail: function getByEmail(email) { | |
68 | return first(_.where(addrs, {email: email})); | |
69 | }, | |
70 | getByLabel: function(label) { | |
71 | return first(_.where(addrs, {label: label})); | |
72 | }, | |
73 | getDefault: function getDefault() { | |
74 | return first(_.where(addrs, {is_default: "1"})); | |
75 | } | |
76 | }; | |
77 | }); | |
78 | ||
744bebee TO |
79 | crmMailing2.factory('crmMsgTemplates', function($q, crmApi) { |
80 | var tpls = _.map(CRM.crmMailing.mesTemplate, function(tpl){ | |
81 | return _.extend({}, tpl, { | |
82 | //id: tpl parseInt(tpl.id) | |
83 | }); | |
84 | }); | |
85 | window.tpls = tpls; | |
86 | var lastModifiedTpl = null; | |
87 | return { | |
88 | // @return Promise MessageTemplate (per APIv3) | |
89 | get: function get(id) { | |
90 | id = ''+id; // parseInt(id); | |
91 | var dfr = $q.defer(); | |
92 | var tpl = _.where(tpls, {id: id}); | |
93 | if (id && tpl && tpl[0]) { | |
94 | dfr.resolve(tpl[0]); | |
95 | } else { | |
96 | dfr.reject(id); | |
97 | } | |
98 | return dfr.promise; | |
99 | }, | |
100 | // Save a template | |
101 | // @param tpl MessageTemplate (per APIv3) For new templates, omit "id" | |
102 | // @return Promise MessageTemplate (per APIv3) | |
103 | save: function(tpl) { | |
104 | return crmApi('MessageTemplate', 'create', tpl).then(function(response){ | |
105 | if (!tpl.id) { | |
106 | tpl.id = ''+response.id; //parseInt(response.id); | |
107 | tpls.push(tpl); | |
108 | } | |
109 | lastModifiedTpl = tpl | |
110 | return tpl; | |
111 | }); | |
112 | }, | |
113 | // @return Object MessageTemplate (per APIv3) | |
114 | getLastModifiedTpl: function() { | |
115 | return lastModifiedTpl; | |
116 | }, | |
117 | getAll: function getAll() { | |
118 | return tpls; | |
119 | } | |
120 | }; | |
121 | }); | |
122 | ||
a0214785 TO |
123 | // The crmMailingMgr service provides business logic for loading, saving, previewing, etc |
124 | crmMailing2.factory('crmMailingMgr', function($q, crmApi, crmFromAddresses) { | |
4dd19229 | 125 | var pickDefaultMailComponent = function pickDefaultMailComponent(type) { |
8dfd5110 TO |
126 | var mcs = _.where(CRM.crmMailing.headerfooterList, { |
127 | component_type:type, | |
128 | is_default: "1" | |
129 | }); | |
130 | return (mcs.length >= 1) ? mcs[0].id : null; | |
131 | }; | |
132 | ||
133 | return { | |
134 | // @param scalar idExpr a number or the literal string 'new' | |
135 | // @return Promise|Object Mailing (per APIv3) | |
4dd19229 | 136 | getOrCreate: function getOrCreate(idExpr) { |
8dfd5110 TO |
137 | return (idExpr == 'new') ? this.create() : this.get(idExpr); |
138 | }, | |
139 | // @return Promise Mailing (per APIv3) | |
4dd19229 | 140 | get: function get(id) { |
8dfd5110 TO |
141 | return crmApi('Mailing', 'getsingle', {id: id}).then(function(mailing){ |
142 | return crmApi('MailingGroup', 'get', {mailing_id: id}).then(function(groupResult){ | |
143 | mailing.groups = {include: [], exclude: []}; | |
144 | mailing.mailings = {include: [], exclude: []}; | |
145 | _.each(groupResult.values, function(mailingGroup) { | |
146 | var bucket = (mailingGroup.entity_table == 'civicrm_group') ? 'groups' : 'mailings'; | |
89a50c67 TO |
147 | var entityId = parseInt(mailingGroup.entity_id); |
148 | mailing[bucket][mailingGroup.group_type].push(entityId); | |
8dfd5110 TO |
149 | }); |
150 | return mailing; | |
151 | }); | |
152 | }); | |
153 | }, | |
154 | // @return Object Mailing (per APIv3) | |
4dd19229 | 155 | create: function create() { |
8dfd5110 TO |
156 | return { |
157 | name: "revert this", // fixme | |
158 | campaign_id: null, | |
a0214785 TO |
159 | from_name: crmFromAddresses.getDefault().author, |
160 | from_email: crmFromAddresses.getDefault().email, | |
8dfd5110 TO |
161 | replyto_email: "", |
162 | subject: "For {contact.display_name}", // fixme | |
163 | dedupe_email: "1", | |
164 | groups: {include: [2], exclude: [4]}, // fixme | |
165 | mailings: {include: [], exclude: []}, | |
166 | body_html: "<b>Hello</b> {contact.display_name}", // fixme | |
167 | body_text: "Hello {contact.display_name}", // fixme | |
168 | footer_id: null, // pickDefaultMailComponent('Footer'), | |
169 | header_id: null, // pickDefaultMailComponent('Header'), | |
170 | visibility: "Public Pages", | |
171 | url_tracking: "1", | |
172 | dedupe_email: "1", | |
173 | forward_replies: "0", | |
174 | auto_responder: "0", | |
175 | open_tracking: "1", | |
176 | override_verp: "1", | |
177 | optout_id: pickDefaultMailComponent('OptOut'), | |
178 | reply_id: pickDefaultMailComponent('Reply'), | |
179 | resubscribe_id: pickDefaultMailComponent('Resubscribe'), | |
180 | unsubscribe_id: pickDefaultMailComponent('Unsubscribe') | |
181 | }; | |
182 | }, | |
183 | ||
705c61e9 TO |
184 | // @param mailing Object (per APIv3) |
185 | // @return Promise | |
186 | 'delete': function(mailing) { | |
187 | if (mailing.id) { | |
188 | return crmApi('Mailing', 'delete', {id: mailing.id}); | |
189 | } else { | |
190 | var d = $q.defer(); | |
191 | d.resolve(); | |
192 | return d.promise; | |
193 | } | |
194 | }, | |
195 | ||
493eb47a TO |
196 | // @param mailing Object (per APIv3) |
197 | // @return Promise an object with "subject", "body_text", "body_html" | |
198 | preview: function preview(mailing) { | |
199 | var params = _.extend({}, mailing, { | |
200 | options: {force_rollback: 1}, | |
201 | 'api.Mailing.preview': { | |
52f515c6 | 202 | id: '$value.id' |
493eb47a TO |
203 | } |
204 | }); | |
205 | return crmApi('Mailing', 'create', params).then(function(result){ | |
beab9d1b | 206 | // changes rolled back, so we don't care about updating mailing |
493eb47a TO |
207 | return result.values[result.id]['api.Mailing.preview'].values; |
208 | }); | |
209 | }, | |
210 | ||
8dfd5110 TO |
211 | // @param mailing Object (per APIv3) |
212 | // @param int previewLimit | |
213 | // @return Promise for a list of recipients (mailing_id, contact_id, api.contact.getvalue, api.email.getvalue) | |
4dd19229 | 214 | previewRecipients: function previewRecipients(mailing, previewLimit) { |
8dfd5110 TO |
215 | // To get list of recipients, we tentatively save the mailing and |
216 | // get the resulting recipients -- then rollback any changes. | |
217 | var params = _.extend({}, mailing, { | |
218 | options: {force_rollback: 1}, | |
7575b840 | 219 | 'api.mailing_job.create': 1, // note: exact match to API default |
8dfd5110 TO |
220 | 'api.MailingRecipients.get': { |
221 | mailing_id: '$value.id', | |
222 | options: { limit: previewLimit }, | |
223 | 'api.contact.getvalue': {'return': 'display_name'}, | |
224 | 'api.email.getvalue': {'return': 'email'} | |
225 | } | |
226 | }); | |
227 | return crmApi('Mailing', 'create', params).then(function(recipResult){ | |
beab9d1b | 228 | // changes rolled back, so we don't care about updating mailing |
8dfd5110 TO |
229 | return recipResult.values[recipResult.id]['api.MailingRecipients.get'].values; |
230 | }); | |
beab9d1b TO |
231 | }, |
232 | ||
43102e47 | 233 | // Save a (draft) mailing |
705c61e9 TO |
234 | // @param mailing Object (per APIv3) |
235 | // @return Promise | |
236 | save: function(mailing) { | |
7575b840 TO |
237 | var params = _.extend({}, mailing, { |
238 | 'api.mailing_job.create': 0 // note: exact match to API default | |
239 | }); | |
43102e47 TO |
240 | |
241 | // WORKAROUND: Mailing.create (aka CRM_Mailing_BAO_Mailing::create()) interprets scheduled_date | |
242 | // as an *intent* to schedule and creates tertiary records. Saving a draft with a scheduled_date | |
243 | // is therefore not allowed. Remove this after fixing Mailing.create's contract. | |
244 | delete params.scheduled_date; | |
245 | ||
705c61e9 TO |
246 | return crmApi('Mailing', 'create', params).then(function(result){ |
247 | if (result.id && !mailing.id) mailing.id = result.id; // no rollback, so update mailing.id | |
43102e47 | 248 | // Perhaps we should reload mailing based on result? |
705c61e9 TO |
249 | return result.values[result.id]; |
250 | }); | |
251 | }, | |
252 | ||
253 | // Schedule/send the mailing | |
254 | // @param mailing Object (per APIv3) | |
255 | // @return Promise | |
43102e47 TO |
256 | submit: function (mailing) { |
257 | var changes = { | |
258 | approval_date: createNow(), | |
259 | approver_id: CRM.crmMailing.contactid, | |
260 | approval_status_id: APPROVAL_STATUSES.Approved, | |
261 | scheduled_date: mailing.scheduled_date ? mailing.scheduled_date : createNow(), | |
262 | scheduled_id: CRM.crmMailing.contactid | |
263 | }; | |
264 | var params = _.extend({}, mailing, changes, { | |
265 | 'api.mailing_job.create': 0 // note: exact match to API default | |
266 | }); | |
267 | return crmApi('Mailing', 'create', params).then(function (result) { | |
268 | if (result.id && !mailing.id) mailing.id = result.id; // no rollback, so update mailing.id | |
269 | _.extend(mailing, changes); // Perhaps we should reload mailing based on result? | |
270 | return result.values[result.id]; | |
271 | }); | |
705c61e9 TO |
272 | }, |
273 | ||
274 | // Immediately send a test message | |
beab9d1b TO |
275 | // @param mailing Object (per APIv3) |
276 | // @param testEmail string | |
277 | // @param testGroup int (id#) | |
278 | // @return Promise for a list of delivery reports | |
279 | sendTest: function(mailing, testEmail, testGroup) { | |
280 | var params = _.extend({}, mailing, { | |
43102e47 | 281 | // options: {force_rollback: 1}, // Test mailings include tracking features, so the mailing must be persistent |
beab9d1b TO |
282 | 'api.Mailing.send_test': { |
283 | mailing_id: '$value.id', | |
284 | test_email: testEmail, | |
285 | test_group: testGroup | |
286 | } | |
287 | }); | |
43102e47 TO |
288 | |
289 | // WORKAROUND: Mailing.create (aka CRM_Mailing_BAO_Mailing::create()) interprets scheduled_date | |
290 | // as an *intent* to schedule and creates tertiary records. Saving a draft with a scheduled_date | |
291 | // is therefore not allowed. Remove this after fixing Mailing.create's contract. | |
292 | delete params.scheduled_date; | |
293 | ||
beab9d1b TO |
294 | return crmApi('Mailing', 'create', params).then(function(result){ |
295 | if (result.id && !mailing.id) mailing.id = result.id; // no rollback, so update mailing.id | |
296 | return result.values[result.id]['api.Mailing.send_test'].values; | |
297 | }); | |
8dfd5110 TO |
298 | } |
299 | }; | |
300 | }); | |
8dfd5110 | 301 | })(angular, CRM.$, CRM._); |