catchup #13
@@ -2,7 +2,6 @@ import express from "express";
|
|||||||
import {
|
import {
|
||||||
Controller,
|
Controller,
|
||||||
Get,
|
Get,
|
||||||
Post,
|
|
||||||
Request,
|
Request,
|
||||||
Route,
|
Route,
|
||||||
Security,
|
Security,
|
||||||
@@ -17,13 +16,6 @@ import { KC_SECURITY_NAME } from "../services/keycloak/user/keycloak-user.js";
|
|||||||
export class FoundEventsController extends Controller {
|
export class FoundEventsController extends Controller {
|
||||||
private readonly foundEventsService = inject(FoundEventsService);
|
private readonly foundEventsService = inject(FoundEventsService);
|
||||||
|
|
||||||
@Post("crawl")
|
|
||||||
@Security(KC_SECURITY_NAME)
|
|
||||||
@SuccessResponse("200", "OK")
|
|
||||||
public async crawl(): Promise<void> {
|
|
||||||
await this.foundEventsService.crawl();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get("future")
|
@Get("future")
|
||||||
@Security(KC_SECURITY_NAME)
|
@Security(KC_SECURITY_NAME)
|
||||||
@SuccessResponse("200", "OK")
|
@SuccessResponse("200", "OK")
|
||||||
|
|||||||
@@ -32,39 +32,13 @@ export class PushContoller extends Controller {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post("reset")
|
|
||||||
@Security(KC_SECURITY_NAME)
|
|
||||||
@SuccessResponse("200", "OK")
|
|
||||||
public async resetSubscriptions(
|
|
||||||
@Request() request: express.Request,
|
|
||||||
): Promise<void> {
|
|
||||||
return await this.pushService.reset(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Post("clearSingle")
|
@Post("clearSingle")
|
||||||
@Security(KC_SECURITY_NAME)
|
@Security(KC_SECURITY_NAME)
|
||||||
@SuccessResponse("200", "OK")
|
@SuccessResponse("200", "OK")
|
||||||
public async clearSubscription(
|
public async clearSubscription(
|
||||||
@Request() request: express.Request,
|
@Request() request: express.Request,
|
||||||
@Query() clientId: string,
|
@Query() clientId?: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.pushService.clearSubscription(clientId, request);
|
await this.pushService.clearSubscription(clientId ?? null, request);
|
||||||
}
|
|
||||||
|
|
||||||
//TODO remove
|
|
||||||
@Post("test-publish")
|
|
||||||
@Security(KC_SECURITY_NAME)
|
|
||||||
@SuccessResponse("200", "OK")
|
|
||||||
public async publishTestMessage(
|
|
||||||
@Request() request: express.Request,
|
|
||||||
): Promise<void> {
|
|
||||||
this.pushService.sendtestNotification(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO remove
|
|
||||||
@Post("notify")
|
|
||||||
@SuccessResponse("200", "OK")
|
|
||||||
public async notifyEvents(): Promise<void> {
|
|
||||||
await this.pushService.sendEventNotifications();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { Controller, Post, Route, Security, SuccessResponse } from "tsoa";
|
||||||
|
import { Claim } from "../dtos/claim.js";
|
||||||
|
import { inject } from "../infrastructure/di/index.js";
|
||||||
|
import { FoundEventsService } from "../services/foundEvents/foundEventsService.js";
|
||||||
|
import { KC_SECURITY_NAME } from "../services/keycloak/user/keycloak-user.js";
|
||||||
|
import { PushService } from "../services/push/pushService.js";
|
||||||
|
|
||||||
|
@Route("test")
|
||||||
|
export class TestContoller extends Controller {
|
||||||
|
private readonly pushService = inject(PushService);
|
||||||
|
private readonly foundEventsService = inject(FoundEventsService);
|
||||||
|
|
||||||
|
@Post("notify")
|
||||||
|
@Security(KC_SECURITY_NAME, [Claim.UserAdmin])
|
||||||
|
@SuccessResponse("200", "OK")
|
||||||
|
public async notifyEvents(): Promise<void> {
|
||||||
|
await this.pushService.sendEventNotifications();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post("crawl")
|
||||||
|
@Security(KC_SECURITY_NAME)
|
||||||
|
@SuccessResponse("200", "OK")
|
||||||
|
public async crawl(): Promise<void> {
|
||||||
|
await this.foundEventsService.crawl();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import constants from "constants";
|
import constants from "constants";
|
||||||
import cors from "cors";
|
import cors from "cors";
|
||||||
|
import { CronJob } from "cron";
|
||||||
import express, {
|
import express, {
|
||||||
type NextFunction,
|
type NextFunction,
|
||||||
type Request,
|
type Request,
|
||||||
@@ -11,7 +12,9 @@ import { RegisterRoutes } from "./generated/routes.js";
|
|||||||
import { inject } from "./infrastructure/di/injector.js";
|
import { inject } from "./infrastructure/di/injector.js";
|
||||||
import { sessionHandler } from "./infrastructure/sessionHandler.js";
|
import { sessionHandler } from "./infrastructure/sessionHandler.js";
|
||||||
import { EnvironmentService } from "./services/environmentService.js";
|
import { EnvironmentService } from "./services/environmentService.js";
|
||||||
|
import { FoundEventsService } from "./services/foundEvents/foundEventsService.js";
|
||||||
import { KeycloakUser } from "./services/keycloak/user/keycloak-user.js";
|
import { KeycloakUser } from "./services/keycloak/user/keycloak-user.js";
|
||||||
|
import { PushService } from "./services/push/pushService.js";
|
||||||
// import helmet from "helmet";
|
// import helmet from "helmet";
|
||||||
// TODO import http2 from 'http2';
|
// TODO import http2 from 'http2';
|
||||||
|
|
||||||
@@ -67,12 +70,13 @@ async function run() {
|
|||||||
// key = fs.readFileSync("src/key.pem");
|
// key = fs.readFileSync("src/key.pem");
|
||||||
|
|
||||||
port = 3000;
|
port = 3000;
|
||||||
app.listen(port, error => {
|
const server = app.listen(port, error => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error("Startup crashed:", error);
|
console.error("Startup crashed:", error);
|
||||||
}
|
}
|
||||||
console.log(`Server is running at http://localhost:${port}`);
|
console.log(`Server is running at http://localhost:${port}`);
|
||||||
});
|
});
|
||||||
|
server.on("close", () => stopCron());
|
||||||
} else {
|
} else {
|
||||||
port = 5443;
|
port = 5443;
|
||||||
const SSL_CERT_PATH = process.env["SSL_CERT_PATH"];
|
const SSL_CERT_PATH = process.env["SSL_CERT_PATH"];
|
||||||
@@ -100,17 +104,56 @@ async function run() {
|
|||||||
constants.SSL_OP_NO_SSLv2 |
|
constants.SSL_OP_NO_SSLv2 |
|
||||||
constants.SSL_OP_NO_SSLv3,
|
constants.SSL_OP_NO_SSLv3,
|
||||||
};
|
};
|
||||||
https.createServer(sslOptions, app).listen(port, () => {
|
const server = https.createServer(sslOptions, app).listen(port, () => {
|
||||||
console.log(`Server is running on port ${port}`);
|
console.log(`Server is running on port ${port}`);
|
||||||
});
|
});
|
||||||
|
server.on("close", () => stopCron());
|
||||||
}
|
}
|
||||||
|
|
||||||
// const h2SslOptions={};
|
// const h2SslOptions={};
|
||||||
// http2.createServer(h2SslOptions, app).listen(port, ()=>{
|
// http2.createServer(h2SslOptions, app).listen(port, ()=>{
|
||||||
// console.log(`HTTP/2 server is running on port ${port}`);
|
// console.log(`HTTP/2 server is running on port ${port}`);
|
||||||
// })
|
// })
|
||||||
|
initJobs();
|
||||||
|
startCron();
|
||||||
|
|
||||||
console.log("setup done");
|
console.log("setup done");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const jobs: CronJob[] = [];
|
||||||
|
|
||||||
|
function initJobs() {
|
||||||
|
const eventsService = inject(FoundEventsService);
|
||||||
|
const crawlJob = CronJob.from({
|
||||||
|
cronTime: "35 4 * * *",
|
||||||
|
onTick: async () => {
|
||||||
|
await eventsService.crawl();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
jobs.push(crawlJob);
|
||||||
|
|
||||||
|
const pushService = inject(PushService);
|
||||||
|
const notifyJob = CronJob.from({
|
||||||
|
cronTime: "10 12 * * *",
|
||||||
|
onTick: async () => {
|
||||||
|
await pushService.sendEventNotifications();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
jobs.push(notifyJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
function startCron() {
|
||||||
|
console.log("starting jobs");
|
||||||
|
for (const job of jobs) {
|
||||||
|
job.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function stopCron() {
|
||||||
|
console.log("stopping jobs");
|
||||||
|
for (const job of jobs) {
|
||||||
|
job.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
run();
|
run();
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export class FoundEventsService {
|
|||||||
maxRequestsPerMinute: 100,
|
maxRequestsPerMinute: 100,
|
||||||
maxConcurrency: 2,
|
maxConcurrency: 2,
|
||||||
requestHandler: async ({ request, page, log }) => {
|
requestHandler: async ({ request, page, log }) => {
|
||||||
if (request.retryCount > 0) return;
|
// if (request.retryCount > 0) return;
|
||||||
|
|
||||||
const label = request.label;
|
const label = request.label;
|
||||||
|
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ export async function parseTUSDetail(
|
|||||||
const aboluteUrl =
|
const aboluteUrl =
|
||||||
url != null
|
url != null
|
||||||
? isAbsolute
|
? isAbsolute
|
||||||
? new URL(url)
|
? new URL(url).toString()
|
||||||
: new URL(url, pageUrl)
|
: new URL(url, pageUrl).toString()
|
||||||
: "";
|
: "";
|
||||||
return {
|
return {
|
||||||
url: aboluteUrl,
|
url: aboluteUrl,
|
||||||
|
|||||||
@@ -134,60 +134,43 @@ export class PushService {
|
|||||||
lang: "de-DE",
|
lang: "de-DE",
|
||||||
// TODO renotify: true, re-enable when tag
|
// TODO renotify: true, re-enable when tag
|
||||||
requireInteraction: true,
|
requireInteraction: true,
|
||||||
timestamp: date?.valueOf(),
|
// timestamp: date?.valueOf(),
|
||||||
vibrate: [100],
|
vibrate: [100],
|
||||||
// TODO tag: Topic.EVENTS, implement grouping in Angular SW
|
// TODO tag: Topic.EVENTS, implement grouping in Angular SW
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const subscription of subscriptions) {
|
for (const s of subscriptions) {
|
||||||
if (
|
if (s.lastNotified && s.lastNotified >= event.foundDate) {
|
||||||
subscription.lastNotified &&
|
|
||||||
subscription.lastNotified >= event.foundDate
|
|
||||||
) {
|
|
||||||
// this subscription has already seen this event
|
// this subscription has already seen this event
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (
|
if (!this.eventMatchesFilter(event, s.topicConfiguration)) {
|
||||||
!this.eventMatchesFilter(
|
|
||||||
event,
|
|
||||||
subscription.topicConfiguration,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
// this subscription does not care for this event
|
// this subscription does not care for this event
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`sending ${subscriptions.length} test messages`);
|
|
||||||
for (const s of subscriptions) {
|
|
||||||
try {
|
try {
|
||||||
let backoff = 500;
|
let backoff = 500;
|
||||||
let retry: boolean;
|
let retry: boolean;
|
||||||
|
let maxRetry = 5;
|
||||||
do {
|
do {
|
||||||
console.log("SENDING");
|
|
||||||
console.dir("payload");
|
|
||||||
retry = await this.sendNotification(
|
retry = await this.sendNotification(
|
||||||
s,
|
s,
|
||||||
payload,
|
payload,
|
||||||
backoff,
|
backoff,
|
||||||
);
|
);
|
||||||
|
if (maxRetry <= 0) {
|
||||||
|
throw new Error("Exceeded max retry");
|
||||||
|
}
|
||||||
backoff *= 2;
|
backoff *= 2;
|
||||||
|
maxRetry--;
|
||||||
} while (retry);
|
} while (retry);
|
||||||
} catch (error) {
|
|
||||||
console.error("Cannot send notification: ", error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.db.doRequest(
|
await this.db.doRequest(
|
||||||
async prisma =>
|
async prisma =>
|
||||||
prisma.pushSubscription.updateMany({
|
prisma.pushSubscription.update({
|
||||||
where: {
|
where: {
|
||||||
id: {
|
id: s.id,
|
||||||
in: subscriptions.map(s => s.id),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
lastNotified: new Date(Date.now()),
|
lastNotified: new Date(Date.now()),
|
||||||
@@ -195,92 +178,21 @@ export class PushService {
|
|||||||
}),
|
}),
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
public async sendtestNotification(request: Request) {
|
|
||||||
const subscriptions = await this.db.doRequest(
|
|
||||||
async prisma =>
|
|
||||||
prisma.pushSubscription.findMany({ where: { topic: "TEST" } }),
|
|
||||||
request,
|
|
||||||
);
|
|
||||||
|
|
||||||
const payload: AngularPushPayload = {
|
|
||||||
notification: {
|
|
||||||
title: "ATitle",
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
action: "explode",
|
|
||||||
title: "Make Boom",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
body: "DatBod",
|
|
||||||
data: {
|
|
||||||
onActionClick: {
|
|
||||||
default: {
|
|
||||||
operation: NotificationActionOperation.OPEN_WINDOW,
|
|
||||||
},
|
|
||||||
explode: {
|
|
||||||
operation: NotificationActionOperation.OPEN_WINDOW,
|
|
||||||
url: "explode.html",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
icon: "https://taekwondo-chemnitz.toni714.de/favicon.ico",
|
|
||||||
lang: "de-DE",
|
|
||||||
renotify: true,
|
|
||||||
requireInteraction: true,
|
|
||||||
tag: "group-tag",
|
|
||||||
timestamp: Date.now(),
|
|
||||||
vibrate: [100, 50, 100],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log(`sending ${subscriptions.length} test messages`);
|
|
||||||
for (const s of subscriptions) {
|
|
||||||
const subscription: webpush.PushSubscription = {
|
|
||||||
endpoint: s.endpoint,
|
|
||||||
keys: {
|
|
||||||
auth: s.auth,
|
|
||||||
p256dh: s.p256dh,
|
|
||||||
},
|
|
||||||
expirationTime: s.expirationTime,
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
const result = await webpush.sendNotification(
|
|
||||||
subscription,
|
|
||||||
JSON.stringify(payload),
|
|
||||||
{
|
|
||||||
topic: Topic.TEST,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
console.log("success");
|
|
||||||
console.dir(result);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Cannot send notification: ", error);
|
console.error("Cannot send notification: ", error);
|
||||||
throw error;
|
// throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async reset(request: Request): Promise<void> {
|
|
||||||
const userId = await this.userService.getUid(request, request.res);
|
|
||||||
const subscriptions = await this.db.doRequest(
|
|
||||||
async prisma =>
|
|
||||||
await prisma.pushSubscription.deleteMany({
|
|
||||||
where: { userId: userId },
|
|
||||||
}),
|
|
||||||
request,
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(`deleted ${subscriptions.count} subs for ${userId}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async clearSubscription(
|
public async clearSubscription(
|
||||||
clientId: string,
|
clientId: string | null,
|
||||||
request: Request,
|
request: Request,
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
const userId = await this.userService.getUid(request, request.res);
|
const userId = await this.userService.getUid(request, request.res);
|
||||||
const batchResult = await this.db.doRequest(
|
const batchResult = clientId
|
||||||
|
? await this.db.doRequest(
|
||||||
async prisma =>
|
async prisma =>
|
||||||
await prisma.pushSubscription.deleteMany({
|
await prisma.pushSubscription.deleteMany({
|
||||||
where: {
|
where: {
|
||||||
@@ -291,6 +203,15 @@ export class PushService {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
request,
|
request,
|
||||||
|
)
|
||||||
|
: await this.db.doRequest(
|
||||||
|
async prisma =>
|
||||||
|
await prisma.pushSubscription.deleteMany({
|
||||||
|
where: {
|
||||||
|
userId: userId,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
request,
|
||||||
);
|
);
|
||||||
return batchResult.count;
|
return batchResult.count;
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 17 KiB |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "frontend",
|
"name": "TKD Club Chemnitz Datenbank",
|
||||||
"short_name": "frontend",
|
"short_name": "TCC DB",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"scope": "./",
|
"scope": "./",
|
||||||
"start_url": "./",
|
"start_url": "./",
|
||||||
@@ -40,18 +40,6 @@
|
|||||||
"sizes": "192x192",
|
"sizes": "192x192",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"purpose": "maskable any"
|
"purpose": "maskable any"
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "icons/icon-384x384.png",
|
|
||||||
"sizes": "384x384",
|
|
||||||
"type": "image/png",
|
|
||||||
"purpose": "maskable any"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "icons/icon-512x512.png",
|
|
||||||
"sizes": "512x512",
|
|
||||||
"type": "image/png",
|
|
||||||
"purpose": "maskable any"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,6 @@ export class Events implements OnInit {
|
|||||||
await this.pushService.resetSubscriptions();
|
await this.pushService.resetSubscriptions();
|
||||||
}
|
}
|
||||||
protected async subscribe() {
|
protected async subscribe() {
|
||||||
this.pushService.subscribeToEvents();
|
await this.pushService.subscribeToEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,28 @@
|
|||||||
<h1>Testeite für interne Berechtigung</h1>
|
<h1>Testeite für interne Berechtigung</h1>
|
||||||
<p>API: {{apiStatus()}}</p>
|
<p>API: {{apiStatus()}}</p>
|
||||||
<p>Auth: {{authTest()}}</p>
|
<p>Auth: {{authTest()}}</p>
|
||||||
<button (click)="pushService.subscribeToEvents()">Subscribe</button>
|
<p>Capabilities: {{pushCaps|json}}</p>
|
||||||
<button (click)="pushService.resetSubscriptions()">Unsubscribe</button>
|
<pre>More Caps: {{asyncCaps()|json}}</pre>
|
||||||
<button (click)="pushService.publishTestMessage()">TestMessage</button>
|
<button [claimGuard]="Claim.Useradmin" (click)="crawl()">Crawl</button>
|
||||||
|
<button
|
||||||
|
[claimGuard]="Claim.Useradmin"
|
||||||
|
(click)="notifyAll()"
|
||||||
|
class="secondary-btn"
|
||||||
|
matButton="filled">
|
||||||
|
Notify All
|
||||||
|
</button>
|
||||||
Claim:
|
Claim:
|
||||||
<ul>
|
<ul>
|
||||||
@let claims = this.auth.claims();
|
@let claims = this.auth.claims(); @if(claims) {
|
||||||
@if(claims) {
|
<pre>
|
||||||
<pre>
|
|
||||||
{{claims | json}}
|
{{claims | json}}
|
||||||
</pre>
|
</pre
|
||||||
|
>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
<details name="UserInfo:">
|
<details name="UserInfo:">
|
||||||
<pre>
|
<pre>
|
||||||
{{this.auth.userInfo() | json}}
|
{{this.auth.userInfo() | json}}
|
||||||
</pre>
|
</pre
|
||||||
|
>
|
||||||
</details>
|
</details>
|
||||||
|
|||||||
@@ -6,25 +6,35 @@ import {
|
|||||||
inject,
|
inject,
|
||||||
signal,
|
signal,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
import { ClaimGuardDirective } from '../../directives/claim-guard.directive';
|
||||||
import * as api from '../../generated-api/api';
|
import * as api from '../../generated-api/api';
|
||||||
import { Authentication } from '../../services/authentication';
|
import { Authentication } from '../../services/authentication';
|
||||||
import { PushService } from '../../services/push/pushService';
|
import { PushService } from '../../services/push/pushService';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-test',
|
selector: 'app-test',
|
||||||
imports: [JsonPipe],
|
imports: [JsonPipe, ClaimGuardDirective],
|
||||||
templateUrl: './test.html',
|
templateUrl: './test.html',
|
||||||
styleUrl: './test.scss',
|
styleUrl: './test.scss',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class Test {
|
export class Test {
|
||||||
protected readonly pushService = inject(PushService);
|
protected readonly pushService = inject(PushService);
|
||||||
protected auth = inject(Authentication);
|
protected readonly auth = inject(Authentication);
|
||||||
|
|
||||||
protected apiStatus = signal<string>('Waiting');
|
protected readonly apiStatus = signal<string>('Waiting');
|
||||||
protected authTest = signal<string>('Waiting');
|
protected readonly authTest = signal<string>('Waiting');
|
||||||
|
protected readonly Claim = api.Claim;
|
||||||
|
protected readonly pushCaps = {
|
||||||
|
serviceWorker: 'serviceWorker' in navigator,
|
||||||
|
pushManager: 'PushManager' in window,
|
||||||
|
notification: 'Notification' in window,
|
||||||
|
notifyPermission: Notification.permission,
|
||||||
|
};
|
||||||
|
protected asyncCaps = signal<any>(null);
|
||||||
|
|
||||||
public constructor() {
|
public constructor() {
|
||||||
|
this.loadCaps();
|
||||||
effect(() => {
|
effect(() => {
|
||||||
const loggedIn = this.auth.loggedIn();
|
const loggedIn = this.auth.loggedIn();
|
||||||
if (!loggedIn) {
|
if (!loggedIn) {
|
||||||
@@ -51,4 +61,22 @@ export class Test {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async loadCaps() {
|
||||||
|
const caps = {
|
||||||
|
registraion: await navigator.serviceWorker.getRegistrations(),
|
||||||
|
subscription: await (
|
||||||
|
await navigator.serviceWorker.ready
|
||||||
|
).pushManager.getSubscription(),
|
||||||
|
};
|
||||||
|
|
||||||
|
this.asyncCaps.set(caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async notifyAll() {
|
||||||
|
await api.notifyEvents();
|
||||||
|
}
|
||||||
|
protected async crawl() {
|
||||||
|
await api.crawl();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,16 +25,21 @@ export class PushService {
|
|||||||
|
|
||||||
public async subscribeToEvents() {
|
public async subscribeToEvents() {
|
||||||
try {
|
try {
|
||||||
|
console.log('trying to subscribe');
|
||||||
const subscription = await this.swPush.requestSubscription({
|
const subscription = await this.swPush.requestSubscription({
|
||||||
serverPublicKey: VAPID.publicKey,
|
serverPublicKey: VAPID.publicKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('returned');
|
||||||
|
console.dir(subscription);
|
||||||
|
console.log('end');
|
||||||
|
|
||||||
const previousCliendId = localStorage.getItem(
|
const previousCliendId = localStorage.getItem(
|
||||||
SUBSCRIPTION_CLIENT_ID,
|
SUBSCRIPTION_CLIENT_ID,
|
||||||
);
|
);
|
||||||
if (previousCliendId) {
|
if (previousCliendId) {
|
||||||
try {
|
try {
|
||||||
await api.clearSubscription(previousCliendId);
|
await api.clearSubscription({ clientId: previousCliendId });
|
||||||
console.log('previous subscription cleared');
|
console.log('previous subscription cleared');
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
@@ -62,11 +67,10 @@ export class PushService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async resetSubscriptions() {
|
public async resetSubscriptions() {
|
||||||
|
const clientId = localStorage.getItem(SUBSCRIPTION_CLIENT_ID);
|
||||||
await this.swPush.unsubscribe();
|
await this.swPush.unsubscribe();
|
||||||
await api.resetSubscriptions();
|
await api.clearSubscription({
|
||||||
}
|
clientId: clientId ?? undefined,
|
||||||
|
});
|
||||||
public async publishTestMessage() {
|
|
||||||
await api.publishTestMessage();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||