[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[reclaim-ui] 154/459: start extracting components
From: |
gnunet |
Subject: |
[reclaim-ui] 154/459: start extracting components |
Date: |
Fri, 11 Jun 2021 23:24:06 +0200 |
This is an automated email from the git hooks/post-receive script.
martin-schanzenbach pushed a commit to branch master
in repository reclaim-ui.
commit 624cd829967891c80a8ec3ea0b963853c56cdb42
Author: Schanzenbach, Martin <mschanzenbach@posteo.de>
AuthorDate: Tue Dec 10 17:24:36 2019 +0100
start extracting components
---
src/app/app-routing.module.ts | 4 +
src/app/app.module.ts | 6 +-
src/app/edit-identity/edit-identity.component.css | 0
src/app/edit-identity/edit-identity.component.html | 126 ++++++++
src/app/edit-identity/edit-identity.component.ts | 331 +++++++++++++++++++++
src/app/identity-list/identity-list.component.html | 169 +----------
src/app/identity-list/identity-list.component.ts | 287 +-----------------
src/app/new-identity/new-identity.component.css | 0
src/app/new-identity/new-identity.component.html | 31 ++
src/app/new-identity/new-identity.component.ts | 83 ++++++
src/app/open-id.service.ts | 6 -
11 files changed, 594 insertions(+), 449 deletions(-)
diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 699b222..30f732c 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -1,11 +1,15 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { IdentityListComponent } from
'./identity-list/identity-list.component';
+import { NewIdentityComponent } from './new-identity/new-identity.component';
+import { EditIdentityComponent } from
'./edit-identity/edit-identity.component';
const routes: Routes = [
{ path: 'index.html', component: IdentityListComponent },
// { path: 'identities', component: IdentityListComponent },
{ path: '', redirectTo: '/index.html', pathMatch: 'full' },
+ { path: 'new-identity', component: NewIdentityComponent },
+ { path: 'edit-identity/:id', component: EditIdentityComponent },
];
@NgModule({
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 99ba0ae..77d4efb 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -15,13 +15,17 @@ import { ModalComponent } from './modal.component';
import { ModalService } from './modal.service';
import { SearchPipe } from './search.pipe';
import { OpenIdService } from './open-id.service';
+import { NewIdentityComponent } from './new-identity/new-identity.component';
+import { EditIdentityComponent } from
'./edit-identity/edit-identity.component';
@NgModule({
declarations: [
AppComponent,
IdentityListComponent,
ModalComponent,
- SearchPipe
+ SearchPipe,
+ NewIdentityComponent,
+ EditIdentityComponent
],
imports: [
BrowserModule,
diff --git a/src/app/edit-identity/edit-identity.component.css
b/src/app/edit-identity/edit-identity.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/edit-identity/edit-identity.component.html
b/src/app/edit-identity/edit-identity.component.html
new file mode 100644
index 0000000..d854707
--- /dev/null
+++ b/src/app/edit-identity/edit-identity.component.html
@@ -0,0 +1,126 @@
+<!-- Identity edit screen -->
+<div class="m-2 card">
+ <div class="card-avatar card-img-top">
+ <div class="card-avatar-character text-dark">
+ Manage identity: <i>{{ identity.name }}</i>
+ </div>
+ </div>
+ <!-- Attribute table -->
+ <div class="card-body">
+ <div>
+ <h6 class="card-subtitle mb-2">Attributes:</h6>
+ <!-- Missing attributes -->
+ <table class="table pb-1" *ngIf="isAttributeMissing()">
+ <tbody>
+ <tr [class.openid]="inOpenIdFlow()"
[class.alert-danger]="newAttribute.name === missing.name" class="text-primary"
*ngFor="let missing of missingAttributes">
+ <td><div style="min-width: 15em">{{missing.name}}</div></td>
+ <td>
+ <input placeholder="Value" [(ngModel)]="missing.value">
+ </td>
+ <td>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <!-- Requested attributes -->
+ <table class="table pb-1" style="">
+ <tbody>
+ <tr [class.openid]="inOpenIdFlow()"
[class.text-primary]="isRequested(attribute)"
[class.alert-danger]="newAttribute.name === attribute.name" *ngFor="let
attribute of attributes">
+ <td><div style="min-width: 15em">{{ attribute.name }}</div></td>
+ <td>
+ <input placeholder="Value" [(ngModel)]="attribute.value">
+ </td>
+ <td>
+ <button class="btn btn-primary"
(click)="deleteAttribute(attribute)">
+ <span class="fa fa-trash"></span>
+ </button>
+ </td>
+ </tr>
+ <tr [class.alert-danger]="isInConflict(newAttribute)">
+ <td>
+ <input [class.text-danger]="!attributeNameValid(newAttribute)"
placeholder="Attribute" [(ngModel)]="newAttribute.name">
+ </td>
+ <td>
+ <input placeholder="Value"
[class.text-danger]="!attributeValueValid(newAttribute)"
[(ngModel)]="newAttribute.value">
+ </td>
+ <td>
+ <button [disabled]="!canAddAttribute(newAttribute)" class="btn
btn-primary" (click)="addAttribute(newAttribute)">
+ <span class="fa fa-plus"></span>
+ </button>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <!-- Attribute creation warning -->
+ <div *ngIf="!attributeNameValid(newAttribute) ||
!attributeValueValid(newAttribute)" class="alert alert-primary
alert-dismissible fade show" role="alert">
+ <span class="fa fa-warning"></span> Note:
+ <ul>
+ <li>Only use alphanumeric attribute names.</li>
+ <li>You cannot define the same name twice.</li>
+ <li>Attribute values may not be empty!</li>
+ </ul>
+ </div>
+ <!-- Authorized entities -->
+ <div style="margin-top: 1.5em;">
+ <table class="table pb-1" *ngIf="showTicketsIdentity">
+ <thead style="border-top-style: hidden">
+ <tr>
+ <th scope="col">
+ <h6 class="card-subtitle mb-2">
+ Authorized Entities:
+ </h6>
+ </th>
+ <th scope="col">
+ <h6 class="card-subtitle mb-2">
+ Shared attributes:
+ </h6>
+ </th>
+ <th scope="col"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let ticket of tickets">
+ <td>
+ <div style="min-width: 15em">
+ {{getAudienceName(ticket)}}
+ </div>
+ </td>
+ <td>
+ <div style="min-width: 15em">
+ {{ticketAttributeMapper[ticket.audience]}}
+ </div>
+ </td>
+ <td>
+ <button class="btn btn-primary" *ngIf="showConfirmRevoke !=
ticket" (click)="confirmRevoke(ticket)">
+ <span class="fa fa-unlink"></span> Revoke
+ </button>
+ <div class="alert alert-danger fade show"
*ngIf="showConfirmRevoke == ticket">
+ Do you really want to revoke this authorization?<br/><br/>
+ <button class="btn btn-primary m-2"
(click)="revokeTicket(ticket)">
+ <span class="fa fa-check"></span> Yes
+ </button>
+ <button class="btn btn-primary m-2"
(click)="hideConfirmRevoke()">
+ <span class="fa fa-close"></span> No
+ </button>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <!-- Edit card buttons -->
+ <div>
+ <button class="btn btn-primary" (click)="saveIdentityAttributes()"
[disabled]="!canSaveIdentity()">
+ <span class="fa fa-save"></span> Save and Back
+ </button>
+ <button *ngIf="(0 < tickets?.length) && !inOpenIdFlow()" class="btn
btn-primary" (click)="toggleShowTickets()" [style.float]="'right'">
+ <span class="fa fa-openid"></span>
+ <span *ngIf="showTicketsIdentity"> Hide</span>
+ <span *ngIf="!showTicketsIdentity"> Show</span>
+ authorizations
+ </button>
+ </div>
+ </div>
+</div>
+
diff --git a/src/app/edit-identity/edit-identity.component.ts
b/src/app/edit-identity/edit-identity.component.ts
new file mode 100644
index 0000000..8acae63
--- /dev/null
+++ b/src/app/edit-identity/edit-identity.component.ts
@@ -0,0 +1,331 @@
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { ReclaimService } from '../reclaim.service';
+import { Ticket } from '../ticket';
+import { Identity } from '../identity';
+import { GnsService } from '../gns.service';
+import { NamestoreService } from '../namestore.service';
+import { OpenIdService } from '../open-id.service';
+import { Attribute } from '../attribute';
+import { IdentityService } from '../identity.service';
+import { finalize } from 'rxjs/operators';
+import { from, forkJoin, EMPTY } from 'rxjs';
+
+@Component({
+ selector: 'app-edit-identity',
+ templateUrl: './edit-identity.component.html',
+ styleUrls: ['./edit-identity.component.css']
+})
+export class EditIdentityComponent implements OnInit {
+
+ tickets: {};
+ identity: Identity;
+ audienceNames: {};
+ showTickets: Boolean;
+ ticketAttributeMapper: {};
+ attributes: Attribute[];
+ requestedAttributes: Attribute[];
+ missingAttributes: Attribute[];
+ newAttribute: Attribute;
+ showConfirmRevoke: any;
+
+ constructor(private reclaimService: ReclaimService,
+ private identityService: IdentityService,
+ private gnsService: GnsService,
+ private oidcService: OpenIdService,
+ private namestoreService: NamestoreService,
+ private activatedRoute: ActivatedRoute,
+ private router: Router) { }
+
+ ngOnInit() {
+ this.tickets = {};
+ this.attributes = [];
+ this.showConfirmRevoke = null;
+ this.identity = new Identity('','');
+ this.newAttribute = new Attribute('', '', '', 'STRING');
+ this.ticketAttributeMapper = {};
+ this.activatedRoute.params.subscribe(p => {
+ if (p['id'] === undefined) {
+ return;
+ }
+ this.identityService.getIdentities().subscribe(
+ ids => {
+ for (let i = 0; i < ids.length; i++) {
+ if (ids[i].name == p['id']) {
+ this.identity = ids[i];
+ this.updateAttributes();
+ }
+ }
+ });
+ });
+ }
+
+ confirmRevoke(ticket) { this.showConfirmRevoke = ticket;}
+
+ hideConfirmRevoke() { this.showConfirmRevoke = null; }
+
+ private mapAudience(ticket) {
+ this.gnsService.getClientName(ticket.audience).subscribe(records => {
+ for (let i = 0; i < records.data.length; i++) {
+ if (records.data[i].record_type !== 'RECLAIM_OIDC_CLIENT') {
+ continue;
+ }
+ this.audienceNames[ticket.audience] = records.data[i].value;
+ break;
+ }
+ });
+ }
+
+ private updateTickets() {
+ this.reclaimService.getTickets(this.identity).subscribe(tickets => {
+ this.tickets = [];
+ if (tickets === null) {
+ return;
+ }
+ this.tickets = tickets;
+ tickets.forEach(ticket => {
+ this.mapAudience(ticket);
+ this.mapAttributes(ticket);
+ });
+ },
+ err => {
+ //this.errorInfos.push("Unable to retrieve tickets for identity ``" +
identity.name + "''");
+ console.log(err);
+ });
+ }
+
+ private mapAttributes(ticket) {
+ this.namestoreService.getNames(this.identity).subscribe(names => {
+ this.ticketAttributeMapper[ticket.audience] = [];
+ names = names.filter(name => name.record_name ===
ticket.rnd.toLowerCase());
+ for (let i = 0; i < names.length; i++) {
+ names[i].data.forEach(record => {
+ if (record.record_type === 'RECLAIM_ATTR_REF') {
+ this.attributes
+ .filter(attr => attr.id === record.value)
+ .map(attr => {
+ this.ticketAttributeMapper[ticket.audience].push(attr.name);
+ });
+ }
+ });
+ }
+ });
+ }
+
+ toggleShowTickets(identity) {
+ this.showTickets = !this.showTickets;
+ }
+
+ revokeTicket(ticket) {
+ this.reclaimService.revokeTicket(ticket).subscribe(
+ result => {
+ this.updateAttributes();
+ },
+ err => {
+ //this.errorInfos.push("Unable to revoke ticket.");
+ console.log(err);
+ });
+ }
+
+ private updateAttributes() {
+ this.reclaimService.getAttributes(this.identity).subscribe(attributes => {
+ this.attributes = [];
+ this.requestedAttributes = [];
+ if (attributes === null) {
+ this.getMissingAttributes();
+ return;
+ }
+ let i;
+ for (i = 0; i < attributes.length; i++) {
+ this.attributes.push(attributes[i]);
+ if (this.oidcService.getScope().includes(attributes[i].name)) {
+ this.requestedAttributes.push(attributes[i]);
+ }
+ }
+ this.getMissingAttributes();
+ this.updateTickets();
+ },
+ err => {
+ //this.errorInfos.push("Error retrieving attributes for ``" +
identity.name + "''");
+ console.log(err);
+ });
+ }
+
+ inOpenIdFlow() {
+ return this.oidcService.inOpenIdFlow();
+ }
+
+ isRequested(attribute) {
+ if (undefined === this.requestedAttributes) {
+ return false;
+ } else {
+ return -1 !==
+ this.requestedAttributes.indexOf(attribute);
+ }
+ }
+
+ getMissingAttributes() {
+ const scopes = this.oidcService.getScope();
+ let i;
+ for (i = 0; i < this.requestedAttributes.length; i++) {
+ const j =
+ scopes.indexOf(this.requestedAttributes[i].name);
+ if (j >= 0) {
+ scopes.splice(j, 1);
+ }
+ }
+ this.missingAttributes = [];
+ for (i = 0; i < scopes.length; i++) {
+ const attribute = new Attribute('', '', '', 'STRING');
+ attribute.name = scopes[i];
+ this.missingAttributes.push(attribute);
+ }
+ }
+
+ isInConflict(attribute) {
+ let i;
+ if (undefined !== this.missingAttributes) {
+ for (i = 0; i < this.missingAttributes.length; i++) {
+ if (attribute.name ===
+ this.missingAttributes[i].name) {
+ return true;
+ }
+ }
+ }
+ if (undefined !== this.attributes) {
+ for (i = 0; i < this.attributes.length; i++) {
+ if (attribute.name === this.attributes[i].name) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ canAddAttribute(attribute) {
+ if ((attribute.name === '') || (attribute.value === '')) {
+ return false;
+ }
+ if (attribute.name.indexOf(' ') >= 0) {
+ return false;
+ }
+ return !this.isInConflict(attribute);
+ }
+
+ canSaveIdentity(identity) {
+ if (this.canAddAttribute(this.newAttribute)) {
+ return true;
+ }
+ return ((this.newAttribute.name === '') &&
+ (this.newAttribute.value === '')) &&
+ !this.isInConflict(this.newAttribute);
+ }
+
+ saveIdentityAttributes() {
+ this.storeAttributes()
+ .pipe(
+ finalize(() => {
+ this.newAttribute.name = '';
+ this.newAttribute.value = '';
+ this.newAttribute.type = 'STRING';
+ }))
+ .subscribe(res => {
+ //FIXME success dialog/banner
+ this.updateAttributes();
+ this.router.navigate(['/']);
+ },
+ err => {
+ console.log(err);
+ //this.errorInfos.push("Failed to update identity ``" +
this.identityInEdit.name + "''");
+ });
+ }
+
+
+ deleteAttribute(attribute) {
+ this.reclaimService.deleteAttribute(this.identity, attribute)
+ .subscribe(res => {
+ //FIXME info dialog
+ this.updateAttributes();
+ },
+ err => {
+ //this.errorInfos.push("Failed to delete attribute ``" +
attribute.name + "''");
+ console.log(err);
+ });
+ }
+
+ private storeAttributes() {
+ const promises = [];
+ let i;
+ if (undefined !== this.missingAttributes) {
+ for (i = 0; i < this.missingAttributes.length; i++) {
+ if (this.missingAttributes[i].value === '') {
+ continue;
+ }
+ promises.push(from(this.reclaimService.addAttribute(
+ this.identity, this.missingAttributes[i])));
+ }
+ }
+ if (undefined !== this.attributes) {
+ for (i = 0; i < this.attributes.length; i++) {
+ promises.push(
+ from(this.reclaimService.addAttribute(this.identity,
this.attributes[i])));
+ }
+ }
+ if (this.newAttribute.value !== '') {
+ promises.push(from(this.reclaimService.addAttribute(this.identity,
this.newAttribute)));
+ }
+
+ return forkJoin(promises);
+ }
+
+ addAttribute() {
+ this.storeAttributes()
+ .pipe(
+ finalize(() => {
+ this.newAttribute.name = '';
+ this.newAttribute.value = '';
+ this.newAttribute.type = 'STRING';
+ this.updateAttributes;
+ }))
+ .subscribe(res => {
+ console.log(res);
+ },
+ err => {
+ console.log(err);
+ //this.errorInfos.push("Failed to update identity ``" +
this.identityInEdit.name + "''");
+ EMPTY
+ });
+ }
+
+ attributeNameValid(attribute) {
+ if (attribute.name === '' && attribute.value === '') {
+ return true;
+ }
+ if (attribute.name.indexOf(' ') >= 0) {
+ return false;
+ }
+ if (!/^[a-zA-Z0-9-]+$/.test(attribute.name)) {
+ return false;
+ }
+ return !this.isInConflict(attribute);
+ }
+
+ attributeValueValid(attribute) {
+ if (attribute.value === '') {
+ return attribute.name === '';
+ }
+ return true;
+ }
+
+ isAttributeMissing() {
+ if (!this.oidcService.inOpenIdFlow()) {
+ return false;
+ }
+ if (undefined === this.requestedAttributes) {
+ return false;
+ }
+ return this.oidcService.getScope().length !==
+ this.requestedAttributes.length;
+ }
+
+}
diff --git a/src/app/identity-list/identity-list.component.html
b/src/app/identity-list/identity-list.component.html
index 2e4c200..2329f24 100644
--- a/src/app/identity-list/identity-list.component.html
+++ b/src/app/identity-list/identity-list.component.html
@@ -65,7 +65,7 @@
<!-- Cancel authorization -->
<div style="margin-bottom: 1em; text-align: center;">
- <button *ngIf="inOpenIdFlow() && !isAddIdentity() && (null ==
identityInEdit) && clientNameFound" class="btn btn-danger mt-2"
(click)="cancelRequest()">
+ <button *ngIf="inOpenIdFlow() && clientNameFound" class="btn btn-danger
mt-2" (click)="cancelRequest()">
<span class="fa fa-ban"></span> Decline authorization request
</button>
</div>
@@ -81,146 +81,20 @@
</div>
<!-- No identities present -->
-<div *ngIf="isConnected() && 0 == identities.length && !isAddIdentity()"
style="text-align: center;" class="alert alert-secondary alert-dismissible fade
show" role="alert">
+<div *ngIf="isConnected() && 0 == identities.length" style="text-align:
center;" class="alert alert-secondary alert-dismissible fade show" role="alert">
You don't have any identities yet.<br/><br/>
<button class="btn btn-primary" (click)="addIdentity()">
<span class="fa fa-plus"></span> Add your first identity!
</button>
</div>
-<!-- Identity edit screen -->
-<div class="m-2 card" *ngIf="(null != identityInEdit) && !isAddIdentity()">
- <div class="card-avatar card-img-top">
- <div class="card-avatar-character text-dark">
- Manage identity: <i>{{ identityInEdit.name }}</i>
- </div>
- </div>
- <!-- Attribute table -->
- <div class="card-body">
- <div>
- <h6 class="card-subtitle mb-2">Attributes:</h6>
- <!-- Missing attributes -->
- <table class="table pb-1" *ngIf="isAttributeMissing(identityInEdit)">
- <tbody>
- <tr [class.openid]="inOpenIdFlow()"
[class.alert-danger]="newAttribute.name === missing.name" class="text-primary"
*ngFor="let missing of missingAttributes[identityInEdit.pubkey]">
- <td><div style="min-width: 15em">{{missing.name}}</div></td>
- <td>
- <input placeholder="Value" [(ngModel)]="missing.value">
- </td>
- <td>
- </td>
- </tr>
- </tbody>
- </table>
- <!-- Requested attributes -->
- <table class="table pb-1" style="">
- <tbody>
- <tr [class.openid]="inOpenIdFlow()"
[class.text-primary]="isRequested(identityInEdit, attribute)"
[class.alert-danger]="newAttribute.name === attribute.name" *ngFor="let
attribute of attributes[identityInEdit.pubkey]">
- <td><div style="min-width: 15em">{{attribute.name}}</div></td>
- <td>
- <input placeholder="Value" [(ngModel)]="attribute.value">
- </td>
- <td>
- <button class="btn btn-primary"
(click)="deleteAttribute(attribute)">
- <span class="fa fa-trash"></span>
- </button>
- </td>
- </tr>
- <tr [class.alert-danger]="isInConflict(identityInEdit,newAttribute)">
- <td>
- <input
[class.text-danger]="!attributeNameValid(identityInEdit,newAttribute)"
placeholder="Attribute" [(ngModel)]="newAttribute.name">
- </td>
- <td>
- <input placeholder="Value"
[class.text-danger]="!attributeValueValid(newAttribute)"
[(ngModel)]="newAttribute.value">
- </td>
- <td>
- <button
[disabled]="!canAddAttribute(identityInEdit,newAttribute)" class="btn
btn-primary" (click)="addAttribute(newAttribute)">
- <span class="fa fa-plus"></span>
- </button>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- <!-- Attribute creation warning -->
- <div *ngIf="!attributeNameValid(identityInEdit,newAttribute) ||
!attributeValueValid(newAttribute)" class="alert alert-primary
alert-dismissible fade show" role="alert">
- <span class="fa fa-warning"></span> Note:
- <ul>
- <li>Only use alphanumeric attribute names.</li>
- <li>You cannot define the same name twice.</li>
- <li>Attribute values may not be empty!</li>
- </ul>
- </div>
- <!-- Authorized entities -->
- <div style="margin-top: 1.5em;">
- <table class="table pb-1" *ngIf="identityInEdit == showTicketsIdentity">
- <thead style="border-top-style: hidden">
- <tr>
- <th scope="col">
- <h6 class="card-subtitle mb-2" *ngIf="identityInEdit ==
showTicketsIdentity">
- Authorized Entities:
- </h6>
- </th>
- <th scope="col">
- <h6 class="card-subtitle mb-2" *ngIf="identityInEdit ==
showTicketsIdentity">
- Shared attributes:
- </h6>
- </th>
- <th scope="col"></th>
- </tr>
- </thead>
- <tbody>
- <tr *ngFor="let ticket of tickets[identityInEdit.pubkey]">
- <td>
- <div style="min-width: 15em">
- {{getAudienceName(ticket)}}
- </div>
- </td>
- <td>
- <div style="min-width: 15em">
- {{ticketAttributeMapper[ticket.audience]}}
- </div>
- </td>
- <td>
- <button class="btn btn-primary" *ngIf="showConfirmRevoke !=
ticket" (click)="confirmRevoke(ticket)">
- <span class="fa fa-unlink"></span> Revoke
- </button>
- <div class="alert alert-danger fade show"
*ngIf="showConfirmRevoke == ticket">
- Do you really want to revoke this authorization?<br/><br/>
- <button class="btn btn-primary m-2"
(click)="revokeTicket(identityInEdit, ticket)">
- <span class="fa fa-check"></span> Yes
- </button>
- <button class="btn btn-primary m-2"
(click)="hideConfirmRevoke()">
- <span class="fa fa-close"></span> No
- </button>
- </div>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- <!-- Edit card buttons -->
- <div>
- <button class="btn btn-primary"
(click)="saveIdentityAttributes(identityInEdit)"
[disabled]="!canSaveIdentity(identityInEdit)">
- <span class="fa fa-save"></span> Save and Back
- </button>
- <button *ngIf="(0 < tickets[identityInEdit.pubkey]?.length) &&
!inOpenIdFlow()" class="btn btn-primary"
(click)="toggleShowTickets(identityInEdit)" [style.float]="'right'">
- <span class="fa fa-openid"></span>
- <span *ngIf="identityInEdit == showTicketsIdentity"> Hide</span>
- <span *ngIf="identityInEdit != showTicketsIdentity"> Show</span>
- authorizations
- </button>
- </div>
- </div>
-</div>
-
<!-- Identity cards -->
<!-- No match -->
<div *ngIf="canSearch()">
<div *ngIf="(identities | search: searchTerm).length == 0"
style="text-align: center;" class="alert alert-secondary alert-dismissible fade
show" role="alert">No matching identities.</div>
</div>
<!-- Cards -->
-<div class="card-columns p-2" *ngIf="(null == identityInEdit) &&
!isAddIdentity()">
+<div class="card-columns p-2">
<div class="card" *ngFor="let identity of identities | search: searchTerm">
<div class="card-avatar card-img-top">
<div class="card-avatar-character text-dark">
@@ -230,7 +104,7 @@
<button class="btn btn-primary" *ngIf="showConfirmDelete != identity"
(click)="confirmDelete(identity)">
<span class="fa fa-trash"></span>
</button>
- <button class="btn btn-primary" *ngIf="showConfirmDelete != identity"
(click)="editIdentity(identity)">
+ <button class="btn btn-primary" *ngIf="showConfirmDelete != identity"
[routerLink]="['/edit-identity', identity.name]">
<span class="fa fa-edit"></span>
</button>
</div>
@@ -265,7 +139,7 @@
<table class="table pb-1">
<tbody>
<tr [class.openid]="inOpenIdFlow()"
[class.text-primary]="isRequested(identity, attribute)"
- [class.alert-danger]="newAttribute.name === attribute.name"
*ngFor="let attribute of attributes[identity.pubkey]">
+ *ngFor="let attribute of attributes[identity.pubkey]">
<td>
<div style="min-width: 15em"><span
*ngIf="isRequested(identity, attribute)" class="fa fa-openid"></span>
{{attribute.name}}</div>
</td>
@@ -296,7 +170,7 @@
</div>
<!-- New identity card -->
- <div class="card identity-new" (click)="addIdentity()" *ngIf="0 !=
identities.length && !isAddIdentity()">
+ <div class="card identity-new" [routerLink]="['/new-identity']" *ngIf="0 !=
identities.length">
<div class="card-avatar card-img-top">
<div class="card-avatar-character text-dark">
<!--<div class="icon m-1 text-uppercase"
[style.background-color]="intToRGB(identity.pubkey)">{{
identity.name[0]}}</div>-->
@@ -315,35 +189,4 @@
</div>
</div>
-<!-- Identity creation -->
-<div *ngIf="isAddIdentity()" class="m-2 card" style="text-align:center;">
- <div class="card-avatar card-img-top">
- <div class="card-avatar-character text-dark">
- Add Identity
- </div>
- </div>
- <!-- Invalid input -->
- <div *ngIf="'' !== newIdentity.name && !canSave() && !isDuplicate()"
class="alert alert-danger alert-dismissible fade show" role="alert">
- Only Alphanumeric input. No spaces or special characters allowed.
- </div>
- <!--Identity already exists -->
- <div *ngIf="isDuplicate()" class="alert alert-warning alert-dismissible fade
show" role="alert">
- An identity with this username already exists.
- </div>
- <!-- Input text -->
- <div *ngIf="'' === newIdentity.name || canSave()" class="alert
alert-secondary alert-dismissible fade show" role="alert">
- Enter a username for your new identity
- </div>
- <div class="card-body">
- <input [class.text-danger]="'' !== newIdentity.name && !canSave()"
style="text-align: center; border: 1px solid #111;"
(keyup.enter)="saveIdentity()" pattern="^[a-zA-Z0-9-]+" placeholder="Username"
title="Only Alphanumeric input. No spaces or special characters allowed."
class="mr-2" [(ngModel)]="newIdentity.name" autofocus>
- <br/>
- <br/>
- <button [disabled]="!canSave()" [style.inactive]="!canSave()" class="-1
btn btn-primary" (click)="saveIdentity()">
- <span class="fa fa-save"></span> Save
- </button>
- <button class="m-1 btn btn-danger" (click)="cancelAddIdentity()">
- <span class="fa fa-close"></span> Cancel
- </button>
- </div>
-</div>
diff --git a/src/app/identity-list/identity-list.component.ts
b/src/app/identity-list/identity-list.component.ts
index 8417c1f..b951fc2 100644
--- a/src/app/identity-list/identity-list.component.ts
+++ b/src/app/identity-list/identity-list.component.ts
@@ -26,16 +26,9 @@ export class IdentityListComponent implements OnInit {
tickets: any;
clientName: any;
identities: Identity[];
- newIdentity: Identity;
- newAttribute: Attribute;
- identityInEdit: Identity;
- identityInEditName: string;
identityNameMapper: any;
- showTicketsIdentity: Identity;
showConfirmDelete: any;
- showConfirmRevoke: any;
connected: any;
- ticketAttributeMapper: any;
modalOpened: any;
clientNameFound: any;
errorInfos: any;
@@ -54,17 +47,13 @@ export class IdentityListComponent implements OnInit {
this.tickets = {};
this.identities = [];
this.showConfirmDelete = null;
- this.showConfirmRevoke = null;
- this.newAttribute = new Attribute('', '', '', 'STRING');
this.requestedAttributes = {};
this.missingAttributes = {};
this.clientName = '-';
this.connected = false;
- this.ticketAttributeMapper = {};
this.modalOpened = false;
this.oidcService.parseRouteParams(this.route.snapshot.queryParams);
this.getClientName();
- this.identityInEditName = '';
this.identityNameMapper = {};
this.updateIdentities();
this.errorInfos = [];
@@ -73,12 +62,9 @@ export class IdentityListComponent implements OnInit {
confirmDelete(identity) { this.showConfirmDelete = identity; }
- confirmRevoke(ticket) { this.showConfirmRevoke = ticket; }
hideConfirmDelete() { this.showConfirmDelete = null; }
- hideConfirmRevoke() { this.showConfirmRevoke = null; }
-
getClientName() {
this.clientNameFound = undefined;
this.clientName = this.oidcService.getClientId();
@@ -120,73 +106,6 @@ export class IdentityListComponent implements OnInit {
return hash;
}
- isAddIdentity() { return null != this.newIdentity; }
-
- isDuplicate() {
- for (let i = 0; i < this.identities.length; i++) {
- if (this.identities[i].name === this.newIdentity.name) {
- return true;
- }
- }
- }
-
- canSave() {
- if (this.newIdentity.name == null) {
- return false;
- }
- if (this.newIdentity.name === '') {
- return false;
- }
- if (!/^[a-zA-Z0-9-]+$/.test(this.newIdentity.name)) {
- return false;
- }
- if (this.isDuplicate()) {
- return false;
- }
- return true;
- }
-
- addIdentity() { this.newIdentity = new Identity('', ''); }
-
- editIdentity(identity) {
- this.identityInEdit = identity;
- this.showTicketsIdentity = null;
- }
-
- isInEdit(identity) { return this.identityInEdit === identity; }
-
- saveIdentityAttributes(identity) {
- this.storeAttributes(identity)
- .pipe(
- finalize(() => {
- this.identityInEdit = null;
- this.newAttribute.name = '';
- this.newAttribute.value = '';
- this.newAttribute.type = 'STRING';
- }))
- .subscribe(res => {
- //FIXME success dialog/banner
- this.identityInEdit = null;
- this.updateAttributes(identity);
- },
- err => {
- console.log(err);
- this.errorInfos.push("Failed to update identity ``" +
this.identityInEdit.name + "''");
- });
- }
-
- deleteAttribute(attribute) {
- this.reclaimService.deleteAttribute(this.identityInEdit, attribute)
- .subscribe(res => {
- //FIXME info dialog
- this.updateAttributes(this.identityInEdit);
- },
- err => {
- this.errorInfos.push("Failed to delete attribute ``" + attribute.name
+ "''");
- console.log(err);
- });
- }
-
getMissingAttributes(identity) {
const scopes = this.getScopes();
let i;
@@ -205,74 +124,6 @@ export class IdentityListComponent implements OnInit {
}
}
- private mapAudience(ticket) {
- this.gnsService.getClientName(ticket.audience).subscribe(records => {
- for (let i = 0; i < records.data.length; i++) {
- if (records.data[i].record_type !== 'RECLAIM_OIDC_CLIENT') {
- continue;
- }
- this.identityNameMapper[ticket.audience] = records.data[i].value;
- break;
- }
- });
- }
-
- private mapAttributes(identity, ticket) {
- this.namestoreService.getNames(identity).subscribe(names => {
- this.ticketAttributeMapper[ticket.audience] = [];
- names = names.filter(name => name.record_name ===
ticket.rnd.toLowerCase());
- for (let i = 0; i < names.length; i++) {
- names[i].data.forEach(record => {
- if (record.record_type === 'RECLAIM_ATTR_REF') {
- this.attributes[identity.pubkey]
- .filter(attr => attr.id === record.value)
- .map(attr => {
- this.ticketAttributeMapper[ticket.audience].push(attr.name);
- });
- }
- });
- }
- });
- }
-
- private updateTickets(identity) {
- this.reclaimService.getTickets(identity).subscribe(tickets => {
- this.tickets[identity.pubkey] = [];
- if (tickets === null) {
- return;
- }
- this.tickets[identity.pubkey] = tickets;
- tickets.forEach(ticket => {
- this.mapAudience(ticket);
- this.mapAttributes(identity, ticket);
- });
- },
- err => {
- this.errorInfos.push("Unable to retrieve tickets for identity ``" +
identity.name + "''");
- console.log(err);
- });
- }
-
- toggleShowTickets(identity) {
- if (this.showTicketsIdentity === identity) {
- this.showTicketsIdentity = null;
- return;
- }
- this.showTicketsIdentity = identity;
- }
-
- revokeTicket(identity, ticket) {
- this.reclaimService.revokeTicket(ticket).subscribe(
- result => {
- this.updateAttributes(identity);
- },
- err => {
- this.errorInfos.push("Unable to revoke ticket.");
- console.log(err);
- });
- }
-
-
private updateAttributes(identity) {
this.reclaimService.getAttributes(identity).subscribe(attributes => {
this.attributes[identity.pubkey] = [];
@@ -289,7 +140,6 @@ export class IdentityListComponent implements OnInit {
}
}
this.getMissingAttributes(identity);
- this.updateTickets(identity);
},
err => {
this.errorInfos.push("Error retrieving attributes for ``" +
identity.name + "''");
@@ -297,72 +147,10 @@ export class IdentityListComponent implements OnInit {
});
}
- private storeAttributes(identity) {
- const promises = [];
- let i;
- if (undefined !== this.missingAttributes[identity.pubkey]) {
- for (i = 0; i < this.missingAttributes[identity.pubkey].length; i++) {
- if (this.missingAttributes[identity.pubkey][i].value === '') {
- continue;
- }
- promises.push(from(this.reclaimService.addAttribute(
- identity, this.missingAttributes[identity.pubkey][i])));
- }
- }
- if (undefined !== this.attributes[identity.pubkey]) {
- for (i = 0; i < this.attributes[identity.pubkey].length; i++) {
- promises.push(
- from(this.reclaimService.addAttribute(identity,
this.attributes[identity.pubkey][i])));
- }
- }
- if (this.newAttribute.value !== '') {
- promises.push(from(this.reclaimService.addAttribute(identity,
this.newAttribute)));
- }
-
- return forkJoin(promises);
- }
-
- addAttribute() {
- this.storeAttributes(this.identityInEdit)
- .pipe(
- finalize(() => {
- this.newAttribute.name = '';
- this.newAttribute.value = '';
- this.newAttribute.type = 'STRING';
- this.updateAttributes(this.identityInEdit);
- }))
- .subscribe(res => {
- console.log(res);
- },
- err => {
- console.log(err);
- this.errorInfos.push("Failed to update identity ``" +
this.identityInEdit.name + "''");
- EMPTY
- });
- }
-
- cancelAddIdentity() { this.newIdentity = null; }
-
- saveIdentity() {
- if (!this.canSave()) {
- return;
- }
- this.identityInEditName = this.newIdentity.name;
- this.identityService.addIdentity(this.newIdentity)
- .subscribe(res => {
- this.newIdentity.name = '';
- this.updateIdentities();
- this.cancelAddIdentity();
- },
- err => {
- this.errorInfos.push("Failed adding new identity ``" +
this.newIdentity.name + "''");
- console.log(err);
- });
- }
-
+
+
deleteIdentity(identity) {
this.showConfirmDelete = false;
- this.identityInEdit = null;
this.identityService.deleteIdentity(identity.pubkey)
.subscribe(res => {
this.updateIdentities();
@@ -414,65 +202,10 @@ export class IdentityListComponent implements OnInit {
return this.oidcService.inOpenIdFlow();
}
- canAddAttribute(identity, attribute) {
- if ((attribute.name === '') || (attribute.value === '')) {
- return false;
- }
- if (attribute.name.indexOf(' ') >= 0) {
- return false;
- }
- return !this.isInConflict(identity, attribute);
- }
-
- attributeNameValid(identity, attribute) {
- if (attribute.name === '' && attribute.value === '') {
- return true;
- }
- if (attribute.name.indexOf(' ') >= 0) {
- return false;
- }
- if (!/^[a-zA-Z0-9-]+$/.test(attribute.name)) {
- return false;
- }
- return !this.isInConflict(identity, attribute);
- }
-
- attributeValueValid(attribute) {
- if (attribute.value === '') {
- return attribute.name === '';
- }
- return true;
- }
-
- canSaveIdentity(identity) {
- if (this.canAddAttribute(identity, this.newAttribute)) {
- return true;
- }
- return ((this.newAttribute.name === '') &&
- (this.newAttribute.value === '')) &&
- !this.isInConflict(identity, this.newAttribute);
- }
-
- isInConflict(identity, attribute) {
- let i;
- if (undefined !== this.missingAttributes[identity.pubkey]) {
- for (i = 0; i < this.missingAttributes[identity.pubkey].length; i++) {
- if (attribute.name ===
- this.missingAttributes[identity.pubkey][i].name) {
- return true;
- }
- }
- }
- if (undefined !== this.attributes[identity.pubkey]) {
- for (i = 0; i < this.attributes[identity.pubkey].length; i++) {
- if (attribute.name === this.attributes[identity.pubkey][i].name) {
- return true;
- }
- }
- }
- return false;
- }
-
+
+
+
+
getScopes() { return this.oidcService.getScope(); }
getScopesPretty() { return this.getScopes().join(', '); }
@@ -488,7 +221,7 @@ export class IdentityListComponent implements OnInit {
getMissingPretty(identity) { return this.getMissing(identity).join(', '); }
canAuthorize(identity) {
- return this.inOpenIdFlow() && !this.isInEdit(identity);
+ return this.inOpenIdFlow();
}
isRequested(identity, attribute) {
@@ -526,10 +259,6 @@ export class IdentityListComponent implements OnInit {
for (i = 0; i < identities.length; i++) {
this.identityNameMapper[identities[i].pubkey] = identities[i].name;
this.identities.push(identities[i]);
- if (this.identityInEditName === identities[i].name) {
- this.editIdentity(this.identities[this.identities.length - 1]);
- this.identityInEditName = '';
- }
}
identities.forEach(identity => {
@@ -557,6 +286,6 @@ export class IdentityListComponent implements OnInit {
}
canSearch() {
- return this.isConnected() && 0 != this.identities.length &&
!this.isAddIdentity() && (null == this.identityInEdit);
+ return this.isConnected() && 0 != this.identities.length;
}
}
diff --git a/src/app/new-identity/new-identity.component.css
b/src/app/new-identity/new-identity.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/new-identity/new-identity.component.html
b/src/app/new-identity/new-identity.component.html
new file mode 100644
index 0000000..4e36507
--- /dev/null
+++ b/src/app/new-identity/new-identity.component.html
@@ -0,0 +1,31 @@
+<!-- Identity creation -->
+<div class="m-2 card" style="text-align:center;">
+ <div class="card-avatar card-img-top">
+ <div class="card-avatar-character text-dark">
+ Add Identity
+ </div>
+ </div>
+ <!-- Invalid input -->
+ <div *ngIf="'' !== newIdentity.name && !canSave() && !isDuplicate()"
class="alert alert-danger alert-dismissible fade show" role="alert">
+ Only Alphanumeric input. No spaces or special characters allowed.
+ </div>
+ <!--Identity already exists -->
+ <div *ngIf="isDuplicate()" class="alert alert-warning alert-dismissible fade
show" role="alert">
+ An identity with this username already exists.
+ </div>
+ <!-- Input text -->
+ <div *ngIf="'' === newIdentity.name || canSave()" class="alert
alert-secondary alert-dismissible fade show" role="alert">
+ Enter a username for your new identity
+ </div>
+ <div class="card-body">
+ <input [class.text-danger]="'' !== newIdentity.name && !canSave()"
style="text-align: center; border: 1px solid #111;"
(keyup.enter)="saveIdentity()" pattern="^[a-zA-Z0-9-]+" placeholder="Username"
title="Only Alphanumeric input. No spaces or special characters allowed."
class="mr-2" [(ngModel)]="newIdentity.name" autofocus>
+ <br/>
+ <br/>
+ <button [disabled]="!canSave()" [style.inactive]="!canSave()" class="-1
btn btn-primary" (click)="saveIdentity()">
+ <span class="fa fa-save"></span> Save
+ </button>
+ <button class="m-1 btn btn-danger" (click)="cancelAddIdentity()">
+ <span class="fa fa-close"></span> Cancel
+ </button>
+ </div>
+</div>
diff --git a/src/app/new-identity/new-identity.component.ts
b/src/app/new-identity/new-identity.component.ts
new file mode 100644
index 0000000..bf1a87e
--- /dev/null
+++ b/src/app/new-identity/new-identity.component.ts
@@ -0,0 +1,83 @@
+import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { Identity } from '../identity';
+import { IdentityService } from '../identity.service';
+
+@Component({
+ selector: 'app-new-identity',
+ templateUrl: './new-identity.component.html',
+ styleUrls: ['./new-identity.component.css']
+})
+export class NewIdentityComponent implements OnInit {
+
+ newIdentity: Identity;
+ identities: Identity[];
+
+ constructor(private identityService: IdentityService,
+ private router: Router) { }
+
+ ngOnInit() {
+ this.identities = [];
+ this.newIdentity = new Identity('','');
+ }
+
+ private updateIdentities() {
+ this.identityService.getIdentities().subscribe(identities => {
+ this.identities = [];
+ let i;
+ for (i = 0; i < identities.length; i++) {
+ this.identities.push(identities[i]);
+ }
+ },
+ error => {
+ console.log(error);
+ //this.openModal('GnunetInfo');
+ //this.connected = false;
+ });
+ }
+
+ cancelAddIdentity() {
+ this.newIdentity.name = '';
+ this.router.navigate(['/']);
+ }
+
+ isDuplicate() {
+ for (let i = 0; i < this.identities.length; i++) {
+ if (this.identities[i].name === this.newIdentity.name) {
+ return true;
+ }
+ }
+ }
+
+ canSave() {
+ if (this.newIdentity.name == null) {
+ return false;
+ }
+ if (this.newIdentity.name === '') {
+ return false;
+ }
+ if (!/^[a-zA-Z0-9-]+$/.test(this.newIdentity.name)) {
+ return false;
+ }
+ if (this.isDuplicate()) {
+ return false;
+ }
+ return true;
+ }
+
+ saveIdentity() {
+ if (!this.canSave()) {
+ return;
+ }
+ this.identityService.addIdentity(this.newIdentity)
+ .subscribe(res => {
+ this.newIdentity.name = '';
+ this.router.navigate(['/']);
+ },
+ err => {
+ //this.errorInfos.push("Failed adding new identity ``" +
this.newIdentity.name + "''");
+ console.log(err);
+ });
+ }
+
+}
diff --git a/src/app/open-id.service.ts b/src/app/open-id.service.ts
index 6838784..5a85f35 100644
--- a/src/app/open-id.service.ts
+++ b/src/app/open-id.service.ts
@@ -47,12 +47,6 @@ export class OpenIdService {
}
inOpenIdFlow(): any {
- if (this.params['redirect_uri'] !== undefined) {
- console.log ('In OIDC flow');
- } else {
- console.log ('Not in OIDC flow');
- console.log (this.params);
- }
return this.params['redirect_uri'] !== undefined;
}
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [reclaim-ui] 160/459: hash does not work with webext, (continued)
- [reclaim-ui] 160/459: hash does not work with webext, gnunet, 2021/06/11
- [reclaim-ui] 179/459: fix, gnunet, 2021/06/11
- [reclaim-ui] 161/459: no slash, gnunet, 2021/06/11
- [reclaim-ui] 159/459: more refactoring, gnunet, 2021/06/11
- [reclaim-ui] 162/459: fix modal bug, gnunet, 2021/06/11
- [reclaim-ui] 163/459: style, gnunet, 2021/06/11
- [reclaim-ui] 158/459: fix styles; fix new and edit links, gnunet, 2021/06/11
- [reclaim-ui] 176/459: only show refs when requested, gnunet, 2021/06/11
- [reclaim-ui] 178/459: handle optional refs, gnunet, 2021/06/11
- [reclaim-ui] 184/459: fix save button, gnunet, 2021/06/11
- [reclaim-ui] 154/459: start extracting components,
gnunet <=
- [reclaim-ui] 190/459: new api, gnunet, 2021/06/11
- [reclaim-ui] 164/459: update, gnunet, 2021/06/11
- [reclaim-ui] 182/459: actually add references to request, gnunet, 2021/06/11
- [reclaim-ui] 183/459: hack constant attestation button against local IdP, gnunet, 2021/06/11
- [reclaim-ui] 165/459: minor fixes, gnunet, 2021/06/11
- [reclaim-ui] 173/459: various fixed and improvements, gnunet, 2021/06/11
- [reclaim-ui] 199/459: Merge branch 'master' of gitlab.com:reclaimid/ui, gnunet, 2021/06/11
- [reclaim-ui] 172/459: manual merge from https://gitlab.com/voggenre/ui due to refactoring, gnunet, 2021/06/11
- [reclaim-ui] 169/459: display name correctly, gnunet, 2021/06/11
- [reclaim-ui] 194/459: fix attest parsing, gnunet, 2021/06/11