From 0a5786527091b6cfe31cd08346d335cfb44ff5d1 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Thu, 17 Jun 2021 14:09:31 -0400 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20type-aware=20a?= =?UTF-8?q?ccount=20display=20in=20admin=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/api/addon/models/account.js | 13 +++------ addons/api/mirage/factories/account.js | 17 ++++++++++- addons/api/mirage/factories/auth-method.js | 4 +-- .../api/mirage/generated/factories/account.js | 7 ++--- addons/api/tests/unit/models/account-test.js | 9 +++--- .../form/user/add-accounts/index.hbs | 10 +++++-- .../auth-method/accounts/index.hbs | 28 +++++++++++++------ .../scopes/scope/users/user/accounts.hbs | 8 ++++-- 8 files changed, 61 insertions(+), 35 deletions(-) diff --git a/addons/api/addon/models/account.js b/addons/api/addon/models/account.js index e5f702541..9412e18aa 100644 --- a/addons/api/addon/models/account.js +++ b/addons/api/addon/models/account.js @@ -26,15 +26,10 @@ export default class AccountModel extends GeneratedAccountModel { * Convenience for getting username in account. * @type {string} */ - @computed('type', 'attributes.login_name') - get username() { - let username = ''; - switch (this.type) { - case 'password': - username = this.attributes.login_name; - break; - } - return username; + @computed('attributes.{email,full_name,login_name}') + get accountName() { + const { email, full_name, login_name } = this.attributes; + return email || full_name || login_name; } // =methods diff --git a/addons/api/mirage/factories/account.js b/addons/api/mirage/factories/account.js index 5908d0a21..5c49f96b5 100644 --- a/addons/api/mirage/factories/account.js +++ b/addons/api/mirage/factories/account.js @@ -1,3 +1,18 @@ import factory from '../generated/factories/account'; +import { random, internet } from 'faker'; -export default factory.extend(); +export default factory.extend({ + attributes() { + switch (this.type) { + case 'password': + return { login_name: random.words() }; + case 'oidc': + return { + issuer: internet.ip(), + subject: 'sub', + email: internet.email(), + full_name: random.words(), + }; + } + }, +}); diff --git a/addons/api/mirage/factories/auth-method.js b/addons/api/mirage/factories/auth-method.js index b7dc8ddda..fd8e705fd 100644 --- a/addons/api/mirage/factories/auth-method.js +++ b/addons/api/mirage/factories/auth-method.js @@ -14,9 +14,9 @@ export default factory.extend({ */ withAccountsAndUsers: trait({ afterCreate(authMethod, server) { - const { scope } = authMethod; + const { scope, type } = authMethod; server.createList('user', 5, { scope }).map((user) => { - const { id } = server.create('account', { scope, authMethod }); + const { id } = server.create('account', { scope, type, authMethod }); user.update({ accountIds: [id] }); }); }, diff --git a/addons/api/mirage/generated/factories/account.js b/addons/api/mirage/generated/factories/account.js index bc5a33c02..92a515a73 100644 --- a/addons/api/mirage/generated/factories/account.js +++ b/addons/api/mirage/generated/factories/account.js @@ -1,15 +1,14 @@ import { Factory } from 'ember-cli-mirage'; -import { random, date, datatype } from 'faker'; +import { date, datatype } from 'faker'; /** * GeneratedAccountFactory */ export default Factory.extend({ type: 'password', - name: () => random.words(), - description: () => random.words(), + // name: () => random.words(), + // description: () => random.words(), created_time: () => date.recent(), updated_time: () => date.recent(), version: () => datatype.number(), - attributes: () => ({ login_name: random.words() }), }); diff --git a/addons/api/tests/unit/models/account-test.js b/addons/api/tests/unit/models/account-test.js index 33021e295..4a4b3b0d4 100644 --- a/addons/api/tests/unit/models/account-test.js +++ b/addons/api/tests/unit/models/account-test.js @@ -10,15 +10,14 @@ module('Unit | Model | account', function (hooks) { assert.ok(model); }); - test('it has an username attribute for password account', function (assert) { + test('it has an accountName attribute for password account', function (assert) { assert.expect(2); const store = this.owner.lookup('service:store'); let model = store.createRecord('account', { - name: 'name', type: 'password', }); - assert.notOk(model.username); - model.attributes.login_name = 'username'; - assert.equal(model.username, 'username'); + assert.notOk(model.accountName); + model.attributes.login_name = 'foobar'; + assert.equal(model.accountName, 'foobar'); }); }); diff --git a/ui/admin/app/components/form/user/add-accounts/index.hbs b/ui/admin/app/components/form/user/add-accounts/index.hbs index eb9ef4123..ac93847f7 100644 --- a/ui/admin/app/components/form/user/add-accounts/index.hbs +++ b/ui/admin/app/components/form/user/add-accounts/index.hbs @@ -17,7 +17,8 @@ {{t 'form.id.label'}} - {{t 'form.username.label'}} + {{t 'form.name.label'}} + {{t 'form.type.label'}} {{t 'resources.auth-method.title'}} @@ -31,7 +32,12 @@ onChange={{fn this.toggleAccount account}} /> - {{account.username}} + {{account.accountName}} + + + {{t (concat 'resources.auth-method.types.' account.type)}} + + {{account.auth_method_id}} diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs index dd16fcb1b..d1ee9dde5 100644 --- a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs +++ b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs @@ -10,6 +10,7 @@ {{t 'form.subject.label'}} {{t 'form.email.label'}} {{t 'form.full_name.label'}} + {{t 'form.type.label'}} {{t 'form.id.label'}} @@ -17,7 +18,13 @@ {{#each @model as |account|}} - {{account.displayName}} + + {{account.accountName}} +

{{account.description}}

+
{{account.attributes.issuer}} @@ -31,6 +38,9 @@ {{account.attributes.full_name}} + + {{account.type}} + {{t 'form.name.label'}} - - {{#if @model.firstObject.isPassword}} - {{t 'form.login_name.label'}} - {{/if}} - + {{t 'form.login_name.label'}} + {{t 'form.type.label'}} {{t 'form.id.label'}} @@ -65,12 +72,15 @@ @route='scopes.scope.auth-methods.auth-method.accounts.account' @model={{account.id}} > - {{account.displayName}} + {{account.accountName}} +

{{account.description}}

-

{{account.description}}

- {{account.username}} + {{account.attributes.login_name}} + + + {{account.type}} {{t 'form.name.label'}} - {{t 'form.login_name.label'}} + {{t 'form.type.label'}} {{t 'form.id.label'}} {{t 'titles.actions'}} @@ -15,11 +15,13 @@ {{#each @model.accounts as |account|}} - {{account.displayName}} + {{account.accountName}}

{{account.description}}

- {{account.username}} + + {{t (concat 'resources.auth-method.types.' account.type)}} + Date: Fri, 18 Jun 2021 09:51:52 -0400 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20OIDC-typed=20a?= =?UTF-8?q?ccount=20form?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/components/form/account/index.hbs | 8 ++ .../components/form/account/oidc/index.hbs | 127 ++++++++++++++++++ .../auth-methods/auth-method/accounts/new.js | 4 +- .../auth-methods/auth-method/-actions.hbs | 23 +--- .../accounts/account/-navigation.hbs | 12 +- .../auth-method/accounts/account/index.hbs | 2 +- .../auth-methods/auth-method/accounts/new.hbs | 2 +- ui/admin/config/environment.js | 2 +- 8 files changed, 153 insertions(+), 27 deletions(-) create mode 100644 ui/admin/app/components/form/account/index.hbs create mode 100644 ui/admin/app/components/form/account/oidc/index.hbs diff --git a/ui/admin/app/components/form/account/index.hbs b/ui/admin/app/components/form/account/index.hbs new file mode 100644 index 000000000..baf4e23fd --- /dev/null +++ b/ui/admin/app/components/form/account/index.hbs @@ -0,0 +1,8 @@ +{{#if @model.type}} + {{component + (concat 'form/account/' @model.type) + model=@model + submit=@submit + cancel=@cancel + }} +{{/if}} \ No newline at end of file diff --git a/ui/admin/app/components/form/account/oidc/index.hbs b/ui/admin/app/components/form/account/oidc/index.hbs new file mode 100644 index 000000000..b3a2dd8a7 --- /dev/null +++ b/ui/admin/app/components/form/account/oidc/index.hbs @@ -0,0 +1,127 @@ + + + + {{#unless @model.isNew}} + + + + + {{/unless}} + + + {{#if @model.errors.name}} + + {{#each @model.errors.name as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{#if @model.errors.description}} + + {{#each @model.errors.description as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + {{#if @model.isNew}} + + {{#if @model.errors.issuer}} + + {{#each @model.errors.issuer as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{#if @model.errors.subject}} + + {{#each @model.errors.subject as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + {{/if}} + + + + \ No newline at end of file diff --git a/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/accounts/new.js b/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/accounts/new.js index 20062c03e..2d31bd683 100644 --- a/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/accounts/new.js +++ b/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/accounts/new.js @@ -8,11 +8,11 @@ export default class ScopesScopeAuthMethodsAuthMethodAccountsNewRoute extends Ro * @return {AccountModel} */ model() { - const { id: auth_method_id } = this.modelFor( + const { id: auth_method_id, type } = this.modelFor( 'scopes.scope.auth-methods.auth-method' ); return this.store.createRecord('account', { - type: 'password', + type, auth_method_id, }); } diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/-actions.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/-actions.hbs index 1ae2b32b3..2d6e7d9a9 100644 --- a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/-actions.hbs +++ b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/-actions.hbs @@ -53,23 +53,12 @@ {{/if}} {{/if}} - {{#if @model.isOIDC}} - {{#if (feature-flag 'oidc-account-crud')}} - - {{t 'resources.account.actions.create'}} - - {{/if}} - {{else}} - - {{t 'resources.account.actions.create'}} - - {{/if}} + + {{t 'resources.account.actions.create'}} + {{t 'titles.details'}} - - {{t 'actions.set-password'}} - + {{#if @model.isPassword}} + + {{t 'actions.set-password'}} + + {{/if}} \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/index.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/index.hbs index 118fea9a8..e20c46a14 100644 --- a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/index.hbs +++ b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/index.hbs @@ -1,4 +1,4 @@ - Date: Fri, 18 Jun 2021 10:23:40 -0400 Subject: [PATCH 3/4] =?UTF-8?q?chore:=20=F0=9F=A4=96=20add=20serialization?= =?UTF-8?q?=20support=20for=20OIDC-type=20accounts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/api/addon/serializers/account.js | 19 +++++ .../tests/unit/serializers/account-test.js | 71 ++++++++++++++++++- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/addons/api/addon/serializers/account.js b/addons/api/addon/serializers/account.js index 939aceb70..128fa10e2 100644 --- a/addons/api/addon/serializers/account.js +++ b/addons/api/addon/serializers/account.js @@ -23,9 +23,28 @@ export default class AccountSerializer extends ApplicationSerializer { switch (snapshot.record.type) { case 'password': return this.serializePassword(...arguments); + case 'oidc': + return this.serializeOIDC(...arguments); } } + /** + * OIDC serialization limits the `attributes` posted on create and omits + * `attributes` entirely on update. + */ + serializeOIDC(snapshot) { + const { isNew } = snapshot?.record; + let serialized = super.serialize(...arguments); + delete serialized.attributes; + if (isNew) { + serialized.attributes = {}; + const { issuer, subject } = snapshot.attr('attributes').record; + if (issuer) serialized.attributes.issuer = issuer; + if (subject) serialized.attributes.subject = subject; + } + return serialized; + } + /** * Password serialization omits `attributes` and handles password-related * custom methods. diff --git a/addons/api/tests/unit/serializers/account-test.js b/addons/api/tests/unit/serializers/account-test.js index 4d5646e08..7af6a504f 100644 --- a/addons/api/tests/unit/serializers/account-test.js +++ b/addons/api/tests/unit/serializers/account-test.js @@ -4,7 +4,75 @@ import { setupTest } from 'ember-qunit'; module('Unit | Serializer | account', function (hooks) { setupTest(hooks); - test('it serializes normally', function (assert) { + test('it serializes OIDC-type with only issuer and subject in `attributes` on create', function (assert) { + assert.expect(1); + const store = this.owner.lookup('service:store'); + const serializer = store.serializerFor('account'); + const record = store.createRecord('account', { + type: 'oidc', + name: 'Name', + auth_method_id: '1', + description: 'Description', + attributes: { + issuer: 'issuer', + subject: 'sub', + full_name: 'full_name', + email: 'email', + }, + version: 1, + }); + const snapshot = record._createSnapshot(); + const serializedRecord = serializer.serialize(snapshot); + assert.deepEqual(serializedRecord, { + type: 'oidc', + name: 'Name', + auth_method_id: '1', + description: 'Description', + version: 1, + attributes: { + issuer: 'issuer', + subject: 'sub', + }, + }); + }); + + test('it serializes OIDC-type without `attributes` on update', function (assert) { + assert.expect(2); + const store = this.owner.lookup('service:store'); + const serializer = store.serializerFor('account'); + store.push({ + data: { + id: '1', + type: 'account', + attributes: { + type: 'oidc', + name: 'Name', + auth_method_id: '1', + description: 'Description', + attributes: { + issuer: 'issuer', + subject: 'sub', + full_name: 'full_name', + email: 'email', + }, + version: 1, + }, + }, + }); + const record = store.peekRecord('account', '1'); + const snapshot = record._createSnapshot(); + const serializedRecord = serializer.serialize(snapshot); + assert.notOk(serializedRecord.attributes); + assert.deepEqual(serializedRecord, { + type: 'oidc', + name: 'Name', + auth_method_id: '1', + description: 'Description', + version: 1, + }); + }); + + test('it serializes password-type normally', function (assert) { assert.expect(1); const store = this.owner.lookup('service:store'); const serializer = store.serializerFor('account'); @@ -19,7 +87,6 @@ module('Unit | Serializer | account', function (hooks) { version: 1, }); const snapshot = record._createSnapshot(); - snapshot.adapterOptions = {}; const serializedRecord = serializer.serialize(snapshot); assert.deepEqual(serializedRecord, { type: 'password', From 50ba2eb73a5802cbbc8e798d34eded0471bd3b72 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Wed, 23 Jun 2021 14:57:56 -0400 Subject: [PATCH 4/4] fix: Fix syntax in about menu option in desktop --- ui/desktop/electron-app/src/config/menu.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/desktop/electron-app/src/config/menu.js b/ui/desktop/electron-app/src/config/menu.js index 071927442..67a2d5449 100644 --- a/ui/desktop/electron-app/src/config/menu.js +++ b/ui/desktop/electron-app/src/config/menu.js @@ -15,8 +15,7 @@ const generateMenuTemplate = () => { type: 'none', message: config.productName, detail: `${appVersion}\n${appCommit}\n\n${cliVersion}\n\n${copyright}`, - }; - dialog.showMessageBox(dialogOpts); + }); }; return [