From 7fdc02aec80e4195f481730fbece103d163b6e47 Mon Sep 17 00:00:00 2001 From: Alex <33497058+bexsoft@users.noreply.github.com> Date: Wed, 5 May 2021 14:33:55 -0500 Subject: [PATCH] Returned multi user list in tenant created modal (#718) Signed-off-by: Benjamin Perez --- models/create_tenant_response.go | 58 +++++------------ models/tenant_response_item.go | 63 ++++++++++++++++++ .../CredentialsPrompt/CredentialsPrompt.tsx | 64 ++++++++++++++----- .../Console/Common/CredentialsPrompt/types.ts | 2 +- .../Console/Tenants/AddTenant/AddTenant.tsx | 28 ++++++-- restapi/admin_tenants.go | 16 +++-- restapi/embedded_spec.go | 55 ++++++++-------- swagger.yml | 18 ++++-- 8 files changed, 204 insertions(+), 100 deletions(-) create mode 100644 models/tenant_response_item.go diff --git a/models/create_tenant_response.go b/models/create_tenant_response.go index cfc51e13b..44ecb9462 100644 --- a/models/create_tenant_response.go +++ b/models/create_tenant_response.go @@ -23,6 +23,8 @@ package models // Editing this file might prove futile when you re-run the swagger generate command import ( + "strconv" + "github.com/go-openapi/errors" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" @@ -34,7 +36,7 @@ import ( type CreateTenantResponse struct { // console - Console *CreateTenantResponseConsole `json:"console,omitempty"` + Console []*TenantResponseItem `json:"console"` } // Validate validates this create tenant response @@ -57,13 +59,20 @@ func (m *CreateTenantResponse) validateConsole(formats strfmt.Registry) error { return nil } - if m.Console != nil { - if err := m.Console.Validate(formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("console") - } - return err + for i := 0; i < len(m.Console); i++ { + if swag.IsZero(m.Console[i]) { // not required + continue } + + if m.Console[i] != nil { + if err := m.Console[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("console" + "." + strconv.Itoa(i)) + } + return err + } + } + } return nil @@ -86,38 +95,3 @@ func (m *CreateTenantResponse) UnmarshalBinary(b []byte) error { *m = res return nil } - -// CreateTenantResponseConsole create tenant response console -// -// swagger:model CreateTenantResponseConsole -type CreateTenantResponseConsole struct { - - // access key - AccessKey string `json:"access_key,omitempty"` - - // secret key - SecretKey string `json:"secret_key,omitempty"` -} - -// Validate validates this create tenant response console -func (m *CreateTenantResponseConsole) Validate(formats strfmt.Registry) error { - return nil -} - -// MarshalBinary interface implementation -func (m *CreateTenantResponseConsole) MarshalBinary() ([]byte, error) { - if m == nil { - return nil, nil - } - return swag.WriteJSON(m) -} - -// UnmarshalBinary interface implementation -func (m *CreateTenantResponseConsole) UnmarshalBinary(b []byte) error { - var res CreateTenantResponseConsole - if err := swag.ReadJSON(b, &res); err != nil { - return err - } - *m = res - return nil -} diff --git a/models/tenant_response_item.go b/models/tenant_response_item.go new file mode 100644 index 000000000..a0f1a9b27 --- /dev/null +++ b/models/tenant_response_item.go @@ -0,0 +1,63 @@ +// Code generated by go-swagger; DO NOT EDIT. + +// This file is part of MinIO Console Server +// Copyright (c) 2021 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// TenantResponseItem tenant response item +// +// swagger:model tenantResponseItem +type TenantResponseItem struct { + + // access key + AccessKey string `json:"access_key,omitempty"` + + // secret key + SecretKey string `json:"secret_key,omitempty"` +} + +// Validate validates this tenant response item +func (m *TenantResponseItem) Validate(formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *TenantResponseItem) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *TenantResponseItem) UnmarshalBinary(b []byte) error { + var res TenantResponseItem + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/portal-ui/src/screens/Console/Common/CredentialsPrompt/CredentialsPrompt.tsx b/portal-ui/src/screens/Console/Common/CredentialsPrompt/CredentialsPrompt.tsx index bf0ebabce..55b27be71 100644 --- a/portal-ui/src/screens/Console/Common/CredentialsPrompt/CredentialsPrompt.tsx +++ b/portal-ui/src/screens/Console/Common/CredentialsPrompt/CredentialsPrompt.tsx @@ -31,6 +31,10 @@ const styles = (theme: Theme) => buttonContainer: { textAlign: "right", }, + credentialsPanel: { + overflowY: "auto", + maxHeight: 350, + } }); interface ICredentialsPromptProps { @@ -84,16 +88,31 @@ const CredentialsPrompt = ({ A new {entity} has been created with the following details: {consoleCreds && ( - + Console Credentials -
    -
  • - Access Key: {consoleCreds.accessKey} -
  • -
  • - Secret Key: {consoleCreds.secretKey} -
  • -
+ {Array.isArray(consoleCreds) && + consoleCreds.map((credentialsPair, index) => { + return ( +
    +
  • + Access Key: {credentialsPair.accessKey} +
  • +
  • + Secret Key: {credentialsPair.secretKey} +
  • +
+ ); + })} + {!Array.isArray(consoleCreds) && ( +
    +
  • + Access Key: {consoleCreds.accessKey} +
  • +
  • + Secret Key: {consoleCreds.secretKey} +
  • +
+ )}
)} @@ -112,12 +131,27 @@ const CredentialsPrompt = ({ let consoleExtras = {}; if (consoleCreds) { - consoleExtras = { - console: { - access_key: consoleCreds.accessKey, - secret_key: consoleCreds.secretKey, - }, - }; + if (!Array.isArray(consoleCreds)) { + consoleExtras = { + console: [ + { + access_key: consoleCreds.accessKey, + secret_key: consoleCreds.secretKey, + }, + ], + }; + } else { + const cCreds = consoleCreds.map((itemMap) => { + return { + access_key: itemMap.accessKey, + secret_key: itemMap.secretKey, + } + }); + + consoleExtras = { + console: [...cCreds], + }; + } } download( diff --git a/portal-ui/src/screens/Console/Common/CredentialsPrompt/types.ts b/portal-ui/src/screens/Console/Common/CredentialsPrompt/types.ts index 7ae8729cf..46193ae55 100644 --- a/portal-ui/src/screens/Console/Common/CredentialsPrompt/types.ts +++ b/portal-ui/src/screens/Console/Common/CredentialsPrompt/types.ts @@ -15,7 +15,7 @@ // along with this program. If not, see . export interface NewServiceAccount { - console?: ConsoleSA; + console?: ConsoleSA | ConsoleSA[]; accessKey?: string; secretKey?: string; } diff --git a/portal-ui/src/screens/Console/Tenants/AddTenant/AddTenant.tsx b/portal-ui/src/screens/Console/Tenants/AddTenant/AddTenant.tsx index e18590f8a..974d4dcc4 100644 --- a/portal-ui/src/screens/Console/Tenants/AddTenant/AddTenant.tsx +++ b/portal-ui/src/screens/Console/Tenants/AddTenant/AddTenant.tsx @@ -15,6 +15,7 @@ // along with this program. If not, see . import React, { Fragment, useEffect, useState } from "react"; +import get from "lodash/get"; import { connect } from "react-redux"; import Grid from "@material-ui/core/Grid"; import { LinearProgress } from "@material-ui/core"; @@ -512,13 +513,30 @@ const AddTenant = ({ api .invoke("POST", `/api/v1/tenants`, dataSend) .then((res) => { - const newSrvAcc: NewServiceAccount = { - console: { - accessKey: res.console.access_key, - secretKey: res.console.secret_key, - }, + const consoleSAList = get(res, "console", []); + + let newSrvAcc: NewServiceAccount = { + console: [], }; + if (consoleSAList && Array.isArray(consoleSAList)) { + const consoleItem = consoleSAList.map((consoleKey) => { + return { + accessKey: consoleKey.access_key, + secretKey: consoleKey.secret_key, + }; + }); + + newSrvAcc.console = consoleItem; + } else { + newSrvAcc = { + console: { + accessKey: res.console.access_key, + secretKey: res.console.secret_key, + }, + }; + } + setAddSending(false); setShowNewCredentials(true); diff --git a/restapi/admin_tenants.go b/restapi/admin_tenants.go index f4a5d6968..4e22d8f44 100644 --- a/restapi/admin_tenants.go +++ b/restapi/admin_tenants.go @@ -767,6 +767,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create // optionals are set below var tenantUserAccessKey string var tenantUserSecretKey string + keyElementEmpty := len(tenantReq.Idp.Keys) == 1 && (*tenantReq.Idp.Keys[0].AccessKey == "" && *tenantReq.Idp.Keys[0].SecretKey == "") enableConsole := true if tenantReq.EnableConsole != nil && *tenantReq.EnableConsole { @@ -775,7 +776,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create if enableConsole { // provision initial user for tenant - if !(len(tenantReq.Idp.Keys) > 0) { + if len(tenantReq.Idp.Keys) == 0 || keyElementEmpty { tenantUserAccessKey = RandomCharString(16) tenantUserSecretKey = RandomCharString(32) consoleUserSecretName := fmt.Sprintf("%s-user-secret", tenantName) @@ -1055,10 +1056,17 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create response = &models.CreateTenantResponse{} // Attach Console Credentials if enableConsole { - response.Console = &models.CreateTenantResponseConsole{ - AccessKey: tenantUserAccessKey, - SecretKey: tenantUserSecretKey, + var itemsToReturn []*models.TenantResponseItem + + if len(tenantReq.Idp.Keys) == 0 || keyElementEmpty { + itemsToReturn = append(itemsToReturn, &models.TenantResponseItem{AccessKey: tenantUserAccessKey, SecretKey: tenantUserSecretKey}) + } else { // IDP Keys + for _, item := range tenantReq.Idp.Keys { + itemsToReturn = append(itemsToReturn, &models.TenantResponseItem{AccessKey: *item.AccessKey, SecretKey: *item.SecretKey}) + } } + + response.Console = itemsToReturn } return response, nil } diff --git a/restapi/embedded_spec.go b/restapi/embedded_spec.go index 1ca74dfdf..ee1745d23 100644 --- a/restapi/embedded_spec.go +++ b/restapi/embedded_spec.go @@ -4330,14 +4330,9 @@ func init() { "type": "object", "properties": { "console": { - "type": "object", - "properties": { - "access_key": { - "type": "string" - }, - "secret_key": { - "type": "string" - } + "type": "array", + "items": { + "$ref": "#/definitions/tenantResponseItem" } } } @@ -6337,6 +6332,17 @@ func init() { } } }, + "tenantResponseItem": { + "type": "object", + "properties": { + "access_key": { + "type": "string" + }, + "secret_key": { + "type": "string" + } + } + }, "tenantUsage": { "type": "object", "properties": { @@ -10463,17 +10469,6 @@ func init() { } } }, - "CreateTenantResponseConsole": { - "type": "object", - "properties": { - "access_key": { - "type": "string" - }, - "secret_key": { - "type": "string" - } - } - }, "GcpConfigurationSecretmanager": { "type": "object", "required": [ @@ -11668,14 +11663,9 @@ func init() { "type": "object", "properties": { "console": { - "type": "object", - "properties": { - "access_key": { - "type": "string" - }, - "secret_key": { - "type": "string" - } + "type": "array", + "items": { + "$ref": "#/definitions/tenantResponseItem" } } } @@ -13528,6 +13518,17 @@ func init() { } } }, + "tenantResponseItem": { + "type": "object", + "properties": { + "access_key": { + "type": "string" + }, + "secret_key": { + "type": "string" + } + } + }, "tenantUsage": { "type": "object", "properties": { diff --git a/swagger.yml b/swagger.yml index ea4dff4c7..cb348d938 100644 --- a/swagger.yml +++ b/swagger.yml @@ -3851,12 +3851,18 @@ definitions: type: object properties: console: - type: object - properties: - access_key: - type: string - secret_key: - type: string + type: array + items: + $ref: "#/definitions/tenantResponseItem" + + tenantResponseItem: + type: object + properties: + access_key: + type: string + secret_key: + type: string + pool: type: object required: