Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create user service #217

Merged
merged 9 commits into from
Nov 2, 2020
Merged
1 change: 1 addition & 0 deletions projects/dsp-ui/src/lib/viewer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export * from './views/list-view/resource-grid/resource-grid.component';
// media representations
export * from './representation/still-image/still-image.component';
// services
export * from './services/user.service';
export * from './services/value.service';
// directives
export * from './directives/text-value-html-link.directive';
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ import {
UpdateIntValue,
UpdateResource,
UpdateValue,
UsersEndpointAdmin,
UserResponse,
ValuesEndpointV2,
WriteValueResponse
} from '@dasch-swiss/dsp-js';
import { of, throwError } from 'rxjs';
import { AsyncSubject, of, throwError } from 'rxjs';
import { AjaxError } from 'rxjs/ajax';
import { DspApiConnectionToken } from '../../../core';
import {
Expand All @@ -50,6 +50,7 @@ import {
} from '../../services/value-operation-event.service';
import { ValueService } from '../../services/value.service';
import { DisplayEditComponent } from './display-edit.component';
import { UserService } from '../../services/user.service';

@Component({
selector: `dsp-text-value-as-string`,
Expand Down Expand Up @@ -271,16 +272,15 @@ describe('DisplayEditComponent', () => {
beforeEach(async(() => {

const valuesSpyObj = {
admin: {
usersEndpoint: jasmine.createSpyObj('usersEndpoint', ['getUserByIri'])
},
v2: {
values: jasmine.createSpyObj('values', ['updateValue', 'getValue', 'deleteValue'])
}
};

const eventSpy = jasmine.createSpyObj('ValueOperationEventService', ['emit']);

const userServiceSpy = jasmine.createSpyObj('UserService', ['getUser']);

TestBed.configureTestingModule({
imports: [
BrowserAnimationsModule,
Expand Down Expand Up @@ -315,6 +315,10 @@ describe('DisplayEditComponent', () => {
provide: ValueOperationEventService,
useValue: eventSpy
},
{
provide: UserService,
useValue: userServiceSpy
},
{
provide: MAT_DIALOG_DATA,
useValue: {}
Expand All @@ -331,13 +335,18 @@ describe('DisplayEditComponent', () => {

beforeEach(() => {

const adminSpy = TestBed.inject(DspApiConnectionToken);
const userSpy = TestBed.inject(UserService);

// mock getUserByIri response
(adminSpy.admin.usersEndpoint as jasmine.SpyObj<UsersEndpointAdmin>).getUserByIri.and.callFake(
(userSpy as jasmine.SpyObj<UserService>).getUser.and.callFake(
() => {
const user = MockUsers.mockUser();
return of(user);

const subj: AsyncSubject<UserResponse> = new AsyncSubject();
subj.next(user.body);
subj.complete();

return subj;
}
);

Expand Down Expand Up @@ -464,6 +473,31 @@ describe('DisplayEditComponent', () => {
expect((testHostComponent.displayEditValueComponent.displayValueComponent as unknown as TestLinkValueComponent).parentResource instanceof ReadResource).toBe(true);
expect((testHostComponent.displayEditValueComponent.displayValueComponent as unknown as TestLinkValueComponent).propIri).toEqual('http://0.0.0.0:3333/ontology/0001/anything/v2#hasOtherThingValue');

const userServiceSpy = TestBed.inject(UserService);

expect(userServiceSpy.getUser).toHaveBeenCalledTimes(1);
expect(userServiceSpy.getUser).toHaveBeenCalledWith('http://rdfh.ch/users/BhkfBc3hTeS_IDo-JgXRbQ');

});

it('should choose the apt component for a link value (standoff link) in the template', () => {

testHostComponent.assignValue('http://0.0.0.0:3333/ontology/0001/anything/v2#hasOtherThingValue');
testHostComponent.readValue.property = Constants.KnoraApiV2 + Constants.Delimiter + 'hasStandoffLinkToValue';
testHostComponent.readValue.attachedToUser = 'http://www.knora.org/ontology/knora-admin#SystemUser'; // sstandoff links are managed by the system
testHostFixture.detectChanges();

expect(testHostComponent.displayEditValueComponent.displayValueComponent instanceof TestLinkValueComponent).toBe(true);
expect(testHostComponent.displayEditValueComponent.displayValueComponent.displayValue instanceof ReadLinkValue).toBe(true);
expect(testHostComponent.displayEditValueComponent.displayValueComponent.mode).toEqual('read');
expect((testHostComponent.displayEditValueComponent.displayValueComponent as unknown as TestLinkValueComponent).parentResource instanceof ReadResource).toBe(true);
expect((testHostComponent.displayEditValueComponent.displayValueComponent as unknown as TestLinkValueComponent).propIri).toEqual('http://api.knora.org/ontology/knora-api/v2#hasStandoffLinkToValue');

const userServiceSpy = TestBed.inject(UserService);

// user info should not be retrieved for system user
expect(userServiceSpy.getUser).toHaveBeenCalledTimes(0);

});

it('should choose the apt component for a list value in the template', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
ConfirmationDialogValueDeletionPayload
} from '../../../action/components/confirmation-dialog/confirmation-dialog.component';
import { DspApiConnectionToken } from '../../../core/core.module';
import { UserService } from '../../services/user.service';
import {
DeletedEventValue,
EmitEvent,
Expand Down Expand Up @@ -105,8 +106,9 @@ export class DisplayEditComponent implements OnInit {
constructor(
@Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection,
private _valueOperationEventService: ValueOperationEventService,
private _valueService: ValueService,
private _dialog: MatDialog) {
private _dialog: MatDialog,
private _userService: UserService,
private _valueService: ValueService,) {
}

ngOnInit() {
Expand All @@ -128,19 +130,23 @@ export class DisplayEditComponent implements OnInit {

this.readOnlyValue = this._valueService.isReadOnly(this.valueTypeOrClass, this.displayValue);

this._dspApiConnection.admin.usersEndpoint.getUserByIri(this.displayValue.attachedToUser).subscribe(
(response: ApiResponseData<UserResponse>) => {
this.user = response.body.user;
},
(error: ApiResponseError) => {
console.error(error);
}
);
// prevent getting info about system user (standoff link values are managed by the system)
if (this.displayValue.attachedToUser !== 'http://www.knora.org/ontology/knora-admin#SystemUser') {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdelez This prevents requesting user info for the system user. Is this fine (the user prop) remains undefined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The info box does not work properly for the system user:

Screenshot 2020-11-02 at 14 28 12

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 089c5af

this._userService.getUser(this.displayValue.attachedToUser).subscribe(
user => {
this.user = user.user;
}
);
}
}

getTooltipText(): string {
return 'Creation date: ' + this.displayValue.valueCreationDate +
'\n Value creator: ' + this.user?.givenName + ' ' + this.user?.familyName;
const creationDate = 'Creation date: ' + this.displayValue.valueCreationDate;

const creatorInfo = this.user ? '\n Value creator: ' + this.user.givenName + ' ' + this.user.familyName : '';


return creationDate + creatorInfo;
}

/**
Expand Down
53 changes: 53 additions & 0 deletions projects/dsp-ui/src/lib/viewer/services/user.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { async, TestBed } from '@angular/core/testing';
import { MockUsers, UserResponse } from '@dasch-swiss/dsp-js';
import { AsyncSubject } from 'rxjs';
import { DspApiConnectionToken } from '../../core/core.module';
import { UserService } from './user.service';

describe('UserService', () => {
let service: UserService;

beforeEach(async(() => {
TestBed.configureTestingModule({
providers: [
{
provide: DspApiConnectionToken,
useValue: {}
}
]
});

service = TestBed.inject(UserService);
}));

it('should be created', () => {
expect(service).toBeTruthy();
expect(service['_userCache']).toBeDefined();
});

it('should get a user', done => {

const userCacheSpy = spyOn(service['_userCache'], 'getUser').and.callFake(
() => {
const user = MockUsers.mockUser();

const subj: AsyncSubject<UserResponse> = new AsyncSubject();
subj.next(user.body);
subj.complete();

return subj;
}
);

service.getUser('http://rdfh.ch/users/root').subscribe(
user => {
expect(user.user.id).toEqual('http://rdfh.ch/users/root');
expect(userCacheSpy).toHaveBeenCalledTimes(1);
expect(userCacheSpy).toHaveBeenCalledWith('http://rdfh.ch/users/root');
done();
}
);

});

});
28 changes: 28 additions & 0 deletions projects/dsp-ui/src/lib/viewer/services/user.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Inject, Injectable } from '@angular/core';
import { KnoraApiConnection, UserCache, UserResponse } from '@dasch-swiss/dsp-js';
import { AsyncSubject } from 'rxjs';
import { DspApiConnectionToken } from '../../core/core.module';

@Injectable({
providedIn: 'root'
})
export class UserService {

// instance of user cache
private _userCache: UserCache;

constructor(@Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection) {
// instantiate user cache
this._userCache = new UserCache(this._dspApiConnection);
}

/**
* Retrieves information about the specified user.
*
* @param userIri the Iri identifying the user.
*/
getUser(userIri: string): AsyncSubject<UserResponse> {
return this._userCache.getUser(userIri);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ import {
MockUsers,
ProjectsEndpointAdmin,
ReadResource,
UsersEndpointAdmin
UserResponse
} from '@dasch-swiss/dsp-js';
import { DspApiConnectionToken } from 'projects/dsp-ui/src/lib/core';
import { AsyncSubject } from 'rxjs';
import { of } from 'rxjs/internal/observable/of';
import { UserService } from '../../../services/user.service';
import { PropertyToolbarComponent } from './property-toolbar.component';

/**
Expand Down Expand Up @@ -66,11 +68,12 @@ describe('PropertyToolbarComponent', () => {

const adminSpyObj = {
admin: {
usersEndpoint: jasmine.createSpyObj('usersEndpoint', ['getUserByIri']),
projectsEndpoint: jasmine.createSpyObj('projectsEndpoint', ['getProjectByIri'])
}
};

const userServiceSpy = jasmine.createSpyObj('UserService', ['getUser']);

TestBed.configureTestingModule({
declarations: [
PropertyToolbarComponent,
Expand All @@ -88,7 +91,11 @@ describe('PropertyToolbarComponent', () => {
{
provide: DspApiConnectionToken,
useValue: adminSpyObj
}
},
{
provide: UserService,
useValue: userServiceSpy
},
]
})
.compileComponents();
Expand All @@ -105,11 +112,20 @@ describe('PropertyToolbarComponent', () => {
return of(project);
}
);

// mock getUserByIri response
(adminSpy.admin.usersEndpoint as jasmine.SpyObj<UsersEndpointAdmin>).getUserByIri.and.callFake(
const userSpy = TestBed.inject(UserService);

// mock getUserByIri response
(userSpy as jasmine.SpyObj<UserService>).getUser.and.callFake(
() => {
const user = MockUsers.mockUser();
return of(user);

const subj: AsyncSubject<UserResponse> = new AsyncSubject();
subj.next(user.body);
subj.complete();

return subj;
}
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '@dasch-swiss/dsp-js';
import { DspApiConnectionToken } from '../../../../core/core.module';
import { NotificationService } from '../../../../action';
import { UserService } from '../../../services/user.service';

@Component({
selector: 'dsp-property-toolbar',
Expand All @@ -34,7 +35,8 @@ export class PropertyToolbarComponent implements OnInit {
constructor(
@Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection,
private _notification: NotificationService,
private _snackBar: MatSnackBar
private _snackBar: MatSnackBar,
private _userService: UserService
) { }

ngOnInit() {
Expand All @@ -47,15 +49,13 @@ export class PropertyToolbarComponent implements OnInit {
this._notification.openSnackBar(error);
}
);

// get user information
this._dspApiConnection.admin.usersEndpoint.getUserByIri(this.resource.attachedToUser).subscribe(
(response: ApiResponseData<UserResponse>) => {
this.user = response.body.user;
},
(error: ApiResponseError) => {
this._notification.openSnackBar(error);
this._userService.getUser(this.resource.attachedToUser).subscribe(
user => {
this.user = user.user;
}
)
);
}


Expand Down
Loading