Skip to content

Commit 58c6aaa

Browse files
[FEATURE] Afficher la date de dernière connexion par rapport à la méthode de connexion utilisée (PIX-16631)
#11547
2 parents ad8ee93 + c20e5e5 commit 58c6aaa

File tree

13 files changed

+121
-40
lines changed

13 files changed

+121
-40
lines changed

admin/app/components/users/user-detail-personal-information/authentication-method.gjs

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { action } from '@ember/object';
55
import { service } from '@ember/service';
66
import Component from '@glimmer/component';
77
import { tracked } from '@glimmer/tracking';
8+
import dayjs from 'dayjs';
89
import dayjsFormat from 'ember-dayjs/helpers/dayjs-format';
910
import { t } from 'ember-intl';
1011

@@ -15,6 +16,7 @@ import ReassignOidcAuthenticationMethodModal from './reassign-oidc-authenticatio
1516
export default class AuthenticationMethod extends Component {
1617
@service pixToast;
1718
@service accessControl;
19+
@service intl;
1820
@service oidcIdentityProviders;
1921

2022
@tracked showAddAuthenticationMethodModal = false;
@@ -87,12 +89,15 @@ export default class AuthenticationMethod extends Component {
8789
get emailAuthenticationMethod() {
8890
return { code: 'EMAIL', name: 'Adresse e-mail' };
8991
}
92+
9093
get userNameAuthenticationMethod() {
9194
return { code: 'USERNAME', name: 'Identifiant' };
9295
}
96+
9397
get garAuthenticationMethod() {
9498
return { code: 'GAR', name: 'Médiacentre' };
9599
}
100+
96101
get userOidcAuthenticationMethods() {
97102
return this.oidcIdentityProviders.list.map((oidcIdentityProvider) => {
98103
const userHasThisOidcAuthenticationMethod = this.authenticationMethods.any(
@@ -110,6 +115,29 @@ export default class AuthenticationMethod extends Component {
110115
});
111116
}
112117

118+
get pixLastLoggedAtAuthenticationMethod() {
119+
const method = this.authenticationMethods.find((method) => method.identityProvider === 'PIX');
120+
return method ? this._displayAuthenticationMethodDate(method.lastLoggedAt) : null;
121+
}
122+
123+
get garLastLoggedAtAuthenticationMethod() {
124+
const method = this.authenticationMethods.find((method) => method.identityProvider === 'GAR');
125+
return method ? this._displayAuthenticationMethodDate(method.lastLoggedAt) : null;
126+
}
127+
128+
_displayAuthenticationMethodDate(date) {
129+
if (!date) return null;
130+
return this.intl.t('components.users.user-detail-personal-information.authentication-method.last-logged-at', {
131+
date: dayjs(date).format('DD/MM/YYYY'),
132+
});
133+
}
134+
135+
@action
136+
oidcLastLoggedAtAuthenticationMethod(oidc) {
137+
const method = this.authenticationMethods.find((method) => method.identityProvider === oidc.code);
138+
return method ? this._displayAuthenticationMethodDate(method.lastLoggedAt) : null;
139+
}
140+
113141
@action
114142
onChangeNewEmail(event) {
115143
this.newEmail = event.target.value;
@@ -188,34 +216,30 @@ export default class AuthenticationMethod extends Component {
188216
<h2 class="page-section__title">Méthodes de connexion</h2>
189217
</header>
190218

191-
<ul>
192-
<li class="authentication-method__connexions-information">
193-
Date de dernière connexion :
219+
<ul class="authentication-method__connexions-information">
220+
<li>
221+
<strong>Date de dernière connexion :</strong>
194222
{{#if @user.lastLoggedAt}}{{dayjsFormat @user.lastLoggedAt "DD/MM/YYYY"}}{{/if}}
195223
</li>
196224
{{#if @user.emailConfirmedAt}}
197-
<li class="authentication-method__connexions-information">
198-
Adresse e-mail confirmée le :
225+
<li>
226+
<strong>Adresse e-mail confirmée le :</strong>
199227
{{dayjsFormat @user.emailConfirmedAt "DD/MM/YYYY"}}
200228
</li>
201229
{{else}}
202-
<li class="authentication-method__connexions-information">
203-
Adresse e-mail non confirmée
230+
<li>
231+
<strong>Adresse e-mail non confirmée</strong>
204232
</li>
205233
{{/if}}
206-
</ul>
207-
208-
{{#if this.hasPixAuthenticationMethod}}
209-
<br />
210-
<ul>
211-
<li class="authentication-method__connexions-information">
212-
{{t "components.users.user-detail-personal-information.authentication-method.should-change-password-status"}}
234+
{{#if this.hasPixAuthenticationMethod}}
235+
<li>
236+
<strong>{{t
237+
"components.users.user-detail-personal-information.authentication-method.should-change-password-status"
238+
}}</strong>
213239
{{#if this.shouldChangePassword}}{{t "common.words.yes"}}{{else}}{{t "common.words.no"}}{{/if}}
214240
</li>
215-
</ul>
216-
{{/if}}
217-
218-
<br />
241+
{{/if}}
242+
</ul>
219243

220244
<table class="authentication-method-table">
221245

@@ -244,6 +268,7 @@ export default class AuthenticationMethod extends Component {
244268
/>
245269
{{/if}}
246270
</td>
271+
<td>{{this.pixLastLoggedAtAuthenticationMethod}}</td>
247272
<td>
248273
{{#if this.accessControl.hasAccessToUsersActionsScope}}
249274
{{#if this.isAllowedToRemoveEmailAuthenticationMethod}}
@@ -284,6 +309,7 @@ export default class AuthenticationMethod extends Component {
284309
/>
285310
{{/if}}
286311
</td>
312+
<td>{{this.pixLastLoggedAtAuthenticationMethod}}</td>
287313
<td>
288314
{{#if this.accessControl.hasAccessToUsersActionsScope}}
289315
{{#if this.isAllowedToRemoveUsernameAuthenticationMethod}}
@@ -319,6 +345,7 @@ export default class AuthenticationMethod extends Component {
319345
/>
320346
{{/if}}
321347
</td>
348+
<td>{{this.garLastLoggedAtAuthenticationMethod}}</td>
322349
<td class="authentication-method-table__actions-column">
323350
{{#if this.accessControl.hasAccessToUsersActionsScope}}
324351
<div>
@@ -361,6 +388,7 @@ export default class AuthenticationMethod extends Component {
361388
/>
362389
{{/if}}
363390
</td>
391+
<td>{{this.oidcLastLoggedAtAuthenticationMethod userOidcAuthenticationMethod}}</td>
364392
<td class="authentication-method-table__actions-column">
365393
{{#if this.accessControl.hasAccessToUsersActionsScope}}
366394
<div>

admin/app/models/authentication-method.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ import Model, { attr } from '@ember-data/model';
33
export default class AuthenticationMethod extends Model {
44
@attr() identityProvider;
55
@attr() authenticationComplement;
6+
@attr() lastLoggedAt;
67
}

admin/app/styles/components/users/authentication-method.scss

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
.authentication-method {
2-
32
&__connexions-information {
43
display: flex;
5-
6-
dt {
7-
font-weight: normal;
8-
}
9-
10-
dd {
11-
margin-left: 6px;
12-
}
4+
flex-direction: column;
5+
margin-bottom: var(--pix-spacing-6x);
6+
margin-left: var(--pix-spacing-6x);
137
}
148
}
159

@@ -21,37 +15,32 @@
2115
}
2216

2317
&__name-column {
24-
min-width: 200px;
18+
padding-left: var(--pix-spacing-6x);
2519
}
2620

2721
&__actions-column {
28-
2922
> div {
3023
display: flex;
3124

3225
button:not(:first-child) {
33-
margin-left: 10px;
26+
margin-left: var(--pix-spacing-3x);
3427
}
3528
}
3629
}
3730

3831
&__check {
39-
margin: 0 20px;
4032
color: var(--pix-success-700);
4133
}
4234

4335
&__uncheck {
44-
margin: 0 20px;
4536
color: var(--pix-neutral-100);
4637
}
4738
}
4839

4940
.reassign-authentication-method-modal {
50-
5141
&__form-body {
52-
5342
p {
54-
margin-bottom: 40px;
43+
margin-bottom: var(--pix-spacing-10x);
5544
padding: 0;
5645
}
5746
}

admin/tests/integration/components/users/user-detail-personal-information/authentication-method-test.gjs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ module('Integration | Component | users | user-detail-personal-information | aut
133133
)
134134
.exists();
135135
});
136+
136137
test('it displays user has not to change password', async function (assert) {
137138
// given
138139
const user = {
@@ -163,6 +164,37 @@ module('Integration | Component | users | user-detail-personal-information | aut
163164
)
164165
.exists();
165166
});
167+
168+
test('it displays the last logged at with PIX authentication method', async function (assert) {
169+
// given
170+
const user = {
171+
authenticationMethods: [
172+
{
173+
identityProvider: 'PIX',
174+
authenticationComplement: {},
175+
lastLoggedAt: new Date('2022-07-01T00:00:00Z'),
176+
},
177+
],
178+
};
179+
this.owner.register('service:access-control', AccessControlStub);
180+
181+
// when
182+
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
183+
184+
// then
185+
const expectedLabel = t(
186+
'components.users.user-detail-personal-information.authentication-method.last-logged-at',
187+
);
188+
const expectedValue = '01/07/2022';
189+
assert
190+
.dom(
191+
screen.getAllByRole('listitem').find((listItem) => {
192+
const childrenText = listItem.textContent.trim().split('\n');
193+
return childrenText[0]?.trim() === expectedLabel && childrenText[1]?.trim() === expectedValue;
194+
}),
195+
)
196+
.exists();
197+
});
166198
});
167199

168200
module('email authentication method', function () {

admin/translations/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@
440440
"copy-username": "Copy user id"
441441
},
442442
"authentication-method": {
443+
"last-logged-at": "Last logged at {date}",
443444
"should-change-password-status": "Temporary password :"
444445
},
445446
"cgu": {

admin/translations/fr.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@
450450
"copy-username": "Copier l’identifiant"
451451
},
452452
"authentication-method": {
453+
"last-logged-at": "Dernière connexion le {date}",
453454
"should-change-password-status": "Mot de passe temporaire :"
454455
},
455456
"cgu": {

api/db/database-builder/factory/build-authentication-method.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ buildAuthenticationMethod.withGarAsIdentityProvider = function ({
2222
userLastName = 'Saint-James',
2323
createdAt = new Date('2020-01-01'),
2424
updatedAt = new Date('2020-01-02'),
25+
lastLoggedAt = new Date(),
2526
} = {}) {
2627
userId = isUndefined(userId) ? buildUser().id : userId;
2728

@@ -36,6 +37,7 @@ buildAuthenticationMethod.withGarAsIdentityProvider = function ({
3637
userId,
3738
createdAt,
3839
updatedAt,
40+
lastLoggedAt,
3941
};
4042
return databaseBuffer.pushInsertable({
4143
tableName: 'authentication-methods',
@@ -50,6 +52,7 @@ buildAuthenticationMethod.withPixAsIdentityProviderAndHashedPassword = function
5052
userId,
5153
createdAt = new Date('2020-01-01'),
5254
updatedAt = new Date('2020-01-02'),
55+
lastLoggedAt = new Date(),
5356
} = {}) {
5457
userId = isUndefined(userId) ? buildUser().id : userId;
5558

@@ -64,6 +67,7 @@ buildAuthenticationMethod.withPixAsIdentityProviderAndHashedPassword = function
6467
userId,
6568
createdAt,
6669
updatedAt,
70+
lastLoggedAt,
6771
};
6872
return databaseBuffer.pushInsertable({
6973
tableName: 'authentication-methods',
@@ -78,6 +82,7 @@ buildAuthenticationMethod.withPixAsIdentityProviderAndPassword = function ({
7882
userId,
7983
createdAt = new Date('2020-01-01'),
8084
updatedAt = new Date('2020-01-02'),
85+
lastLoggedAt = new Date(),
8186
} = {}) {
8287
userId = isUndefined(userId) ? buildUser().id : userId;
8388

@@ -92,6 +97,7 @@ buildAuthenticationMethod.withPixAsIdentityProviderAndPassword = function ({
9297
userId,
9398
createdAt,
9499
updatedAt,
100+
lastLoggedAt,
95101
};
96102
return databaseBuffer.pushInsertable({
97103
tableName: 'authentication-methods',
@@ -108,7 +114,7 @@ buildAuthenticationMethod.withPoleEmploiAsIdentityProvider = function ({
108114
userId,
109115
createdAt = new Date('2020-01-01'),
110116
updatedAt = new Date('2020-01-02'),
111-
lastLoggedAt = null,
117+
lastLoggedAt = new Date(),
112118
} = {}) {
113119
userId = isUndefined(userId) ? buildUser().id : userId;
114120

@@ -141,6 +147,7 @@ buildAuthenticationMethod.withOidcProviderAsIdentityProvider = function ({
141147
externalIdentifier,
142148
userId,
143149
identityProvider,
150+
lastLoggedAt = new Date(),
144151
}) {
145152
userId = isUndefined(userId) ? buildUser().id : userId;
146153

@@ -159,7 +166,7 @@ buildAuthenticationMethod.withOidcProviderAsIdentityProvider = function ({
159166
}),
160167
createdAt: new Date('2020-01-01'),
161168
updatedAt: new Date('2020-01-02'),
162-
lastLoggedAt: null,
169+
lastLoggedAt,
163170
};
164171
return databaseBuffer.pushInsertable({
165172
tableName: 'authentication-methods',
@@ -174,7 +181,7 @@ buildAuthenticationMethod.withIdentityProvider = function ({
174181
userId,
175182
createdAt = new Date('2020-01-01'),
176183
updatedAt = new Date('2020-01-02'),
177-
lastLoggedAt = null,
184+
lastLoggedAt = new Date(),
178185
} = {}) {
179186
userId = isUndefined(userId) ? buildUser().id : userId;
180187

api/db/seeds/data/team-acces/build-users.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@ function _buildUserWithPoleEmploiAuthenticationMethod(databaseBuilder) {
1212
});
1313
}
1414

15+
function _buildGarUser(databaseBuilder) {
16+
const user = databaseBuilder.factory.buildUser.withRawPassword({
17+
firstName: 'Gar',
18+
lastName: 'User',
19+
20+
});
21+
22+
databaseBuilder.factory.buildAuthenticationMethod.withGarAsIdentityProvider({
23+
userId: user.id,
24+
});
25+
}
26+
1527
function _buildOidcUser(databaseBuilder) {
1628
const user = databaseBuilder.factory.buildUser({
1729
firstName: 'Oidc',
@@ -62,5 +74,6 @@ function _buildUsers(databaseBuilder) {
6274
export function buildUsers(databaseBuilder) {
6375
_buildUsers(databaseBuilder);
6476
_buildUserWithPoleEmploiAuthenticationMethod(databaseBuilder);
77+
_buildGarUser(databaseBuilder);
6578
_buildOidcUser(databaseBuilder);
6679
}

api/src/identity-access-management/infrastructure/repositories/user.repository.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ const getUserDetailsForAdmin = async function (userId) {
134134
'authentication-methods.id',
135135
'authentication-methods.identityProvider',
136136
'authentication-methods.authenticationComplement',
137+
'authentication-methods.lastLoggedAt',
137138
])
138139
.join('users', 'users.id', 'authentication-methods.userId')
139140
.where({ userId });

api/src/identity-access-management/infrastructure/serializers/jsonapi/user-details-for-admin.serializer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ const serialize = function (usersDetailsForAdmin) {
6161
authenticationMethods: {
6262
ref: 'id',
6363
includes: true,
64-
attributes: ['identityProvider', 'authenticationComplement'],
64+
attributes: ['identityProvider', 'authenticationComplement', 'lastLoggedAt'],
6565
},
6666
userLogin: {
6767
ref: 'id',

0 commit comments

Comments
 (0)