Skip to content

Commit

Permalink
Merge pull request #1103 from ORCID/update-user
Browse files Browse the repository at this point in the history
Update user
  • Loading branch information
bobcaprice authored Feb 5, 2024
2 parents e2dae53 + 67e0b60 commit 6445ebc
Show file tree
Hide file tree
Showing 12 changed files with 705 additions and 21 deletions.
1 change: 0 additions & 1 deletion ui/src/app/account/password/password.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export class PasswordComponent implements OnInit {
this.account = account
this.username = this.accountService.getUsername()
this.passwordForUsernameString = $localize`:@@password.title.string:Password for ${this.username} (You)`
console.log('username:', this.username)
})
}

Expand Down
11 changes: 11 additions & 0 deletions ui/src/app/app.constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { FormControl } from "@angular/forms";

export enum EventType {
LOG_IN_SUCCESS = 'LOG_IN_SUCCESS',
AFFILIATION_CREATED = 'AFFILIATION_CREATED',
Expand All @@ -16,3 +18,12 @@ export const DATE_FORMAT = 'YYYY-MM-DD'
export const DATE_TIME_FORMAT = 'YYYY-MM-DDTHH:mm'

export const ITEMS_PER_PAGE = 20

export function emailValidator(control: FormControl): { [key: string]: any } | null {
// eslint-disable-next-line
const emailRegexp = /^([^@\s/."'\(\)\[\]\{\}\\/,:;]+\.)*([^@\s\."\(\)\[\]\{\}\\/,:;]|(".+"))+@[^@\s\."'\(\)\[\]\{\}\\/,:;]+(\.[^@\s\."'\(\)\[\]\{\}\\/,:;]{2,})+$/;
if (control.value && !emailRegexp.test(control.value)) {
return { invalidEmail: true };
}
return null
}
8 changes: 4 additions & 4 deletions ui/src/app/member/model/member.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ export interface IMember {
superadminEnabled?: boolean
assertionServiceEnabled?: boolean
createdBy?: string
createdDate?: Moment
createdDate?: Moment | undefined | null
lastModifiedBy?: string
lastModifiedDate?: Moment
lastModifiedDate?: Moment | undefined | null
type?: string
status?: string
defaultLanguage?: string
Expand All @@ -31,9 +31,9 @@ export class Member implements IMember {
public superadminEnabled?: boolean,
public assertionServiceEnabled?: boolean,
public createdBy?: string,
public createdDate?: Moment,
public createdDate?: Moment | undefined | null,
public lastModifiedBy?: string,
public lastModifiedDate?: Moment,
public lastModifiedDate?: Moment | undefined | null,
public type?: string,
public status?: string,
public defaultLaungage?: string
Expand Down
17 changes: 17 additions & 0 deletions ui/src/app/member/service/member.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { IMember } from '../model/member.model'
import * as moment from 'moment'

type EntityResponseType = HttpResponse<IMember>
type EntityArrayResponseType = HttpResponse<IMember[]>;

@Injectable({ providedIn: 'root' })
export class MemberService {
Expand All @@ -26,6 +27,12 @@ export class MemberService {
)
}

getAllMembers(): Observable<EntityArrayResponseType> {
return this.http
.get<IMember[]>(`${this.resourceUrl}/members/list/all`, { observe: 'response' })
.pipe(map((res: EntityArrayResponseType) => this.convertDateArrayFromServer(res)));
}

getManagedMember(): Observable<string | null> {
return this.managedMember.asObservable()
}
Expand All @@ -41,4 +48,14 @@ export class MemberService {
}
return res.body
}

protected convertDateArrayFromServer(res: EntityArrayResponseType): EntityArrayResponseType {
if (res.body) {
res.body.forEach((member: IMember) => {
member.createdDate = member.createdDate != null ? moment(member.createdDate) : null;
member.lastModifiedDate = member.lastModifiedDate != null ? moment(member.lastModifiedDate) : null;
});
}
return res;
}
}
1 change: 0 additions & 1 deletion ui/src/app/user/user-detail.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { UserService } from './service/user.service'
import { MemberService } from '../member/service/member.service'
import { User } from './model/user.model'
import { of } from 'rxjs'
import { Member } from '../member/model/member.model'

describe('UserDetailComponent', () => {
let component: UserDetailComponent
Expand Down
149 changes: 149 additions & 0 deletions ui/src/app/user/user-update.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<div class="row justify-content-center">
<div class="col-8">
<form name="editForm" role="form" novalidate [formGroup]="editForm">
<h1 id="jhi-ms-user-heading" class="mt-5" i18n="@@gatewayApp.msUserServiceMSUser.home.createOrEditLabel.string">
Create or edit a User Settings
</h1>
<div>
<app-alert></app-alert>
<div class="alerts top right" role="alert" *ngIf="validation.errors && validation.errors.length > 0">
<ngb-alert
class="alert alert-danger alert-dismissible"
role="alert"
ng-reflect-type="danger"
(close)="validation.errors = null"
>
<ul class="validation-errors">
<li *ngFor="let error of validation.errors">
{{ error }}
</li>
</ul>
</ngb-alert>
</div>
<div class="form-group">
<label class="form-control-label" i18n="@@gatewayApp.msUserServiceMSUser.email.string" for="field_email"
>Login</label
>
<input type="text" class="form-control" name="email" id="field_email" formControlName="email" />
</div>
<div class="form-group">
<label
class="form-control-label"
i18n="@@gatewayApp.msUserServiceMSUser.firstName.string"
for="field_firstName.string"
>First Name</label
>
<input type="text" class="form-control" name="firstName" id="field_firstName" formControlName="firstName" />
</div>
<div class="form-group">
<label
class="form-control-label"
i18n="@@gatewayApp.msUserServiceMSUser.lastName.string"
for="field_lastName.string"
>Last Name</label
>
<input type="text" class="form-control" name="lastName" id="field_lastName" formControlName="lastName" />
</div>
<div class="form-group">
<input
type="checkbox"
class="form-control"
name="mainContact"
id="field_mainContact"
formControlName="mainContact"
(change)="validateOrgOwners()"
/>
<label
class="form-control-label"
i18n="@@gatewayApp.msUserServiceMSUser.mainContact.string"
for="field_mainContact"
>Main Contact</label
>
</div>
<div class="form-group">
<label
class="form-control-label"
i18n="@@gatewayApp.msUserServiceMSUser.salesforceId.string"
for="field_salesforceId.string"
>Salesforce Id</label
>
<fieldset [disabled]="disableSalesForceIdDD()">
<select
*ngIf="memberList.length > 0"
class="custom-select"
name="salesforceId"
id="field_salesforceId"
formControlName="salesforceId"
(change)="validateOrgOwners()"
>
<option *ngFor="let member of memberList" [ngValue]="member.salesforceId">{{ member.clientName }}</option>
</select>
</fieldset>
<fieldset [disabled]="true">
<div class="form-group">
<input
type="checkbox"
class="form-control"
name="activated"
id="field_activated"
formControlName="activated"
/>
<label
class="form-control-label"
i18n="@@gatewayApp.msUserServiceMSUser.activated.string"
for="field_activated.string"
>Activated</label
>
</div>
</fieldset>
<div class="form-group" *ngIf="showIsAdminCheckbox">
<input type="checkbox" class="form-control" name="isAdmin" id="field_isAdmin" formControlName="isAdmin" />
<label
class="form-control-label"
i18n="@@gatewayApp.msUserServiceMSUser.isAdmin.string"
for="field_isAdmin.string"
>Admin</label
>
</div>
</div>
</div>
<div class="form-group">
<button type="button" id="cancel-save" class="btn btn-outline-primary" (click)="navigateToUsersList()">
<fa-icon [icon]="faBan"></fa-icon>&nbsp;<span i18n="@@entity.action.cancel.string">Cancel</span>
</button>

<button
*ngIf="hasOwner"
jhi-ownershipChange
(then)="save()"
(else)="(false)"
type="submit"
id="save-entity"
[disabled]="editForm.invalid || isSaving || memberList.length === 0"
class="btn btn-primary"
>
<fa-icon [icon]="faSave"></fa-icon>&nbsp;<span i18n="@@entity.action.save.string">Save</span>
</button>
<button
*ngIf="!hasOwner"
(click)="save()"
type="submit"
id="save-entity2"
[disabled]="editForm.invalid || isSaving || memberList.length === 0"
class="btn btn-primary"
>
<fa-icon [icon]="faSave"></fa-icon>&nbsp;<span i18n="@@entity.action.save.string">Save</span>
</button>
<button
*ngIf="displaySendActivate()"
type="button"
(click)="sendActivate()"
class="btn btn-primary btn-sm ml-1"
>
<fa-icon [icon]="faCheckCircle"></fa-icon>
<span class="d-none d-md-inline" i18n="@@entity.action.activate.string">Activate</span>
</button>
</div>
</form>
</div>
</div>
Empty file.
145 changes: 145 additions & 0 deletions ui/src/app/user/user-update.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { of } from 'rxjs';
import { UserUpdateComponent } from './user-update.component';
import { UserService } from './service/user.service';
import { AccountService } from '../account';
import { MemberService } from '../member/service/member.service';
import { AlertService } from '../shared/service/alert.service';
import { ErrorService } from '../error/service/error.service';
import { IUser, User } from './model/user.model';
import { Member } from '../member/model/member.model';
import { UserValidation } from './model/user-validation.model';

describe('UserUpdateComponent', () => {
let component: UserUpdateComponent;
let fixture: ComponentFixture<UserUpdateComponent>;
let userService: jasmine.SpyObj<UserService>;
let accountService: jasmine.SpyObj<AccountService>;
let alertService: jasmine.SpyObj<AlertService>;
let memberService: jasmine.SpyObj<MemberService>;

beforeEach(() => {
const userServiceSpy = jasmine.createSpyObj('UserService', [
'validate',
'update',
'sendActivate',
'hasOwner',
'create',
'update'
]);
const accountServiceSpy = jasmine.createSpyObj('AccountService', [
'getAccountData',
'hasAnyAuthority',
'getSalesforceId'
]);
const alertServiceSpy = jasmine.createSpyObj('AlertService', ['broadcast']);
const memberServiceSpy = jasmine.createSpyObj('MemberService', [
'find',
]);

TestBed.configureTestingModule({
declarations: [UserUpdateComponent],
imports: [ReactiveFormsModule],
providers: [
FormBuilder,
{ provide: ActivatedRoute, useValue: { data: of({ user: {salesforceId: 'test'} as IUser }) } },
// rewrite in the same way as other services
// eslint-disable-next-line
{ provide: Router, useValue: { navigate: () => {} } },
{ provide: UserService, useValue: userServiceSpy },
{ provide: AccountService, useValue: accountServiceSpy },
{ provide: MemberService, useValue: memberServiceSpy },
{ provide: AlertService, useValue: alertServiceSpy },
{ provide: ErrorService, useValue: {} },
]
}).compileComponents();

fixture = TestBed.createComponent(UserUpdateComponent);
component = fixture.componentInstance;
userService = TestBed.inject(UserService) as jasmine.SpyObj<UserService>;
accountService = TestBed.inject(AccountService) as jasmine.SpyObj<AccountService>;
alertService = TestBed.inject(AlertService) as jasmine.SpyObj<AlertService>;
memberService = TestBed.inject(MemberService) as jasmine.SpyObj<MemberService>;

accountService.getAccountData.and.returnValue(of({
activated: true,
authorities: ['ROLE_USER'],
email: '[email protected]',
firstName: 'name',
langKey: 'en',
lastName: 'surname',
imageUrl: 'url',
salesforceId: 'sfid',
loggedAs: false,
loginAs: 'sfid',
mainContact: false,
mfaEnabled: false,
}));
userService.hasOwner.and.returnValue(of(true));
userService.validate.and.returnValue(of(new UserValidation(true, null)));
userService.update.and.returnValue(of({}));
userService.sendActivate.and.returnValue(of(new User()));
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should navigate to users list', () => {
const router = TestBed.inject(Router);
const navigateSpy = spyOn(router, 'navigate');
component.navigateToUsersList();
expect(navigateSpy).toHaveBeenCalledWith(['/users']);
});

it('should disable salesforceId dropdown for non-admin users', fakeAsync(() => {
accountService.hasAnyAuthority.and.returnValue(false);
memberService.find.and.returnValue(of(new Member()))
component.isExistentMember = true;

tick();
fixture.detectChanges();
expect(component.disableSalesForceIdDD()).toBe(true);
}));

it('should enable salesforceId dropdown for admin users', () => {
accountService.hasAnyAuthority.and.returnValue(true);
expect(component.disableSalesForceIdDD()).toBe(false);
});

it('should validate org owners', () => {
component.editForm.patchValue({ salesforceId: '123', mainContact: true });
component.validateOrgOwners();
expect(component.hasOwner).toBe(true);
expect(component.editForm.get('salesforceId')?.disabled).toBe(true);
});

/* fit('should create new user', fakeAsync(() => {
component.isExistentMember = false;
component.editForm.patchValue({salesforceId: 'sfid', email: "[email protected]", firstName: "firstName", lastName: "lastName", activated: false, })
console.log(component.editForm.value);
userService.create.and.returnValue(of(new User()))
component.save();
tick();
expect(userService.validate).toHaveBeenCalled();
expect(userService.create).toHaveBeenCalled();
})); */

it('should send activation email for existing user', fakeAsync(() => {
component.existentUser = { email: '[email protected]', activated: false } as IUser;
component.sendActivate();
tick();
expect(userService.sendActivate).toHaveBeenCalled();
}));

it('should display send activation option for existing user with unactivated email', () => {
component.existentUser = { email: '[email protected]', activated: false } as IUser;
expect(component.displaySendActivate()).toBe(true);
});

});
Loading

0 comments on commit 6445ebc

Please sign in to comment.