EmailNotification::runStep()   B
last analyzed

Complexity

Conditions 7
Paths 15

Size

Total Lines 49

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 49
ccs 27
cts 27
cp 1
rs 8.1793
c 0
b 0
f 0
cc 7
nc 15
nop 2
crap 7
1
<?php
2
/**
3
 * @author Joas Schilling <[email protected]>
4
 * @author Morris Jobke <[email protected]>
5
 *
6
 * @copyright Copyright (c) 2016, ownCloud, Inc.
7
 * @license AGPL-3.0
8
 *
9
 * This code is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License, version 3,
11
 * as published by the Free Software Foundation.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License, version 3,
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
20
 *
21
 */
22
23
namespace OCA\Activity\BackgroundJob;
24
25
use OC\BackgroundJob\TimedJob;
26
use OCA\Activity\AppInfo\Application;
27
use OCA\Activity\MailQueueHandler;
28
use OCP\IConfig;
29
use OCP\ILogger;
30
31
/**
32
 * Class EmailNotification
33
 *
34
 * @package OCA\Activity\BackgroundJob
35
 */
36
class EmailNotification extends TimedJob {
37
	const CLI_EMAIL_BATCH_SIZE = 500;
38
	const WEB_EMAIL_BATCH_SIZE = 25;
39
40
	/** @var MailQueueHandler */
41
	protected $mqHandler;
42
43
	/** @var IConfig */
44
	protected $config;
45
46
	/** @var ILogger */
47
	protected $logger;
48
49
	/** @var bool */
50
	protected $isCLI;
51
52
	/**
53
	 * @param MailQueueHandler $mailQueueHandler
54
	 * @param IConfig $config
55
	 * @param ILogger $logger
56
	 * @param bool|null $isCLI
57
	 */
58 5
	public function __construct(MailQueueHandler $mailQueueHandler = null,
59
								IConfig $config = null,
60
								ILogger $logger = null,
61
								$isCLI = null) {
62
		// Run all 15 Minutes
63 5
		$this->setInterval(15 * 60);
64
65 5
		if ($mailQueueHandler === null || $config === null || $logger === null || $isCLI === null) {
66 1
			$this->fixDIForJobs();
67
		} else {
68 4
			$this->mqHandler = $mailQueueHandler;
69 4
			$this->config = $config;
70 4
			$this->logger = $logger;
71 4
			$this->isCLI = $isCLI;
72
		}
73 5
	}
74
75 1
	protected function fixDIForJobs() {
76 1
		$application = new Application();
77
78 1
		$this->mqHandler = $application->getContainer()->query('MailQueueHandler');
79 1
		$this->config = \OC::$server->getConfig();
80 1
		$this->logger = \OC::$server->getLogger();
81 1
		$this->isCLI = \OC::$CLI;
82 1
	}
83
84 3
	protected function run($argument) {
85
		// We don't use time() but "time() - 1" here, so we don't run into
86
		// runtime issues later and delete emails, which were created in the
87
		// same second, but were not collected for the emails.
88 3
		$sendTime = \time() - 1;
89
90 3
		if ($this->isCLI) {
91
			do {
92
				// If we are in CLI mode, we keep sending emails
93
				// until we are done.
94 2
				$emails_sent = $this->runStep(self::CLI_EMAIL_BATCH_SIZE, $sendTime);
95 2
			} while ($emails_sent === self::CLI_EMAIL_BATCH_SIZE);
96
		} else {
97
			// Only send 25 Emails in one go for web cron
98 1
			$this->runStep(self::WEB_EMAIL_BATCH_SIZE, $sendTime);
99
		}
100 3
	}
101
102
	/**
103
	 * Send an email to {$limit} users
104
	 *
105
	 * @param int $limit Number of users we want to send an email to
106
	 * @param int $sendTime The latest send time
107
	 * @return int Number of users we sent an email to
108
	 * @throws \Exception
109
	 */
110 5
	protected function runStep($limit, $sendTime) {
111
		// Get all users which should receive an email
112 5
		$affectedUsers = $this->mqHandler->getAffectedUsers($limit, $sendTime);
113 5
		if (empty($affectedUsers)) {
114
			// No users found to notify, mission abort
115 3
			return 0;
116
		}
117 2
		$affectedUIDs = \array_map(function ($u) {
118 2
			return $u['uid'];
119 2
		}, $affectedUsers);
120
121 2
		$userLanguages = $this->config->getUserValueForUsers('core', 'lang', $affectedUIDs);
122 2
		$userTimezones = $this->config->getUserValueForUsers('core', 'timezone', $affectedUIDs);
123
124
		// Send Email
125 2
		$default_lang = $this->config->getSystemValue('default_language', 'en');
126 2
		$defaultTimeZone = \date_default_timezone_get();
127
128 2
		$sentMailForUsers = [];
129
130 2
		foreach ($affectedUsers as $user) {
131 2
			$uid = $user['uid'];
132 2
			if (empty($user['email'])) {
133
				// The user did not setup an email address
134
				// So we will not send an email but still discard the queue entries
135 1
				$this->logger->debug("Couldn't send notification email to user '$uid' (email address isn't set for that user)", ['app' => 'activity']);
136 1
				$sentMailForUsers[] = $uid;
137 1
				continue;
138
			}
139
140 2
			$language = (!empty($userLanguages[$uid])) ? $userLanguages[$uid] : $default_lang;
141 2
			$timezone = (!empty($userTimezones[$uid])) ? $userTimezones[$uid] : $defaultTimeZone;
142
143
			try {
144 2
				$this->mqHandler->sendEmailToUser($uid, $user['email'], $language, $timezone, $sendTime);
145 1
				$sentMailForUsers[] = $uid;
146 1
			} catch (\Exception $e) {
147
				// Run cleanup before we die
148 1
				$this->mqHandler->deleteSentItems($sentMailForUsers, $sendTime);
149
				// Throw the exception again - which gets logged by core and the job is handled appropriately
150 2
				throw $e;
151
			}
152
		}
153
154
		// Delete all entries we dealt with
155 1
		$this->mqHandler->deleteSentItems($sentMailForUsers, $sendTime);
156
157 1
		return \sizeof($affectedUsers);
158
	}
159
}
160