AccountsController::send()   F
last analyzed

Complexity

Conditions 17
Paths 644

Size

Total Lines 86
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 47
CRAP Score 18.9728

Importance

Changes 0
Metric Value
dl 0
loc 86
ccs 47
cts 58
cp 0.8103
rs 2.3769
c 0
b 0
f 0
cc 17
eloc 55
nc 644
nop 11
crap 18.9728

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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
 * 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 View Code Duplication
	public function __construct($appName,
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
		foreach ($mailAccounts as $mailAccount) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
128 1
			$conf = $mailAccount->getConfiguration();
129 1
			$conf['aliases'] = $this->aliasesService->findAll($conf['accountId'], $this->currentUserId);
130 1
			$json[] = $conf;
131 1
		}
132 1
		return new JSONResponse($json);
133
	}
134
135
	/**
136
	 * @NoAdminRequired
137
	 *
138
	 * @param int $accountId
139
	 * @return JSONResponse
140
	 */
141 2
	public function show($accountId) {
142
		try {
143 2
			$account = $this->accountService->find($this->currentUserId, $accountId);
144
145 2
			return new JSONResponse($account->getConfiguration());
146 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...
147 1
			return new JSONResponse([], 404);
148
		}
149
	}
150
151
	/**
152
	 * @NoAdminRequired
153
	 */
154
	public function update() {
155
		$response = new Response();
156
		$response->setStatus(Http::STATUS_NOT_IMPLEMENTED);
157
		return $response;
158
	}
159
160
	/**
161
	 * @NoAdminRequired
162
	 *
163
	 * @param int $accountId
164
	 * @return JSONResponse
165
	 */
166 2
	public function destroy($accountId) {
167
		try {
168 2
			$this->accountService->delete($this->currentUserId, $accountId);
169
170 1
			return new JSONResponse();
171 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...
172 1
			return new JSONResponse();
173
		}
174
	}
175
176
	/**
177
	 * @NoAdminRequired
178
	 *
179
	 * @param string $accountName
180
	 * @param string $emailAddress
181
	 * @param string $password
182
	 * @param string $imapHost
183
	 * @param int $imapPort
184
	 * @param string $imapSslMode
185
	 * @param string $imapUser
186
	 * @param string $imapPassword
187
	 * @param string $smtpHost
188
	 * @param int $smtpPort
189
	 * @param string $smtpSslMode
190
	 * @param string $smtpUser
191
	 * @param string $smtpPassword
192
	 * @param bool $autoDetect
193
	 * @return JSONResponse
194
	 */
195 2
	public function create($accountName, $emailAddress, $password,
196
		$imapHost, $imapPort, $imapSslMode, $imapUser, $imapPassword,
197
		$smtpHost, $smtpPort, $smtpSslMode, $smtpUser, $smtpPassword,
198
		$autoDetect) {
199
		try {
200 2
			if ($autoDetect) {
201 2
				$this->logger->info('setting up auto detected account');
202 2
				$newAccount = $this->autoConfig->createAutoDetected($emailAddress, $password, $accountName);
203 2
			} else {
204
				$this->logger->info('Setting up manually configured account');
205
				$newAccount = new MailAccount([
206
					'accountName'  => $accountName,
207
					'emailAddress' => $emailAddress,
208
					'imapHost'     => $imapHost,
209
					'imapPort'     => $imapPort,
210
					'imapSslMode'  => $imapSslMode,
211
					'imapUser'     => $imapUser,
212
					'imapPassword' => $imapPassword,
213
					'smtpHost'     => $smtpHost,
214
					'smtpPort'     => $smtpPort,
215
					'smtpSslMode'  => $smtpSslMode,
216
					'smtpUser'     => $smtpUser,
217
					'smtpPassword' => $smtpPassword
218
				]);
219
				$newAccount->setUserId($this->currentUserId);
220
				$newAccount->setInboundPassword(
221
					$this->crypto->encrypt(
222
						$newAccount->getInboundPassword()
223
					)
224
				);
225
				$newAccount->setOutboundPassword(
226
					$this->crypto->encrypt(
227
						$newAccount->getOutboundPassword()
228
					)
229
				);
230
231
				$a = new Account($newAccount);
232
				$this->logger->debug('Connecting to account {account}', ['account' => $newAccount->getEmail()]);
233
				$a->testConnectivity();
234
			}
235
236 2
			if ($newAccount) {
237 1
				$this->accountService->save($newAccount);
238 1
				$this->logger->debug("account created " . $newAccount->getId());
239 1
				return new JSONResponse(
240 1
					['data' => ['id' => $newAccount->getId()]],
241 1
					Http::STATUS_CREATED);
242
			}
243 1
		} catch (Exception $ex) {
244
			$this->logger->error('Creating account failed: ' . $ex->getMessage());
245
			return new JSONResponse(
246
				array('message' => $this->l10n->t('Creating account failed: ') . $ex->getMessage()),
247
				HTTP::STATUS_BAD_REQUEST);
248
		}
249
250 1
		$this->logger->info('Auto detect failed');
251 1
		return new JSONResponse(
252 1
			array('message' => $this->l10n->t('Auto detect failed. Please use manual mode.')),
253 1
			HTTP::STATUS_BAD_REQUEST);
254
	}
255
256
	/**
257
	 * @NoAdminRequired
258
	 *
259
	 * @param int $accountId
260
	 * @param string $folderId
261
	 * @param string $subject
262
	 * @param string $body
263
	 * @param string $to
264
	 * @param string $cc
265
	 * @param string $bcc
266
	 * @param int $draftUID
267
	 * @param string $messageId
268
	 * @param mixed $attachments
269
	 * @return JSONResponse
270
	 */
