Skip to content

Commit cf064aa

Browse files
committed
feat(admin): Add OIDC information
1 parent 681c377 commit cf064aa

File tree

5 files changed

+114
-29
lines changed

5 files changed

+114
-29
lines changed

Diff for: admin/app/components/users/user-overview.gjs

+16
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@ export default class UserOverview extends Component {
2727
@service pixToast;
2828
@service references;
2929
@service store;
30+
@service oidcIdentityProviders;
3031

3132
@tracked displayAnonymizeModal = false;
3233
@tracked isEditionMode = false;
34+
@tracked authenticationMethods = [];
3335

3436
languages = this.references.availableLanguages;
3537
locales = this.references.availableLocales;
@@ -39,6 +41,9 @@ export default class UserOverview extends Component {
3941
constructor() {
4042
super(...arguments);
4143
this.form = this.store.createRecord('user-form');
44+
Promise.resolve(this.args.user.authenticationMethods).then((authenticationMethods) => {
45+
this.authenticationMethods = authenticationMethods;
46+
});
4247
}
4348

4449
get externalURL() {
@@ -86,6 +91,14 @@ export default class UserOverview extends Component {
8691
return this.args.user.username ? null : 'obligatoire';
8792
}
8893

94+
get hasOidcAuthentication() {
95+
const oidcProvidersCodes = this.oidcIdentityProviders.list.map((provider) => provider.code);
96+
const userHasThisOidcAuthenticationMethod = this.authenticationMethods.any((authenticationMethod) =>
97+
oidcProvidersCodes.includes(authenticationMethod.identityProvider),
98+
);
99+
return userHasThisOidcAuthenticationMethod ? 'common.words.yes' : 'common.words.no';
100+
}
101+
89102
_initForm() {
90103
this.form.firstName = this.args.user.firstName;
91104
this.form.lastName = this.args.user.lastName;
@@ -331,6 +344,9 @@ export default class UserOverview extends Component {
331344
{{/if}}
332345
</span>
333346
</li>
347+
<li class="user-detail-personal-information-section__user-informations flex space-between gap-4x">
348+
<span>{{t "components.users.user-overview.sso"}} : {{t this.hasOidcAuthentication}}</span>
349+
</li>
334350
</ul>
335351

336352
<ul class="user-detail-personal-information-section__infogroup">

Diff for: admin/tests/integration/components/users/user-overview-test.gjs

+71
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,14 @@ module('Integration | Component | users | user-overview', function (hooks) {
8383

8484
test('displays the update button', async function (assert) {
8585
// given
86+
const store = this.owner.lookup('service:store');
8687
const user = {
8788
firstName: 'John',
8889
lastName: 'Harry',
8990
email: 'john.harry@example.net',
9091
username: 'john.harry0102',
9192
};
93+
user.authenticationMethods = [await store.createRecord('authentication-method', { identityProvider: 'abc' })];
9294

9395
// when
9496
const screen = await render(<template><UserOverview @user={{user}} /></template>);
@@ -392,13 +394,15 @@ module('Integration | Component | users | user-overview', function (hooks) {
392394
module('When the admin member click to update user details', function () {
393395
test('displays the edit and cancel buttons', async function (assert) {
394396
// given
397+
const store = this.owner.lookup('service:store');
395398
const user = {
396399
firstName: 'John',
397400
lastName: 'Harry',
398401
email: 'john.harry@example.net',
399402
username: null,
400403
lang: null,
401404
};
405+
user.authenticationMethods = [await store.createRecord('authentication-method', { identityProvider: 'abc' })];
402406

403407
// when
404408
const screen = await render(<template><UserOverview @user={{user}} /></template>);
@@ -416,6 +420,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
416420
firstName: 'John',
417421
email: 'john.harry@gmail.com',
418422
username: null,
423+
authenticationMethods: [],
419424
});
420425

421426
// when
@@ -450,6 +455,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
450455
firstName: 'John',
451456
email: 'john.harry@gmail.com',
452457
username: null,
458+
authenticationMethods: [],
453459
});
454460

455461
// when
@@ -469,6 +475,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
469475
firstName: 'John',
470476
email: 'john.harry@gmail.com',
471477
username: null,
478+
authenticationMethods: [],
472479
});
473480

474481
// when
@@ -486,6 +493,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
486493
firstName: 'John',
487494
email: 'john.harry@gmail.com',
488495
username: null,
496+
authenticationMethods: [],
489497
});
490498

491499
// when
@@ -505,6 +513,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
505513
firstName: 'John',
506514
email: null,
507515
username: 'user.name1212',
516+
authenticationMethods: [],
508517
});
509518

510519
// when
@@ -522,6 +531,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
522531
firstName: 'John',
523532
email: null,
524533
username: 'user.name1212',
534+
authenticationMethods: [],
525535
});
526536

527537
// when
@@ -543,6 +553,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
543553
firstName: 'John',
544554
email: null,
545555
username: undefined,
556+
authenticationMethods: [],
546557
});
547558

548559
// when
@@ -563,6 +574,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
563574
firstName: 'John',
564575
email: 'john.harry@gmail.com',
565576
username: null,
577+
authenticationMethods: [],
566578
});
567579

