notification service implementation

This commit is contained in:
Kyle Spearrin 2018-08-20 22:21:13 -04:00
parent eaf08c45d9
commit 85ca10dbb3
8 changed files with 85 additions and 9 deletions

2
jslib

@ -1 +1 @@
Subproject commit b64757132faf1ebb5438bec00720c58604fd29f6
Subproject commit 50666a761dba3d2d7d880f1faf488fd9d719ea50

5
package-lock.json generated
View File

@ -96,6 +96,11 @@
"tslib": "^1.7.1"
}
},
"@aspnet/signalr": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@aspnet/signalr/-/signalr-1.0.2.tgz",
"integrity": "sha512-sXleqUCCbodCOqUA8MjLSvtAgDTvDhEq6j3JyAq/w4RMJhpZ+dXK9+6xEMbzag2hisq5e/8vDC82JYutkcOISQ=="
},
"@ngtools/webpack": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-1.10.2.tgz",

View File

@ -66,6 +66,7 @@
"@angular/platform-browser-dynamic": "5.2.0",
"@angular/router": "5.2.0",
"@angular/upgrade": "5.2.0",
"@aspnet/signalr": "1.0.2",
"angular2-toaster": "4.0.2",
"angulartics2": "5.0.1",
"bootstrap": "4.1.1",

View File

