feat(api): Reflected api-changes to different api-requests and fixed mock-api. (TV-371)

Squashed commit of the following:

commit 01ef668c8ddd8e0d8ff459d60f45ca0c7780f184
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Aug 17 11:53:36 2021 +0200

    Fixed issue with authentication

commit e40f4728203388175f405184693b3604001afc5e
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Aug 17 11:09:46 2021 +0200

    Added some more fixes to API requests based on latest changes

commit 920eb03302ee65852141f7bcce72d832507d2c07
Merge: c2d5d7c bfa8ed5
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Aug 17 09:34:48 2021 +0200

    Merge branch 'develop' into feature/TV-371-api-fix

commit c2d5d7c9a7b812a57234b0038da79bc1d0c07881
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Aug 17 07:50:11 2021 +0200

    Updated mock-api

commit 5578b0ffdba27e0e80dabe05e920b96e46331fb0
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Mon Aug 16 15:17:46 2021 +0200

    Fixed fetching of userinfo and organizations

commit 116b3092bf9a685354738146ef7cd0eb619fa009
Merge: 6a32f19 01dc4b3
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Mon Aug 16 13:09:53 2021 +0200

    Merge branch 'develop' into feature/TV-371-api-fix

commit 6a32f1997e9ddb912cf2995a333faa9aa0205852
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Mon Aug 16 13:07:38 2021 +0200

    Updated API-endpoints
This commit is contained in:
Erik Tiekstra
2021-08-17 11:55:22 +02:00
parent 39cdcff53d
commit d003842e4e
21 changed files with 247 additions and 200 deletions

View File

@@ -28,13 +28,13 @@
<div class="avrop-table__cell"> <div class="avrop-table__cell">
<digi-typography> <digi-typography>
<strong class="avrop-table__label">Startdatum:</strong> <strong class="avrop-table__label">Startdatum:</strong>
<span>{{deltagare?.startDate | date: 'yyyy-MM-dd'}}</span> <digi-typography-time *ngIf="deltagare?.startDate" [afDateTime]="deltagare?.startDate"></digi-typography-time>
</digi-typography> </digi-typography>
</div> </div>
<div class="avrop-table__cell"> <div class="avrop-table__cell">
<digi-typography> <digi-typography>
<strong class="avrop-table__label">Slutdatum:</strong> <strong class="avrop-table__label">Slutdatum:</strong>
<span>{{deltagare?.endDate | date: 'yyyy-MM-dd'}}</span> <digi-typography-time *ngIf="deltagare?.endDate" [afDateTime]="deltagare?.endDate"></digi-typography-time>
</digi-typography> </digi-typography>
</div> </div>
</div> </div>
@@ -42,7 +42,7 @@
<div class="avrop-table__cell"> <div class="avrop-table__cell">
<digi-typography> <digi-typography>
<strong class="avrop-table__label">Språkstöd/Tolk:</strong> <strong class="avrop-table__label">Språkstöd/Tolk:</strong>
<span>{{deltagare?.sprakstod.beskrivning + '/' + deltagare?.tolkbehov.beskrivning}}</span> <span>{{deltagare?.sprakstod + '/' + deltagare?.tolkbehov}}</span>
</digi-typography> </digi-typography>
</div> </div>
<div class="avrop-table__cell"> <div class="avrop-table__cell">

View File

@@ -0,0 +1,8 @@
export interface AuthenticationResponse {
id: string;
access_token: string;
scope: string;
id_token: string;
token_type: string;
expires_in: number;
}

View File

@@ -0,0 +1,4 @@
export interface OrganizationResponse {
name: string;
organizationnumber: string;
}

View File

@@ -0,0 +1,6 @@
export interface UserInfoResponse {
id: string;
firstName: string;
lastName: string;
roles: string[];
}

View File

