fix: user info card

Closes #305
This commit is contained in:
Jovan Krunić
2022-10-14 21:49:48 +02:00
parent e395e9d270
commit 998edcb5cd
7 changed files with 323 additions and 175 deletions

View File

@@ -12,8 +12,15 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {SCAuthorizationProvider, SCBackendAggregationConfiguration, SCThingType} from '@openstapps/core';
import {
SCAboutPageContentType,
SCAuthorizationProvider,
SCBackendAggregationConfiguration,
SCIndexResponse, SCSettingInputType, SCThingOriginType,
SCThingType
} from '@openstapps/core';
import {Polygon} from 'geojson';
import packageJson from "../../../../package.json";
// provides sample aggregations to be used in tests or backendless development
export const sampleAggregations: SCBackendAggregationConfiguration[] = [
@@ -118,3 +125,161 @@ export const sampleDefaultPolygon: Polygon = {
],
"type": "Polygon"
}
const scVersion = packageJson.dependencies['@openstapps/core'];
export const sampleIndexResponse: SCIndexResponse = {
app: {
aboutPages: {
about: {
title: 'About',
content: [
{
value: 'This is the about page',
type: SCAboutPageContentType.MARKDOWN,
translations: {
en: {
value: 'This is the about page',
},
},
},
],
translations: {
en: {
title: 'About',
},
},
},
},
campusPolygon: {
coordinates: [[[1, 2]], [[1, 2]]],
type: 'Polygon',
},
features: {},
menus: [
{
icon: 'icon',
id: 'main',
items: [
{
icon: 'icon',
route: '/index',
title: 'start',
translations: {
de: {
title: 'Start',
},
en: {
title: 'start',
},
},
},
],
name: 'main',
translations: {
de: {
name: 'Haupt',
},
en: {
name: 'main',
},
},
},
],
name: 'StApps',
privacyPolicyUrl: 'foo.bar',
settings: [
{
categories: ['credentials'],
defaultValue: '',
inputType: SCSettingInputType.Text,
name: 'username',
order: 0,
origin: {
indexed: '2018-09-11T12:30:00Z',
name: 'Dummy',
type: SCThingOriginType.Remote,
},
translations: {
de: {
name: 'Benutzername',
},
en: {
name: 'Username',
},
},
type: SCThingType.Setting,
uid: '',
},
],
},
auth: {},
backend: {
SCVersion: scVersion,
externalRequestTimeout: 5000,
hiddenTypes: [SCThingType.DateSeries, SCThingType.Diff, SCThingType.Floor],
mappingIgnoredTags: [],
maxMultiSearchRouteQueries: 5,
maxRequestBodySize: 512 * 1024,
name: 'Technische Universität Berlin',
namespace: '909a8cbc-8520-456c-b474-ef1525f14209',
sortableFields: [
{
fieldName: 'name',
sortTypes: ['ducet'],
},
{
fieldName: 'type',
sortTypes: ['ducet'],
},
{
fieldName: 'categories',
onlyOnTypes: [
SCThingType.AcademicEvent,
SCThingType.Building,
SCThingType.Catalog,
SCThingType.Dish,
SCThingType.PointOfInterest,
SCThingType.Room,
],
sortTypes: ['ducet'],
},
{
fieldName: 'geo',
onlyOnTypes: [
SCThingType.Building,
SCThingType.PointOfInterest,
SCThingType.Room,
],
sortTypes: ['distance'],
},
{
fieldName: 'geo',
onlyOnTypes: [
SCThingType.Building,
SCThingType.PointOfInterest,
SCThingType.Room,
],
sortTypes: ['distance'],
},
{
fieldName: 'inPlace.geo',
onlyOnTypes: [
SCThingType.DateSeries,
SCThingType.Dish,
SCThingType.Floor,
SCThingType.Organization,
SCThingType.PointOfInterest,
SCThingType.Room,
SCThingType.Ticket,
],
sortTypes: ['distance'],
},
{
fieldName: 'offers',
onlyOnTypes: [SCThingType.Dish],
sortTypes: ['price'],
},
],
},
};

View File

