Skip to content

Commit

Permalink
fixup! enh: add notification for quota depletion
Browse files Browse the repository at this point in the history
  • Loading branch information
miaulalala committed Jul 20, 2023
1 parent 2073e2a commit 8700ae7
Show file tree
Hide file tree
Showing 4 changed files with 312 additions and 9 deletions.
4 changes: 4 additions & 0 deletions lib/Account.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,4 +239,8 @@ public function calculateAndSetQuotaPercentage(Service\Quota $quota): void {
$percentage = (int)round($quota->getUsage() / $quota->getLimit() * 100);
$this->account->setQuotaPercentage($percentage);
}

public function getQuotaPercentage(): int {
return $this->account->getQuotaPercentage();
}
}
28 changes: 19 additions & 9 deletions lib/BackgroundJob/QuotaJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
namespace OCA\Mail\BackgroundJob;

use Horde_Imap_Client_Exception;
use OCA\Mail\Account;
use OCA\Mail\Contracts\IMailManager;
use OCA\Mail\Db\MailAccountMapper;
use OCA\Mail\Exception\IncompleteSyncException;
Expand Down Expand Up @@ -79,7 +80,15 @@ public function __construct(ITimeFactory $time,
*/
protected function run($argument): void {
$accountId = (int)$argument['accountId'];
$account = $this->accountService->findById($accountId);
try {
/** @var Account $account */
$account = $this->accountService->findById($accountId);
} catch (DoesNotExistException $e) {
$this->logger->debug('Could not find account <' . $accountId . '> removing from jobs');
$this->jobList->remove(self::class, $argument);
return;
}

$user = $this->userManager->get($account->getUserId());
if ($user === null || !$user->isEnabled()) {
$this->logger->debug(sprintf(
Expand All @@ -90,20 +99,21 @@ protected function run($argument): void {
return;
}

/** @var Quota $quota */
$quota = $this->mailManager->getQuota($account);
if($quota === null) {
$this->logger->debug('Could not get quota information for account <' . $account->getEmail() . '>', ['app' => 'mail']);
return;
}
$previous = $account->getMailAccount()->getQuotaPercentage();
$previous = $account->getQuotaPercentage();
$account->calculateAndSetQuotaPercentage($quota);
$account = $this->accountService->update($account->getMailAccount());

$this->accountService->update($account->getMailAccount());
$current = $account->getQuotaPercentage();

// Only notify if we've reached the rising edge
if($previous < $account->getQuotaPercentage() && $previous <= 90 && $account->getQuotaPercentage() > 90) {
$this->logger->debug('New quota information for <' . $account->getEmail() . '> - previous: ' . $previous . ', current: ' . $account->getQuotaPercentage(), ['app' => 'mail']);

if($previous < $current && $previous <= 90 && $current > 90) {
$this->logger->debug('New quota information for <' . $account->getEmail() . '> - previous: ' . $previous . ', current: ' . $current);
$time = $this->time->getDateTime('now');
$notification = $this->notificationManager->createNotification();
$notification
->setApp('mail')
Expand All @@ -113,10 +123,10 @@ protected function run($argument): void {
'id' => $accountId,
'account_email' => $account->getEmail()
])
->setDateTime(new \DateTime())
->setDateTime($time)
->setMessage('percentage', [
'id' => $accountId,
'quota_percentage' => (string)$account->getQuotaPercentage(),
'quota_percentage' => $current,
]
);
$this->notificationManager->notify($notification);
Expand Down
3 changes: 3 additions & 0 deletions tests/Integration/Db/MailAccountTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public function testToAPI() {
$a->setEditorMode('html');
$a->setProvisioningId(null);
$a->setOrder(13);
$a->setQuotaPercentage(10);

$this->assertEquals([
'id' => 12345,
Expand Down Expand Up @@ -74,6 +75,7 @@ public function testToAPI() {
'signatureAboveQuote' => false,
'signatureMode' => null,
'smimeCertificateId' => null,
'quotaPercentage' => 10,
], $a->toJson());
}

Expand Down Expand Up @@ -105,6 +107,7 @@ public function testMailAccountConstruct() {
'signatureAboveQuote' => false,
'signatureMode' => null,
'smimeCertificateId' => null,
'quotaPercentage' => null,
];
$a = new MailAccount($expected);
// TODO: fix inconsistency
Expand Down
286 changes: 286 additions & 0 deletions tests/Unit/BackgroundJob/QuotaJobTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
<?php

declare(strict_types=1);

/*
* @copyright 2021 Christoph Wurst <[email protected]>
*
* @author 2021 Christoph Wurst <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

namespace OCA\Mail\Tests\Unit\BackgroundJob;

use ChristophWurst\Nextcloud\Testing\ServiceMockObject;
use ChristophWurst\Nextcloud\Testing\TestCase;
use OC\BackgroundJob\JobList;
use OCA\Mail\Account;
use OCA\Mail\BackgroundJob\QuotaJob;
use OCA\Mail\BackgroundJob\SyncJob;
use OCA\Mail\Db\MailAccount;
use OCA\Mail\Service\Quota;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\ILogger;
use OCP\IUser;
use OCP\Notification\INotification;

class QuotaJobTest extends TestCase {
/** @var ServiceMockObject*/
private $serviceMock;

/** @var SyncJob */
private $job;

protected function setUp(): void {
parent::setUp();

$this->serviceMock = $this->createServiceMock(QuotaJob::class);
$this->job = $this->serviceMock->getService();

// Make sure the job is actually run
$this->serviceMock->getParameter('time')
->method('getTime')
->willReturn(500000);

// Set our common argument
$this->job->setArgument([
'accountId' => 123,
]);
// Set a fake ID
$this->job->setId(99);
}

public function testAccountDoesntExist(): void {
$this->serviceMock->getParameter('accountService')
->expects(self::once())
->method('findById')
->with(123)
->willThrowException(new DoesNotExistException(''));
$this->serviceMock->getParameter('logger')
->expects(self::once())
->method('debug')
->with('Could not find account <123> removing from jobs');
$this->serviceMock->getParameter('jobList')
->expects(self::once())
->method('remove')
->with(QuotaJob::class, ['accountId' => 123]);
$this->serviceMock->getParameter('mailManager')
->expects(self::never())
->method('getQuota');

$this->job->setArgument([
'accountId' => 123,
]);
$this->job->setLastRun(0);
$this->job->execute(
$this->createMock(JobList::class),
$this->createMock(ILogger::class)
);
}

public function testUserDoesntExist(): void {
$account = $this->createMock(Account::class);
$account->method('getId')->willReturn(123);
$account->method('getUserId')->willReturn('user123');
$this->serviceMock->getParameter('accountService')
->expects(self::once())
->method('findById')
->with(123)
->willReturn($account);
$user = $this->createMock(IUser::class);
$this->serviceMock->getParameter('userManager')
->expects(self::once())
->method('get')
->with('user123')
->willReturn($user);
$this->serviceMock->getParameter('logger')
->expects(self::once())
->method('debug')
->with('Account 123 of user user123 could not be found or was disabled, skipping quota query');
$this->serviceMock->getParameter('mailManager')
->expects(self::never())
->method('getQuota');

$this->job->setArgument([
'accountId' => 123,
]);
$this->job->execute(
$this->createMock(JobList::class),
$this->createMock(ILogger::class)
);
}

public function testQuotaTooLow(): void {
$oldQuota = 10;
$newQuota = 20;
$quotaDTO = new Quota(20, 100);
$mailAccount = $this->createMock(MailAccount::class);
$account = $this->createConfiguredMock(Account::class, [
'getId' => 123,
'getUserId' => 'user123',
'getMailAccount' => $mailAccount,
]);
$user = $this->createConfiguredMock(IUser::class, [
'isEnabled' => true,
]);

$this->serviceMock->getParameter('accountService')
->expects(self::once())
->method('findById')
->with(123)
->willReturn($account);
$this->serviceMock->getParameter('userManager')
->expects(self::once())
->method('get')
->with('user123')
->willReturn($user);
$this->serviceMock->getParameter('logger')
->expects(self::never())
->method('debug');
$this->serviceMock->getParameter('mailManager')
->expects(self::once())
->method('getQuota')
->willReturn($quotaDTO);
$account->expects(self::once())
->method('calculateAndSetQuotaPercentage')
->with($quotaDTO);
$account->expects(self::once())
->method('getMailAccount')
->willReturn($mailAccount);
$account->expects(self::exactly(2))
->method('getQuotaPercentage')
->willReturnOnConsecutiveCalls($oldQuota, $newQuota);
$this->serviceMock->getParameter('accountService')
->expects(self::once())
->method('update')
->with($mailAccount);

$this->job->setArgument([
'accountId' => 123,
]);
$this->job->execute(
$this->createMock(JobList::class),
$this->createMock(ILogger::class)
);
}

public function testQuotaWithNotification(): void {
$oldQuota = 85;
$newQuota = 95;
$quotaDTO = new Quota(95, 100);
$mailAccount = $this->createMock(MailAccount::class);
$account = $this->createConfiguredMock(Account::class, [
'getId' => 123,
'getUserId' => 'user123',
'getMailAccount' => $mailAccount,
'getEmail' => '[email protected]',
]);
$user = $this->createConfiguredMock(IUser::class, [
'isEnabled' => true,
]);
$notification = $this->createMock(INotification::class);

$this->serviceMock->getParameter('accountService')
->expects(self::once())
->method('findById')
->with(123)
->willReturn($account);
$this->serviceMock->getParameter('userManager')
->expects(self::once())
->method('get')
->with('user123')
->willReturn($user);
$this->serviceMock->getParameter('mailManager')
->expects(self::once())
->method('getQuota')
->willReturn($quotaDTO);
$account->expects(self::once())
->method('calculateAndSetQuotaPercentage')
->with($quotaDTO);
$account->expects(self::once())
->method('getMailAccount')
->willReturn($mailAccount);
$account->expects(self::exactly(2))
->method('getQuotaPercentage')
->willReturnOnConsecutiveCalls($oldQuota, $newQuota);
$account->expects(self::exactly(2))
->method('getUserId')
->willReturn('user123');
$account->expects(self::exactly(2))
->method('getEmail')
->willReturn('[email protected]');
$this->serviceMock->getParameter('accountService')
->expects(self::once())
->method('update')
->with($mailAccount);
$this->serviceMock->getParameter('logger')
->expects(self::once())
->method('debug')
->with('New quota information for <[email protected]> - previous: ' . $oldQuota . ', current: ' . $newQuota);
$this->serviceMock->getParameter('notificationManager')
->expects(self::once())
->method('createNotification')
->willReturn($notification);
$time = new \DateTime('now');
$this->serviceMock->getParameter('time')
->expects(self::once())
->method('getDateTime')
->willReturn($time);
$notification->expects(self::once())
->method('setApp')
->with('mail')
->willReturn($notification);
$notification->expects(self::once())
->method('setUser')
->with('user123')
->willReturn($notification);
$notification->expects(self::once())
->method('setObject')
->with('quota', 123)
->willReturn($notification);
$notification->expects(self::once())
->method('setSubject')
->with('quota_depleted', [
'id' => 123,
'account_email' => '[email protected]'
])
->willReturn($notification);
$notification->expects(self::once())
->method('setDateTime')
->with($time)
->willReturn($notification);
$notification->expects(self::once())
->method('setMessage')
->with('percentage', [
'id' => 123,
'quota_percentage' => $newQuota,
])
->willReturn($notification);
$this->serviceMock->getParameter('notificationManager')
->expects(self::once())
->method('notify')
->with($notification);

$this->job->setArgument([
'accountId' => 123,
]);
$this->job->execute(
$this->createMock(JobList::class),
$this->createMock(ILogger::class)
);
}
}

0 comments on commit 8700ae7

Please sign in to comment.