Commit | Line | Data |
---|---|---|
95a718e1 JP |
1 | <?php |
2 | ||
3 | /** | |
4 | * Include dataProvider for tests | |
5 | * @group headless | |
6 | */ | |
7 | class CRM_Activity_Form_ActivityTest extends CiviUnitTestCase { | |
8 | ||
9 | public function setUp() { | |
10 | parent::setUp(); | |
9099cab3 | 11 | $this->assignee1 = $this->individualCreate([ |
95a718e1 JP |
12 | 'first_name' => 'testassignee1', |
13 | 'last_name' => 'testassignee1', | |
14 | 'email' => 'testassignee1@gmail.com', | |
9099cab3 CW |
15 | ]); |
16 | $this->assignee2 = $this->individualCreate([ | |
95a718e1 JP |
17 | 'first_name' => 'testassignee2', |
18 | 'last_name' => 'testassignee2', | |
19 | 'email' => 'testassignee2@gmail.com', | |
9099cab3 | 20 | ]); |
95a718e1 JP |
21 | $this->target = $this->individualCreate(); |
22 | $this->source = $this->individualCreate(); | |
23 | } | |
24 | ||
25 | public function testActivityCreate() { | |
26 | Civi::settings()->set('activity_assignee_notification', TRUE); | |
27 | //Reset filter to none. | |
9099cab3 | 28 | Civi::settings()->set('do_not_notify_assignees_for', []); |
95a718e1 JP |
29 | $mut = new CiviMailUtils($this, TRUE); |
30 | $mut->clearMessages(); | |
31 | ||
32 | $form = new CRM_Activity_Form_Activity(); | |
33 | $activityTypeId = CRM_Core_PseudoConstant::getKey('CRM_Activity_DAO_Activity', 'activity_type_id', 'Meeting'); | |
9099cab3 | 34 | $params = [ |
95a718e1 | 35 | 'source_contact_id' => $this->source, |
9099cab3 CW |
36 | 'assignee_contact_id' => [$this->assignee1], |
37 | 'target_contact_id' => [$this->target], | |
38 | 'followup_assignee_contact_id' => [], | |
95a718e1 | 39 | 'activity_type_id' => $activityTypeId, |
9099cab3 | 40 | ]; |
95a718e1 JP |
41 | |
42 | $activityRef = new ReflectionClass('CRM_Activity_Form_Activity'); | |
43 | $method = $activityRef->getMethod('processActivity'); | |
44 | $method->setAccessible(TRUE); | |
9099cab3 | 45 | $method->invokeArgs($form, [&$params]); |
95a718e1 JP |
46 | |
47 | $msg = $mut->getMostRecentEmail(); | |
48 | $this->assertNotEmpty($msg); | |
49 | $mut->clearMessages(); | |
50 | ||
51 | //Block Meeting notification. | |
9099cab3 CW |
52 | Civi::settings()->set('do_not_notify_assignees_for', [$activityTypeId]); |
53 | $params['assignee_contact_id'] = [$this->assignee2]; | |
54 | $method->invokeArgs($form, [&$params]); | |
95a718e1 JP |
55 | $msg = $mut->getMostRecentEmail(); |
56 | $this->assertEmpty($msg); | |
57 | } | |
58 | ||
70ea7358 KJ |
59 | public function testActivityDelete() { |
60 | // Set the parameters of the test. | |
61 | $numberOfSingleActivitiesToCreate = 3; | |
62 | $numberOfRepeatingActivitiesToCreate = 6; | |
63 | $singleActivityToDeleteOffset = 1; | |
64 | $mode1ActivityToDeleteOffset = 1; | |
65 | $mode2ActivityToDeleteOffset = 3; | |
66 | $mode3ActivityToDeleteOffset = 2; | |
67 | ||
68 | // Track the target contact's activities. | |
69 | $expectedActivityIds = array_keys(CRM_Activity_BAO_Activity::getActivities(['contact_id' => $this->target])); | |
70 | ||
71 | // Create non-repeating activities. | |
72 | $meetingActivityTypeId = CRM_Core_PseudoConstant::getKey('CRM_Activity_DAO_Activity', 'activity_type_id', 'Meeting'); | |
73 | $singleActivityIds = []; | |
74 | for ($activityCount = 0; $activityCount < $numberOfSingleActivitiesToCreate; $activityCount++) { | |
75 | $activityParams = [ | |
76 | 'source_contact_id' => $this->source, | |
77 | 'target_contact_id' => $this->target, | |
78 | 'activity_type_id' => $meetingActivityTypeId, | |
79 | 'activity_date_time' => date_create('+' . $activityCount . ' weeks')->format('YmdHis'), | |
80 | ]; | |
81 | $singleActivityBao = CRM_Activity_BAO_Activity::create($activityParams); | |
82 | $singleActivityIds[] = $singleActivityBao->id; | |
83 | } | |
84 | $expectedActivityIds = array_merge($expectedActivityIds, $singleActivityIds); | |
85 | ||
86 | // Create an activity to be repeated. | |
87 | $activityParams = [ | |
88 | 'source_contact_id' => $this->source, | |
89 | 'target_contact_id' => $this->target, | |
90 | 'activity_type_id' => $meetingActivityTypeId, | |
91 | 'activity_date_time' => date('YmdHis'), | |
92 | ]; | |
93 | $repeatingActivityBao = CRM_Activity_BAO_Activity::create($activityParams); | |
94 | ||
95 | // Create the repeating activity's schedule. | |
96 | $actionScheduleParams = [ | |
97 | 'used_for' => 'civicrm_activity', | |
98 | 'entity_value' => $repeatingActivityBao->id, | |
99 | 'start_action_date' => $repeatingActivityBao->activity_date_time, | |
100 | 'repetition_frequency_unit' => 'week', | |
101 | 'repetition_frequency_interval' => 1, | |
102 | 'start_action_offset' => $numberOfRepeatingActivitiesToCreate - 1, | |
103 | ]; | |
104 | $actionScheduleBao = CRM_Core_BAO_ActionSchedule::add($actionScheduleParams); | |
105 | ||
106 | // Create the activity's repeats. | |
107 | $recurringEntityBao = new CRM_Core_BAO_RecurringEntity(); | |
108 | $recurringEntityBao->entity_table = 'civicrm_activity'; | |
109 | $recurringEntityBao->entity_id = $repeatingActivityBao->id; | |
110 | $recurringEntityBao->dateColumns = ['activity_date_time']; | |
111 | $recurringEntityBao->linkedEntities = [ | |
112 | [ | |
113 | 'table' => 'civicrm_activity_contact', | |
114 | 'findCriteria' => ['activity_id' => $repeatingActivityBao->id], | |
115 | 'linkedColumns' => ['activity_id'], | |
116 | 'isRecurringEntityRecord' => FALSE, | |
117 | ], | |
118 | ]; | |
119 | $recurringEntityBao->scheduleId = $actionScheduleBao->id; | |
120 | $newEntities = $recurringEntityBao->generate(); | |
121 | $repeatingActivityIds = array_merge([$repeatingActivityBao->id], $newEntities['civicrm_activity']); | |
122 | $expectedActivityIds = array_merge($expectedActivityIds, $repeatingActivityIds); | |
123 | ||
124 | // Assert that the expected activities exist. | |
125 | $this->assertTargetActivityIds($expectedActivityIds); | |
126 | ||
127 | // Delete a non-repeating activity. | |
128 | $activityId = $singleActivityIds[$singleActivityToDeleteOffset]; | |
129 | $this->deleteActivity($activityId); | |
130 | $expectedActivityIds = array_diff($expectedActivityIds, [$activityId]); | |
131 | $this->assertTargetActivityIds($expectedActivityIds); | |
132 | ||
133 | // Delete one activity from series (mode 1). | |
134 | $activityId = $repeatingActivityIds[$mode1ActivityToDeleteOffset]; | |
135 | $this->deleteActivity($activityId, 1); | |
136 | $expectedActivityIds = array_diff($expectedActivityIds, [$activityId]); | |
137 | $this->assertTargetActivityIds($expectedActivityIds); | |
138 | ||
139 | // Delete from one activity until end of series (mode 2). | |
140 | $activityId = $repeatingActivityIds[$mode2ActivityToDeleteOffset]; | |
141 | $this->deleteActivity($activityId, 2); | |
142 | $expectedActivityIds = array_diff($expectedActivityIds, array_slice($repeatingActivityIds, $mode2ActivityToDeleteOffset)); | |
143 | $this->assertTargetActivityIds($expectedActivityIds); | |
144 | ||
145 | // Delete all activities in series (mode 3). | |
146 | $activityId = $repeatingActivityIds[$mode3ActivityToDeleteOffset]; | |
147 | $this->deleteActivity($activityId, 3); | |
148 | $expectedActivityIds = array_diff($expectedActivityIds, $repeatingActivityIds); | |
149 | $this->assertTargetActivityIds($expectedActivityIds); | |
150 | } | |
151 | ||
152 | /** | |
153 | * Asserts that the target contact has the expected activity IDs | |
154 | * | |
155 | * @param array $expectedActivityIds | |
156 | * An array of the activity IDs that are expected to exist for the target contact | |
157 | */ | |
158 | private function assertTargetActivityIds($expectedActivityIds) { | |
159 | $actualActivityIds = array_keys(CRM_Activity_BAO_Activity::getActivities(['contact_id' => $this->target])); | |
160 | $this->assertEquals(array_fill_keys($expectedActivityIds, NULL), array_fill_keys($actualActivityIds, NULL)); | |
161 | } | |
162 | ||
163 | /** | |
164 | * Tests the form's deletion of activities, with optional mode for repeating activities | |
165 | * | |
166 | * @param int $activityId | |
167 | * The ID of the activity to delete | |
168 | * @param int $mode | |
169 | * 1 - delete the specified activity | |
170 | * 2 - delete the specified activity and all following activities in the series | |
171 | * 3 - delete all activities in the series | |
172 | */ | |
173 | private function deleteActivity($activityId, $mode = NULL) { | |
174 | // For repeating activities, set the recurring entity mode. | |
175 | if (!is_null($mode)) { | |
176 | $recurringEntityBao = new CRM_Core_BAO_RecurringEntity(); | |
177 | $recurringEntityBao->entity_table = 'civicrm_activity'; | |
178 | $recurringEntityBao->entity_id = $activityId; | |
179 | $recurringEntityBao->mode($mode); | |
180 | } | |
181 | ||
182 | // Use a form to delete the activity. | |
183 | $form = new CRM_Activity_Form_Activity(); | |
184 | $form->_action = CRM_Core_Action::DELETE; | |
185 | $form->_activityId = $activityId; | |
186 | $form->postProcess(); | |
187 | } | |
188 | ||
c6bbfc3a D |
189 | /** |
190 | * This is a bit messed up having a variable called name that means label but we don't want to fix it because it's a form member variable _activityTypeName that might be used in form hooks, so just make sure it doesn't flip between name and label. dev/core#1116 | |
191 | */ | |
192 | public function testActivityTypeNameIsReallyLabel() { | |
193 | $form = new CRM_Activity_Form_Activity(); | |
194 | ||
195 | // the actual value is irrelevant we just need something for the tested function to act on | |
196 | $form->_currentlyViewedContactId = $this->source; | |
197 | ||
198 | // Let's make a new activity type that has a different name from its label just to be sure. | |
199 | $actParams = [ | |
200 | 'option_group_id' => 'activity_type', | |
201 | 'name' => 'wp1234', | |
202 | 'label' => 'Water Plants', | |
203 | 'is_active' => 1, | |
204 | 'is_default' => 0, | |
205 | ]; | |
206 | $result = $this->callAPISuccess('option_value', 'create', $actParams); | |
207 | ||
208 | $form->_activityTypeId = $result['values'][$result['id']]['value']; | |
209 | $this->assertNotEmpty($form->_activityTypeId); | |
210 | ||
211 | // Do the thing we want to test | |
212 | $form->assignActivityType(); | |
213 | ||
214 | $this->assertEquals('Water Plants', $form->_activityTypeName); | |
11a60382 D |
215 | |
216 | // cleanup | |
217 | $this->callAPISuccess('option_value', 'delete', ['id' => $result['id']]); | |
218 | } | |
219 | ||
220 | /** | |
221 | * Test that the machineName and displayLabel are assigned correctly to the | |
222 | * smarty template. | |
223 | * | |
224 | * See also testActivityTypeNameIsReallyLabel() | |
225 | */ | |
226 | public function testActivityTypeAssignment() { | |
227 | $form = new CRM_Activity_Form_Activity(); | |
228 | ||
229 | $form->_currentlyViewedContactId = $this->source; | |
230 | ||
231 | // Let's make a new activity type that has a different name from its label just to be sure. | |
232 | $actParams = [ | |
233 | 'option_group_id' => 'activity_type', | |
234 | 'name' => '47395hc', | |
235 | 'label' => 'Hide Cookies', | |
236 | 'is_active' => 1, | |
237 | 'is_default' => 0, | |
238 | ]; | |
239 | $result = $this->callAPISuccess('option_value', 'create', $actParams); | |
240 | ||
241 | $form->_activityTypeId = $result['values'][$result['id']]['value']; | |
242 | ||
243 | // Do the thing we want to test | |
244 | $form->assignActivityType(); | |
245 | ||
246 | // Check the smarty template has the correct values assigned. | |
f692bf33 | 247 | $keyValuePair = $form->getTemplate()->get_template_vars('activityTypeNameAndLabel'); |
11a60382 D |
248 | $this->assertEquals('47395hc', $keyValuePair['machineName']); |
249 | $this->assertEquals('Hide Cookies', $keyValuePair['displayLabel']); | |
250 | ||
251 | // cleanup | |
252 | $this->callAPISuccess('option_value', 'delete', ['id' => $result['id']]); | |
c6bbfc3a D |
253 | } |
254 | ||
b819b81a | 255 | /** |
256 | * Test that inbound email is still treated properly if you change the label. | |
257 | * I'm not crazy about the strategy used in this test but I can't see another | |
258 | * way to do it. | |
259 | */ | |
260 | public function testInboundEmailDisplaysWithLinebreaks() { | |
261 | // Change label | |
262 | $inbound_email = $this->callAPISuccess('OptionValue', 'getsingle', [ | |
263 | 'option_group_id' => 'activity_type', | |
264 | 'name' => 'Inbound Email', | |
265 | ]); | |
266 | $this->callAPISuccess('OptionValue', 'create', [ | |
267 | 'id' => $inbound_email['id'], | |
268 | 'label' => 'Probably Spam', | |
269 | ]); | |
270 | ||
271 | // Fake an inbound email and store it | |
272 | ||
273 | $messageBody = <<<ENDBODY | |
274 | -ALTERNATIVE ITEM 0- | |
275 | Hi, | |
276 | ||
277 | Wassup!?!? | |
278 | ||
279 | Let's check if the output when viewing the form has legible line breaks in the output. | |
280 | ||
281 | Thanks! | |
282 | ||
283 | -ALTERNATIVE ITEM 1- | |
284 | ||
285 | <div dir="ltr">Hi,<br></div> | |
286 | <div dir="ltr"><br></div> | |
287 | <div dir="ltr">Wassup!?!?<br></div> | |
288 | <div dir="ltr"><br></div> | |
289 | <div dir="ltr">Let's check if the output when viewing the form has legible line breaks in the output.<br></div> | |
290 | <div dir="ltr"><br></div> | |
291 | <div dir="ltr">Thanks!<br></div> | |
292 | -ALTERNATIVE END- | |
293 | ENDBODY; | |
294 | ||
295 | $activity = $this->activityCreate([ | |
296 | 'subject' => 'Important message read immediately!', | |
297 | 'duration' => NULL, | |
298 | 'location' => NULL, | |
299 | 'details' => $messageBody, | |
300 | 'status_id' => 'Completed', | |
301 | 'activity_type_id' => 'Inbound Email', | |
302 | 'source_contact_id' => $this->source, | |
303 | 'assignee_contact_id' => NULL, | |
304 | ]); | |
305 | $activity_id = $activity['id']; | |
306 | ||
307 | // Simulate viewing it from the form. | |
308 | ||
309 | $form = new CRM_Activity_Form_Activity(); | |
310 | $form->controller = new CRM_Core_Controller_Simple('CRM_Activity_Form_Activity', 'Activity'); | |
311 | $form->set('context', 'standalone'); | |
312 | $form->set('cid', $this->source); | |
313 | $form->set('action', 'view'); | |
314 | $form->set('id', $activity_id); | |
315 | $form->set('atype', $activity['values'][$activity_id]['activity_type_id']); | |
316 | ||
317 | $form->buildForm(); | |
318 | ||
319 | // Wish there was another way to do this | |
320 | $form->controller->handle($form, 'display'); | |
321 | ||
322 | // This isn't a faithful representation of the output since there'll | |
323 | // probably be a lot missing, but for now I don't see a simpler way to | |
324 | // do this. | |
325 | // Also this is printing the template code to the console. It doesn't hurt | |
326 | // the test but it's clutter and I don't know where it's coming from | |
327 | // and can't seem to prevent it. | |
328 | $output = $form->getTemplate()->fetch($form->getTemplateFileName()); | |
329 | ||
330 | // This kind of suffers from the same problem as the old webtests. It's | |
331 | // a bit brittle and tied to the UI. | |
332 | $this->assertContains("Hi,<br />\n<br />\nWassup!?!?<br />\n<br />\nLet's check if the output when viewing the form has legible line breaks in the output.<br />\n<br />\nThanks!", $output); | |
333 | ||
334 | // Put label back | |
335 | $this->callAPISuccess('OptionValue', 'create', [ | |
336 | 'id' => $inbound_email['id'], | |
337 | 'label' => $inbound_email['label'], | |
338 | ]); | |
339 | } | |
340 | ||
95a718e1 | 341 | } |