mirror of https://github.com/rancher/dashboard.git
save method in model fixes payload, validator catches the rest (#9758)
This commit is contained in:
parent
718ffd6201
commit
6f0a3d436a
|
|
@ -5712,6 +5712,7 @@ validation:
|
|||
missingResource: You must specify a Resource for each resource grant
|
||||
missingApiGroup: You must specify an API Group for each resource grant
|
||||
missingOneResource: You must specify at least one Resource, Non-Resource URL or API Group for each resource grant
|
||||
noResourceAndNonResource: Each rule may contain Resources or Non-Resource URLs but not both
|
||||
service:
|
||||
externalName:
|
||||
none: External Name is required on an ExternalName Service.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
import { MANAGEMENT, RBAC } from '@shell/config/types';
|
||||
import CruResource from '@shell/components/CruResource';
|
||||
import CreateEditView from '@shell/mixins/create-edit-view';
|
||||
import FormValidation from '@shell/mixins/form-validation';
|
||||
import Error from '@shell/components/form/Error';
|
||||
import { RadioGroup } from '@components/Form/Radio';
|
||||
import Select from '@shell/components/form/Select';
|
||||
import ArrayList from '@shell/components/form/ArrayList';
|
||||
|
|
@ -58,9 +60,10 @@ export default {
|
|||
Tabbed,
|
||||
SortableTable,
|
||||
Loading,
|
||||
Error
|
||||
},
|
||||
|
||||
mixins: [CreateEditView],
|
||||
mixins: [CreateEditView, FormValidation],
|
||||
|
||||
async fetch() {
|
||||
// We don't want to get all schemas from the cluster because there are
|
||||
|
|
@ -109,6 +112,9 @@ export default {
|
|||
scopedResources: SCOPED_RESOURCES,
|
||||
defaultValue: false,
|
||||
selectFocused: null,
|
||||
fvFormRuleSets: [
|
||||
{ path: 'displayName', rules: ['required'] }
|
||||
],
|
||||
};
|
||||
},
|
||||
|
||||
|
|
@ -524,7 +530,8 @@ export default {
|
|||
:can-yaml="!isCreate"
|
||||
:mode="mode"
|
||||
:resource="value"
|
||||
:errors="errors"
|
||||
:errors="fvUnreportedValidationErrors"
|
||||
:validation-passed="fvFormIsValid"
|
||||
:cancel-event="true"
|
||||
@error="e=>errors = e"
|
||||
@finish="save"
|
||||
|
|
@ -568,6 +575,7 @@ export default {
|
|||
name-key="displayName"
|
||||
description-key="description"
|
||||
label="Name"
|
||||
:rules="{ name: fvGetAndReportPathRules('displayName') }"
|
||||
/>
|
||||
<div
|
||||
v-if="isRancherType"
|
||||
|
|
@ -606,6 +614,11 @@ export default {
|
|||
:label="t('rbac.roletemplate.tabs.grantResources.label')"
|
||||
:weight="1"
|
||||
>
|
||||
<Error
|
||||
:value="value.rules"
|
||||
:rules="fvGetAndReportPathRules('rules')"
|
||||
as-banner
|
||||
/>
|
||||
<ArrayList
|
||||
v-model="value.rules"
|
||||
label="Resources"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { CATTLE_API_GROUP, SUBTYPE_MAPPING, CREATE_VERBS } from '@shell/models/m
|
|||
import { uniq } from '@shell/utils/array';
|
||||
import { get } from '@shell/utils/object';
|
||||
import SteveDescriptionModel from '@shell/plugins/steve/steve-description-class';
|
||||
import Role from './rbac.authorization.k8s.io.role';
|
||||
import { AS, MODE, _CLONE, _UNFLAG } from '@shell/config/query-params';
|
||||
|
||||
const BASE = 'user-base';
|
||||
|
|
@ -16,7 +15,14 @@ const GLOBAL = SUBTYPE_MAPPING.GLOBAL.key;
|
|||
|
||||
export default class GlobalRole extends SteveDescriptionModel {
|
||||
get customValidationRules() {
|
||||
return Role.customValidationRules();
|
||||
return [
|
||||
{
|
||||
path: 'rules',
|
||||
validators: [`roleTemplateRules:${ this.type }`],
|
||||
nullable: false,
|
||||
type: 'array',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
get details() {
|
||||
|
|
@ -137,6 +143,15 @@ export default class GlobalRole extends SteveDescriptionModel {
|
|||
async save() {
|
||||
const norman = await this.norman;
|
||||
|
||||
for (const rule of norman.rules) {
|
||||
if (rule.nonResourceURLs.length) {
|
||||
delete rule.resources;
|
||||
delete rule.apiGroups;
|
||||
} else {
|
||||
delete rule.nonResourceURLs;
|
||||
}
|
||||
}
|
||||
|
||||
return norman.save();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import { get } from '@shell/utils/object';
|
|||
import { DESCRIPTION } from '@shell/config/labels-annotations';
|
||||
import { NORMAN } from '@shell/config/types';
|
||||
import SteveDescriptionModel from '@shell/plugins/steve/steve-description-class';
|
||||
import Role from './rbac.authorization.k8s.io.role';
|
||||
import { AS, MODE, _CLONE, _UNFLAG } from '@shell/config/query-params';
|
||||
|
||||
export const CATTLE_API_GROUP = '.cattle.io';
|
||||
|
|
@ -60,7 +59,14 @@ export const CREATE_VERBS = new Set(['PUT', 'blocked-PUT']);
|
|||
|
||||
export default class RoleTemplate extends SteveDescriptionModel {
|
||||
get customValidationRules() {
|
||||
return Role.customValidationRules();
|
||||
return [
|
||||
{
|
||||
path: 'rules',
|
||||
validators: [`roleTemplateRules:${ this.type }`],
|
||||
nullable: false,
|
||||
type: 'array',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
get details() {
|
||||
|
|
@ -185,6 +191,15 @@ export default class RoleTemplate extends SteveDescriptionModel {
|
|||
async save() {
|
||||
const norman = await this.norman;
|
||||
|
||||
for (const rule of norman.rules) {
|
||||
if (rule.nonResourceURLs.length) {
|
||||
delete rule.resources;
|
||||
delete rule.apiGroups;
|
||||
} else {
|
||||
delete rule.nonResourceURLs;
|
||||
}
|
||||
}
|
||||
|
||||
return norman.save();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -393,6 +393,18 @@ describe('formRules', () => {
|
|||
expect(formRuleResult).toStrictEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('"roleTemplateRules" : returns correct message when type is RBAC role rule defines both resources and nonResourceURLs', () => {
|
||||
const testValue: [{}] = [
|
||||
{
|
||||
verbs: ['verb1'], resources: ['resource1'], apiGroups: ['apiGroup1'], nonResourceURLs: ['nonResourceUrl1']
|
||||
}
|
||||
];
|
||||
const formRuleResult = formRules.roleTemplateRules('rbac.authorization.k8s.io.role')(testValue);
|
||||
const expectedResult = JSON.stringify({ message: 'validation.roleTemplate.roleTemplateRules.noResourceAndNonResource' });
|
||||
|
||||
expect(formRuleResult).toStrictEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('"roleTemplateRules" : returns correct message when type is RBAC role and value is missing apiGroups', () => {
|
||||
const testValue: [{}] = [
|
||||
{
|
||||
|
|
@ -408,7 +420,7 @@ describe('formRules', () => {
|
|||
it('"roleTemplateRules" : returns undefined when type is not RBAC role and value contains valid rules', () => {
|
||||
const testValue: [{}] = [
|
||||
{
|
||||
verbs: ['verb1'], nonResourceURLs: ['nonResourceURL1'], resources: ['resource1'], apiGroups: ['apiGroup1']
|
||||
verbs: ['verb1'], resources: ['resource1'], apiGroups: ['apiGroup1']
|
||||
}
|
||||
];
|
||||
const formRuleResult = formRules.roleTemplateRules('nonrbactype')(testValue);
|
||||
|
|
|
|||
|
|
@ -370,6 +370,10 @@ export default function(t: Translation, { key = 'Value' }: ValidationOptions): {
|
|||
return t('validation.roleTemplate.roleTemplateRules.missingVerb');
|
||||
}
|
||||
|
||||
if (val.some((rule: any) => rule.resources?.length && rule.nonResourceURLs?.length)) {
|
||||
return t('validation.roleTemplate.roleTemplateRules.noResourceAndNonResource');
|
||||
}
|
||||
|
||||
if (type === RBAC.ROLE) {
|
||||
if (val.some((rule: any) => isEmpty(rule.resources))) {
|
||||
return t('validation.roleTemplate.roleTemplateRules.missingResource');
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@ export function roleTemplateRules(rules = [], getters, errors, validatorArgs = [
|
|||
errors.push(getters['i18n/t']('validation.roleTemplate.roleTemplateRules.missingVerb'));
|
||||
}
|
||||
|
||||
if (rules.some((rule) => rule.resources?.length && rule.nonResourceURLs?.length)) {
|
||||
errors.push(getters['i18n/t']('validation.roleTemplate.roleTemplateRules.noResourceAndNonResource'));
|
||||
}
|
||||
|
||||
if (validatorArgs[0] === RBAC.ROLE) {
|
||||
if (rules.some((rule) => isEmpty(rule.resources))) {
|
||||
errors.push(getters['i18n/t']('validation.roleTemplate.roleTemplateRules.missingResource'));
|
||||
|
|
@ -13,7 +17,11 @@ export function roleTemplateRules(rules = [], getters, errors, validatorArgs = [
|
|||
if (rules.some((rule) => isEmpty(rule.apiGroups))) {
|
||||
errors.push(getters['i18n/t']('validation.roleTemplate.roleTemplateRules.missingApiGroup'));
|
||||
}
|
||||
} else if (rules.some((rule) => isEmpty(rule.resources) && isEmpty(rule.nonResourceURLs) && isEmpty(rule.apiGroups))) {
|
||||
} else if (rules.some((rule) => rule.resources?.length && rule.nonResourceUrls?.length)) {
|
||||
errors.push(getters['i18n/t']('validation.roleTemplate.roleTemplateRules.noResourceAndNonResource'));
|
||||
}
|
||||
|
||||
if (rules.some((rule) => isEmpty(rule.resources) && isEmpty(rule.nonResourceURLs) && isEmpty(rule.apiGroups))) {
|
||||
errors.push(getters['i18n/t']('validation.roleTemplate.roleTemplateRules.missingOneResource'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue