Skip to content

Commit 0eaf312

Browse files
committed
feat: add notification when quota exceeded
Signed-off-by: Lukas Schaefer <[email protected]>
1 parent 5d46c3d commit 0eaf312

File tree

3 files changed

+123
-2
lines changed

3 files changed

+123
-2
lines changed

lib/AppInfo/Application.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace OCA\OpenAi\AppInfo;
99

10+
use OCA\OpenAi\Notification\Notifier;
1011
use OCA\OpenAi\Capabilities;
1112
use OCA\OpenAi\OldProcessing\Translation\TranslationProvider as OldTranslationProvider;
1213
use OCA\OpenAi\TaskProcessing\AudioToAudioChatProvider;
@@ -152,6 +153,7 @@ public function register(IRegistrationContext $context): void {
152153
}
153154

154155
$context->registerCapability(Capabilities::class);
156+
$context->registerNotifierService(Notifier::class);
155157
}
156158

157159
public function boot(IBootContext $context): void {

lib/Notification/Notifier.php

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
3+
/**
4+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-License-Identifier: AGPL-3.0-or-later
6+
*/
7+
8+
namespace OCA\OpenAi\Notification;
9+
10+
use InvalidArgumentException;
11+
use OCA\OpenAi\AppInfo\Application;
12+
use OCP\IURLGenerator;
13+
use OCP\L10N\IFactory;
14+
use OCP\Notification\IAction;
15+
use OCP\Notification\INotification;
16+
17+
use OCP\Notification\INotifier;
18+
use Psr\Log\LoggerInterface;
19+
20+
class Notifier implements INotifier {
21+
22+
public function __construct(
23+
private IFactory $factory,
24+
private IURLGenerator $url,
25+
private LoggerInterface $logger,
26+
) {
27+
}
28+
29+
/**
30+
* Identifier of the notifier, only use [a-z0-9_]
31+
*
32+
* @return string
33+
* @since 17.0.0
34+
*/
35+
public function getID(): string {
36+
return Application::APP_ID;
37+
}
38+
/**
39+
* Human readable name describing the notifier
40+
*
41+
* @return string
42+
* @since 17.0.0
43+
*/
44+
public function getName(): string {
45+
return $this->factory->get(Application::APP_ID)->t('integration_openai');
46+
}
47+
48+
/**
49+
* @param INotification $notification
50+
* @param string $languageCode The code of the language that should be used to prepare the notification
51+
* @return INotification
52+
* @throws InvalidArgumentException When the notification was not prepared by a notifier
53+
* @since 9.0.0
54+
*/
55+
public function prepare(INotification $notification, string $languageCode): INotification {
56+
$this->logger->error('Preparing notification adsadsdsa', ['notification' => $notification, 'subject' => $notification->getSubject()]);
57+
if ($notification->getApp() !== Application::APP_ID) {
58+
// Not my app => throw
59+
throw new InvalidArgumentException();
60+
}
61+
if ($notification->getSubject() !== 'quota_exceeded') {
62+
// Not a valid subject => throw
63+
throw new InvalidArgumentException();
64+
}
65+
66+
$l = $this->factory->get(Application::APP_ID, $languageCode);
67+
68+
$params = $notification->getSubjectParameters();
69+
70+
$subject = $l->t('Quota exceeded');
71+
$content = '';
72+
switch ($params['type']) {
73+
case Application::QUOTA_TYPE_TEXT:
74+
$content = $l->t('Text generation quota exceeded');
75+
break;
76+
case Application::QUOTA_TYPE_IMAGE:
77+
$content = $l->t('Image generation quota exceeded');
78+
break;
79+
case Application::QUOTA_TYPE_TRANSCRIPTION:
80+
$content = $l->t('Audio transcription quota exceeded');
81+
break;
82+
case Application::QUOTA_TYPE_SPEECH:
83+
$content = $l->t('Speech generation quota exceeded');
84+
break;
85+
}
86+
87+
$link = $this->url->getWebroot() . '/settings/user/ai';
88+
$iconUrl = $this->url->getAbsoluteURL($this->url->imagePath(Application::APP_ID, 'app-dark.svg'));
89+
90+
$notification
91+
->setParsedSubject($subject)
92+
->setParsedMessage($content)
93+
->setLink($link)
94+
->setIcon($iconUrl);
95+
96+
$actionLabel = $params['actionLabel'] ?? $l->t('View quota');
97+
$action = $notification->createAction();
98+
$action->setLabel($actionLabel)
99+
->setParsedLabel($actionLabel)
100+
->setLink($notification->getLink(), IAction::TYPE_WEB)
101+
->setPrimary(true);
102+
103+
$notification->addParsedAction($action);
104+
105+
return $notification;
106+
}
107+
}

lib/Service/OpenAiAPIService.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace OCA\OpenAi\Service;
99

10+
use DateTime;
1011
use Exception;
1112
use GuzzleHttp\Exception\ClientException;
1213
use GuzzleHttp\Exception\ServerException;
@@ -25,6 +26,7 @@
2526
use OCP\ICacheFactory;
2627
use OCP\IL10N;
2728
use OCP\Lock\LockedException;
29+
use OCP\Notification\IManager as INotificationManager;
2830
use OCP\TaskProcessing\ShapeEnumValue;
2931
use Psr\Log\LoggerInterface;
3032
use RuntimeException;
@@ -46,6 +48,7 @@ public function __construct(
4648
private ICacheFactory $cacheFactory,
4749
private QuotaUsageMapper $quotaUsageMapper,
4850
private OpenAiSettingsService $openAiSettingsService,
51+
private INotificationManager $notificationManager,
4952
IClientService $clientService,
5053
) {
5154
$this->client = $clientService->newClient();
@@ -252,8 +255,17 @@ public function isQuotaExceeded(?string $userId, int $type): bool {
252255
$this->logger->warning('Could not retrieve quota usage for user: ' . $userId . ' and quota type: ' . $type . '. Error: ' . $e->getMessage());
253256
throw new Exception('Could not retrieve quota usage.', Http::STATUS_INTERNAL_SERVER_ERROR);
254257
}
255-
256-
return $quotaUsage >= $quota;
258+
if ($quotaUsage >= $quota) {
259+
$notification = $this->notificationManager->createNotification();
260+
$notification->setApp(Application::APP_ID)
261+
->setUser($userId)
262+
->setDateTime(new DateTime())
263+
->setObject('quota_exceeded', (string)$type)
264+
->setSubject('quota_exceeded', ['type' => $type]);
265+
$this->notificationManager->notify($notification);
266+
return true;
267+
}
268+
return false;
257269
}
258270

259271
/**

0 commit comments

Comments
 (0)