Skip to content

Commit

Permalink
Merge pull request #1074 from nextcloud/MailNotifications
Browse files Browse the repository at this point in the history
Sending unseen notifications as email periodically. Includes a new us…
  • Loading branch information
nickvergessen authored Oct 11, 2021
2 parents 02f671d + 64777d9 commit 5fae938
Show file tree
Hide file tree
Showing 21 changed files with 1,315 additions and 2 deletions.
1 change: 1 addition & 0 deletions .php_cs.dist
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ $config
->getFinder()
->notPath('build')
->notPath('l10n')
->notPath('node_modules')
->notPath('src')
->notPath('vendor')
->in(__DIR__);
Expand Down
12 changes: 11 additions & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
📣 Announcement center: An announcement was posted by an admin]]></description>

<version>2.11.0</version>
<version>2.11.1</version>
<licence>agpl</licence>
<author>Joas Schilling</author>

Expand All @@ -35,8 +35,18 @@
<nextcloud min-version="23" max-version="23" />
</dependencies>

<background-jobs>
<job>OCA\Notifications\BackgroundJob\GenerateUserSettings</job>
<job>OCA\Notifications\BackgroundJob\SendNotificationMails</job>
</background-jobs>

<commands>
<command>OCA\Notifications\Command\Generate</command>
<command>OCA\Notifications\Command\TestPush</command>
</commands>

<settings>
<personal>OCA\Notifications\Settings\Personal</personal>
<personal-section>OCA\Notifications\Settings\PersonalSection</personal-section>
</settings>
</info>
2 changes: 2 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,7 @@
['name' => 'Push#removeDevice', 'url' => '/api/{apiVersion}/push', 'verb' => 'DELETE', 'requirements' => ['apiVersion' => 'v2']],

['name' => 'API#generateNotification', 'url' => '/api/{apiVersion}/admin_notifications/{userId}', 'verb' => 'POST', 'requirements' => ['apiVersion' => 'v(1|2)']],

['name' => 'Settings#personal', 'url' => '/api/{apiVersion}/settings', 'verb' => 'POST', 'requirements' => ['apiVersion' => 'v2']],
],
];
3 changes: 3 additions & 0 deletions js/notifications-settings.js

Large diffs are not rendered by default.

54 changes: 54 additions & 0 deletions js/notifications-settings.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <[email protected]> <http://feross.org>
* @license MIT
*/

/*!
* Vue.js v2.6.14
* (c) 2014-2021 Evan You
* Released under the MIT License.
*/

/**
* @copyright Copyright (c) 2019 Greta Doci <[email protected]>
*
* @author Greta Doci <[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/>.
*
*/

/**
* @copyright Copyright (c) 2021 Julien Barnoin <[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/>.
*
*/
1 change: 1 addition & 0 deletions js/notifications-settings.js.map

Large diffs are not rendered by default.

87 changes: 87 additions & 0 deletions lib/BackgroundJob/GenerateUserSettings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2021 Joas Schilling <[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\Notifications\BackgroundJob;

use OCA\Notifications\Model\Settings;
use OCA\Notifications\Model\SettingsMapper;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\BackgroundJob\TimedJob;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IDBConnection;
use OCP\IUser;
use OCP\IUserManager;

class GenerateUserSettings extends TimedJob {
/** @var IDBConnection */
private $connection;
/** @var IUserManager */
private $userManager;
/** @var SettingsMapper */
private $settingsMapper;

public function __construct(
ITimeFactory $time,
IDBConnection $connection,
IUserManager $userManager,
SettingsMapper $settingsMapper
) {
parent::__construct($time);

$this->connection = $connection;
$this->userManager = $userManager;
$this->settingsMapper = $settingsMapper;

// run every day
$this->setInterval(24 * 60 * 60);
}

protected function run($argument): void {
$query = $this->connection->getQueryBuilder();
$query->selectAlias('id', 'max_id')
->from('notifications')
->orderBy('id', 'DESC')
->setMaxResults(1);

$result = $query->executeQuery();
$maxId = (int) $result->fetchOne();
$result->closeCursor();

$this->userManager->callForSeenUsers(function (IUser $user) use ($maxId) {
if ($user->isEnabled()) {
return;
}

try {
$this->settingsMapper->getSettingsByUser($user->getUID());
} catch (DoesNotExistException $e) {
$settings = new Settings();
$settings->setUserId($user->getUID());
$settings->setNextSendTime(1);
$settings->setBatchTime(Settings::EMAIL_SEND_3HOURLY);
$settings->setLastSendId($maxId);
$this->settingsMapper->insert($settings);
}
});
}
}
51 changes: 51 additions & 0 deletions lib/BackgroundJob/SendNotificationMails.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2021 Julien Barnoin <[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\Notifications\BackgroundJob;

use OCP\BackgroundJob\TimedJob;
use OCA\Notifications\MailNotifications;
use OCP\AppFramework\Utility\ITimeFactory;

class SendNotificationMails extends TimedJob {

/** @var MailNotifications */
protected $mailNotifications;
/** @var bool */
protected $isCLI;

public function __construct(ITimeFactory $timeFactory,
MailNotifications $mailNotifications,
bool $isCLI) {
parent::__construct($timeFactory);

$this->mailNotifications = $mailNotifications;
$this->isCLI = $isCLI;
}

protected function run($argument): void {
$time = $this->time->getTime();
$batchSize = $this->isCLI ? MailNotifications::BATCH_SIZE_CLI : MailNotifications::BATCH_SIZE_WEB;
$this->mailNotifications->sendEmails($batchSize, $time);
}
}
58 changes: 58 additions & 0 deletions lib/Controller/SettingsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2021 Julien Barnoin <[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\Notifications\Controller;

use OCA\Notifications\Model\SettingsMapper;
use OCP\AppFramework\OCSController;
use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest;

class SettingsController extends OCSController {
/** @var SettingsMapper */
protected $settingsMapper;

/** @var string */
protected $userId;

public function __construct(string $appName,
IRequest $request,
SettingsMapper $settingsMapper,
string $userId) {
parent::__construct($appName, $request);
$this->settingsMapper = $settingsMapper;
$this->userId = $userId;
}

/**
* @NoAdminRequired
*
* @param int $batchSetting
* @return DataResponse
*/
public function personal(int $batchSetting): DataResponse {
$this->settingsMapper->setBatchSettingForUser($this->userId, $batchSetting);
return new DataResponse();
}
}
31 changes: 31 additions & 0 deletions lib/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,37 @@ public function getById(int $id, string $user): INotification {
}
}

/**
* Get the notifications after (and excluding) the given id
*
* @param int $startAfterId
* @param string $userId
* @param int $limit
* @return array [notification_id => INotification]
*/
public function getAfterId(int $startAfterId, string $userId, int $limit = 25): array {
$sql = $this->connection->getQueryBuilder();
$sql->select('*')
->from('notifications')
->where($sql->expr()->gt('notification_id', $sql->createNamedParameter($startAfterId)))
->andWhere($sql->expr()->eq('user', $sql->createNamedParameter($userId)))
->orderBy('notification_id', 'DESC')
->setMaxResults($limit);
$statement = $sql->executeQuery();

$notifications = [];
while ($row = $statement->fetch()) {
try {
$notifications[(int)$row['notification_id']] = $this->notificationFromRow($row);
} catch (\InvalidArgumentException $e) {
continue;
}
}
$statement->closeCursor();

return $notifications;
}

/**
* Return the notifications matching the given Notification
*
Expand Down
Loading

0 comments on commit 5fae938

Please sign in to comment.