@@ -0,0 +1,136 @@
/*
* Copyright (C) 2022 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {TestBed} from '@angular/core/testing';
import {AuthHelperService} from './auth-helper.service';
import {ConfigProvider} from '../config/config.provider';
import {StorageProvider} from '../storage/storage.provider';
import {DefaultAuthService} from './default-auth.service';
import {Browser} from 'ionic-appauth';
import {Requestor, StorageBackend} from '@openid/appauth';
import {TranslateService} from '@ngx-translate/core';
import {PAIAAuthService} from './paia/paia-auth.service';
import {LoggerConfig, LoggerModule, NGXLogger} from 'ngx-logger';
import {StAppsWebHttpClient} from '../data/stapps-web-http-client.provider';
import {HttpClientModule} from '@angular/common/http';
describe('AuthHelperService', () => {
let authHelperService: AuthHelperService;
const storageProviderSpy = jasmine.createSpyObj('StorageProvider', [
'init',
'get',
'has',
'put',
'search',
]);
const translateServiceSpy = jasmine.createSpyObj('TranslateService', [
'setDefaultLang',
'use',
]);
const defaultAuthServiceMock = jasmine.createSpyObj('DefaultAuthService', [
'init',
'setupConfiguration',
]);
const paiaAuthServiceMock = jasmine.createSpyObj('PAIAAuthService', [
'init',
'setupConfiguration',
]);
const authHelperServiceMock = jasmine.createSpyObj('AuthHelperService', [
'constructor',
]);
const configProvider = jasmine.createSpyObj('ConfigProvider', {
getAnyValue: {
default: {
endpoints: {
mapping: {
id: '$.id',
email: '$.attributes.mailPrimaryAddress',
givenName: '$.attributes.givenName',
familyName: '$.attributes.sn',
name: '$.attributes.sn',
role: '$.attributes.eduPersonPrimaryAffiliation',
studentId: '$.attributes.employeeNumber',
},
},
},
},
});
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule, LoggerModule],
providers: [
NGXLogger,
StAppsWebHttpClient,
LoggerConfig,
{
provide: TranslateService,
useValue: translateServiceSpy,
},
{
provide: StorageProvider,
useValue: storageProviderSpy,
},
{
provider: DefaultAuthService,
useValue: defaultAuthServiceMock,
},
{
provider: PAIAAuthService,
useValue: paiaAuthServiceMock,
},
{
provide: ConfigProvider,
useValue: configProvider,
},
Browser,
StorageBackend,
Requestor,
{
provider: AuthHelperService,
useValue: authHelperServiceMock,
},
],
});
authHelperService = TestBed.inject(AuthHelperService);
});
describe('getUserFromUserInfo', () => {
it('should provide user configuration from userInfo', async () => {
const userConfiguration = authHelperService.getUserFromUserInfo({
attributes: {
eduPersonPrimaryAffiliation: 'student',
employeeNumber: '123456',
givenName: 'Erika',
mailPrimaryAddress: 'emuster@anyschool.de',
oauthClientId: '123-abc-123',
sn: 'Musterfrau',
uid: 'emuster',
},
id: 'emuster',
client_id: '123-abc-123',
});
expect(userConfiguration).toEqual({
id: 'emuster',
givenName: 'Erika',
familyName: 'Musterfrau',
name: 'Erika Musterfrau',
email: 'emuster@anyschool.de',
role: 'student',
studentId: '123456',
});
});
});
});

View File

@@ -2,7 +2,6 @@ import {Injectable} from '@angular/core';
import {IPAIAAuthAction} from './paia/paia-auth-action';
import {AuthActions, IAuthAction} from 'ionic-appauth';
import {TranslateService} from '@ngx-translate/core';
import {JSONFile} from '@angular/cli/utilities/json-file';
import {JSONPath} from 'jsonpath-plus';
import {
SCAuthorizationProvider,
@@ -56,8 +55,12 @@ export class AuthHelperService {
return message;
}
getUserFromUserInfo(userInfo: JSONFile) {
const user: SCUserConfiguration = {id: '', name: '', role: 'student'};
getUserFromUserInfo(userInfo: object) {
const user: SCUserConfiguration = {
id: '',
name: '',
role: 'student',
};
for (const key in this.userConfigurationMap) {
user[key as keyof SCUserConfiguration] = JSONPath({
path: this.userConfigurationMap[
@@ -67,6 +70,14 @@ export class AuthHelperService {
preventEval: true,
})[0];
}
if (
user.givenName &&
user.givenName.length > 0 &&
user.familyName &&
user.familyName.length > 0
) {
user.name = `${user.givenName} ${user.familyName}`;
}
return user;
}

View File

@@ -13,13 +13,6 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {TestBed} from '@angular/core/testing';
import {
SCAboutPageContentType,
SCIndexResponse,
SCSettingInputType,
SCThingOriginType,
SCThingType,
} from '@openstapps/core';
import {StAppsWebHttpClient} from '../data/stapps-web-http-client.provider';
import {StorageProvider} from '../storage/storage.provider';
import {ConfigProvider, STORAGE_KEY_CONFIG} from './config.provider';
@@ -30,7 +23,7 @@ import {
WrongConfigVersionInStorage,
} from './errors';
import {NGXLogger} from 'ngx-logger';
import packageJson from '../../../../package.json';
import {sampleIndexResponse} from '../../_helpers/data/sample-configuration';
describe('ConfigProvider', () => {
let configProvider: ConfigProvider;
@@ -192,161 +185,3 @@ describe('ConfigProvider', () => {
);
});
});
const scVersion = packageJson.dependencies['@openstapps/core'];
const sampleIndexResponse: SCIndexResponse = {
app: {
aboutPages: {
about: {
title: 'About',
content: [
{
value: 'This is the about page',
type: SCAboutPageContentType.MARKDOWN,
translations: {
en: {
value: 'This is the about page',
},
},
},
],
translations: {
en: {
title: 'About',
},
},
},
},
campusPolygon: {
coordinates: [[[1, 2]], [[1, 2]]],
type: 'Polygon',
},
features: {},
menus: [
{
icon: 'icon',
id: 'main',
items: [
{
icon: 'icon',
route: '/index',
title: 'start',
translations: {
de: {
title: 'Start',
},
en: {
title: 'start',
},
},
},
],
name: 'main',
translations: {
de: {
name: 'Haupt',
},
en: {
name: 'main',
},
},
},
],
name: 'StApps',
privacyPolicyUrl: 'foo.bar',
settings: [
{
categories: ['credentials'],
defaultValue: '',
inputType: SCSettingInputType.Text,
name: 'username',
order: 0,
origin: {
indexed: '2018-09-11T12:30:00Z',
name: 'Dummy',
type: SCThingOriginType.Remote,
},
translations: {
de: {
name: 'Benutzername',
},
en: {
name: 'Username',
},
},
type: SCThingType.Setting,
uid: '',
},
],
},
auth: {},
backend: {
SCVersion: scVersion,
externalRequestTimeout: 5000,
hiddenTypes: [SCThingType.DateSeries, SCThingType.Diff, SCThingType.Floor],
mappingIgnoredTags: [],
maxMultiSearchRouteQueries: 5,
maxRequestBodySize: 512 * 1024,
name: 'Technische Universität Berlin',
namespace: '909a8cbc-8520-456c-b474-ef1525f14209',
sortableFields: [
{
fieldName: 'name',
sortTypes: ['ducet'],
},
{
fieldName: 'type',
sortTypes: ['ducet'],
},
{
fieldName: 'categories',
onlyOnTypes: [
SCThingType.AcademicEvent,
SCThingType.Building,
SCThingType.Catalog,
SCThingType.Dish,
SCThingType.PointOfInterest,
SCThingType.Room,
],
sortTypes: ['ducet'],
},
{
fieldName: 'geo',
onlyOnTypes: [
SCThingType.Building,
SCThingType.PointOfInterest,
SCThingType.Room,
],
sortTypes: ['distance'],
},
{
fieldName: 'geo',
onlyOnTypes: [
SCThingType.Building,
SCThingType.PointOfInterest,
SCThingType.Room,
],
sortTypes: ['distance'],
},
{
fieldName: 'inPlace.geo',
onlyOnTypes: [
SCThingType.DateSeries,
SCThingType.Dish,
SCThingType.Floor,
SCThingType.Organization,
SCThingType.PointOfInterest,
SCThingType.Room,
SCThingType.Ticket,
],
sortTypes: ['distance'],
},
{
fieldName: 'offers',
onlyOnTypes: [SCThingType.Dish],
sortTypes: ['price'],
},
],
},
};

View File

@@ -38,7 +38,9 @@ export const STORAGE_KEY_CONFIG = 'stapps.config';
/**
* Provides configuration
*/
@Injectable()
@Injectable({
providedIn: 'root',
})
export class ConfigProvider {
/**
* Api client

View File

@@ -50,8 +50,7 @@
class="main-info"
>
<ion-text class="full-name">
{{ userInfo?.givenName }}
{{ userInfo?.familyName }}
{{ userInfo?.name }}
</ion-text>
<div class="matriculation-number">
<ion-label>
@@ -65,7 +64,7 @@
<ion-label>
{{ 'profile.userInfo.username' | translate | uppercase }}
</ion-label>
<ion-text>{{ userInfo?.name }}</ion-text>
<ion-text>{{ userInfo?.id }}</ion-text>
</div>
<div class="email">
<ion-label>

View File

@@ -72,7 +72,7 @@
height: 100%;
width: 50%;
margin-left: calc(var(--spacing-md) * -4);
object-position: left 50%;
object-position: left bottom;
}
.main-info {