Skip to content

Commit e648026

Browse files
feat(admin): display applications last logged at
Co-authored-by: P-Jeremy <jemyplu@gmail.com> Co-authored-by: LEGO Technix <109212476+lego-technix@users.noreply.github.com>
1 parent b66c1c1 commit e648026

File tree

6 files changed

+79
-22
lines changed

6 files changed

+79
-22
lines changed

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

+13
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,19 @@ export default class AuthenticationMethod extends Component {
235235
{{#if this.shouldChangePassword}}{{t "common.words.yes"}}{{else}}{{t "common.words.no"}}{{/if}}
236236
</li>
237237
{{/if}}
238+
239+
{{#each @user.orderedLastApplicationConnections as |orderedLastApplicationConnection|}}
240+
<li>
241+
{{t
242+
"components.users.user-detail-personal-information.authentication-method.last-application-connection-date"
243+
}}
244+
{{orderedLastApplicationConnection.label}}
245+
:
246+
{{#if orderedLastApplicationConnection.lastLoggedAt}}
247+
{{dayjsFormat orderedLastApplicationConnection.lastLoggedAt "DD/MM/YYYY"}}
248+
{{/if}}
249+
</li>
250+
{{/each}}
238251
</ul>
239252

240253
<table class="authentication-method-table">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import Model, { attr } from '@ember-data/model';
2+
3+
export default class LastApplicationConnection extends Model {
4+
@attr() application;
5+
@attr() lastLoggedAt;
6+
}

admin/app/models/user.js

+21
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
import { computed } from '@ember/object';
33
import Model, { attr, belongsTo, hasMany } from '@ember-data/model';
44

5+
const orderedApplicationNames = ['app', 'orga', 'certif'];
6+
7+
const applicationLabels = {
8+
app: 'Pix App',
9+
orga: 'Pix Orga',
10+
certif: 'Pix Certif',
11+
};
12+
513
export default class User extends Model {
614
@attr() firstName;
715
@attr() lastName;
@@ -31,6 +39,7 @@ export default class User extends Model {
3139
@hasMany('certification-center-membership', { async: true, inverse: 'user' }) certificationCenterMemberships;
3240
@hasMany('organization-learner', { async: true, inverse: 'user' }) organizationLearners;
3341
@hasMany('authentication-method', { async: true, inverse: null }) authenticationMethods;
42+
@hasMany('last-application-connection', { async: false, inverse: null }) lastApplicationConnections;
3443
@hasMany('user-participation', { async: true, inverse: null }) participations;
3544

3645
@computed('firstName', 'lastName')
@@ -54,4 +63,16 @@ export default class User extends Model {
5463
get authenticationMethodCount() {
5564
return this.username && this.email ? this.authenticationMethods.length + 1 : this.authenticationMethods.length;
5665
}
66+
67+
get orderedLastApplicationConnections() {
68+
const connections = orderedApplicationNames.map((applicationName) => {
69+
const lastLoggedAt = this.lastApplicationConnections?.find((connection) => {
70+
return connection.application === applicationName;
71+
})?.lastLoggedAt;
72+
73+
return { lastLoggedAt, label: applicationLabels[applicationName] };
74+
});
75+
76+
return connections;
77+
}
5778
}

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

+37-22
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,19 @@ import setupIntlRenderingTest from '../../../../helpers/setup-intl-rendering';
1010
module('Integration | Component | users | user-detail-personal-information | authentication-method', function (hooks) {
1111
setupIntlRenderingTest(hooks);
1212

13-
module('When the admin member has access to users actions scope', function () {
14-
class AccessControlStub extends Service {
13+
module('When the admin member has access to users actions scope', function (hooks) {
14+
const stub = class AccessControlStub extends Service {
1515
hasAccessToUsersActionsScope = true;
16-
}
16+
};
17+
hooks.beforeEach(function () {
18+
this.owner.register('service:access-control', stub);
19+
});
1720

1821
module('When user has authentication methods', function () {
1922
module('when user has confirmed his email address', function () {
2023
test('should display email confirmed date', async function (assert) {
2124
// given
2225
const user = { emailConfirmedAt: new Date('2020-10-30'), authenticationMethods: [] };
23-
this.owner.register('service:access-control', AccessControlStub);
2426

2527
// when
2628
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
@@ -44,7 +46,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
4446
test('it should display "Adresse e-mail non confirmée"', async function (assert) {
4547
// given
4648
const user = { emailConfirmedAt: null, authenticationMethods: [] };
47-
this.owner.register('service:access-control', AccessControlStub);
4849

4950
// when
5051
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
@@ -71,7 +72,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
7172
},
7273
],
7374
};
74-
this.owner.register('service:access-control', AccessControlStub);
7575

7676
// when
7777
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
@@ -102,8 +102,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
102102
],
103103
};
104104

105-
this.owner.register('service:access-control', AccessControlStub);
106-
107105
// when
108106
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
109107

@@ -133,7 +131,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
133131
},
134132
],
135133
};
136-
this.owner.register('service:access-control', AccessControlStub);
137134

138135
// when
139136
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
@@ -159,7 +156,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
159156
test('should display information', async function (assert) {
160157
// given
161158
const user = { email: 'pix.aile@example.net', authenticationMethods: [{ identityProvider: 'PIX' }] };
162-
this.owner.register('service:access-control', AccessControlStub);
163159

164160
// when
165161
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
@@ -173,7 +169,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
173169
test('should display information', async function (assert) {
174170
// given
175171
const user = { authenticationMethods: [] };
176-
this.owner.register('service:access-control', AccessControlStub);
177172

178173
// when
179174
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
@@ -191,7 +186,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
191186
test('should display information', async function (assert) {
192187
// given
193188
const user = { username: 'PixAile', authenticationMethods: [{ identityProvider: 'PIX' }] };
194-
this.owner.register('service:access-control', AccessControlStub);
195189

196190
// when
197191
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
@@ -205,7 +199,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
205199
test('should display information', async function (assert) {
206200
// given
207201
const user = { authenticationMethods: [] };
208-
this.owner.register('service:access-control', AccessControlStub);
209202

210203
// when
211204
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
@@ -223,7 +216,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
223216
test('should display information and reassign authentication method button', async function (assert) {
224217
// given
225218
const user = { authenticationMethods: [{ identityProvider: 'GAR' }] };
226-
this.owner.register('service:access-control', AccessControlStub);
227219

228220
// when
229221
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
@@ -238,7 +230,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
238230
test('should display information', async function (assert) {
239231
// given
240232
const user = { username: 'PixAile', authenticationMethods: [{ identityProvider: 'PIX' }] };
241-
this.owner.register('service:access-control', AccessControlStub);
242233

243234
// when
244235
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
@@ -265,7 +256,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
265256
test('should display information', async function (assert) {
266257
// given
267258
const user = { authenticationMethods: [] };
268-
this.owner.register('service:access-control', AccessControlStub);
269259
this.owner.register('service:oidc-identity-providers', OidcIdentityProvidersStub);
270260

271261
// when
@@ -287,7 +277,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
287277
authenticationMethods: [{ identityProvider: 'PIX' }, { identityProvider: 'SUNLIGHT_NAVIGATIONS' }],
288278
};
289279

290-
this.owner.register('service:access-control', AccessControlStub);
291280
this.owner.register('service:oidc-identity-providers', OidcIdentityProvidersStub);
292281

293282
// when
@@ -312,7 +301,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
312301
authenticationMethods: [{ identityProvider: 'PIX' }],
313302
};
314303

315-
this.owner.register('service:access-control', AccessControlStub);
316304
this.owner.register('service:oidc-identity-providers', OidcIdentityProvidersStub);
317305

318306
// when
@@ -340,7 +328,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
340328
test('it should not display a remove authentication method link', async function (assert) {
341329
// given
342330
const user = { username: 'PixAile', authenticationMethods: [{ identityProvider: 'PIX' }] };
343-
this.owner.register('service:access-control', AccessControlStub);
344331

345332
// when
346333
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
@@ -367,7 +354,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
367354
username: 'PixAile',
368355
authenticationMethods: [{ identityProvider: 'SUNLIGHT_NAVIGATIONS' }],
369356
};
370-
this.owner.register('service:access-control', AccessControlStub);
371357

372358
// when
373359
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
@@ -383,7 +369,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
383369
const user = {
384370
authenticationMethods: [],
385371
};
386-
this.owner.register('service:access-control', AccessControlStub);
387372

388373
// when
389374
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
@@ -397,7 +382,6 @@ module('Integration | Component | users | user-detail-personal-information | aut
397382
test('it should not display add authentication method button', async function (assert) {
398383
// given
399384
const user = { username: 'PixAile', authenticationMethods: [{ identityProvider: 'PIX' }] };
400-
this.owner.register('service:access-control', AccessControlStub);
401385

402386
// when
403387
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
@@ -408,6 +392,37 @@ module('Integration | Component | users | user-detail-personal-information | aut
408392
});
409393
});
410394
});
395+
396+
test('it displays last application connections', async function (assert) {
397+
// given
398+
const store = this.owner.lookup('service:store');
399+
const user = store.createRecord('user', {
400+
username: 'PixAile',
401+
authenticationMethods: [store.createRecord('authentication-method', { identityProvider: 'PIX' })],
402+
lastApplicationConnections: [
403+
store.createRecord('last-application-connection', {
404+
application: 'app',
405+
lastLoggedAt: new Date('2022-05-01T00:00:00Z'),
406+
}),
407+
store.createRecord('last-application-connection', {
408+
application: 'orga',
409+
lastLoggedAt: new Date('2022-01-01T00:00:00Z'),
410+
}),
411+
store.createRecord('last-application-connection', {
412+
application: 'certif',
413+
lastLoggedAt: new Date('2022-02-01T00:00:00Z'),
414+
}),
415+
],
416+
});
417+
418+
// when
419+
const screen = await render(<template><AuthenticationMethod @user={{user}} /></template>);
420+
421+
// then
422+
assert.dom(screen.getByText('Date de dernière connexion Pix App : 01/05/2022')).exists();
423+
assert.dom(screen.getByText('Date de dernière connexion Pix Orga : 01/01/2022')).exists();
424+
assert.dom(screen.getByText('Date de dernière connexion Pix Certif : 01/02/2022')).exists();
425+
});
411426
});
412427

413428
module('When the admin member does not have access to users actions scope', function () {

admin/translations/en.json

+1
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@
488488
"copy-username": "Copy user id"
489489
},
490490
"authentication-method": {
491+
"last-application-connection-date": "Last application connection date",
491492
"last-logged-at": "Last logged at {date}",
492493
"should-change-password-status": "Temporary password :"
493494
},

admin/translations/fr.json

+1
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,7 @@
498498
"copy-username": "Copier l’identifiant"
499499
},
500500
"authentication-method": {
501+
"last-application-connection-date": "Date de dernière connexion",
501502
"last-logged-at": "Dernière connexion le {date}",
502503
"should-change-password-status": "Mot de passe temporaire :"
503504
},

0 commit comments

Comments
 (0)