Send mails with quota and fix opting out
This commit is contained in:
Родитель
f7402757fb
Коммит
29a5a53ccb
|
@ -80,6 +80,7 @@ class OptoutController extends Controller {
|
|||
|
||||
/**
|
||||
* @PublicPage
|
||||
* @NoCSRFRequired
|
||||
* @UserRateThrottle
|
||||
* @param bool $token
|
||||
* @param bool $optedOut
|
||||
|
@ -94,12 +95,17 @@ class OptoutController extends Controller {
|
|||
]);
|
||||
}
|
||||
|
||||
public function updateOptingOut(string $token, bool $optedOut): TemplateResponse {
|
||||
/**
|
||||
* @PublicPage
|
||||
* @UserRateThrottle
|
||||
* @param bool $token
|
||||
* @return DataResponse
|
||||
*/
|
||||
public function updateOptingOut(string $token): Response {
|
||||
try {
|
||||
$this->service->uptadeOptedOutByToken($token, $optedOut);
|
||||
return new PublicTemplateResponse($this->appName, 'public-opting-out', [
|
||||
'token' => $token,
|
||||
'optedOut' => $optedOut,
|
||||
$this->service->uptadeOptedOutByToken($token, true);
|
||||
return new DataResponse([
|
||||
'done' => true
|
||||
]);
|
||||
} catch (NotFoundException $exception) {
|
||||
return new NotFoundResponse();
|
||||
|
|
|
@ -48,29 +48,35 @@ class NotificationTrackerMapper extends QBMapper {
|
|||
/**
|
||||
* @throws \OCP\DB\Exception
|
||||
*/
|
||||
public function uptadeOptedOutByToken(string $token, bool $optedOut) {
|
||||
public function updateOptedOutByToken(string $token, bool $optedOut): void {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$qb->update($this->getTableName(), 'o')
|
||||
->set('o.opted_out', $qb->createNamedParameter($optedOut))
|
||||
->where('o.secret_token', $qb->createNamedParameter($token))
|
||||
->executeStatement();
|
||||
$qb->update($this->getTableName())
|
||||
->set('opted_out', $qb->createNamedParameter($optedOut))
|
||||
->where($qb->expr()->eq('secret_token', $qb->createNamedParameter($token)));
|
||||
$qb->executeStatement();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateTimeInterface $date
|
||||
* @return NotificationTracker[]
|
||||
* @throws \OCP\DB\Exception
|
||||
*/
|
||||
public function findAllOlderThan(\DateTimeInterface $date, int $limit): array {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$qb->select('*')
|
||||
->from($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->lt('lastSendNotification', $qb->createNamedParameter($date->getTimestamp()))
|
||||
)
|
||||
->setMaxResults($limit);
|
||||
try {
|
||||
$qb->select('*')
|
||||
->from($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->gt('lastSendNotification', $date->getTimestamp())
|
||||
)
|
||||
->andWhere(
|
||||
$qb->expr()->eq('opted_out', false)
|
||||
)
|
||||
->setMaxResults($limit);
|
||||
} catch (\Exception $e) {
|
||||
echo 'rerre';
|
||||
}
|
||||
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
|
|
@ -29,12 +29,12 @@ namespace OCA\MonthlyNotifications\Jobs;
|
|||
use OCA\MonthlyNotifications\Service\NotificationTrackerService;
|
||||
use OCP\AppFramework\Utility\ITimeFactory;
|
||||
use OCP\BackgroundJob\TimedJob;
|
||||
use OCP\Files\FileInfo;
|
||||
use OCP\IConfig;
|
||||
use OCP\IUser;
|
||||
use OCP\IL10N;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUserManager;
|
||||
use OCP\Mail\IEMailTemplate;
|
||||
use OCP\Mail\IMailer;
|
||||
use OCP\User\Backend\IGetRealUIDBackend;
|
||||
|
||||
class SendNotifications extends TimedJob {
|
||||
/** @var NotificationTrackerService $service */
|
||||
|
@ -52,29 +52,42 @@ class SendNotifications extends TimedJob {
|
|||
* @var IMailer
|
||||
*/
|
||||
private $mailer;
|
||||
/**
|
||||
* @var IL10N
|
||||
*/
|
||||
private $l;
|
||||
/**
|
||||
* @var IURLGenerator
|
||||
*/
|
||||
private $generator;
|
||||
|
||||
public function __construct($appName,
|
||||
ITimeFactory $time,
|
||||
NotificationTrackerService $service,
|
||||
IUserManager $userManager,
|
||||
IConfig $config,
|
||||
IMailer $mailer) {
|
||||
$this->setInterval(60 * 60 * 3); // every 3 hours
|
||||
IMailer $mailer,
|
||||
IL10N $l,
|
||||
IURLGenerator $generator) {
|
||||
parent::__construct($time);
|
||||
//$this->setInterval(60 * 60 * 3); // every 3 hours
|
||||
$this->service = $service;
|
||||
$this->userManager = $userManager;
|
||||
$this->config = $config;
|
||||
$this->appName = $appName;
|
||||
$this->mailer = $mailer;
|
||||
$this->l = $l;
|
||||
$this->generator = $generator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function run($argument): void {
|
||||
$limit = $this->config->getAppValue($this->appName, 'max_mail_sent', 100);
|
||||
$limit = (int)$this->config->getAppValue($this->appName, 'max_mail_sent', 100);
|
||||
|
||||
$trackedNotifications = $this->service->findAllOlderThan(new \DateTime("-1 month"), $limit);
|
||||
//$trackedNotifications = $this->service->findAllOlderThan(new \DateTime("-1 month"), $limit);
|
||||
$trackedNotifications = $this->service->findAllOlderThan(new \DateTime('now'), $limit);
|
||||
foreach ($trackedNotifications as $trackedNotification) {
|
||||
$message = $this->mailer->createMessage();
|
||||
$user = $this->userManager->get($trackedNotification->getUserId());
|
||||
|
@ -89,9 +102,39 @@ class SendNotifications extends TimedJob {
|
|||
|
||||
$emailTemplate = $this->mailer->createEMailTemplate('quote.notification');
|
||||
$emailTemplate->addHeader();
|
||||
$emailTemplate->addHeading('Welcome aboard');
|
||||
$emailTemplate->addBodyText('Quota: ' . $user->getQuota());
|
||||
$emailTemplate->addFooter('Optional footer text');
|
||||
$emailTemplate->addHeading('Hello ' . $user->getDisplayName());
|
||||
|
||||
// make sure FS is setup before querying storage related stuff...
|
||||
\OC_Util::setupFS($user->getUID());
|
||||
|
||||
$storageInfo = \OC_Helper::getStorageInfo('/');
|
||||
if ($storageInfo['quota'] === FileInfo::SPACE_UNLIMITED) {
|
||||
$totalSpace = $this->l->t('Unlimited');
|
||||
} else {
|
||||
$totalSpace = \OC_Helper::humanFileSize($storageInfo['total']);
|
||||
}
|
||||
$usedSpace = \OC_Helper::humanFileSize($storageInfo['used']);
|
||||
if ($storageInfo['quota'] !== FileInfo::SPACE_UNLIMITED) {
|
||||
$quota = \OC_Helper::humanFileSize($storageInfo['quota']);
|
||||
$emailTemplate->addBodyText(
|
||||
$this->l->t('You are currently using <strong>' . $usedSpace . '</strong> of <strong>' . $quota . '</strong>.'),
|
||||
$this->l->t('You are currently using ' . $usedSpace . ' of ' . $quota . '.')
|
||||
);
|
||||
if ($storageInfo['usage_relative'] > 80) {
|
||||
// todo display warning
|
||||
$emailTemplate->addBodyText($this->l->t('You are using over 80% of your quota.'));
|
||||
}
|
||||
} else {
|
||||
$emailTemplate->addBodyText(
|
||||
$this->l->t('You are currently using <strong>' . $usedSpace . '</strong> of storage.'),
|
||||
$this->l->t('You are currently using ' . $usedSpace . ' of storage.')
|
||||
);
|
||||
}
|
||||
$emailTemplate->addFooter($this->l->t('You can unsubscribe by clicking on this link: <a href="%s">Unsubscribe</a>', [
|
||||
$this->generator->getAbsoluteURL($this->generator->linkToRoute($this->appName.'.optout.displayOptingOutPage', [
|
||||
'token' => $trackedNotification->getSecretToken()
|
||||
]))
|
||||
]));
|
||||
$message->useTemplate($emailTemplate);
|
||||
$this->mailer->send($message);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@ class Version23000Date2021090112000001 extends SimpleMigrationStep {
|
|||
$table->addColumn('id', 'integer', [
|
||||
'autoincrement' => true,
|
||||
'notnull' => true,
|
||||
'unique' => true,
|
||||
]);
|
||||
$table->addColumn('user_id', 'string', [
|
||||
'notnull' => true,
|
||||
|
@ -60,8 +59,8 @@ class Version23000Date2021090112000001 extends SimpleMigrationStep {
|
|||
$table->addColumn('secret_token', 'string', [
|
||||
'notnull' => true,
|
||||
'default' => false,
|
||||
'unique' => true,
|
||||
]);
|
||||
$table->addUniqueIndex(['user_id', 'secret_token']);
|
||||
|
||||
$table->setPrimaryKey(['id']);
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ class NotificationTrackerService {
|
|||
try {
|
||||
return $this->mapper->find($userId);
|
||||
} catch(\Exception $e) {
|
||||
$this->handleException($e);
|
||||
return $this->create($userId, false, time());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ class NotificationTrackerService {
|
|||
|
||||
public function uptadeOptedOutByToken(string $token, bool $optedOut) {
|
||||
try {
|
||||
$this->mapper->uptadeOptedOutByToken($token, $optedOut);
|
||||
$this->mapper->updateOptedOutByToken($token, $optedOut);
|
||||
} catch (Exception $e) {
|
||||
$this->handleException($e);
|
||||
}
|
||||
|
|
|
@ -24,14 +24,39 @@ declare(strict_types=1);
|
|||
|
||||
namespace OCA\MonthlyNotifications\Settings;
|
||||
|
||||
use OCA\MonthlyNotifications\Service\NotificationTrackerService;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\AppFramework\Services\IInitialState;
|
||||
use OCP\IUserSession;
|
||||
use OCP\Settings\ISettings;
|
||||
|
||||
class PersonalSettings implements ISettings {
|
||||
/**
|
||||
* @var IInitialState
|
||||
*/
|
||||
private $initialState;
|
||||
/**
|
||||
* @var NotificationTrackerService
|
||||
*/
|
||||
private $service;
|
||||
/**
|
||||
* @var IUserSession
|
||||
*/
|
||||
private $userSession;
|
||||
|
||||
public function __construct(IInitialState $initialState,
|
||||
NotificationTrackerService $service,
|
||||
IUserSession $userSession) {
|
||||
$this->initialState = $initialState;
|
||||
$this->service = $service;
|
||||
$this->userSession = $userSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TemplateResponse
|
||||
*/
|
||||
public function getForm(): TemplateResponse {
|
||||
$this->initialState->provideInitialState('opted-out', $this->service->find($this->userSession->getUser()->getUID())->getOptedOut());
|
||||
return new TemplateResponse('monthly_notifications', 'settings-personal', []);
|
||||
}
|
||||
|
||||
|
|
|
@ -71,16 +71,13 @@
|
|||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@juliushaertl/vue-richtext": "^0.3.3",
|
||||
"@nextcloud/auth": "^1.3.0",
|
||||
"@nextcloud/axios": "^1.6.0",
|
||||
"@nextcloud/l10n": "^1.4.1",
|
||||
"@nextcloud/logger": "^2.0.0",
|
||||
"@nextcloud/moment": "^1.1.1",
|
||||
"@nextcloud/paths": "^2.0.0",
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/initial-state": "^2.0.0",
|
||||
"@nextcloud/vue": "^3.9.0",
|
||||
"@nextcloud/vue-dashboard": "^2.0.1",
|
||||
"vue": "^2.6.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
</p>
|
||||
<p>
|
||||
<input id="send-notifications"
|
||||
v-model="sendNotifications"
|
||||
type="checkbox"
|
||||
class="checkbox"
|
||||
v-model="sendNotification">
|
||||
class="checkbox">
|
||||
<label for="send-notifications">{{ t('monthly_notifications', 'Send monthly summary') }}</label>
|
||||
</p>
|
||||
</div>
|
||||
|
@ -17,23 +17,24 @@
|
|||
<script>
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import axios from '@nextcloud/axios'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
|
||||
export default {
|
||||
name: 'PersonalSettings',
|
||||
data() {
|
||||
return {
|
||||
sendNotification: false,
|
||||
sendNotifications: !loadState('monthly_notifications', 'opted-out', false),
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
sendNotification() {
|
||||
sendNotifications() {
|
||||
this.saveSetting()
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async saveSetting() {
|
||||
const data = {
|
||||
optedOut: !this.sendNotification,
|
||||
optedOut: !this.sendNotifications,
|
||||
}
|
||||
await axios.post(generateUrl('/apps/monthly_notifications/') + 'update', data)
|
||||
},
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2021 Carl Schwan <carl@carlschwan.eu>
|
||||
*
|
||||
* @author Carl Schwan <carl@carlschwan.eu>
|
||||
*
|
||||
* @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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
import axios from '@nextcloud/axios'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
|
||||
(function() {
|
||||
const queryString = window.location.search
|
||||
const urlParams = new URLSearchParams(queryString)
|
||||
|
||||
axios.post(generateUrl('/apps/monthly_notifications/') + 'optout', {
|
||||
token: urlParams.get('token'),
|
||||
})
|
||||
})()
|
|
@ -22,5 +22,13 @@ declare(strict_types=1);
|
|||
*
|
||||
*/
|
||||
|
||||
script('monthly_notifications', 'send-opt-out');
|
||||
/** @var \OCP\IL10N $l */
|
||||
/** @var array $_ */
|
||||
|
||||
script('monthly_notifications', 'monthly_notifications-publicOptout');
|
||||
?>
|
||||
<div class="section">
|
||||
<h2><?php echo $l->t('Monthly status update'); ?></h2>
|
||||
|
||||
<p><?php echo $l->t('You just unsubscribed from the monthly status update. You can any time subscribe again from your account.') ?></p>
|
||||
</div>
|
||||
|
|
|
@ -24,6 +24,7 @@ const webpackConfig = require('@nextcloud/webpack-vue-config')
|
|||
|
||||
webpackConfig.entry = {
|
||||
personalSettings: path.join(__dirname, 'src', 'main-personal-settings.js'),
|
||||
publicOptout: path.join(__dirname, 'src', 'main-public-optout.js'),
|
||||
}
|
||||
|
||||
module.exports = webpackConfig
|
||||
|
|
Загрузка…
Ссылка в новой задаче