568580
const screen = await render(<template><UserOverview @user={{user}} /></template>);
@@ -588,6 +600,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
588600
firstName: 'John',
589601
email: 'john.harry@gmail.com',
590602
username: null,
603+
authenticationMethods: [],
591604
});
592605

593606
const screen = await render(<template><UserOverview @user={{user}} /></template>);
@@ -660,6 +673,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
660673
firstName: 'John',
661674
email: 'john.harry@gmail.com',
662675
isPixAgent: true,
676+
authenticationMethods: [],
663677
});
664678

665679
// when
@@ -675,11 +689,67 @@ module('Integration | Component | users | user-overview', function (hooks) {
675689
assert.dom(anonymizationDisabledTooltip).exists();
676690
});
677691
});
692+
693+
module('Displays OIDC information', function (hooks) {
694+
class OidcIdentityProvidersStub extends Service {
695+
get list() {
696+
return [
697+
{
698+
code: 'SUNLIGHT_NAVIGATIONS',
699+
organizationName: 'Sunlight Navigations',
700+
},
701+
];
702+
}
703+
}
704+
705+
hooks.beforeEach(function () {
706+
this.owner.register('service:oidc-identity-providers', OidcIdentityProvidersStub);
707+
});
708+
709+
test('When user has not OIDC authentication method', async function (assert) {
710+
// given
711+
const store = this.owner.lookup('service:store');
712+
const user = {
713+
firstName: 'John',
714+
lastName: 'Harry',
715+
email: 'john.harry@example.net',
716+
username: 'john.harry0102',
717+
};
718+
user.authenticationMethods = [await store.createRecord('authentication-method', { identityProvider: 'abc' })];
719+
720+
// when
721+
const screen = await render(<template><UserOverview @user={{user}} /></template>);
722+
723+
// then
724+
assert.dom(screen.getByText('SSO : Non')).exists();
725+
});
726+
727+
test('When user has OIDC authentication method', async function (assert) {
728+
// given
729+
const store = this.owner.lookup('service:store');
730+
const user = {
731+
firstName: 'John',
732+
lastName: 'Harry',
733+
email: 'john.harry@example.net',
734+
username: 'john.harry0102',
735+
};
736+
user.authenticationMethods = [
737+
await store.createRecord('authentication-method', { identityProvider: 'SUNLIGHT_NAVIGATIONS' }),
738+
];
739+
740+
// when
741+
const screen = await render(<template><UserOverview @user={{user}} /></template>);
742+
743+
// then
744+
assert.dom(screen.getByText('SSO : Oui')).exists();
745+
});
746+
});
678747
});
679748

