Completed
Pull Request — master (#1523)
by
unknown
21:43
created

AccountsController   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 364
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 13

Test Coverage

Coverage 66.67%

Importance

Changes 6
Bugs 2 Features 1
Metric Value
wmc 36
c 6
b 2
f 1
lcom 1
cbo 13
dl 0
loc 364
ccs 114
cts 171
cp 0.6667
rs 8.8

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 23 1
A index() 0 12 3
A show() 0 9 2
A update() 0 5 1
A destroy() 0 9 2
B create() 0 60 4
F send() 0 86 17
B draft() 0 43 6
1
<?php
2
3
/**
4
 * @author Christoph Wurst <[email protected]>
5
 * @author Christoph Wurst <[email protected]>
6
 * @author Jan-Christoph Borchardt <[email protected]>
7
 * @author Lukas Reschke <[email protected]>
8
 * @author Robin McCorkell <[email protected]>
9
 * @author Thomas Müller <[email protected]>
10
 *
11
 * ownCloud - Mail
12
 *
13
 * This code is free software: you can redistribute it and/or modify
14
 * it under the terms of the GNU Affero General Public License, version 3,
15
 * as published by the Free Software Foundation.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License, version 3,
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
24
 *
25
 */
26
27
namespace OCA\Mail\Controller;
28
29
use Exception;
30
use Horde_Exception;
31
use Horde_Imap_Client;
32
use OCA\Mail\Account;
33
use OCA\Mail\Db\MailAccount;
34
use OCA\Mail\Model\Message;
35
use OCA\Mail\Model\ReplyMessage;
36
use OCA\Mail\Service\AccountService;
37
use OCA\Mail\Service\AutoCompletion\AddressCollector;
38
use OCA\Mail\Service\AutoConfig\AutoConfig;
39
use OCA\Mail\Service\Logger;
40
use OCA\Mail\Service\UnifiedAccount;
41
use OCP\AppFramework\Controller;
42
use OCP\AppFramework\Db\DoesNotExistException;
43
use OCP\AppFramework\Http;
44
use OCP\AppFramework\Http\JSONResponse;
45
use OCP\AppFramework\Http\Response;
46
use OCP\Files\File;
47
use OCP\Files\Folder;
48
use OCP\IL10N;
49
use OCP\IRequest;
50
use OCP\Security\ICrypto;
51
use OCA\Mail\Service\AliasesService;
52
53
class AccountsController extends Controller {
54
55
	/** @var AccountService */
56
	private $accountService;
57
58
	/** @var string */
59
	private $currentUserId;
60
61
	/** @var AutoConfig */
62
	private $autoConfig;
63
64
	/** @var Folder */
65
	private $userFolder;
66
67
	/** @var Logger */
68
	private $logger;
69
70
	/** @var IL10N */
71
	private $l10n;
72
73
	/** @var ICrypto */
74
	private $crypto;
75
76
	/** @var AddressCollector  */
77
	private $addressCollector;
78
79
	/** @var AliasesService  */
80
	private $aliasesService;
81
82
	/**
83
	 * @param string $appName
84
	 * @param IRequest $request
85
	 * @param AccountService $accountService
86
	 * @param $UserId
87
	 * @param $userFolder
88
	 * @param AutoConfig $autoConfig
89
	 * @param Logger $logger
90
	 * @param IL10N $l10n
91
	 * @param ICrypto $crypto
92
	 */
93 15
	public function __construct($appName,
94
		IRequest $request,
95
		AccountService $accountService,
96
		$UserId,
97
		$userFolder,
98
		AutoConfig $autoConfig,
99
		Logger $logger,
100
		IL10N $l10n,
101
		ICrypto $crypto,
102
		AddressCollector $addressCollector,
103
		AliasesService $aliasesService
104
	) {
105 15
		parent::__construct($appName, $request);
106 15
		$this->accountService = $accountService;
107 15
		$this->currentUserId = $UserId;
108 15
		$this->userFolder = $userFolder;
109 15
		$this->autoConfig = $autoConfig;
110 15
		$this->logger = $logger;
111 15
		$this->l10n = $l10n;
112 15
		$this->crypto = $crypto;
113 15
		$this->addressCollector = $addressCollector;
114 15
		$this->aliasesService = $aliasesService;
115 15
	}
116
117
	/**
118
	 * @NoAdminRequired
119
	 * @NoCSRFRequired
120
	 *
121
	 * @return JSONResponse
122
	 */
123 1
	public function index() {
124 1
		$mailAccounts = $this->accountService->findByUserId($this->currentUserId);
125
126 1
		$json = [];
127 1
		foreach ($mailAccounts as $mailAccount) {
128 1
			$json[] = $mailAccount->getConfiguration();
129 1
		}
130 1
		foreach ($json as $key => $mailAccount) {
131 1
			$json[$key]['aliases'] = $this->aliasesService->findAll($mailAccount['accountId'], $this->currentUserId);
132
		}
133
		return new JSONResponse($json);
134
	}
135
136
	/**
137
	 * @NoAdminRequired
138
	 *
139
	 * @param int $accountId
140
	 * @return JSONResponse
141
	 */
142 2
	public function show($accountId) {
143
		try {
144 2
			$account = $this->accountService->find($this->currentUserId, $accountId);
145
146 2
			return new JSONResponse($account->getConfiguration());
147 1
		} catch (DoesNotExistException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\AppFramework\Db\DoesNotExistException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
148 1
			return new JSONResponse([], 404);
149
		}
150
	}
151
152
	/**
153
	 * @NoAdminRequired
154
	 */
155
	public function update() {
156
		$response = new Response();
157
		$response->setStatus(Http::STATUS_NOT_IMPLEMENTED);
158
		return $response;
159
	}
160
161
	/**
162
	 * @NoAdminRequired
163
	 *
164
	 * @param int $accountId
165
	 * @return JSONResponse
166
	 */
167 2
	public function destroy($accountId) {
168
		try {
169 2
			$this->accountService->delete($this->currentUserId, $accountId);
170
171 1
			return new JSONResponse();
172 1
		} catch (DoesNotExistException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\AppFramework\Db\DoesNotExistException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
173 1
			return new JSONResponse();
174
		}
175
	}
176
177
	/**
178
	 * @NoAdminRequired
179
	 *
180
	 * @param string $accountName
181
	 * @param string $emailAddress
182
	 * @param string $password
183
	 * @param string $imapHost
184
	 * @param int $imapPort
185
	 * @param string $imapSslMode
186
	 * @param string $imapUser
187
	 * @param string $imapPassword
188
	 * @param string $smtpHost
189
	 * @param int $smtpPort
190
	 * @param string $smtpSslMode
191
	 * @param string $smtpUser
192
	 * @param string $smtpPassword
193
	 * @param bool $autoDetect
194
	 * @return JSONResponse
195
	 */
196 2
	public function create($accountName, $emailAddress, $password,
197
		$imapHost, $imapPort, $imapSslMode, $imapUser, $imapPassword,
198
		$smtpHost, $smtpPort, $smtpSslMode, $smtpUser, $smtpPassword,
199
		$autoDetect) {
200
		try {
201 2
			if ($autoDetect) {
202 2
				$this->logger->info('setting up auto detected account');
203 2
				$newAccount = $this->autoConfig->createAutoDetected($emailAddress, $password, $accountName);
204 2
			} else {
205
				$this->logger->info('Setting up manually configured account');
206
				$newAccount = new MailAccount([
207
					'accountName'  => $accountName,
208
					'emailAddress' => $emailAddress,
209
					'imapHost'     => $imapHost,
210
					'imapPort'     => $imapPort,
211
					'imapSslMode'  => $imapSslMode,
212
					'imapUser'     => $imapUser,
213
					'imapPassword' => $imapPassword,
214
					'smtpHost'     => $smtpHost,
215
					'smtpPort'     => $smtpPort,
216
					'smtpSslMode'  => $smtpSslMode,
217
					'smtpUser'     => $smtpUser,
218
					'smtpPassword' => $smtpPassword
219
				]);
220
				$newAccount->setUserId($this->currentUserId);
221
				$newAccount->setInboundPassword(
222
					$this->crypto->encrypt(
223
						$newAccount->getInboundPassword()
224
					)
225
				);
226
				$newAccount->setOutboundPassword(
227
					$this->crypto->encrypt(
228
						$newAccount->getOutboundPassword()
229
					)
230
				);
231
232
				$a = new Account($newAccount);
233
				$this->logger->debug('Connecting to account {account}', ['account' => $newAccount->getEmail()]);
234
				$a->testConnectivity();
235
			}
236
237 2
			if ($newAccount) {
238 1
				$this->accountService->save($newAccount);
239 1
				$this->logger->debug("account created " . $newAccount->getId());
240 1
				return new JSONResponse(
241 1
					['data' => ['id' => $newAccount->getId()]],
242 1
					Http::STATUS_CREATED);
243
			}
244 1
		} catch (Exception $ex) {
245
			$this->logger->error('Creating account failed: ' . $ex->getMessage());
246
			return new JSONResponse(
247
				array('message' => $this->l10n->t('Creating account failed: ') . $ex->getMessage()),
248
				HTTP::STATUS_BAD_REQUEST);
249
		}
250
251 1
		$this->logger->info('Auto detect failed');
252 1
		return new JSONResponse(
253 1
			array('message' => $this->l10n->t('Auto detect failed. Please use manual mode.')),
254 1
			HTTP::STATUS_BAD_REQUEST);
255
	}
256
257
	/**
258
	 * @NoAdminRequired
259
	 *
260
	 * @param int $accountId
261
	 * @param string $folderId
262
	 * @param string $subject
263
	 * @param string $body
264
	 * @param string $to
265
	 * @param string $cc
266
	 * @param string $bcc
267
	 * @param int $draftUID
268
	 * @param string $messageId
269
	 * @param mixed $attachments
270
	 * @return JSONResponse
271
	 */
272 4
	public function send($accountId, $folderId, $subject, $body, $to, $cc,
273
		$bcc, $draftUID, $messageId, $attachments, $aliasId) {
274 4
		$account = $this->accountService->find($this->currentUserId, $accountId);
275 4
		$alias = $aliasId ? $this->aliasesService->find($aliasId, $this->currentUserId) : null;
276 4
		if ($account instanceof UnifiedAccount) {
277 2
			list($account, $folderId, $messageId) = $account->resolve($messageId);
278 2
		}
279 4
		if (!$account instanceof Account) {
280
			return new JSONResponse(
281
				['message' => 'Invalid account'],
282
				Http::STATUS_BAD_REQUEST
283
			);
284
		}
285
286 4
		$mailbox = null;
287 4
		if (!is_null($folderId) && !is_null($messageId)) {
288
			// Reply
289 2
			$message = $account->newReplyMessage();
290
291 2
			$mailbox = $account->getMailbox(base64_decode($folderId));
292 2
			$repliedMessage = $mailbox->getMessage($messageId);
293
294 2
			if (is_null($subject)) {
295
				// No subject set – use the original one
296
				$message->setSubject($repliedMessage->getSubject());
297
			} else {
298 2
				$message->setSubject($subject);
299
			}
300
301 2
			if (is_null($to)) {
302
				$message->setTo(Message::parseAddressList($repliedMessage->getToList()));
0 ignored issues
show
Documentation introduced by
$repliedMessage->getToList() is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
303
			} else {
304 2
				$message->setTo(Message::parseAddressList($to));
305
			}
306
307 2
			$message->setRepliedMessage($repliedMessage);
308 2
		} else {
309
			// New message
310 2
			$message = $account->newMessage();
311 2
			$message->setTo(Message::parseAddressList($to));
312 2
			$message->setSubject($subject ? : '');
313
		}
314
315 4
		$account->setAlias($alias);
0 ignored issues
show
Documentation introduced by
$alias is of type array<integer,object<OCA\Mail\Db\Alias>>|null, but the function expects a object<OCA\Mail\Db\Alias>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
316 4
		$message->setFrom($alias ? $alias->alias : $account->getEMailAddress());
317 4
		$message->setCC(Message::parseAddressList($cc));
318 4
		$message->setBcc(Message::parseAddressList($bcc));
319 4
		$message->setContent($body);
320
321 4
		if (is_array($attachments)) {
322 4
			foreach($attachments as $attachment) {
323 4
				$fileName = $attachment['fileName'];
324 4
				if ($this->userFolder->nodeExists($fileName)) {
325 4
					$f = $this->userFolder->get($fileName);
326 4
					if ($f instanceof File) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\File does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
327 4
						$message->addAttachmentFromFiles($f);
328 4
					}
329 4
				}
330 4
			}
331 4
		}
332
333
		try {
334 4
			$account->sendMessage($message, $draftUID);
335
336
			// in case of reply we flag the message as answered
337 4
			if ($message instanceof ReplyMessage) {
338 2
				$mailbox->setMessageFlag($messageId, Horde_Imap_Client::FLAG_ANSWERED, true);
339 2
			}
340
341
			// Collect mail addresses
342
			try {
343 4
				$addresses = array_merge($message->getToList(), $message->getCCList(), $message->getBCCList());
344 4
				$this->addressCollector->addAddresses($addresses);
345 4
			} catch (Exception $e) {
346 1
				$this->logger->error("Error while collecting mail addresses: " . $e->getMessage());
347
			}
348 4
		} catch (Horde_Exception $ex) {
0 ignored issues
show
Bug introduced by
The class Horde_Exception does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
349
			$this->logger->error('Sending mail failed: ' . $ex->getMessage());
350
			return new JSONResponse(
351
				array('message' => $ex->getMessage()),
352
				Http::STATUS_INTERNAL_SERVER_ERROR
353
			);
354
		}
355
356 4
		return new JSONResponse();
357
	}
358
359
	/**
360
	 * @NoAdminRequired
361
	 * 
362
	 * @param int $accountId
363
	 * @param string $subject
364
	 * @param string $body
365
	 * @param string $to
366
	 * @param string $cc
367
	 * @param string $bcc
368
	 * @param int $uid
369
	 * @param string $messageId
370
	 * @return JSONResponse
371
	 */
372 4
	public function draft($accountId, $subject, $body, $to, $cc, $bcc, $uid, $messageId) {
373 4
		if (is_null($uid)) {
374 2
			$this->logger->info("Saving a new draft in account <$accountId>");
375 2
		} else {
376 2
			$this->logger->info("Updating draft <$uid> in account <$accountId>");
377
		}
378
379 4
		$account = $this->accountService->find($this->currentUserId, $accountId);
380 4
		if ($account instanceof UnifiedAccount) {
381 2
			list($account) = $account->resolve($messageId);
382 2
		}
383 4
		if (!$account instanceof Account) {
384
			return new JSONResponse(
385
				array('message' => 'Invalid account'),
386
				Http::STATUS_BAD_REQUEST
387
			);
388
		}
389
390 4
		$message = $account->newMessage();
391 4
		$message->setTo(Message::parseAddressList($to));
392 4
		$message->setSubject($subject ? : '');
393 4
		$message->setFrom($account->getEMailAddress());
394 4
		$message->setCC(Message::parseAddressList($cc));
395 4
		$message->setBcc(Message::parseAddressList($bcc));
396 4
		$message->setContent($body);
397
398
		// create transport and save message
399
		try {
400 4
			$newUID = $account->saveDraft($message, $uid);
401 4
		} catch (Horde_Exception $ex) {
0 ignored issues
show
Bug introduced by
The class Horde_Exception does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
402
			$this->logger->error('Saving draft failed: ' . $ex->getMessage());
403
			return new JSONResponse(
404
				[
405
					'message' => $ex->getMessage()
406
				],
407
				Http::STATUS_INTERNAL_SERVER_ERROR
408
			);
409
		}
410
411 4
		return new JSONResponse([
412
			'uid' => $newUID
413 4
		]);
414
	}
415
416
}
417