EmailProviderTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2019, Thomas Citharel
  5. * @copyright Copyright (c) 2019, Georg Ehrke
  6. *
  7. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  8. * @author Georg Ehrke <oc.list@georgehrke.com>
  9. * @author Joas Schilling <coding@schilljs.com>
  10. * @author Richard Steinmetz <richard@steinmetz.cloud>
  11. * @author Roeland Jago Douma <roeland@famdouma.nl>
  12. * @author Thomas Citharel <nextcloud@tcit.fr>
  13. *
  14. * @license GNU AGPL version 3 or any later version
  15. *
  16. * This program is free software: you can redistribute it and/or modify
  17. * it under the terms of the GNU Affero General Public License as
  18. * published by the Free Software Foundation, either version 3 of the
  19. * License, or (at your option) any later version.
  20. *
  21. * This program is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU Affero General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU Affero General Public License
  27. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  28. *
  29. */
  30. namespace OCA\DAV\Tests\unit\CalDAV\Reminder\NotificationProvider;
  31. use OCA\DAV\CalDAV\Reminder\NotificationProvider\EmailProvider;
  32. use OCP\IConfig;
  33. use OCP\IL10N;
  34. use OCP\IURLGenerator;
  35. use OCP\IUser;
  36. use OCP\L10N\IFactory as L10NFactory;
  37. use OCP\Mail\IEMailTemplate;
  38. use OCP\Mail\IMailer;
  39. use OCP\Mail\IMessage;
  40. use PHPUnit\Framework\MockObject\MockObject;
  41. use Sabre\VObject\Component\VCalendar;
  42. class EmailProviderTest extends AbstractNotificationProviderTest {
  43. public const USER_EMAIL = 'frodo@hobb.it';
  44. /** @var IMailer|MockObject */
  45. private $mailer;
  46. protected function setUp(): void {
  47. parent::setUp();
  48. $this->mailer = $this->createMock(IMailer::class);
  49. $this->provider = new EmailProvider(
  50. $this->config,
  51. $this->mailer,
  52. $this->logger,
  53. $this->l10nFactory,
  54. $this->urlGenerator
  55. );
  56. }
  57. public function testSendWithoutAttendees():void {
  58. [$user1, $user2, $user3, , $user5] = $users = $this->getUsers();
  59. $principalEmailAddresses = [$user1->getEmailAddress()];
  60. $enL10N = $this->createMock(IL10N::class);
  61. $enL10N->method('t')
  62. ->willReturnArgument(0);
  63. $enL10N->method('l')
  64. ->willReturnArgument(0);
  65. $deL10N = $this->createMock(IL10N::class);
  66. $deL10N->method('t')
  67. ->willReturnArgument(0);
  68. $deL10N->method('l')
  69. ->willReturnArgument(0);
  70. $this->l10nFactory
  71. ->method('getUserLanguage')
  72. ->willReturnMap([
  73. [$user1, 'en'],
  74. [$user2, 'de'],
  75. [$user3, 'de'],
  76. [$user5, 'de'],
  77. ]);
  78. $this->l10nFactory
  79. ->method('findGenericLanguage')
  80. ->willReturn('en');
  81. $this->l10nFactory
  82. ->method('languageExists')
  83. ->willReturnMap([
  84. ['dav', 'en', true],
  85. ['dav', 'de', true],
  86. ]);
  87. $this->l10nFactory
  88. ->method('get')
  89. ->willReturnMap([
  90. ['dav', 'en', null, $enL10N],
  91. ['dav', 'de', null, $deL10N],
  92. ]);
  93. $template1 = $this->getTemplateMock();
  94. $message11 = $this->getMessageMock('uid1@example.com', $template1);
  95. $template2 = $this->getTemplateMock();
  96. $message21 = $this->getMessageMock('uid2@example.com', $template2);
  97. $message22 = $this->getMessageMock('uid3@example.com', $template2);
  98. $this->mailer->expects($this->at(0))
  99. ->method('createEMailTemplate')
  100. ->with('dav.calendarReminder')
  101. ->willReturn($template1);
  102. $this->mailer->expects($this->at(1))
  103. ->method('validateMailAddress')
  104. ->with('uid1@example.com')
  105. ->willReturn(true);
  106. $this->mailer->expects($this->at(2))
  107. ->method('createMessage')
  108. ->with()
  109. ->willReturn($message11);
  110. $this->mailer->expects($this->at(3))
  111. ->method('send')
  112. ->with($message11)
  113. ->willReturn([]);
  114. $this->mailer->expects($this->at(4))
  115. ->method('createEMailTemplate')
  116. ->with('dav.calendarReminder')
  117. ->willReturn($template2);
  118. $this->mailer->expects($this->at(5))
  119. ->method('validateMailAddress')
  120. ->with('uid2@example.com')
  121. ->willReturn(true);
  122. $this->mailer->expects($this->at(6))
  123. ->method('createMessage')
  124. ->with()
  125. ->willReturn($message21);
  126. $this->mailer->expects($this->at(7))
  127. ->method('send')
  128. ->with($message21)
  129. ->willReturn([]);
  130. $this->mailer->expects($this->at(8))
  131. ->method('validateMailAddress')
  132. ->with('uid3@example.com')
  133. ->willReturn(true);
  134. $this->mailer->expects($this->at(9))
  135. ->method('createMessage')
  136. ->with()
  137. ->willReturn($message22);
  138. $this->mailer->expects($this->at(10))
  139. ->method('send')
  140. ->with($message22)
  141. ->willReturn([]);
  142. $this->mailer->expects($this->at(11))
  143. ->method('validateMailAddress')
  144. ->with('invalid')
  145. ->willReturn(false);
  146. $this->setupURLGeneratorMock(2);
  147. $vcalendar = $this->getNoAttendeeVCalendar();
  148. $this->provider->send($vcalendar->VEVENT, $this->calendarDisplayName, $principalEmailAddresses, $users);
  149. }
  150. public function testSendWithAttendeesWhenOwnerIsOrganizer(): void {
  151. [$user1, $user2, $user3, , $user5] = $users = $this->getUsers();
  152. $principalEmailAddresses = [$user1->getEmailAddress()];
  153. $enL10N = $this->createMock(IL10N::class);
  154. $enL10N->method('t')
  155. ->willReturnArgument(0);
  156. $enL10N->method('l')
  157. ->willReturnArgument(0);
  158. $deL10N = $this->createMock(IL10N::class);
  159. $deL10N->method('t')
  160. ->willReturnArgument(0);
  161. $deL10N->method('l')
  162. ->willReturnArgument(0);
  163. $this->l10nFactory
  164. ->method('getUserLanguage')
  165. ->willReturnMap([
  166. [$user1, 'en'],
  167. [$user2, 'de'],
  168. [$user3, 'de'],
  169. [$user5, 'de'],
  170. ]);
  171. $this->l10nFactory
  172. ->method('findGenericLanguage')
  173. ->willReturn('en');
  174. $this->l10nFactory
  175. ->method('languageExists')
  176. ->willReturnMap([
  177. ['dav', 'en', true],
  178. ['dav', 'de', true],
  179. ]);
  180. $this->l10nFactory
  181. ->method('get')
  182. ->willReturnMap([
  183. ['dav', 'en', null, $enL10N],
  184. ['dav', 'de', null, $deL10N],
  185. ]);
  186. $template1 = $this->getTemplateMock();
  187. $message11 = $this->getMessageMock('foo1@example.org', $template1);
  188. $message12 = $this->getMessageMock('uid2@example.com', $template1);
  189. $message13 = $this->getMessageMock('uid3@example.com', $template1);
  190. $template2 = $this->getTemplateMock();
  191. $message21 = $this->getMessageMock('foo3@example.org', $template2);
  192. $message22 = $this->getMessageMock('foo4@example.org', $template2);
  193. $message23 = $this->getMessageMock('uid1@example.com', $template2);
  194. $this->mailer->expects(self::exactly(2))
  195. ->method('createEMailTemplate')
  196. ->with('dav.calendarReminder')
  197. ->willReturnOnConsecutiveCalls(
  198. $template1,
  199. $template2,
  200. );
  201. $this->mailer->expects($this->atLeastOnce())
  202. ->method('validateMailAddress')
  203. ->willReturnMap([
  204. ['foo1@example.org', true],
  205. ['foo3@example.org', true],
  206. ['foo4@example.org', true],
  207. ['uid1@example.com', true],
  208. ['uid2@example.com', true],
  209. ['uid3@example.com', true],
  210. ['invalid', false],
  211. ]);
  212. $this->mailer->expects($this->exactly(6))
  213. ->method('createMessage')
  214. ->with()
  215. ->willReturnOnConsecutiveCalls(
  216. $message11,
  217. $message12,
  218. $message13,
  219. $message21,
  220. $message22,
  221. $message23,
  222. );
  223. $this->mailer->expects($this->exactly(6))
  224. ->method('send')
  225. ->withConsecutive(
  226. [$message11],
  227. [$message12],
  228. [$message13],
  229. [$message21],
  230. [$message22],
  231. [$message23],
  232. )->willReturn([]);
  233. $this->setupURLGeneratorMock(2);
  234. $vcalendar = $this->getAttendeeVCalendar();
  235. $this->provider->send($vcalendar->VEVENT, $this->calendarDisplayName, $principalEmailAddresses, $users);
  236. }
  237. public function testSendWithAttendeesWhenOwnerIsAttendee(): void {
  238. [$user1, $user2, $user3] = $this->getUsers();
  239. $users = [$user2, $user3];
  240. $principalEmailAddresses = [$user2->getEmailAddress()];
  241. $deL10N = $this->createMock(IL10N::class);
  242. $deL10N->method('t')
  243. ->willReturnArgument(0);
  244. $deL10N->method('l')
  245. ->willReturnArgument(0);
  246. $this->l10nFactory
  247. ->method('getUserLanguage')
  248. ->willReturnMap([
  249. [$user2, 'de'],
  250. [$user3, 'de'],
  251. ]);
  252. $this->l10nFactory
  253. ->method('findGenericLanguage')
  254. ->willReturn('en');
  255. $this->l10nFactory
  256. ->method('languageExists')
  257. ->willReturnMap([
  258. ['dav', 'de', true],
  259. ]);
  260. $this->l10nFactory
  261. ->method('get')
  262. ->willReturnMap([
  263. ['dav', 'de', null, $deL10N],
  264. ]);
  265. $template1 = $this->getTemplateMock();
  266. $message12 = $this->getMessageMock('uid2@example.com', $template1);
  267. $message13 = $this->getMessageMock('uid3@example.com', $template1);
  268. $this->mailer->expects(self::once())
  269. ->method('createEMailTemplate')
  270. ->with('dav.calendarReminder')
  271. ->willReturnOnConsecutiveCalls(
  272. $template1,
  273. );
  274. $this->mailer->expects($this->atLeastOnce())
  275. ->method('validateMailAddress')
  276. ->willReturnMap([
  277. ['foo1@example.org', true],
  278. ['foo3@example.org', true],
  279. ['foo4@example.org', true],
  280. ['uid1@example.com', true],
  281. ['uid2@example.com', true],
  282. ['uid3@example.com', true],
  283. ['invalid', false],
  284. ]);
  285. $this->mailer->expects($this->exactly(2))
  286. ->method('createMessage')
  287. ->with()
  288. ->willReturnOnConsecutiveCalls(
  289. $message12,
  290. $message13,
  291. );
  292. $this->mailer->expects($this->exactly(2))
  293. ->method('send')
  294. ->withConsecutive(
  295. [$message12],
  296. [$message13],
  297. )->willReturn([]);
  298. $this->setupURLGeneratorMock(1);
  299. $vcalendar = $this->getAttendeeVCalendar();
  300. $this->provider->send($vcalendar->VEVENT, $this->calendarDisplayName, $principalEmailAddresses, $users);
  301. }
  302. /**
  303. * @return IEMailTemplate
  304. */
  305. private function getTemplateMock():IEMailTemplate {
  306. $template = $this->createMock(IEMailTemplate::class);
  307. $template->expects($this->at(0))
  308. ->method('addHeader')
  309. ->with()
  310. ->willReturn($template);
  311. $template->expects($this->at(1))
  312. ->method('setSubject')
  313. ->with()
  314. ->willReturn($template);
  315. $template->expects($this->at(2))
  316. ->method('addHeading')
  317. ->with()
  318. ->willReturn($template);
  319. $template->expects($this->at(3))
  320. ->method('addBodyListItem')
  321. ->with()
  322. ->willReturn($template);
  323. $template->expects($this->at(4))
  324. ->method('addBodyListItem')
  325. ->with()
  326. ->willReturn($template);
  327. $template->expects($this->at(5))
  328. ->method('addBodyListItem')
  329. ->with()
  330. ->willReturn($template);
  331. $template->expects($this->at(6))
  332. ->method('addBodyListItem')
  333. ->with()
  334. ->willReturn($template);
  335. $template->expects($this->at(7))
  336. ->method('addFooter')
  337. ->with()
  338. ->willReturn($template);
  339. return $template;
  340. }
  341. /**
  342. * @param string $toMail
  343. * @param IEMailTemplate $templateMock
  344. * @param array|null $replyTo
  345. * @return IMessage
  346. */
  347. private function getMessageMock(string $toMail, IEMailTemplate $templateMock, array $replyTo = null):IMessage {
  348. $message = $this->createMock(IMessage::class);
  349. $i = 0;
  350. $message->expects($this->at($i++))
  351. ->method('setFrom')
  352. ->with([\OCP\Util::getDefaultEmailAddress('reminders-noreply')])
  353. ->willReturn($message);
  354. if ($replyTo) {
  355. $message->expects($this->at($i++))
  356. ->method('setReplyTo')
  357. ->with($replyTo)
  358. ->willReturn($message);
  359. }
  360. $message->expects($this->at($i++))
  361. ->method('setTo')
  362. ->with([$toMail])
  363. ->willReturn($message);
  364. $message->expects($this->at($i++))
  365. ->method('useTemplate')
  366. ->with($templateMock)
  367. ->willReturn($message);
  368. return $message;
  369. }
  370. private function getNoAttendeeVCalendar():VCalendar {
  371. $vcalendar = new VCalendar();
  372. $vcalendar->add('VEVENT', [
  373. 'SUMMARY' => 'Fellowship meeting',
  374. 'DTSTART' => new \DateTime('2017-01-01 00:00:00+00:00'), // 1483228800,
  375. 'UID' => 'uid1234',
  376. 'LOCATION' => 'Location 123',
  377. 'DESCRIPTION' => 'DESCRIPTION 456',
  378. ]);
  379. return $vcalendar;
  380. }
  381. private function getAttendeeVCalendar():VCalendar {
  382. $vcalendar = new VCalendar();
  383. $vcalendar->add('VEVENT', [
  384. 'SUMMARY' => 'Fellowship meeting',
  385. 'DTSTART' => new \DateTime('2017-01-01 00:00:00+00:00'), // 1483228800,
  386. 'UID' => 'uid1234',
  387. 'LOCATION' => 'Location 123',
  388. 'DESCRIPTION' => 'DESCRIPTION 456',
  389. ]);
  390. $vcalendar->VEVENT->add(
  391. 'ORGANIZER',
  392. 'mailto:uid1@example.com',
  393. [
  394. 'LANG' => 'en'
  395. ]
  396. );
  397. $vcalendar->VEVENT->add(
  398. 'ATTENDEE',
  399. 'mailto:foo1@example.org',
  400. [
  401. 'LANG' => 'de',
  402. 'PARTSTAT' => 'NEEDS-ACTION',
  403. ]
  404. );
  405. $vcalendar->VEVENT->add(
  406. 'ATTENDEE',
  407. 'mailto:foo2@example.org',
  408. [
  409. 'LANG' => 'de',
  410. 'PARTSTAT' => 'DECLINED',
  411. ]
  412. );
  413. $vcalendar->VEVENT->add(
  414. 'ATTENDEE',
  415. 'mailto:foo3@example.org',
  416. [
  417. 'LANG' => 'en',
  418. 'PARTSTAT' => 'CONFIRMED',
  419. ]
  420. );
  421. $vcalendar->VEVENT->add(
  422. 'ATTENDEE',
  423. 'mailto:foo4@example.org'
  424. );
  425. $vcalendar->VEVENT->add(
  426. 'ATTENDEE',
  427. 'tomail:foo5@example.org'
  428. );
  429. return $vcalendar;
  430. }
  431. private function setupURLGeneratorMock(int $times = 1):void {
  432. for ($i = 0; $i < $times; $i++) {
  433. $this->urlGenerator
  434. ->expects($this->at(8 * $i))
  435. ->method('imagePath')
  436. ->with('core', 'actions/info.png')
  437. ->willReturn('imagePath1');
  438. $this->urlGenerator
  439. ->expects($this->at(8 * $i + 1))
  440. ->method('getAbsoluteURL')
  441. ->with('imagePath1')
  442. ->willReturn('AbsURL1');
  443. $this->urlGenerator
  444. ->expects($this->at(8 * $i + 2))
  445. ->method('imagePath')
  446. ->with('core', 'places/calendar.png')
  447. ->willReturn('imagePath2');
  448. $this->urlGenerator
  449. ->expects($this->at(8 * $i + 3))
  450. ->method('getAbsoluteURL')
  451. ->with('imagePath2')
  452. ->willReturn('AbsURL2');
  453. $this->urlGenerator
  454. ->expects($this->at(8 * $i + 4))
  455. ->method('imagePath')
  456. ->with('core', 'actions/address.png')
  457. ->willReturn('imagePath3');
  458. $this->urlGenerator
  459. ->expects($this->at(8 * $i + 5))
  460. ->method('getAbsoluteURL')
  461. ->with('imagePath3')
  462. ->willReturn('AbsURL3');
  463. $this->urlGenerator
  464. ->expects($this->at(8 * $i + 6))
  465. ->method('imagePath')
  466. ->with('core', 'actions/more.png')
  467. ->willReturn('imagePath4');
  468. $this->urlGenerator
  469. ->expects($this->at(8 * $i + 7))
  470. ->method('getAbsoluteURL')
  471. ->with('imagePath4')
  472. ->willReturn('AbsURL4');
  473. }
  474. }
  475. private function getUsers(): array {
  476. $user1 = $this->createMock(IUser::class);
  477. $user1->method('getUID')
  478. ->willReturn('uid1');
  479. $user1->method('getEMailAddress')
  480. ->willReturn('uid1@example.com');
  481. $user2 = $this->createMock(IUser::class);
  482. $user2->method('getUID')
  483. ->willReturn('uid2');
  484. $user2->method('getEMailAddress')
  485. ->willReturn('uid2@example.com');
  486. $user3 = $this->createMock(IUser::class);
  487. $user3->method('getUID')
  488. ->willReturn('uid3');
  489. $user3->method('getEMailAddress')
  490. ->willReturn('uid3@example.com');
  491. $user4 = $this->createMock(IUser::class);
  492. $user4->method('getUID')
  493. ->willReturn('uid4');
  494. $user4->method('getEMailAddress')
  495. ->willReturn(null);
  496. $user5 = $this->createMock(IUser::class);
  497. $user5->method('getUID')
  498. ->willReturn('uid5');
  499. $user5->method('getEMailAddress')
  500. ->willReturn('invalid');
  501. return [$user1, $user2, $user3, $user4, $user5];
  502. }
  503. }