Repository navigation
Expand file tree
/
Copy pathEvents.php
More file actions
176 lines (150 loc) · 7.2 KB
/
Copy pathEvents.php
File metadata and controls
176 lines (150 loc) · 7.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
<?php
namespace humhub\modules\fcmPush;
use humhub\modules\fcmPush\assets\FcmPushAsset;
use humhub\modules\fcmPush\assets\FirebaseAsset;
use humhub\modules\fcmPush\components\NotificationTargetProvider;
use humhub\modules\fcmPush\helpers\MobileAppHelper;
use humhub\modules\fcmPush\helpers\WebAppHelper;
use humhub\modules\fcmPush\jobs\SendSilentUnreadNotificationCountJob;
use humhub\modules\fcmPush\services\ServiceWorkerService;
use humhub\modules\fcmPush\widgets\EnableNotificationsBanner;
use humhub\modules\fcmPush\widgets\RegisterDeviceTokenButton;
use humhub\modules\notification\events\UnreadCountChangedEvent;
use humhub\modules\notification\targets\MobileTargetProvider;
use humhub\modules\notification\widgets\NotificationSettingsForm;
use humhub\modules\web\pwa\controllers\ServiceWorkerController;
use humhub\helpers\DeviceDetectorHelper;
use humhub\widgets\LayoutAddons;
use Yii;
use yii\base\WidgetEvent;
class Events
{
public static function onBeforeRequest()
{
/** @var Module $module */
$module = Yii::$app->getModule('fcm-push');
// Replace the core MobileTargetProvider binding with our own implementation so that
// HumHub's notification module dispatches mobile notifications through FCM.
// This is done here (not in config.php) because we only want to override when at least
// one driver is actually configured — otherwise the original provider is left intact.
if ($module->getDriverService()->hasConfiguredDriver()) {
Yii::$container->set(MobileTargetProvider::class, NotificationTargetProvider::class);
}
}
public static function onServiceWorkerControllerInit($event): void
{
/** @var ServiceWorkerController $controller */
$controller = $event->sender;
/** @var Module $module */
$module = Yii::$app->getModule('fcm-push');
if (!$module->getDriverService()->hasConfiguredWebDriver()) {
return;
}
// Service Worker Addons
$controller->additionalJs .= (new ServiceWorkerService($module))->getJs();
}
public static function onLayoutAddonInit($event)
{
// After login: the session flag set by onAfterLogin is consumed here so the
// registration script runs exactly once on the first post-login page render.
if (Yii::$app->session->has(MobileAppHelper::SESSION_VAR_REGISTER_NOTIFICATION)) {
MobileAppHelper::registerNotificationScript();
Yii::$app->session->remove(MobileAppHelper::SESSION_VAR_REGISTER_NOTIFICATION);
}
// After logout: unregister tokens so this device stops receiving push notifications.
// The session flags are set by onAfterLogout and consumed once here.
if (Yii::$app->session->has(WebAppHelper::SESSION_VAR_UNREGISTER_NOTIFICATION)) {
static::registerAssets();
WebAppHelper::unregisterNotificationScript();
Yii::$app->session->remove(WebAppHelper::SESSION_VAR_UNREGISTER_NOTIFICATION);
}
if (Yii::$app->session->has(MobileAppHelper::SESSION_VAR_UNREGISTER_NOTIFICATION)) {
MobileAppHelper::unregisterNotificationScript();
Yii::$app->session->remove(MobileAppHelper::SESSION_VAR_UNREGISTER_NOTIFICATION);
}
if (!Yii::$app->user->isGuest) {
static::registerAssets();
static::addEnableNotificationsBanner($event->sender);
}
}
/**
* After login: show the enable-notifications banner once per login session, on the
* first full page the user reaches after all user gates (legal confirmation, 2FA check,
* forced password change, ...) are closed. The session flag set by onAfterLogin is
* consumed here, so the banner never comes back during this login, whether the user
* enabled notifications, closed it or just navigated away.
* Whether the banner is actually visible is decided in the browser: only when the
* Notification API exists, permission has not been decided yet and the user has not
* dismissed the banner with "No thanks" recently (see EnableNotificationsBanner).
*/
private static function addEnableNotificationsBanner(LayoutAddons $layoutAddons): void
{
if (!Yii::$app->session->has(WebAppHelper::SESSION_VAR_SHOW_ENABLE_NOTIFICATIONS_BANNER)) {
return;
}
// Native apps register tokens through the Flutter bridge (MobileAppHelper), not the
// browser Notification API. PJAX responses do not render layout addons anyway.
if (DeviceDetectorHelper::isAppRequest() || Yii::$app->request->isPjax) {
return;
}
/** @var Module $module */
$module = Yii::$app->getModule('fcm-push');
if (!$module->getDriverService()->hasConfiguredWebDriver()) {
Yii::$app->session->remove(WebAppHelper::SESSION_VAR_SHOW_ENABLE_NOTIFICATIONS_BANNER);
return;
}
// Keep the flag while a gate is open: the gate page itself must not show the banner,
// the first regular page after the gate flow does.
if (Yii::$app->gateManager->hasOpenGate()) {
return;
}
Yii::$app->session->remove(WebAppHelper::SESSION_VAR_SHOW_ENABLE_NOTIFICATIONS_BANNER);
$layoutAddons->addWidget(EnableNotificationsBanner::class);
}
private static function registerAssets()
{
/** @var Module $module */
$module = Yii::$app->getModule('fcm-push');
if (!$module->getDriverService()->hasConfiguredWebDriver()) {
return;
}
FcmPushAsset::register(Yii::$app->view);
FirebaseAsset::register(Yii::$app->view);
}
public static function onAfterLogin()
{
Yii::$app->session->set(MobileAppHelper::SESSION_VAR_REGISTER_NOTIFICATION, 1);
Yii::$app->session->set(WebAppHelper::SESSION_VAR_SHOW_ENABLE_NOTIFICATIONS_BANNER, 1);
}
public static function onAfterLogout()
{
Yii::$app->session->set(WebAppHelper::SESSION_VAR_UNREGISTER_NOTIFICATION, 1);
Yii::$app->session->set(MobileAppHelper::SESSION_VAR_UNREGISTER_NOTIFICATION, 1);
}
public static function onNotificationSettingsFormAfterRun(WidgetEvent $event)
{
/** @var NotificationSettingsForm $form */
$form = $event->sender;
if ($form->model->user) { // Only show the button for User settings (not admin settings)
$event->result = RegisterDeviceTokenButton::widget() . $event->result;
}
}
/**
* Pushes a delayed, exclusive-per-user job that sends the updated unread notification
* count as a silent push to the user's devices, whenever the count changed.
*
* The delay collapses multiple count changes within a short time frame into a single
* push carrying the final count
*/
public static function onUnreadCountChanged(UnreadCountChangedEvent $event): void
{
/** @var Module $module */
$module = Yii::$app->getModule('fcm-push');
if (!$module->getDriverService()->hasConfiguredDriver()) {
return;
}
Yii::$app->queue->delay($module->silentUnreadNotificationCountPushDelay)->push(new SendSilentUnreadNotificationCountJob([
'userId' => $event->user->id,
]));
}
}