org cipher add/edit

This commit is contained in:
Kyle Spearrin 2018-07-05 09:42:50 -04:00
parent b97378dd40
commit f578ebe4ef
6 changed files with 127 additions and 10 deletions

2
jslib

@ -1 +1 @@
Subproject commit 278b4402da94ab36b4def76f520599a23308f7f1
Subproject commit 9b008ff382d1dd6682185cf092afbf02a83ce951

View File

@ -32,6 +32,7 @@ import { RegisterComponent } from './accounts/register.component';
import { TwoFactorOptionsComponent } from './accounts/two-factor-options.component';
import { TwoFactorComponent } from './accounts/two-factor.component';
import { AddEditComponent as OrgAddEditComponent } from './organizations/add-edit.component';
import { CiphersComponent as OrgCiphersComponent } from './organizations/ciphers.component';
import { GroupingsComponent as OrgGroupingsComponent } from './organizations/groupings.component';
import { VaultComponent as OrgVaultComponent } from './organizations/vault.component';
@ -152,6 +153,7 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
ModalComponent,
NavbarComponent,
OptionsComponent,
OrgAddEditComponent,
OrgCiphersComponent,
OrgGroupingsComponent,
OrganizationsComponent,
@ -197,6 +199,7 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
DeleteAccountComponent,
FolderAddEditComponent,
ModalComponent,
OrgAddEditComponent,
PasswordGeneratorHistoryComponent,
PurgeVaultComponent,
ShareComponent,

View File

@ -0,0 +1,73 @@
import {
Component,
OnInit,
} from '@angular/core';
import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
import { ApiService } from 'jslib/abstractions/api.service';
import { AuditService } from 'jslib/abstractions/audit.service';
import { CipherService } from 'jslib/abstractions/cipher.service';
import { FolderService } from 'jslib/abstractions/folder.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { StateService } from 'jslib/abstractions/state.service';
import { TokenService } from 'jslib/abstractions/token.service';
import { TotpService } from 'jslib/abstractions/totp.service';
import { CipherData } from 'jslib/models/data/cipherData';
import { Cipher } from 'jslib/models/domain/cipher';
import { Organization } from 'jslib/models/domain/organization';
import { CipherRequest } from 'jslib/models/request/cipherRequest';
import { AddEditComponent as BaseAddEditComponent } from '../vault/add-edit.component';
@Component({
selector: 'app-org-vault-add-edit',
templateUrl: '../vault/add-edit.component.html',
})
export class AddEditComponent extends BaseAddEditComponent implements OnInit {
organization: Organization;
constructor(cipherService: CipherService, folderService: FolderService,
i18nService: I18nService, platformUtilsService: PlatformUtilsService,
analytics: Angulartics2, toasterService: ToasterService,
auditService: AuditService, stateService: StateService,
tokenService: TokenService, totpService: TotpService,
passwordGenerationService: PasswordGenerationService, private apiService: ApiService) {
super(cipherService, folderService, i18nService, platformUtilsService, analytics,
toasterService, auditService, stateService, tokenService, totpService, passwordGenerationService);
}
protected async loadCipher() {
if (this.organization.isAdmin) {
const response = await this.apiService.getCipherAdmin(this.cipherId);
return new Cipher(new CipherData(response));
} else {
return await super.loadCipher();
}
}
protected async saveCipher(cipher: Cipher) {
if (this.organization.isAdmin) {
const request = new CipherRequest(cipher);
if (this.editMode) {
return this.apiService.putCipherAdmin(this.cipherId, request);
} else {
return this.apiService.postCipherAdmin(request);
}
} else {
return super.saveCipher(cipher);
}
}
protected async deleteCipher() {
if (this.organization.isAdmin) {
return this.apiService.deleteCipherAdmin(this.cipherId);
} else {
return super.deleteCipher();
}
}
}

View File

