push service

This commit is contained in:
toni
2026-03-13 21:54:43 +01:00
parent 71ca4d81e1
commit 29c6828dd1
23 changed files with 526 additions and 137 deletions
+2
View File
@@ -44,3 +44,5 @@ Thumbs.db
###
src/app/generated-api/
src/app/services/push/vapid.json
+85 -84
View File
@@ -1,91 +1,92 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"cli": {
"packageManager": "pnpm"
},
"newProjectRoot": "projects",
"projects": {
"frontend": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular/build:application",
"options": {
"browser": "src/main.ts",
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": ["src/styles.scss"]
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kB",
"maximumError": "1MB"
},
{
"type": "anyComponentStyle",
"maximumWarning": "4kB",
"maximumError": "8kB"
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"cli": {
"packageManager": "pnpm"
},
"newProjectRoot": "projects",
"projects": {
"frontend": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
],
"outputHashing": "all",
"serviceWorker": "ngsw-config.json"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular/build:application",
"options": {
"browser": "src/main.ts",
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": ["src/styles.scss"]
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kB",
"maximumError": "1MB"
},
{
"type": "anyComponentStyle",
"maximumWarning": "4kB",
"maximumError": "8kB"
}
],
"outputHashing": "all",
"serviceWorker": "ngsw-config.json"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true,
"serviceWorker": "ngsw-config.json"
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular/build:dev-server",
"configurations": {
"production": {
"buildTarget": "frontend:build:production"
},
"development": {
"buildTarget": "frontend:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular/build:extract-i18n"
},
"test": {
"builder": "@angular/build:karma",
"options": {
"tsConfig": "tsconfig.spec.json",
"inlineStyleLanguage": "scss",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": ["src/styles.scss"]
}
}
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular/build:dev-server",
"configurations": {
"production": {
"buildTarget": "frontend:build:production"
},
"development": {
"buildTarget": "frontend:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular/build:extract-i18n"
},
"test": {
"builder": "@angular/build:karma",
"options": {
"tsConfig": "tsconfig.spec.json",
"inlineStyleLanguage": "scss",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": ["src/styles.scss"]
}
}
}
}
}
}
+2 -1
View File
@@ -42,7 +42,8 @@
"keycloak-angular": "^21.0.0",
"keycloak-js": "^26.2.3",
"rxjs": "^7.8.2",
"tslib": "^2.8.1"
"tslib": "^2.8.1",
"uuid": "^13.0.0"
},
"devDependencies": {
"@angular/build": "^21.2.1",
+1 -1
View File
@@ -86,7 +86,7 @@ export const appConfig: ApplicationConfig = {
{ provide: MAT_DATE_FORMATS, useValue: MAT_DATE_FNS_FORMATS },
{ provide: MAT_DATE_LOCALE, useValue: de },
provideServiceWorker('ngsw-worker.js', {
enabled: !isDevMode(),
enabled: true,//!isDevMode(),
registrationStrategy: 'registerWhenStable:30000',
}),
],
@@ -1,6 +1,9 @@
<h1>Testeite für interne Berechtigung</h1>
<p>API: {{apiStatus()}}</p>
<p>Auth: {{authTest()}}</p>
<button (click)="pushService.subscribeToEvents()">Subscribe</button>
<button (click)="pushService.resetSubscriptions()">Unsubscribe</button>
<button (click)="pushService.publishTestMessage()">TestMessage</button>
Claim:
<ul>
@let claims = this.auth.claims();
@@ -8,6 +8,7 @@ import {
} from '@angular/core';
import * as api from '../../generated-api/api';
import { Authentication } from '../../services/authentication';
import { PushService } from '../../services/push/pushService';
@Component({
selector: 'app-test',
@@ -17,6 +18,7 @@ import { Authentication } from '../../services/authentication';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class Test {
protected readonly pushService = inject(PushService);
protected auth = inject(Authentication);
protected apiStatus = signal<string>('Waiting');
@@ -0,0 +1,70 @@
import { inject, Injectable } from '@angular/core';
import { SwPush } from '@angular/service-worker';
import { v7 as uuidv7 } from 'uuid';
import * as api from '../../generated-api/api';
import VAPID from './vapid.json' with { type: "json" };
const SUBSCRIPTION_CLIENT_ID="subscriptionClientId";
@Injectable({providedIn: 'root'})
export class PushService{
private readonly swPush=inject(SwPush);
private arrayBufferToString(buffer: ArrayBuffer|null){
if(buffer==null){
return '';
}
let binary = '';
const bytes = new Uint8Array(buffer);
const len = bytes.length;
for(let i = 0; i< len; i++){
binary+=String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
public async subscribeToEvents(){
try{
const subscription = await this.swPush.requestSubscription({
serverPublicKey: VAPID.publicKey
});
const decoder = new TextDecoder();
const previousCliendId = localStorage.getItem(SUBSCRIPTION_CLIENT_ID);
if(previousCliendId){
try{
await api.clearSubscription(previousCliendId);
console.log("previous subscription cleared");
}catch{}
}
const newClientId= uuidv7();
await api.addSubscription({
endpoint: subscription.endpoint,
keys: {
auth: this.arrayBufferToString(subscription.getKey('auth')),
p256dh: this.arrayBufferToString(subscription.getKey('p256dh')),
},
expirationTime: subscription.expirationTime,
topic: api.Topic.Test,
topicConfiguration: null,
clientId: newClientId,
});
localStorage.setItem(SUBSCRIPTION_CLIENT_ID, newClientId);
}catch(error){
console.error("Subscribing failed: ", error);
}
}
public async resetSubscriptions(){
await this.swPush.unsubscribe();
await api.resetSubscriptions();
}
public async publishTestMessage(){
await api.publishTestMessage();
}
}