@ -31,6 +31,7 @@ import { CryptoService } from 'jslib/abstractions/crypto.service';
import { FolderService } from 'jslib/abstractions/folder.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { LockService } from 'jslib/abstractions/lock.service';
import { NotificationsService } from 'jslib/abstractions/notifications.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { SearchService } from 'jslib/abstractions/search.service';
@ -71,7 +72,8 @@ export class AppComponent implements OnDestroy, OnInit {
private platformUtilsService: PlatformUtilsService, private ngZone: NgZone,
private lockService: LockService, private storageService: StorageService,
private cryptoService: CryptoService, private collectionService: CollectionService,
private routerService: RouterService, private searchService: SearchService) { }
private routerService: RouterService, private searchService: SearchService,
private notificationsService: NotificationsService) { }
ngOnInit() {
this.ngZone.runOutsideAngular(() => {
@ -87,8 +89,10 @@ export class AppComponent implements OnDestroy, OnInit {
this.ngZone.run(async () => {
switch (message.command) {
case 'loggedIn':
case 'unlocked':
case 'loggedOut':
this.notificationsService.updateConnection();
break;
case 'unlocked':
break;
case 'logout':
this.logOut(!!message.expired);

View File

@ -209,7 +209,8 @@ export class OrganizationBillingComponent implements OnInit {
}
get isExpired() {
return this.billing != null && this.billing.expiration != null && this.billing.expiration < new Date();
return this.billing != null && this.billing.expiration != null &&
new Date(this.billing.expiration) < new Date();
}
get subscriptionMarkedForCancel() {

View File

@ -1,7 +1,10 @@
import { Location } from '@angular/common';
import {
ChangeDetectorRef,
Component,
ComponentFactoryResolver,
NgZone,
OnDestroy,
OnInit,
ViewChild,
ViewContainerRef,
@ -16,6 +19,8 @@ import { MessagingService } from 'jslib/abstractions/messaging.service';
import { SyncService } from 'jslib/abstractions/sync.service';
import { UserService } from 'jslib/abstractions/user.service';
import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
import { Organization } from 'jslib/models/domain/organization';
import { CipherView } from 'jslib/models/view/cipherView';
@ -30,11 +35,13 @@ import { CiphersComponent } from './ciphers.component';
import { CollectionsComponent } from './collections.component';
import { GroupingsComponent } from './groupings.component';
const BroadcasterSubscriptionId = 'OrgVaultComponent';
@Component({
selector: 'app-org-vault',
templateUrl: 'vault.component.html',
})
export class VaultComponent implements OnInit {
export class VaultComponent implements OnInit, OnDestroy {
@ViewChild(GroupingsComponent) groupingsComponent: GroupingsComponent;
@ViewChild(CiphersComponent) ciphersComponent: CiphersComponent;
@ViewChild('attachments', { read: ViewContainerRef }) attachmentsModalRef: ViewContainerRef;
@ -52,7 +59,9 @@ export class VaultComponent implements OnInit {
constructor(private route: ActivatedRoute, private userService: UserService,
private location: Location, private router: Router,
private syncService: SyncService, private i18nService: I18nService,
private componentFactoryResolver: ComponentFactoryResolver, private messagingService: MessagingService) { }
private componentFactoryResolver: ComponentFactoryResolver, private messagingService: MessagingService,
private broadcasterService: BroadcasterService, private ngZone: NgZone,
private changeDetectorRef: ChangeDetectorRef) { }
ngOnInit() {
this.route.parent.params.subscribe(async (params) => {
@ -65,6 +74,21 @@ export class VaultComponent implements OnInit {
this.ciphersComponent.searchText = this.groupingsComponent.searchText = qParams.search;
if (!this.organization.isAdmin) {
await this.syncService.fullSync(false);
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
this.ngZone.run(async () => {
switch (message.command) {
case 'syncCompleted':
if (message.successfully) {
await Promise.all([
this.groupingsComponent.load(),
this.ciphersComponent.refresh(),
]);
this.changeDetectorRef.detectChanges();
}
break;
}
});
});
}
await this.groupingsComponent.load();
@ -95,6 +119,10 @@ export class VaultComponent implements OnInit {
});
}
ngOnDestroy() {
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
}
async clearGroupingFilters() {
this.ciphersComponent.showAddNew = true;
this.groupingsComponent.searchPlaceholder = this.i18nService.t('searchVault');

View File

@ -38,6 +38,7 @@ import { ExportService } from 'jslib/services/export.service';
import { FolderService } from 'jslib/services/folder.service';
import { ImportService } from 'jslib/services/import.service';
import { LockService } from 'jslib/services/lock.service';
import { NotificationsService } from 'jslib/services/notifications.service';
import { PasswordGenerationService } from 'jslib/services/passwordGeneration.service';
import { SearchService } from 'jslib/services/search.service';
import { SettingsService } from 'jslib/services/settings.service';
@ -64,6 +65,7 @@ import { ImportService as ImportServiceAbstraction } from 'jslib/abstractions/im
import { LockService as LockServiceAbstraction } from 'jslib/abstractions/lock.service';
import { LogService as LogServiceAbstraction } from 'jslib/abstractions/log.service';
import { MessagingService as MessagingServiceAbstraction } from 'jslib/abstractions/messaging.service';
import { NotificationsService as NotificationsServiceAbstraction } from 'jslib/abstractions/notifications.service';
import {
PasswordGenerationService as PasswordGenerationServiceAbstraction,
} from 'jslib/abstractions/passwordGeneration.service';
@ -92,7 +94,6 @@ const tokenService = new TokenService(storageService);
const appIdService = new AppIdService(storageService);
const apiService = new ApiService(tokenService, platformUtilsService,
async (expired: boolean) => messagingService.send('logout', { expired: expired }));
const environmentService = new EnvironmentService(apiService, storageService);
const userService = new UserService(tokenService, storageService);
const settingsService = new SettingsService(userService, storageService);
export let searchService: SearchService = null;
@ -114,6 +115,9 @@ const authService = new AuthService(cryptoService, apiService,
userService, tokenService, appIdService, i18nService, platformUtilsService, messagingService);
const exportService = new ExportService(folderService, cipherService, apiService);
const importService = new ImportService(cipherService, folderService, apiService, i18nService, collectionService);
const notificationsService = new NotificationsService(userService, tokenService, syncService, appIdService,
apiService);
const environmentService = new EnvironmentService(apiService, storageService, notificationsService);
const auditService = new AuditService(cryptoFunctionService, apiService);
const analytics = new Analytics(window, () => platformUtilsService.isDev() || platformUtilsService.isSelfHost(),
@ -127,6 +131,7 @@ export function initFactory(): Function {
if (!isDev && platformUtilsService.isSelfHost()) {
environmentService.baseUrl = window.location.origin;
}
environmentService.notificationsUrl = isDev ? 'http://localhost:61840' : null;
await apiService.setUrls({
base: isDev ? null : window.location.origin,
api: isDev ? 'http://localhost:4000' : null,
@ -139,6 +144,7 @@ export function initFactory(): Function {
// api: 'https://api.bitwarden.com',
// identity: 'https://identity.bitwarden.com',
});
setTimeout(() => notificationsService.init(environmentService), 3000);
lockService.init(true);
const locale = await storageService.get<string>(ConstantsService.localeKey);
@ -194,6 +200,7 @@ export function initFactory(): Function {
{ provide: ExportServiceAbstraction, useValue: exportService },
{ provide: SearchServiceAbstraction, useValue: searchService },
{ provide: ImportServiceAbstraction, useValue: importService },
{ provide: NotificationsServiceAbstraction, useValue: notificationsService },
{ provide: CryptoFunctionServiceAbstraction, useValue: cryptoFunctionService },
{
provide: APP_INITIALIZER,

View File

@ -1,7 +1,10 @@
import { Location } from '@angular/common';
import {
ChangeDetectorRef,
Component,
ComponentFactoryResolver,
NgZone,
OnDestroy,
OnInit,
ViewChild,
ViewContainerRef,
@ -40,11 +43,15 @@ import { SyncService } from 'jslib/abstractions/sync.service';
import { TokenService } from 'jslib/abstractions/token.service';
import { UserService } from 'jslib/abstractions/user.service';
import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
const BroadcasterSubscriptionId = 'VaultComponent';
@Component({
selector: 'app-vault',
templateUrl: 'vault.component.html',
})
export class VaultComponent implements OnInit {
export class VaultComponent implements OnInit, OnDestroy {
@ViewChild(GroupingsComponent) groupingsComponent: GroupingsComponent;
@ViewChild(CiphersComponent) ciphersComponent: CiphersComponent;
@ViewChild(OrganizationsComponent) organizationsComponent: OrganizationsComponent;
@ -74,7 +81,9 @@ export class VaultComponent implements OnInit {
private i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver,
private tokenService: TokenService, private cryptoService: CryptoService,
private messagingService: MessagingService, private userService: UserService,
private platformUtilsService: PlatformUtilsService, private toasterService: ToasterService) { }
private platformUtilsService: PlatformUtilsService, private toasterService: ToasterService,
private broadcasterService: BroadcasterService, private ngZone: NgZone,
private changeDetectorRef: ChangeDetectorRef) { }
async ngOnInit() {
this.showVerifyEmail = !(await this.tokenService.getEmailVerified());
@ -85,6 +94,23 @@ export class VaultComponent implements OnInit {
this.route.queryParams.subscribe(async (params) => {
await this.syncService.fullSync(false);
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
this.ngZone.run(async () => {
switch (message.command) {
case 'syncCompleted':
if (message.successfully) {
await Promise.all([
this.groupingsComponent.load(),
this.organizationsComponent.load(),
this.ciphersComponent.refresh(),
]);
this.changeDetectorRef.detectChanges();
}
break;
}
});
});
await Promise.all([
this.groupingsComponent.load(),
this.organizationsComponent.load(),
@ -120,6 +146,10 @@ export class VaultComponent implements OnInit {
});
}
ngOnDestroy() {
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
}
async clearGroupingFilters() {
this.ciphersComponent.showAddNew = true;
this.groupingsComponent.searchPlaceholder = this.i18nService.t('searchVault');