Merge pull request #4657 from tsiegleauq/service-worker-addons
Service Worker Updates
This commit is contained in:
commit
e1b8e74e8d
@ -5,21 +5,15 @@
|
|||||||
"name": "app",
|
"name": "app",
|
||||||
"installMode": "prefetch",
|
"installMode": "prefetch",
|
||||||
"resources": {
|
"resources": {
|
||||||
"files": [
|
"files": ["/favicon.png", "/index.html", "/*.css", "/*.js"]
|
||||||
"/favicon.png",
|
|
||||||
"/index.html",
|
|
||||||
"/*.css",
|
|
||||||
"/*.js"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"name": "assets",
|
"name": "assets",
|
||||||
"installMode": "lazy",
|
"installMode": "lazy",
|
||||||
"updateMode": "prefetch",
|
"updateMode": "prefetch",
|
||||||
"resources": {
|
"resources": {
|
||||||
"files": [
|
"files": ["/assets/**"]
|
||||||
"/assets/**"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -12,6 +12,7 @@ import { OperatorService } from './core/core-services/operator.service';
|
|||||||
import { ServertimeService } from './core/core-services/servertime.service';
|
import { ServertimeService } from './core/core-services/servertime.service';
|
||||||
import { ThemeService } from './core/ui-services/theme.service';
|
import { ThemeService } from './core/ui-services/theme.service';
|
||||||
import { DataStoreUpgradeService } from './core/core-services/data-store-upgrade.service';
|
import { DataStoreUpgradeService } from './core/core-services/data-store-upgrade.service';
|
||||||
|
import { UpdateService } from './core/ui-services/update.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Angular's global App Component
|
* Angular's global App Component
|
||||||
@ -38,6 +39,8 @@ export class AppComponent {
|
|||||||
* @param countUsersService to call the constructor of the CountUserService
|
* @param countUsersService to call the constructor of the CountUserService
|
||||||
* @param configService to call the constructor of the ConfigService
|
* @param configService to call the constructor of the ConfigService
|
||||||
* @param loadFontService to call the constructor of the LoadFontService
|
* @param loadFontService to call the constructor of the LoadFontService
|
||||||
|
* @param dataStoreUpgradeService
|
||||||
|
* @param update Service Worker Updates
|
||||||
*/
|
*/
|
||||||
public constructor(
|
public constructor(
|
||||||
translate: TranslateService,
|
translate: TranslateService,
|
||||||
@ -50,7 +53,8 @@ export class AppComponent {
|
|||||||
countUsersService: CountUsersService, // Needed to register itself.
|
countUsersService: CountUsersService, // Needed to register itself.
|
||||||
configService: ConfigService,
|
configService: ConfigService,
|
||||||
loadFontService: LoadFontService,
|
loadFontService: LoadFontService,
|
||||||
dataStoreUpgradeService: DataStoreUpgradeService // to start it.
|
dataStoreUpgradeService: DataStoreUpgradeService, // to start it.
|
||||||
|
update: UpdateService
|
||||||
) {
|
) {
|
||||||
// manually add the supported languages
|
// manually add the supported languages
|
||||||
translate.addLangs(['en', 'de', 'cs']);
|
translate.addLangs(['en', 'de', 'cs']);
|
||||||
|
18
client/src/app/core/ui-services/update.service.spec.ts
Normal file
18
client/src/app/core/ui-services/update.service.spec.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { UpdateService } from './update.service';
|
||||||
|
import { E2EImportsModule } from 'e2e-imports.module';
|
||||||
|
|
||||||
|
describe('UpdateService', () => {
|
||||||
|
beforeEach(() =>
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [E2EImportsModule],
|
||||||
|
providers: [UpdateService]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
const service: UpdateService = TestBed.get(UpdateService);
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
61
client/src/app/core/ui-services/update.service.ts
Normal file
61
client/src/app/core/ui-services/update.service.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
import { SwUpdate } from '@angular/service-worker';
|
||||||
|
import { MatSnackBar } from '@angular/material';
|
||||||
|
import { NotifyService } from '../core-services/notify.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle Service Worker updates using the SwUpdate service form angular.
|
||||||
|
*/
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class UpdateService {
|
||||||
|
private static NOTIFY_NAME = 'swCheckForUpdate';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
* Listens to available updates
|
||||||
|
*
|
||||||
|
* @param swUpdate Service Worker update service
|
||||||
|
* @param matSnackBar Currently to show that an update is available
|
||||||
|
*/
|
||||||
|
public constructor(private swUpdate: SwUpdate, matSnackBar: MatSnackBar, private notify: NotifyService) {
|
||||||
|
swUpdate.available.subscribe(() => {
|
||||||
|
// TODO: Find a better solution OR make an update-bar like for history mode
|
||||||
|
const ref = matSnackBar.open('A new update is available!', 'Refresh', {
|
||||||
|
duration: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
// Enforces an update
|
||||||
|
ref.onAction().subscribe(() => {
|
||||||
|
this.swUpdate.activateUpdate().then(() => {
|
||||||
|
document.location.reload();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Listen on requests from other users to check for updates.
|
||||||
|
this.notify.getMessageObservable(UpdateService.NOTIFY_NAME).subscribe(() => {
|
||||||
|
this.checkForUpdate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger that to manually check for updates
|
||||||
|
*/
|
||||||
|
public checkForUpdate(): void {
|
||||||
|
if (this.swUpdate.isEnabled) {
|
||||||
|
this.swUpdate.checkForUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits a message to all clients initiating to check for updates. This method
|
||||||
|
* can only be called by users with 'users.can_manage'. This will be checked by
|
||||||
|
* the server.
|
||||||
|
*/
|
||||||
|
public initiateUpdateCheckForAllClients(): void {
|
||||||
|
this.notify.sendToAllUsers(UpdateService.NOTIFY_NAME, {});
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
<os-head-bar [nav]=false [goBack]=true>
|
<os-head-bar [nav]="false" [goBack]="true">
|
||||||
<div class="title-slot">
|
<div class="title-slot">
|
||||||
<h2 translate>Legal notice</h2>
|
<h2 translate>Legal notice</h2>
|
||||||
</div>
|
</div>
|
||||||
@ -7,9 +7,29 @@
|
|||||||
<os-legal-notice-content></os-legal-notice-content>
|
<os-legal-notice-content></os-legal-notice-content>
|
||||||
|
|
||||||
<mat-card class="os-card">
|
<mat-card class="os-card">
|
||||||
|
<div>
|
||||||
<button type="button" mat-button (click)="resetCache()">
|
<button type="button" mat-button (click)="resetCache()">
|
||||||
<span translate>Reset cache</span>
|
<span translate>Reset cache</span>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button type="button" mat-button (click)="checkForUpdate()">
|
||||||
|
<span translate>Check for updates</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *osPerms="'users.can_manage'">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
mat-button
|
||||||
|
(click)="initiateUpdateCheckForAllClients()"
|
||||||
|
matTooltip="{{ 'This will send an update notification to all active clients' | translate }}"
|
||||||
|
>
|
||||||
|
<span translate>Initiate update check for all clients</span>
|
||||||
|
<mat-icon class="warning spacer-left-10">warning</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
|
||||||
<os-count-users></os-count-users>
|
<os-count-users></os-count-users>
|
||||||
|
@ -1,14 +1,23 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { OpenSlidesService } from 'app/core/core-services/openslides.service';
|
import { OpenSlidesService } from 'app/core/core-services/openslides.service';
|
||||||
|
import { UpdateService } from 'app/core/ui-services/update.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'os-legal-notice',
|
selector: 'os-legal-notice',
|
||||||
templateUrl: './legal-notice.component.html'
|
templateUrl: './legal-notice.component.html'
|
||||||
})
|
})
|
||||||
export class LegalNoticeComponent {
|
export class LegalNoticeComponent {
|
||||||
public constructor(private openSlidesService: OpenSlidesService) {}
|
public constructor(private openSlidesService: OpenSlidesService, private update: UpdateService) {}
|
||||||
|
|
||||||
public resetCache(): void {
|
public resetCache(): void {
|
||||||
this.openSlidesService.reset();
|
this.openSlidesService.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public checkForUpdate(): void {
|
||||||
|
this.update.checkForUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public initiateUpdateCheckForAllClients(): void {
|
||||||
|
this.update.initiateUpdateCheckForAllClients();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from typing import Any
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
from ..utils.auth import async_has_perm
|
||||||
from ..utils.constants import get_constants
|
from ..utils.constants import get_constants
|
||||||
from ..utils.projector import get_projector_data
|
from ..utils.projector import get_projector_data
|
||||||
from ..utils.websocket import (
|
from ..utils.websocket import (
|
||||||
@ -44,10 +45,25 @@ class NotifyWebsocketClientMessage(BaseWebsocketClientMessage):
|
|||||||
},
|
},
|
||||||
"required": ["name", "content"],
|
"required": ["name", "content"],
|
||||||
}
|
}
|
||||||
|
# Define a required permission for a notify message here. If the emitting user does not
|
||||||
|
# have this permission, he will get an error message in response.
|
||||||
|
notify_permissions: Dict[str, str] = {"swCheckForUpdate": "users.can_manage"}
|
||||||
|
|
||||||
async def receive_content(
|
async def receive_content(
|
||||||
self, consumer: "ProtocollAsyncJsonWebsocketConsumer", content: Any, id: str
|
self, consumer: "ProtocollAsyncJsonWebsocketConsumer", content: Any, id: str
|
||||||
) -> None:
|
) -> None:
|
||||||
|
# Check if the user is allowed to send this notify message
|
||||||
|
perm = self.notify_permissions.get(content["name"])
|
||||||
|
if perm is not None and not await async_has_perm(
|
||||||
|
consumer.scope["user"]["id"], perm
|
||||||
|
):
|
||||||
|
await consumer.send_json(
|
||||||
|
type="error",
|
||||||
|
content=f"You need '{perm}' to send this message.",
|
||||||
|
in_response=id,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Forward to all other active site consumers to handle the notify message.
|
||||||
await consumer.channel_layer.group_send(
|
await consumer.channel_layer.group_send(
|
||||||
"site",
|
"site",
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user