680749
module('When the admin member does not have access to users actions scope', function () {
681750
test('does not display the action buttons "Modifier" and "Anonymiser cet utilisateur"', async function (assert) {
682751
// given
752+
const store = this.owner.lookup('service:store');
683753
class AccessControlStub extends Service {
684754
hasAccessToUsersActionsScope = false;
685755
}
@@ -690,6 +760,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
690760
email: 'john.harry@example.net',
691761
username: 'john.harry0102',
692762
};
763+
user.authenticationMethods = [await store.createRecord('authentication-method', { identityProvider: 'abc' })];
693764
this.owner.register('service:access-control', AccessControlStub);
694765

695766
// when

Diff for: admin/tests/unit/components/users/user-overview-test.js

+21-29
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,15 @@ module('Unit | Component | users | user-overview', function (hooks) {
1313
module('#externalURL', function () {
1414
test('it should generate dashboard URL based on environment and object', async function (assert) {
1515
// given
16-
const component = createGlimmerComponent('component:users/user-overview');
17-
18-
const args = {
16+
const baseUrl = 'https://metabase.pix.fr/dashboard/132?id=';
17+
ENV.APP.USER_DASHBOARD_URL = baseUrl;
18+
const component = createGlimmerComponent('component:users/user-overview', {
1919
user: {
2020
id: 1,
21+
authenticationMethods: [],
2122
},
22-
};
23-
const baseUrl = 'https://metabase.pix.fr/dashboard/132?id=';
24-
const expectedUrl = baseUrl + args.user.id;
25-
26-
ENV.APP.USER_DASHBOARD_URL = baseUrl;
27-
component.args = args;
23+
});
24+
const expectedUrl = baseUrl + '1';
2825

2926
// when
3027
const actualUrl = component.externalURL;
@@ -38,9 +35,8 @@ module('Unit | Component | users | user-overview', function (hooks) {
3835
module('when user already has an email', function () {
3936
test('it should allow email modification', async function (assert) {
4037
// given
41-
const component = createGlimmerComponent('component:users/user-overview');
42-
const user = { email: 'lisa@example.net', firstName: 'Lisa', lastName: 'Dupont' };
43-
component.args.user = user;
38+
const user = { email: 'lisa@example.net', firstName: 'Lisa', lastName: 'Dupont', authenticationMethods: [] };
39+
const component = createGlimmerComponent('component:users/user-overview', { user });
4440

4541
// when & then
4642
assert.true(component.canModifyEmail);
@@ -50,9 +46,8 @@ module('Unit | Component | users | user-overview', function (hooks) {
5046
module('when user has an username', function () {
5147
test('it should also allow email modification', async function (assert) {
5248
// given
53-
const component = createGlimmerComponent('component:users/user-overview');
54-
const user = { username: 'lisa.dupont', firstName: 'Lisa', lastName: 'Dupont' };
55-
component.args.user = user;
49+
const user = { username: 'lisa.dupont', firstName: 'Lisa', lastName: 'Dupont', authenticationMethods: [] };
50+
const component = createGlimmerComponent('component:users/user-overview', { user });
5651

5752
// when & then
5853
assert.true(component.canModifyEmail);
@@ -62,9 +57,8 @@ module('Unit | Component | users | user-overview', function (hooks) {
6257
module('when user has neither a username nor an email', function () {
6358
test('it should not allow email modification', async function (assert) {
6459
// given
65-
const component = createGlimmerComponent('component:users/user-overview');
66-
const user = { firstName: 'Lisa', lastName: 'Dupont' };
67-
component.args.user = user;
60+
const user = { firstName: 'Lisa', lastName: 'Dupont', authenticationMethods: [] };
61+
const component = createGlimmerComponent('component:users/user-overview', { user });
6862

6963
// when & then
7064
assert.false(component.canModifyEmail);
@@ -76,7 +70,8 @@ module('Unit | Component | users | user-overview', function (hooks) {
7670
module('when user has no login informations yet', function () {
7771
test('should not display temporary blocked date', function (assert) {
7872
// given
79-
const component = createGlimmerComponent('component:users/user-overview');
73+
const user = { authenticationMethods: [] };
74+
const component = createGlimmerComponent('component:users/user-overview', { user });
8075

8176
// when && then
8277
assert.false(component.shouldDisplayTemporaryBlockedDate);
@@ -86,9 +81,8 @@ module('Unit | Component | users | user-overview', function (hooks) {
8681
module('when user has login but not temporary blocked', function () {
8782
test('should not display temporary blocked date', function (assert) {
8883
// given
89-
const component = createGlimmerComponent('component:users/user-overview');
90-
const user = { firstName: 'Lisa', lastName: 'Dupont' };
91-
component.args.user = user;
84+
const user = { firstName: 'Lisa', lastName: 'Dupont', authenticationMethods: [] };
85+
const component = createGlimmerComponent('component:users/user-overview', { user });
9286
const getTemporaryBlockedUntilProperty = () => null;
9387
const userLoginProxy = { get: getTemporaryBlockedUntilProperty };
9488
component.args.user.userLogin = userLoginProxy;
@@ -101,11 +95,10 @@ module('Unit | Component | users | user-overview', function (hooks) {
10195
module('when user has login and temporary blocked date', function () {
10296
test('should display temporary blocked date when now date is after temporaty blocked date', function (assert) {
10397
// given
104-
const component = createGlimmerComponent('component:users/user-overview');
105-
const user = { firstName: 'Lisa', lastName: 'Dupont' };
98+
const user = { firstName: 'Lisa', lastName: 'Dupont', authenticationMethods: [] };
10699
const getTemporaryBlockedUntilProperty = () => new Date(Date.now() + 3600 * 1000);
100+
const component = createGlimmerComponent('component:users/user-overview', { user });
107101
const userLoginProxy = { get: getTemporaryBlockedUntilProperty };
108-
component.args.user = user;
109102
component.args.user.userLogin = userLoginProxy;
110103

111104
// when && then
@@ -114,9 +107,8 @@ module('Unit | Component | users | user-overview', function (hooks) {
114107

115108
test('should not display temporary blocked date when now date is before temporaty blocked date', function (assert) {
116109
// given
117-
const component = createGlimmerComponent('component:users/user-overview');
118-
const user = { firstName: 'Lisa', lastName: 'Dupont' };
119-
component.args.user = user;
110+
const user = { firstName: 'Lisa', lastName: 'Dupont', authenticationMethods: [] };
111+
const component = createGlimmerComponent('component:users/user-overview', { user });
120112
const getTemporaryBlockedUntilProperty = () => new Date(Date.now() - 3600 * 1000);
121113
const userLoginProxy = { get: getTemporaryBlockedUntilProperty };
122114
component.args.user.userLogin = userLoginProxy;
@@ -131,7 +123,7 @@ module('Unit | Component | users | user-overview', function (hooks) {
131123
test('should empty organization learners', async function (assert) {
132124
// given
133125
const organizationLearners = [{ firstName: 'fanny', lastName: 'epi' }];
134-
const user = { organizationLearners, save: sinon.stub().resolves() };
126+
const user = { organizationLearners, save: sinon.stub().resolves(), authenticationMethods: [] };
135127
const component = createGlimmerComponent('component:users/user-overview', { user });
136128

137129
// when

Diff for: admin/translations/en.json

+3
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,9 @@
403403
}
404404
},
405405
"copied": "Copied!"
406+
},
407+
"user-overview": {
408+
"sso": "SSO"
406409
}
407410
}
408411
},

Diff for: admin/translations/fr.json

+3
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,9 @@
413413
}
414414
},
415415
"copied": "Copié !"
416+
},
417+
"user-overview": {
418+
"sso": "SSO"
416419
}
417420
}
418421
},

0 commit comments

Comments
 (0)