diff --git a/jslib b/jslib index 9ddec9baf8b..859f317d591 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit 9ddec9baf8b6e7de58c00744eb371dc68e1b6383 +Subproject commit 859f317d59189d223072a406bc2d6924e1fb71bc diff --git a/src/app/send/add-edit.component.ts b/src/app/send/add-edit.component.ts index 406f8e34347..eb10f43208f 100644 --- a/src/app/send/add-edit.component.ts +++ b/src/app/send/add-edit.component.ts @@ -1,15 +1,7 @@ import { DatePipe } from '@angular/common'; -import { - EventEmitter, - Input, - Output, -} from '@angular/core'; - import { Component } from '@angular/core'; -import { SendType } from 'jslib/enums/sendType'; - import { EnvironmentService } from 'jslib/abstractions/environment.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; import { MessagingService } from 'jslib/abstractions/messaging.service'; @@ -17,220 +9,17 @@ import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { SendService } from 'jslib/abstractions/send.service'; import { UserService } from 'jslib/abstractions/user.service'; -import { SendFileView } from 'jslib/models/view/sendFileView'; -import { SendTextView } from 'jslib/models/view/sendTextView'; -import { SendView } from 'jslib/models/view/sendView'; - -import { Send } from 'jslib/models/domain/send'; +import { AddEditComponent as BaseAddEditComponent } from 'jslib/angular/components/send/add-edit.component'; @Component({ selector: 'app-send-add-edit', templateUrl: 'add-edit.component.html', }) -export class AddEditComponent { - @Input() sendId: string; - @Input() type: SendType; - - @Output() onSavedSend = new EventEmitter(); - @Output() onDeletedSend = new EventEmitter(); - @Output() onCancelled = new EventEmitter(); - - editMode: boolean = false; - send: SendView; - link: string; - title: string; - deletionDate: string; - expirationDate: string; - hasPassword: boolean; - password: string; - formPromise: Promise; - deletePromise: Promise; - sendType = SendType; - typeOptions: any[]; - deletionDateOptions: any[]; - expirationDateOptions: any[]; - deletionDateSelect = 168; - expirationDateSelect: number = null; - canAccessPremium = true; - premiumRequiredAlertShown = false; - - constructor(private i18nService: I18nService, private platformUtilsService: PlatformUtilsService, - private environmentService: EnvironmentService, private datePipe: DatePipe, - private sendService: SendService, private userService: UserService, - private messagingService: MessagingService) { - this.typeOptions = [ - { name: i18nService.t('sendTypeFile'), value: SendType.File }, - { name: i18nService.t('sendTypeText'), value: SendType.Text }, - ]; - this.deletionDateOptions = this.expirationDateOptions = [ - { name: i18nService.t('oneHour'), value: 1 }, - { name: i18nService.t('oneDay'), value: 24 }, - { name: i18nService.t('days', '2'), value: 48 }, - { name: i18nService.t('days', '3'), value: 72 }, - { name: i18nService.t('days', '7'), value: 168 }, - { name: i18nService.t('days', '30'), value: 720 }, - { name: i18nService.t('custom'), value: 0 }, - ]; - this.expirationDateOptions = [ - { name: i18nService.t('never'), value: null }, - ].concat([...this.deletionDateOptions]); - } - - async ngOnInit() { - await this.load(); - } - - async load() { - this.editMode = this.sendId != null; - if (this.editMode) { - this.editMode = true; - this.title = this.i18nService.t('editSend'); - } else { - this.title = this.i18nService.t('createSend'); - } - - this.canAccessPremium = await this.userService.canAccessPremium(); - if (!this.canAccessPremium) { - this.type = SendType.Text; - } - - if (this.send == null) { - if (this.editMode) { - const send = await this.loadSend(); - this.send = await send.decrypt(); - } else { - this.send = new SendView(); - this.send.type = this.type == null ? SendType.File : this.type; - this.send.file = new SendFileView(); - this.send.text = new SendTextView(); - this.send.deletionDate = new Date(); - this.send.deletionDate.setDate(this.send.deletionDate.getDate() + 7); - } - } - - this.hasPassword = this.send.password != null && this.send.password.trim() !== ''; - - // Parse dates - this.deletionDate = this.dateToString(this.send.deletionDate); - this.expirationDate = this.dateToString(this.send.expirationDate); - - if (this.editMode) { - let webVaultUrl = this.environmentService.getWebVaultUrl(); - if (webVaultUrl == null) { - webVaultUrl = 'https://vault.bitwarden.com'; - } - this.link = webVaultUrl + '/#/send/' + this.send.accessId + '/' + this.send.urlB64Key; - } - } - - async submit(): Promise { - if (this.send.name == null || this.send.name === '') { - this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), - this.i18nService.t('nameRequired')); - return false; - } - - let file: File = null; - if (this.send.type === SendType.File && !this.editMode) { - const fileEl = document.getElementById('file') as HTMLInputElement; - const files = fileEl.files; - if (files == null || files.length === 0) { - this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), - this.i18nService.t('selectFile')); - return; - } - - file = files[0]; - if (file.size > 104857600) { // 100 MB - this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), - this.i18nService.t('maxFileSize')); - return; - } - } - - if (!this.editMode) { - const now = new Date(); - if (this.deletionDateSelect > 0) { - const d = new Date(); - d.setHours(now.getHours() + this.deletionDateSelect); - this.deletionDate = this.dateToString(d); - } - if (this.expirationDateSelect != null && this.expirationDateSelect > 0) { - const d = new Date(); - d.setHours(now.getHours() + this.expirationDateSelect); - this.expirationDate = this.dateToString(d); - } - } - - const encSend = await this.encryptSend(file); - try { - this.formPromise = this.sendService.saveWithServer(encSend); - await this.formPromise; - this.send.id = encSend[0].id; - this.platformUtilsService.showToast('success', null, - this.i18nService.t(this.editMode ? 'editedSend' : 'createdSend')); - this.onSavedSend.emit(this.send); - return true; - } catch { } - - return false; - } - - clearExpiration() { - this.expirationDate = null; - } - - async delete(): Promise { - if (this.deletePromise != null) { - return; - } - const confirmed = await this.platformUtilsService.showDialog( - this.i18nService.t('deleteSendConfirmation'), - this.i18nService.t('deleteSend'), - this.i18nService.t('yes'), this.i18nService.t('no'), 'warning'); - if (!confirmed) { - return; - } - - try { - this.deletePromise = this.sendService.deleteWithServer(this.send.id); - await this.deletePromise; - this.platformUtilsService.showToast('success', null, this.i18nService.t('deletedSend')); - await this.load(); - this.onDeletedSend.emit(this.send); - } catch { } - } - - typeChanged() { - if (!this.canAccessPremium && this.send.type === SendType.File && !this.premiumRequiredAlertShown) { - this.premiumRequiredAlertShown = true; - this.messagingService.send('premiumRequired'); - } - } - - protected async loadSend(): Promise { - return this.sendService.get(this.sendId); - } - - protected async encryptSend(file: File): Promise<[Send, ArrayBuffer]> { - const sendData = await this.sendService.encrypt(this.send, file, this.password, null); - - // Parse dates - try { - sendData[0].deletionDate = this.deletionDate == null ? null : new Date(this.deletionDate); - } catch { - sendData[0].deletionDate = null; - } - try { - sendData[0].expirationDate = this.expirationDate == null ? null : new Date(this.expirationDate); - } catch { - sendData[0].expirationDate = null; - } - - return sendData; - } - - protected dateToString(d: Date) { - return d == null ? null : this.datePipe.transform(d, 'yyyy-MM-ddTHH:mm'); +export class AddEditComponent extends BaseAddEditComponent { + constructor(i18nService: I18nService, platformUtilsService: PlatformUtilsService, + environmentService: EnvironmentService, datePipe: DatePipe, + sendService: SendService, userService: UserService, + messagingService: MessagingService) { + super(i18nService, platformUtilsService, environmentService, datePipe, sendService, userService, messagingService); } } diff --git a/src/app/send/send.component.ts b/src/app/send/send.component.ts index e776f01b25c..ba78da5c677 100644 --- a/src/app/send/send.component.ts +++ b/src/app/send/send.component.ts @@ -2,20 +2,17 @@ import { Component, ComponentFactoryResolver, NgZone, - OnInit, ViewChild, ViewContainerRef, } from '@angular/core'; -import { SendType } from 'jslib/enums/sendType'; - import { SendView } from 'jslib/models/view/sendView'; import { AddEditComponent } from './add-edit.component'; +import { SendComponent as BaseSendComponent } from 'jslib/angular/components/send/send.component'; import { ModalComponent } from '../modal.component'; -import { ApiService } from 'jslib/abstractions/api.service'; import { EnvironmentService } from 'jslib/abstractions/environment.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; @@ -23,103 +20,20 @@ import { SendService } from 'jslib/abstractions/send.service'; import { BroadcasterService } from 'jslib/angular/services/broadcaster.service'; -const BroadcasterSubscriptionId = 'SendComponent'; - @Component({ selector: 'app-send', templateUrl: 'send.component.html', }) -export class SendComponent implements OnInit { +export class SendComponent extends BaseSendComponent { @ViewChild('sendAddEdit', { read: ViewContainerRef, static: true }) sendAddEditModalRef: ViewContainerRef; - sendType = SendType; - loaded = false; - loading = true; - refreshing = false; - expired: boolean = false; - type: SendType = null; - sends: SendView[] = []; - filteredSends: SendView[] = []; - searchText: string; - selectedType: SendType; - selectedAll: boolean; - searchPlaceholder: string; - filter: (cipher: SendView) => boolean; - searchPending = false; - modal: ModalComponent = null; - actionPromise: any; - private searchTimeout: any; - - constructor(private apiService: ApiService, private sendService: SendService, - private i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver, - private platformUtilsService: PlatformUtilsService, private environmentService: EnvironmentService, - private broadcasterService: BroadcasterService, private ngZone: NgZone) { } - - async ngOnInit() { - this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => { - this.ngZone.run(async () => { - switch (message.command) { - case 'syncCompleted': - if (message.successfully) { - await this.load(); - } - break; - } - }); - }); - - await this.load(); - } - - ngOnDestroy() { - this.broadcasterService.unsubscribe(BroadcasterSubscriptionId); - } - - async load(filter: (send: SendView) => boolean = null) { - this.loading = true; - const sends = await this.sendService.getAllDecrypted(); - this.sends = sends; - this.selectAll(); - this.loading = false; - this.loaded = true; - } - - async reload(filter: (send: SendView) => boolean = null) { - this.loaded = false; - this.sends = []; - await this.load(filter); - } - - async refresh() { - try { - this.refreshing = true; - await this.reload(this.filter); - } finally { - this.refreshing = false; - } - } - - async applyFilter(filter: (send: SendView) => boolean = null) { - this.filter = filter; - await this.search(null); - } - - async search(timeout: number = null) { - this.searchPending = false; - if (this.searchTimeout != null) { - clearTimeout(this.searchTimeout); - } - if (timeout == null) { - this.filteredSends = this.sends.filter((s) => this.filter == null || this.filter(s)); - return; - } - this.searchPending = true; - this.searchTimeout = setTimeout(async () => { - this.filteredSends = this.sends.filter((s) => this.filter == null || this.filter(s)); - this.searchPending = false; - }, timeout); + constructor(sendService: SendService, i18nService: I18nService, + platformUtilsService: PlatformUtilsService, environmentService: EnvironmentService, + broadcasterService: BroadcasterService, ngZone: NgZone, + private componentFactoryResolver: ComponentFactoryResolver) { + super(sendService, i18nService, platformUtilsService, environmentService, broadcasterService, ngZone); } addSend() { @@ -153,78 +67,4 @@ export class SendComponent implements OnInit { return childComponent; } - - async removePassword(s: SendView): Promise { - if (this.actionPromise != null || s.password == null) { - return; - } - const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('removePasswordConfirmation'), - this.i18nService.t('removePassword'), - this.i18nService.t('yes'), this.i18nService.t('no'), 'warning'); - if (!confirmed) { - return false; - } - - try { - this.actionPromise = this.sendService.removePasswordWithServer(s.id); - await this.actionPromise; - this.platformUtilsService.showToast('success', null, this.i18nService.t('removedPassword')); - await this.load(); - } catch { } - this.actionPromise = null; - } - - async delete(s: SendView): Promise { - if (this.actionPromise != null) { - return false; - } - const confirmed = await this.platformUtilsService.showDialog( - this.i18nService.t('deleteSendConfirmation'), - this.i18nService.t('deleteSend'), - this.i18nService.t('yes'), this.i18nService.t('no'), 'warning'); - if (!confirmed) { - return false; - } - - try { - this.actionPromise = this.sendService.deleteWithServer(s.id); - await this.actionPromise; - this.platformUtilsService.showToast('success', null, this.i18nService.t('deletedSend')); - await this.load(); - } catch { } - this.actionPromise = null; - return true; - } - - copy(s: SendView) { - let webVaultUrl = this.environmentService.getWebVaultUrl(); - if (webVaultUrl == null) { - webVaultUrl = 'https://vault.bitwarden.com'; - } - const link = webVaultUrl + '/#/send/' + s.accessId + '/' + s.urlB64Key; - this.platformUtilsService.copyToClipboard(link); - this.platformUtilsService.showToast('success', null, - this.i18nService.t('valueCopied', this.i18nService.t('sendLink'))); - } - - searchTextChanged() { - this.search(200); - } - - selectAll() { - this.clearSelections(); - this.selectedAll = true; - this.applyFilter(null); - } - - selectType(type: SendType) { - this.clearSelections(); - this.selectedType = type; - this.applyFilter((s) => s.type === type); - } - - clearSelections() { - this.selectedAll = false; - this.selectedType = null; - } }