@@ -1,18 +1,11 @@
export interface AuthenticationResult { import { AuthenticationResponse } from './api/authentication.response.model';
export interface Authentication {
idToken: string; idToken: string;
expiresIn: number; expiresIn: number;
} }
export interface AuthenticationApiResponse { export function mapAuthApiResponseToAuthenticationResult(data: AuthenticationResponse): Authentication {
id: string;
access_token: string;
scope: string;
id_token: string;
token_type: string;
expires_in: number;
}
export function mapAuthApiResponseToAuthenticationResult(data: AuthenticationApiResponse): AuthenticationResult {
const { id_token, expires_in } = data; const { id_token, expires_in } = data;
return { return {
idToken: id_token, idToken: id_token,

View File

@@ -0,0 +1,10 @@
export interface Environment {
environment: 'api' | 'local' | 'prod';
clientId: string;
loginUrl: string;
production: boolean;
api: {
url: string;
headers: { [key: string]: string };
};
}

View File

@@ -1,12 +1,15 @@
import { OrganizationResponse } from './api/organization.response.model';
export interface Organization { export interface Organization {
id: string;
name: string; name: string;
kaNumber: number; organizationNumber: string;
address: { }
street: string;
houseNumber: number; export function mapResponseToOrganization(data: OrganizationResponse): Organization {
postalCode: string; const { name, organizationnumber } = data;
city: string;
kommun: string; return {
name,
organizationNumber: organizationnumber,
}; };
} }

View File

@@ -0,0 +1,21 @@
import { UserInfoResponse } from './api/user-info.response.model';
export interface UserInfo {
id: string;
firstName: string;
lastName: string;
fullName: string;
roles: string[];
}
export function mapResponseToUserInfo(data: UserInfoResponse): UserInfo {
const { id, firstName, lastName, roles } = data;
return {
id,
firstName,
lastName,
fullName: `${firstName} ${lastName}`,
roles,
};
}

View File

@@ -1,39 +1,21 @@
import { Authorization } from './authorization.model'; import { OrganizationResponse } from './api/organization.response.model';
import { Organization } from './organization.model'; import { UserInfoResponse } from './api/user-info.response.model';
import { mapResponseToOrganization, Organization } from './organization.model';
import { UserInfo } from './user-info.model';
export interface User { export interface User extends UserInfo {
id: string;
firstName: string;
lastName: string;
fullName: string;
ssn: string;
organizations: Organization[]; organizations: Organization[];
authorizations: Authorization[];
} }
export interface UserApiResponse { export function mapUserApiResponseToUser(userInfo: UserInfoResponse, organizations: OrganizationResponse[]): User {
data: UserApiResponseData; const { id, firstName, lastName, roles } = userInfo;
}
export interface UserApiResponseData {
id: string;
firstName: string;
lastName: string;
ssn: string;
organizations: Organization[];
authorizations: Authorization[];
}
export function mapUserApiResponseToUser(data: UserApiResponseData): User {
const { id, firstName, lastName, ssn, organizations, authorizations } = data;
return { return {
id, id,
firstName, firstName,
lastName, lastName,
fullName: `${firstName} ${lastName}`, fullName: `${firstName} ${lastName}`,
ssn, roles,
organizations, organizations: organizations ? organizations.map(organization => mapResponseToOrganization(organization)) : [],
authorizations,
}; };
} }

View File

@@ -1,11 +1,8 @@
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { environment } from '@dafa-environment'; import { environment } from '@dafa-environment';
import { import { AuthenticationResponse } from '@dafa-models/api/authentication.response.model';
AuthenticationApiResponse, import { Authentication, mapAuthApiResponseToAuthenticationResult } from '@dafa-models/authentication.model';
AuthenticationResult,
mapAuthApiResponseToAuthenticationResult,
} from '@dafa-models/authentication.model';
import { add, isBefore } from 'date-fns'; import { add, isBefore } from 'date-fns';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators'; import { map, tap } from 'rxjs/operators';
@@ -33,7 +30,7 @@ export class AuthenticationService {
return `${environment.api.url}/auth/token?accessCode=${code}`; return `${environment.api.url}/auth/token?accessCode=${code}`;
} }
private _setSession(authenticationResult: AuthenticationResult): void { private _setSession(authenticationResult: Authentication): void {
const expiresAt = add(new Date(), { seconds: authenticationResult.expiresIn }); const expiresAt = add(new Date(), { seconds: authenticationResult.expiresIn });
this._token$.next(authenticationResult.idToken); this._token$.next(authenticationResult.idToken);
@@ -42,11 +39,14 @@ export class AuthenticationService {
localStorage.setItem('expires_at', JSON.stringify(expiresAt.valueOf())); localStorage.setItem('expires_at', JSON.stringify(expiresAt.valueOf()));
} }
login$(authorizationCodeFromCiam: string): Observable<AuthenticationResult> { login$(authorizationCodeFromCiam: string): Observable<Authentication> {
return this.httpClient return this.httpClient
.get<AuthenticationApiResponse>(AuthenticationService._authTokenApiUrl(authorizationCodeFromCiam), API_HEADERS) .get<{ data: AuthenticationResponse }>(
AuthenticationService._authTokenApiUrl(authorizationCodeFromCiam),
API_HEADERS
)
.pipe( .pipe(
map(response => mapAuthApiResponseToAuthenticationResult(response)), map(({ data }) => mapAuthApiResponseToAuthenticationResult(data)),
tap(authenticationResult => { tap(authenticationResult => {
this._setSession(authenticationResult); this._setSession(authenticationResult);
}) })

View File

@@ -18,9 +18,7 @@ export class AuthorizationService {
private _authorizationsApiUrl = `${environment.api.url}/authorizations`; private _authorizationsApiUrl = `${environment.api.url}/authorizations`;
public authorizations$: Observable<Authorization[]> = this.httpClient public authorizations$: Observable<Authorization[]> = this.httpClient
.get<AuthorizationApiResponse>(this._authorizationsApiUrl, API_HEADERS) .get<AuthorizationApiResponse>(this._authorizationsApiUrl, API_HEADERS)
.pipe( .pipe(map(({ data }) => data.map(authorization => mapAuthorizationApiResponseToAuthorization(authorization))));
map(response => response.data.map(authorization => mapAuthorizationApiResponseToAuthorization(authorization)))
);
constructor(private httpClient: HttpClient) {} constructor(private httpClient: HttpClient) {}
} }

View File

@@ -29,7 +29,7 @@ const tempMockDelay = 300;
export class AvropApiService { export class AvropApiService {
private _apiBaseUrl = `${environment.api.url}/avrop`; private _apiBaseUrl = `${environment.api.url}/avrop`;
constructor(private httpClient: HttpClient) { } constructor(private httpClient: HttpClient) {}
getNyaAvrop$( getNyaAvrop$(
tjanstIds: MultiselectFilterOption[], tjanstIds: MultiselectFilterOption[],
@@ -41,10 +41,8 @@ export class AvropApiService {
return this.httpClient return this.httpClient
.get<{ data: AvropResponse[] }>(`${this._apiBaseUrl}`, { ...API_HEADERS }) .get<{ data: AvropResponse[] }>(`${this._apiBaseUrl}`, { ...API_HEADERS })
.pipe( .pipe(
filter(response => !!response), filter(response => !!response?.data),
map(response => { map(({ data }) => data.map(avrop => mapAvropResponseToAvrop(avrop)))
return response.data.map(avrop => mapAvropResponseToAvrop(avrop))
})
); );
} }
@@ -58,29 +56,24 @@ export class AvropApiService {
selectedKommuner: MultiselectFilterOption[], selectedKommuner: MultiselectFilterOption[],
selectedUtforandeVerksamheter: MultiselectFilterOption[] selectedUtforandeVerksamheter: MultiselectFilterOption[]
): Observable<MultiselectFilterOption[]> { ): Observable<MultiselectFilterOption[]> {
return this.httpClient.get<{ data: TjanstResponse[] }>(`${this._apiBaseUrl}/tjanster`) return this.httpClient.get<{ data: TjanstResponse[] }>(`${this._apiBaseUrl}/tjanster`).pipe(
.pipe( filter(response => !!response?.data),
filter(response => !!response), map(({ data }) => data.map(tjanster => ({ label: mapTjanstResponseToTjanst(tjanster).name })))
map(response => { );
return response.data.map(tjanster => {
return { label: mapTjanstResponseToTjanst(tjanster).name }
})
})
);
} }
getSelectableUtforandeVerksamheter$( getSelectableUtforandeVerksamheter$(
selectedTjanster: MultiselectFilterOption[], selectedTjanster: MultiselectFilterOption[],
selectedKommuner: MultiselectFilterOption[] selectedKommuner: MultiselectFilterOption[]
): Observable<MultiselectFilterOption[]> { ): Observable<MultiselectFilterOption[]> {
return this.httpClient.get<{ data: UtforandeVerksamhetResponse[] }>(`${this._apiBaseUrl}/utforandeverksamheter`, { ...API_HEADERS }) return this.httpClient
.get<{ data: UtforandeVerksamhetResponse[] }>(`${this._apiBaseUrl}/utforandeverksamheter`, { ...API_HEADERS })
.pipe( .pipe(
filter(response => !!response), filter(response => !!response?.data),
map(response => { map(({ data }) =>
return response.data.map(utforandeverksamheter => { data.map(utforandeverksamheter => ({
return { label: mapUtforandeVerksamhetResponseToUtforandeVerksamhet(utforandeverksamheter).name } label: mapUtforandeVerksamhetResponseToUtforandeVerksamhet(utforandeverksamheter).name,
}) }))
}
) )
); );
} }
@@ -89,14 +82,11 @@ export class AvropApiService {
selectedTjanster: MultiselectFilterOption[], selectedTjanster: MultiselectFilterOption[],
selectedUtforandeVerksamheter: MultiselectFilterOption[] selectedUtforandeVerksamheter: MultiselectFilterOption[]
): Observable<MultiselectFilterOption[]> { ): Observable<MultiselectFilterOption[]> {
return this.httpClient.get<{ data: KommunResponse[] }>(`${this._apiBaseUrl}/kommuner`, { ...API_HEADERS }) return this.httpClient
.get<{ data: KommunResponse[] }>(`${this._apiBaseUrl}/kommuner`, { ...API_HEADERS })
.pipe( .pipe(
filter(response => !!response), filter(response => !!response?.data),
map(response => { map(({ data }) => data.map(kommun => ({ label: mapKommunResponseToKommun(kommun).name })))
return response.data.map(kommun => {
return { label: mapKommunResponseToKommun(kommun).name }
})
})
); );
} }

View File

@@ -31,8 +31,7 @@ const API_HEADERS = { headers: environment.api.headers };
providedIn: 'root', providedIn: 'root',
}) })
export class DeltagareService extends UnsubscribeDirective { export class DeltagareService extends UnsubscribeDirective {
private _apiBaseUrl = `${environment.api.url}/customerinfo`; private _apiBaseUrl = `${environment.api.url}/deltagare`;
private _apiAvropUrl = `${environment.api.url}/avrop`;
private _currentDeltagareId$ = new BehaviorSubject<string>(null); private _currentDeltagareId$ = new BehaviorSubject<string>(null);
constructor(private httpClient: HttpClient, private errorService: ErrorService) { constructor(private httpClient: HttpClient, private errorService: ErrorService) {
@@ -53,8 +52,8 @@ export class DeltagareService extends UnsubscribeDirective {
public deltagare$: Observable<Deltagare> = this._deltagare$.asObservable(); public deltagare$: Observable<Deltagare> = this._deltagare$.asObservable();
public allDeltagare$: Observable<DeltagareCompact[]> = this.httpClient public allDeltagare$: Observable<DeltagareCompact[]> = this.httpClient
.get<{ data: AvropResponse[] }>(`${this._apiAvropUrl}`, { ...API_HEADERS }) .get<{ data: AvropResponse[] }>(`${this._apiBaseUrl}`, { ...API_HEADERS })
.pipe(map(response => response.data.map(deltagare => mapResponseToDeltagareCompact(deltagare)))); .pipe(map(({ data }) => data.map(deltagare => mapResponseToDeltagareCompact(deltagare))));
public setCurrentDeltagareId(currentDeltagareId: string): void { public setCurrentDeltagareId(currentDeltagareId: string): void {
this._deltagare$.next(null); this._deltagare$.next(null);
@@ -63,9 +62,9 @@ export class DeltagareService extends UnsubscribeDirective {
private _fetchContactInformation$(id: string): Observable<ContactInformation | Partial<ContactInformation>> { private _fetchContactInformation$(id: string): Observable<ContactInformation | Partial<ContactInformation>> {
return this.httpClient return this.httpClient
.get<{ data: ContactInformationResponse }>(`${this._apiBaseUrl}/contact/${id}`, { ...API_HEADERS }) .get<{ data: ContactInformationResponse }>(`${this._apiBaseUrl}/${id}/contact`, { ...API_HEADERS })
.pipe( .pipe(
map(response => mapResponseToContactInformation(response.data)), map(({ data }) => mapResponseToContactInformation(data)),
catchError(error => { catchError(error => {
this.errorService.add(errorToCustomError(error)); this.errorService.add(errorToCustomError(error));
return of({}); return of({});
@@ -75,9 +74,9 @@ export class DeltagareService extends UnsubscribeDirective {
private _fetchDriversLicense$(id: string): Observable<DriversLicense | Partial<DriversLicense>> { private _fetchDriversLicense$(id: string): Observable<DriversLicense | Partial<DriversLicense>> {
return this.httpClient return this.httpClient
.get<{ data: DriversLicenseResponse }>(`${this._apiBaseUrl}/driverlicense/${id}`, { ...API_HEADERS }) .get<{ data: DriversLicenseResponse }>(`${this._apiBaseUrl}/${id}/driverlicense`, { ...API_HEADERS })
.pipe( .pipe(
map(response => mapResponseToDriversLicense(response.data)), map(({ data }) => mapResponseToDriversLicense(data)),
catchError(error => { catchError(error => {
this.errorService.add(errorToCustomError(error)); this.errorService.add(errorToCustomError(error));
return of({}); return of({});
@@ -87,9 +86,9 @@ export class DeltagareService extends UnsubscribeDirective {
private _fetchHighestEducation$(id: string): Observable<HighestEducation | Partial<HighestEducation>> { private _fetchHighestEducation$(id: string): Observable<HighestEducation | Partial<HighestEducation>> {
return this.httpClient return this.httpClient
.get<{ data: HighestEducationResponse }>(`${this._apiBaseUrl}/education/highest/${id}`, { ...API_HEADERS }) .get<{ data: HighestEducationResponse }>(`${this._apiBaseUrl}/${id}/educationlevels/highest`, { ...API_HEADERS })
.pipe( .pipe(
map(response => mapResponseToHighestEducation(response.data)), map(({ data }) => mapResponseToHighestEducation(data)),
catchError(error => { catchError(error => {
this.errorService.add(errorToCustomError(error)); this.errorService.add(errorToCustomError(error));
return of({}); return of({});
@@ -99,31 +98,28 @@ export class DeltagareService extends UnsubscribeDirective {
private _fetchEducations$(id: string): Observable<Education[]> { private _fetchEducations$(id: string): Observable<Education[]> {
return this.httpClient return this.httpClient
.get<{ data: EducationsResponse }>(`${this._apiBaseUrl}/education/${id}`, { ...API_HEADERS }) .get<{ data: EducationsResponse }>(`${this._apiBaseUrl}/${id}/educations`, { ...API_HEADERS })
.pipe( .pipe(
map(response => { map(({ data }) =>
if (response.data.utbildningar) { data.utbildningar
return response.data.utbildningar.sort((a, b) => ? data.utbildningar.sort((a, b) =>
sortFromToDates({ from: a.period_from, to: a.period_tom }, { from: b.period_from, to: b.period_tom }) sortFromToDates({ from: a.period_from, to: a.period_tom }, { from: b.period_from, to: b.period_tom })
); )
} : []
return []; ),
}), map(educations => educations.map(utbildning => mapResponseToEducation(utbildning))),
map( catchError(error => {
educations => educations.map(utbildning => mapResponseToEducation(utbildning)), this.errorService.add(errorToCustomError(error));
catchError(error => { return of([]);
this.errorService.add(errorToCustomError(error)); })
return of([]);
})
)
); );
} }
private _fetchTranslator$(id: string): Observable<string> { private _fetchTranslator$(id: string): Observable<string> {
return this.httpClient return this.httpClient
.get<{ data: TranslatorResponse }>(`${this._apiBaseUrl}/translator/${id}`, { ...API_HEADERS }) .get<{ data: TranslatorResponse }>(`${this._apiBaseUrl}/${id}/translator`, { ...API_HEADERS })
.pipe( .pipe(
map(response => (response.data.sprak ? response.data.sprak.beskrivning : null)), map(({ data }) => data.sprak?.beskrivning || null),
catchError(error => { catchError(error => {
this.errorService.add(errorToCustomError(error)); this.errorService.add(errorToCustomError(error));
return of(''); return of('');
@@ -133,9 +129,9 @@ export class DeltagareService extends UnsubscribeDirective {
private _fetchWorkLanguages$(id: string): Observable<string[]> { private _fetchWorkLanguages$(id: string): Observable<string[]> {
return this.httpClient return this.httpClient
.get<{ data: WorkLanguagesResponse }>(`${this._apiBaseUrl}/work/languages/${id}`, { ...API_HEADERS }) .get<{ data: WorkLanguagesResponse }>(`${this._apiBaseUrl}/${id}/work/languages`, { ...API_HEADERS })
.pipe( .pipe(
map(response => (response.data.sprak ? response.data.sprak.map(sprak => sprak.beskrivning) : [])), map(({ data }) => data?.sprak?.map(sprak => sprak.beskrivning) || []),
catchError(error => { catchError(error => {
this.errorService.add(errorToCustomError(error)); this.errorService.add(errorToCustomError(error));
return of([]); return of([]);
@@ -145,13 +141,9 @@ export class DeltagareService extends UnsubscribeDirective {
private _fetchDisabilities$(id: string): Observable<Disability[]> { private _fetchDisabilities$(id: string): Observable<Disability[]> {
return this.httpClient return this.httpClient
.get<{ data: DisabilityResponse[] }>(`${this._apiBaseUrl}/work/disability/${id}`, { ...API_HEADERS }) .get<{ data: DisabilityResponse[] }>(`${this._apiBaseUrl}/${id}/work/disabilities`, { ...API_HEADERS })
.pipe( .pipe(
map(response => map(({ data }) => data?.map(funktionsnedsattning => mapResponseToDisability(funktionsnedsattning)) || []),
response.data.length
? response.data.map(funktionsnedsattning => mapResponseToDisability(funktionsnedsattning))
: []
),
catchError(error => { catchError(error => {
this.errorService.add(errorToCustomError(error)); this.errorService.add(errorToCustomError(error));
return of([]); return of([]);
@@ -161,16 +153,14 @@ export class DeltagareService extends UnsubscribeDirective {
private _fetchWorkExperiences$(id: string): Observable<WorkExperience[]> { private _fetchWorkExperiences$(id: string): Observable<WorkExperience[]> {
return this.httpClient return this.httpClient
.get<{ data: WorkExperiencesResponse }>(`${this._apiBaseUrl}/work/experience/${id}`, { ...API_HEADERS }) .get<{ data: WorkExperiencesResponse }>(`${this._apiBaseUrl}/${id}/work/experiences`, { ...API_HEADERS })
.pipe( .pipe(
map(response => { map(
if (response.data.arbetslivserfarenheter) { ({ data }) =>
return response.data.arbetslivserfarenheter.sort((a, b) => data?.arbetslivserfarenheter?.sort((a, b) =>
sortFromToDates({ from: a.period_from, to: a.period_tom }, { from: b.period_from, to: b.period_tom }) sortFromToDates({ from: a.period_from, to: a.period_tom }, { from: b.period_from, to: b.period_tom })
); ) || []
} ),
return [];
}),
map(workExperiences => workExperiences.map(erfarenhet => mapResponseToWorkExperience(erfarenhet))), map(workExperiences => workExperiences.map(erfarenhet => mapResponseToWorkExperience(erfarenhet))),
catchError(error => { catchError(error => {
this.errorService.add(errorToCustomError(error)); this.errorService.add(errorToCustomError(error));
@@ -181,9 +171,9 @@ export class DeltagareService extends UnsubscribeDirective {
private _fetchAvropInformation$(id: string): Observable<Avrop | Partial<Avrop>> { private _fetchAvropInformation$(id: string): Observable<Avrop | Partial<Avrop>> {
return this.httpClient return this.httpClient
.get<{ data: AvropResponse }>(`${this._apiAvropUrl}/${id}`, { ...API_HEADERS }) .get<{ data: AvropResponse }>(`${this._apiBaseUrl}/${id}/avrop`, { ...API_HEADERS })
.pipe( .pipe(
map(response => (response.data ? mapAvropResponseToAvrop(response.data) : {})), map(({ data }) => (data ? mapAvropResponseToAvrop(data) : {})),
catchError(error => { catchError(error => {
this.errorService.add(errorToCustomError(error)); this.errorService.add(errorToCustomError(error));
return of({}); return of({});

View File

@@ -1,8 +1,13 @@
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { UnsubscribeDirective } from '@dafa-directives/unsubscribe.directive';
import { environment } from '@dafa-environment'; import { environment } from '@dafa-environment';
import { mapUserApiResponseToUser, User, UserApiResponse } from '@dafa-models/user.model'; import { OrganizationResponse } from '@dafa-models/api/organization.response.model';
import { Observable } from 'rxjs'; import { UserInfoResponse } from '@dafa-models/api/user-info.response.model';
import { mapResponseToOrganization, Organization } from '@dafa-models/organization.model';
import { mapResponseToUserInfo, UserInfo } from '@dafa-models/user-info.model';
import { User } from '@dafa-models/user.model';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { filter, map } from 'rxjs/operators'; import { filter, map } from 'rxjs/operators';
const API_HEADERS = { headers: environment.api.headers }; const API_HEADERS = { headers: environment.api.headers };
@@ -10,12 +15,32 @@ const API_HEADERS = { headers: environment.api.headers };
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
}) })
export class UserService { export class UserService extends UnsubscribeDirective {
private _userApiUrl = `${environment.api.url}/auth`; private _authApiUrl = `${environment.api.url}/auth`;
public user$: Observable<User> = this.httpClient.get<UserApiResponse>(this._userApiUrl, API_HEADERS).pipe( private _user$ = new BehaviorSubject<User>(null);
filter(response => !!response.data),
map(response => mapUserApiResponseToUser(response.data))
);
constructor(private httpClient: HttpClient) {} public user$: Observable<User> = this._user$.asObservable();
constructor(private httpClient: HttpClient) {
super();
this.unsubscribeOnDestroy(
combineLatest([this._fetchUserInfo$(), this._fetchOrganizations$()]).subscribe(([userInfo, organizations]) => {
this._user$.next({ ...userInfo, organizations });
})
);
}
private _fetchOrganizations$(): Observable<Organization[]> {
return this.httpClient.get<{ data: OrganizationResponse[] }>(`${this._authApiUrl}/organizations`, API_HEADERS).pipe(
filter(response => !!response?.data),
map(({ data }) => data.map(organization => mapResponseToOrganization(organization)))
);
}
private _fetchUserInfo$(): Observable<UserInfo> {
return this.httpClient.get<{ data: UserInfoResponse }>(`${this._authApiUrl}/userinfo`, API_HEADERS).pipe(
filter(response => !!response?.data),
map(({ data }) => mapResponseToUserInfo(data))
);
}
} }

View File

@@ -1,10 +1,14 @@
export const environment = { import { Environment } from '@dafa-models/environment.model';
export const environment: Environment = {
environment: 'api', environment: 'api',
clientId: '5d08c2e4-763e-42f6-b858-24e4773bb83d', clientId: '5d08c2e4-763e-42f6-b858-24e4773bb83d',
loginUrl: 'https://ciam-test.arbetsformedlingen.se:8443/uas/oauth2/authorization?response_type=code&scope=openid', loginUrl: 'https://ciam-test.arbetsformedlingen.se:8443/uas/oauth2/authorization?response_type=code&scope=openid',
production: false, production: false,
api: { api: {
url: '/api', url: '/api',
headers: {}, headers: {
orgnr: '5568301337', // Until we have an organisation-selector
},
}, },
}; };

View File

@@ -1,4 +1,8 @@
export const environment: any = { import { Environment } from '@dafa-models/environment.model';
export const environment: Environment = {
environment: 'prod',
clientId: '',
loginUrl: 'https://ciam.arbetsformedlingen.se/', loginUrl: 'https://ciam.arbetsformedlingen.se/',
production: true, production: true,
api: { api: {

View File

@@ -1,4 +1,6 @@
export const environment: any = { import { Environment } from '@dafa-models/environment.model';
export const environment: Environment = {
environment: 'local', environment: 'local',
clientId: '', clientId: '',
loginUrl: '/mock-login', loginUrl: '/mock-login',

View File

@@ -1,6 +1,6 @@
{ {
"/api": { "/api": {
"target": "https://mina-sidor-fa-test-api.tocp.arbetsformedlingen.se", "target": "https://mina-sidor-fa-test.tocp.arbetsformedlingen.se",
"secure": false, "secure": false,
"changeOrigin": true "changeOrigin": true
} }

View File

@@ -12,11 +12,8 @@ function generateCurrentUser() {
id: faker.datatype.uuid(), id: faker.datatype.uuid(),
firstName: faker.name.firstName(), firstName: faker.name.firstName(),
lastName: faker.name.lastName(), lastName: faker.name.lastName(),
ssn: `${faker.date.between('1950', '2000').toISOString().split('T')[0].replace(/-/g, '')}-${faker.datatype.number({ roles: ['Admin'],
min: 1000, organizations: chooseRandom(ORGANIZATIONS, ORGANIZATIONS.length),
max: 9999,
})}`,
organizations: [ORGANIZATIONS[Math.floor(Math.random() * ORGANIZATIONS.length)]],
authorizations: chooseRandom(AUTHORIZATIONS, faker.datatype.number(3)), authorizations: chooseRandom(AUTHORIZATIONS, faker.datatype.number(3)),
}; };
} }

View File

@@ -11,13 +11,13 @@ function generateOrganizations(amount = 10) {
for (let i = 1; i <= amount; ++i) { for (let i = 1; i <= amount; ++i) {
organizations.push({ organizations.push({
id: faker.datatype.uuid(), id: faker.datatype.uuid(),
organizationNumber: `${faker.datatype.number({ organizationNumber: `${faker.datatype.number({
min: 100000, min: 100000,
max: 999999 max: 999999,
})}-${faker.datatype.number({ })}${faker.datatype.number({
min: 1000, min: 1000,
max: 9999 max: 9999,
})}`, })}`,
name: faker.company.companyName(), name: faker.company.companyName(),
kaNumber: faker.datatype.number({ min: 100000, max: 999999 }), kaNumber: faker.datatype.number({ min: 100000, max: 999999 }),
address: { address: {

View File

@@ -16,13 +16,14 @@ server.use(
'/employee*': '/employees$1', '/employee*': '/employees$1',
'/participants': '/participants?_embed=employees', '/participants': '/participants?_embed=employees',
'/participant/:id': '/participants/:id?_embed=employees', '/participant/:id': '/participants/:id?_embed=employees',
'/auth': '/currentUser', '/auth/userinfo': '/currentUser',
'/customerinfo/*/*': '/deltagare/$2', '/auth/organizations': '/currentUser',
'/customerinfo': '/deltagare',
'/avrop/tjanster*': '/tjanster$1', '/avrop/tjanster*': '/tjanster$1',
'/avrop/utforandeverksamheter*': '/organizations$1', '/avrop/utforandeverksamheter*': '/organizations$1',
'/avrop/kommuner*': '/kommuner$1', '/avrop/kommuner*': '/kommuner$1',
'/avrop/:sokandeId': '/avrop?sokandeId=:sokandeId', '/deltagare': '/avrop',
'/deltagare/:sokandeId/avrop': '/avrop?sokandeId=:sokandeId',
'/deltagare/:sokandeId/*': '/deltagare/:sokandeId',
'*page=*': '$1_page=$2', '*page=*': '$1_page=$2',
'*limit=*': '$1_limit=$2', '*limit=*': '$1_limit=$2',
'*sort=*': '$1_sort=$2', '*sort=*': '$1_sort=$2',
@@ -53,41 +54,50 @@ router.render = (req, res) => {
req.body.createdAt = Date.now(); req.body.createdAt = Date.now();
} }
if (pathname.includes('/auth/token')) { let data = res.locals.data;
res.jsonp(res.locals.data); const deltagareRegex = /(?:\/deltagare\/)(?:\d\/)(contact|driverlicense|educationlevels\/highest|educations|translator|work\/disabilities|work\/languages|work\/experiences)/g;
} else { const isDeltagarePath = deltagareRegex.exec(pathname);
let data = res.locals.data; const avropRegex = /(?:\/avrop\/(?:tjanster|utforandeverksamheter|kommuner|\d))|(?:\/deltagare\/\d\/(avrop))/g;
const deltagareRegex = /(?:\/customerinfo\/)(contact|driverlicense|education\/highest|education|translator|work\/disability|work\/languages|work\/experience)/g; const isAvropPath = avropRegex.exec(pathname);
const isDeltagarePath = deltagareRegex.exec(pathname); const authRegex = /(?:\/auth\/)(userinfo|organizations)/g;
const avropRegex = /(?:\/avrop\/)(tjanster|utforandeverksamheter|kommuner|\d)/g; const isAuthPath = authRegex.exec(pathname);
const isAvropPath = avropRegex.exec(pathname);
if (isDeltagarePath) { if (isAuthPath) {
const deltagareSubPath = getDeltagareSubPath(isDeltagarePath[1]); const authSubPath = isAuthPath[1];
data = res.locals.data[deltagareSubPath] || {};
if (authSubPath === 'organizations') {
data = res.locals.data[authSubPath].map(organization => ({
name: organization.name,
organizationnumber: organization.organizationNumber,
}));
} }
if (isAvropPath) {
if (params) {
const newData = [];
params.forEach((value, key) => {
if (key === 'kommunCodes') {
value = +value;
}
newData.push(...data.filter(item => item[`related_${key}`].includes(value)));
});
data = newData.filter((value, index, arr) => arr.findIndex(item => item.code === value.code) === index);
} else if (isAvropPath[1]) {
data = data[0];
}
}
res.jsonp({
data,
...appendMetaData(params, res),
});
} }
if (isDeltagarePath) {
const deltagareSubPath = getDeltagareSubPath(isDeltagarePath[1]);
data = res.locals.data[deltagareSubPath] || {};
}
if (isAvropPath) {
if (params) {
const newData = [];
params.forEach((value, key) => {
if (key === 'kommunCodes') {
value = +value;
}
newData.push(...data.filter(item => item[`related_${key}`].includes(value)));
});
data = newData.filter((value, index, arr) => arr.findIndex(item => item.code === value.code) === index);
} else if (isAvropPath[1]) {
data = data[0];
}
}
res.jsonp({
data,
...appendMetaData(params, res),
});
}; };
server.use(router); server.use(router);
@@ -116,13 +126,13 @@ function appendMetaData(params, res) {
function getDeltagareSubPath(path) { function getDeltagareSubPath(path) {
switch (path) { switch (path) {
case 'education/highest': case 'educationlevels/highest':
return 'highestEducation'; return 'highestEducation';
case 'work/disability': case 'work/disabilities':
return 'disabilities'; return 'disabilities';
case 'work/languages': case 'work/languages':
return 'workLanguages'; return 'workLanguages';
case 'work/experience': case 'work/experiences':
return 'workExperiences'; return 'workExperiences';
default: default:
return path; return path;