@ -1,8 +1,10 @@
import { Location } from '@angular/common';
import {
Component,
ComponentFactoryResolver,
OnInit,
ViewChild,
ViewContainerRef,
} from '@angular/core';
import {
ActivatedRoute,
@ -18,6 +20,9 @@ import { CipherView } from 'jslib/models/view/cipherView';
import { CipherType } from 'jslib/enums/cipherType';
import { ModalComponent } from '../modal.component';
import { AddEditComponent } from './add-edit.component';
import { CiphersComponent } from './ciphers.component';
import { GroupingsComponent } from './groupings.component';
@ -28,14 +33,18 @@ import { GroupingsComponent } from './groupings.component';
export class VaultComponent implements OnInit {
@ViewChild(GroupingsComponent) groupingsComponent: GroupingsComponent;
@ViewChild(CiphersComponent) ciphersComponent: CiphersComponent;
@ViewChild('cipherAddEdit', { read: ViewContainerRef }) cipherAddEditModalRef: ViewContainerRef;
organization: Organization;
collectionId: string;
type: CipherType;
private modal: ModalComponent = null;
constructor(private route: ActivatedRoute, private userService: UserService,
private location: Location, private router: Router,
private syncService: SyncService, private i18nService: I18nService) { }
private syncService: SyncService, private i18nService: I18nService,
private componentFactoryResolver: ComponentFactoryResolver) { }
ngOnInit() {
this.route.parent.params.subscribe(async (params) => {
@ -116,6 +125,38 @@ export class VaultComponent implements OnInit {
this.ciphersComponent.searchText = searchText;
}
addCipher() {
const component = this.editCipher(null);
component.type = this.type;
}
editCipher(cipher: CipherView) {
if (this.modal != null) {
this.modal.close();
}
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
this.modal = this.cipherAddEditModalRef.createComponent(factory).instance;
const childComponent = this.modal.show<AddEditComponent>(AddEditComponent, this.cipherAddEditModalRef);
childComponent.organization = this.organization;
childComponent.cipherId = cipher == null ? null : cipher.id;
childComponent.onSavedCipher.subscribe(async (c: CipherView) => {
this.modal.close();
await this.ciphersComponent.refresh();
});
childComponent.onDeletedCipher.subscribe(async (c: CipherView) => {
this.modal.close();
await this.ciphersComponent.refresh();
});
this.modal.onClosed.subscribe(() => {
this.modal = null;
});
return childComponent;
}
private clearFilters() {
this.collectionId = null;
this.type = null;

View File

@ -21,7 +21,7 @@
<label for="name">{{'name' | i18n}}</label>
<input id="name" class="form-control" type="text" name="Name" [(ngModel)]="cipher.name">
</div>
<div class="col-6 form-group">
<div class="col-6 form-group" *ngIf="!organization">
<label for="folder">{{'folder' | i18n}}</label>
<select id="folder" name="FolderId" [(ngModel)]="cipher.folderId" class="form-control">
<option *ngFor="let f of folders" [ngValue]="f.id">{{f.name}}</option>
@ -356,7 +356,7 @@
{{'cancel' | i18n}}
</button>
<div class="ml-auto" *ngIf="cipher">
<button appBlurClick type="button" (click)="toggleFavorite()" class="btn btn-link" title="{{(cipher.favorite ? 'unfavorite' : 'favorite') | i18n}}">
<button *ngIf="!organization" appBlurClick type="button" (click)="toggleFavorite()" class="btn btn-link" title="{{(cipher.favorite ? 'unfavorite' : 'favorite') | i18n}}">
<i class="fa fa-lg" [ngClass]="{'fa-star': cipher.favorite, 'fa-star-o': !cipher.favorite}"></i>
</button>
<button #deleteBtn appBlurClick type="button" (click)="delete()" class="btn btn-outline-danger" title="{{'delete' | i18n}}"

View File

@ -33,14 +33,14 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit {
totpSec: number;
totpLow: boolean;
private totpInterval: number;
protected totpInterval: number;
constructor(cipherService: CipherService, folderService: FolderService,
i18nService: I18nService, platformUtilsService: PlatformUtilsService,
analytics: Angulartics2, toasterService: ToasterService,
auditService: AuditService, stateService: StateService,
private tokenService: TokenService, private totpService: TotpService,
private passwordGenerationService: PasswordGenerationService) {
protected tokenService: TokenService, protected totpService: TotpService,
protected passwordGenerationService: PasswordGenerationService) {
super(cipherService, folderService, i18nService, platformUtilsService, analytics,
toasterService, auditService, stateService);
}
@ -94,13 +94,13 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit {
return confirmed;
}
private cleanUp() {
protected cleanUp() {
if (this.totpInterval) {
window.clearInterval(this.totpInterval);
}
}
private async totpUpdateCode() {
protected async totpUpdateCode() {
if (this.cipher == null || this.cipher.type !== CipherType.Login || this.cipher.login.totp == null) {
if (this.totpInterval) {
window.clearInterval(this.totpInterval);
@ -119,7 +119,7 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit {
}
}
private async totpTick() {
protected async totpTick() {
const epoch = Math.round(new Date().getTime() / 1000.0);
const mod = epoch % 30;