271 4
	public function send($accountId, $folderId, $subject, $body, $to, $cc,
272
		$bcc, $draftUID, $messageId, $attachments, $aliasId) {
273 4
		$account = $this->accountService->find($this->currentUserId, $accountId);
274 4
		$alias = $aliasId ? $this->aliasesService->find($aliasId, $this->currentUserId) : null;
275 4
		if ($account instanceof UnifiedAccount) {
276 2
			list($account, $folderId, $messageId) = $account->resolve($messageId);
277 2
		}
278 4
		if (!$account instanceof Account) {
279
			return new JSONResponse(
280
				['message' => 'Invalid account'],
281
				Http::STATUS_BAD_REQUEST
282
			);
283
		}
284
285 4
		$mailbox = null;
286 4
		if (!is_null($folderId) && !is_null($messageId)) {
287
			// Reply
288 2
			$message = $account->newReplyMessage();
289
290 2
			$mailbox = $account->getMailbox(base64_decode($folderId));
291 2
			$repliedMessage = $mailbox->getMessage($messageId);
292
293 2
			if (is_null($subject)) {
294
				// No subject set – use the original one
295
				$message->setSubject($repliedMessage->getSubject());
296
			} else {
297 2
				$message->setSubject($subject);
298
			}
299
300 2
			if (is_null($to)) {
301
				$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...
302
			} else {
303 2
				$message->setTo(Message::parseAddressList($to));
304
			}
305
306 2
			$message->setRepliedMessage($repliedMessage);
307 2
		} else {
308
			// New message
309 2
			$message = $account->newMessage();
310 2
			$message->setTo(Message::parseAddressList($to));
311 2
			$message->setSubject($subject ? : '');
312
		}
313
314 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...
315 4
		$message->setFrom($alias ? $alias->alias : $account->getEMailAddress());
316 4
		$message->setCC(Message::parseAddressList($cc));
317 4
		$message->setBcc(Message::parseAddressList($bcc));
318 4
		$message->setContent($body);
319
320 4
		if (is_array($attachments)) {
321 4
			foreach($attachments as $attachment) {
322 4
				$fileName = $attachment['fileName'];
323 4
				if ($this->userFolder->nodeExists($fileName)) {
324 4
					$f = $this->userFolder->get($fileName);
325 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...
326 4
						$message->addAttachmentFromFiles($f);
327 4
					}
328 4
				}
329 4
			}
330 4
		}
331
332
		try {
333 4
			$account->sendMessage($message, $draftUID);
334
335
			// in case of reply we flag the message as answered
336 4
			if ($message instanceof ReplyMessage) {
337 2
				$mailbox->setMessageFlag($messageId, Horde_Imap_Client::FLAG_ANSWERED, true);
338 2
			}
339
340
			// Collect mail addresses
341
			try {
342 4
				$addresses = array_merge($message->getToList(), $message->getCCList(), $message->getBCCList());
343 4
				$this->addressCollector->addAddresses($addresses);
344 4
			} catch (Exception $e) {
345 1
				$this->logger->error("Error while collecting mail addresses: " . $e->getMessage());
346
			}
347 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...
348
			$this->logger->error('Sending mail failed: ' . $ex->getMessage());
349
			return new JSONResponse(
350
				array('message' => $ex->getMessage()),
351
				Http::STATUS_INTERNAL_SERVER_ERROR
352
			);
353
		}
354
355 4
		return new JSONResponse();
356
	}
357
358
	/**
359
	 * @NoAdminRequired
360
	 * 
361
	 * @param int $accountId
362
	 * @param string $subject
363
	 * @param string $body
364
	 * @param string $to
365
	 * @param string $cc
366
	 * @param string $bcc
367
	 * @param int $uid
368
	 * @param string $messageId
369
	 * @return JSONResponse
370
	 */
371 4
	public function draft($accountId, $subject, $body, $to, $cc, $bcc, $uid, $messageId) {
372 4
		if (is_null($uid)) {
373 2
			$this->logger->info("Saving a new draft in account <$accountId>");
374 2
		} else {
375 2
			$this->logger->info("Updating draft <$uid> in account <$accountId>");
376
		}
377
378 4
		$account = $this->accountService->find($this->currentUserId, $accountId);
379 4
		if ($account instanceof UnifiedAccount) {
380 2
			list($account) = $account->resolve($messageId);
381 2
		}
382 4
		if (!$account instanceof Account) {
383
			return new JSONResponse(
384
				array('message' => 'Invalid account'),
385
				Http::STATUS_BAD_REQUEST
386
			);
387
		}
388
389 4
		$message = $account->newMessage();
390 4
		$message->setTo(Message::parseAddressList($to));
391 4
		$message->setSubject($subject ? : '');
392 4
		$message->setFrom($account->getEMailAddress());
393 4
		$message->setCC(Message::parseAddressList($cc));
394 4
		$message->setBcc(Message::parseAddressList($bcc));
395 4
		$message->setContent($body);
396
397
		// create transport and save message
398
		try {
399 4
			$newUID = $account->saveDraft($message, $uid);
400 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...
401
			$this->logger->error('Saving draft failed: ' . $ex->getMessage());
402
			return new JSONResponse(
403
				[
404
					'message' => $ex->getMessage()
405
				],
406
				Http::STATUS_INTERNAL_SERVER_ERROR
407
			);
408
		}
409
410 4
		return new JSONResponse([
411
			'uid' => $newUID
412 4
		]);
413
	}
414
415
}
416