CEC-4576: update permission for updateDeploy action (#370)

* CEC-4576: use new UpdateDeploy permission

* update manifest deploy permission
This commit is contained in:
Tristan Timblin
2023-06-27 09:07:43 -04:00
committed by GitHub
parent 26eb084da5
commit df760fa73f
17 changed files with 87 additions and 289 deletions

View File

@@ -6651,24 +6651,6 @@ exports[`App Route /packages authenticated 1`] = `
/>
</svg>
</a>
<a
class=""
href="/package-deploy/1"
style="margin: 5px;"
title="Deploy \\"Test Manifest 1.0\\""
>
<svg
aria-hidden="true"
aria-label="Deploy Test Manifest 1.0"
class="MuiSvgIcon-root"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"
/>
</svg>
</a>
</td>
</tr>
</tbody>
@@ -11561,63 +11543,7 @@ exports[`App Route /vehicle-status authenticated 1`] = `
</div>
<div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
>
<label
class="MuiFormControlLabel-root"
>
<span
aria-disabled="false"
class="MuiButtonBase-root MuiIconButton-root PrivateSwitchBase-root-0 MuiCheckbox-root MuiCheckbox-colorSecondary MuiIconButton-colorSecondary"
>
<span
class="MuiIconButton-label"
>
<input
class="PrivateSwitchBase-input-0"
data-indeterminate="false"
type="checkbox"
value=""
/>
<svg
aria-hidden="true"
class="MuiSvgIcon-root"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"
/>
</svg>
</span>
<span
class="MuiTouchRipple-root"
/>
</span>
<span
class="MuiTypography-root MuiFormControlLabel-label MuiTypography-body1"
>
Force Config Update
</span>
</label>
<a
class=""
href="/vehicle-status/FISKER123"
title="Push Config Update to \\"FISKER123\\""
>
<svg
aria-hidden="true"
aria-label="Push Config Update to \\"FISKER123\\""
class="MuiSvgIcon-root MuiSvgIcon-fontSizeLarge css-tzssek-MuiSvgIcon-root"
data-testid="UploadIcon"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M5 20h14v-2H5v2zm0-10h4v6h6v-6h4l-7-7-7 7z"
/>
</svg>
</a>
</div>
/>
<div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
>

View File

@@ -160,63 +160,7 @@ exports[`VehicleDetailsTab Render 1`] = `
</div>
<div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
>
<label
class="MuiFormControlLabel-root"
>
<span
aria-disabled="false"
class="MuiButtonBase-root MuiIconButton-root PrivateSwitchBase-root-0 MuiCheckbox-root MuiCheckbox-colorSecondary MuiIconButton-colorSecondary"
>
<span
class="MuiIconButton-label"
>
<input
class="PrivateSwitchBase-input-0"
data-indeterminate="false"
type="checkbox"
value=""
/>
<svg
aria-hidden="true"
class="MuiSvgIcon-root"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"
/>
</svg>
</span>
<span
class="MuiTouchRipple-root"
/>
</span>
<span
class="MuiTypography-root MuiFormControlLabel-label MuiTypography-body1"
>
Force Config Update
</span>
</label>
<a
class=""
href="/"
title="Push Config Update to \\"TESTVIN1234567890\\""
>
<svg
aria-hidden="true"
aria-label="Push Config Update to \\"TESTVIN1234567890\\""
class="MuiSvgIcon-root MuiSvgIcon-fontSizeLarge css-tzssek-MuiSvgIcon-root"
data-testid="UploadIcon"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M5 20h14v-2H5v2zm0-10h4v6h6v-6h4l-7-7-7 7z"
/>
</svg>
</a>
</div>
/>
<div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
>

View File

@@ -115,38 +115,38 @@ const MainForm = ({ vin }) => {
<b>Info Source</b>: {vehicle.info_source}
</p>
<p>
<b>Tags</b>: {vehicle.tags ? vehicle.tags.join(", ") : "none" }
<b>Tags</b>: {vehicle.tags ? vehicle.tags.join(", ") : "none"}
</p>
</Grid>
<Grid item md={12} className={classes.textCenterAlign}>
{vehicle.log_level != null && (
{vehicle.log_level != null && (
<p>
<b>Log Level</b>: {vehicle.log_level}
</p>
)}
{vehicle.canbus && (
<>
<p>
<b>CANBus Enabled</b>: {vehicle.canbus.enabled.toString()}
</p>
<p>
<b>Max Memory Buffer Size</b>: {vehicle.canbus.max_mem_buffer_size ?? "Default"}
</p>
<p>
<b>Data Logger Enabled</b>: {vehicle.canbus.data_logger_enabled.toString()}
</p>
<p>
<b>Max Disk Buffer Size</b>: {vehicle.canbus.max_disk_buffer_size ?? "Default"}
</p>
<p>
<b>Filters</b>: {vehicle.canbus.filters ? vehicle.canbus.filters.length : 0}
</p>
<p>
<b>DTC Enabled</b>: { (vehicle.canbus.dtc_enabled || false).toString() }
</p>
</>
)}
</Grid>
{vehicle.canbus && (
<>
<p>
<b>CANBus Enabled</b>: {vehicle.canbus.enabled.toString()}
</p>
<p>
<b>Max Memory Buffer Size</b>: {vehicle.canbus.max_mem_buffer_size ?? "Default"}
</p>
<p>
<b>Data Logger Enabled</b>: {vehicle.canbus.data_logger_enabled.toString()}
</p>
<p>
<b>Max Disk Buffer Size</b>: {vehicle.canbus.max_disk_buffer_size ?? "Default"}
</p>
<p>
<b>Filters</b>: {vehicle.canbus.filters ? vehicle.canbus.filters.length : 0}
</p>
<p>
<b>DTC Enabled</b>: {(vehicle.canbus.dtc_enabled || false).toString()}
</p>
</>
)}
</Grid>
{showDebugMask && (
<Grid item md={12} className={classes.textCenterAlign}>
<p>
@@ -156,19 +156,19 @@ const MainForm = ({ vin }) => {
)}
<Grid item md={12} className={classes.textCenterAlign}>
<RoleWrap
groups={groups}
providers={providers}
rolesPerProvider={Permissions.FiskerCreate}
>
groups={groups}
providers={providers}
rolesPerProvider={Permissions.FiskerUpdateDeploy}
>
<FormControlLabel
label="Force Config Update"
control={
<Checkbox
checked={forced}
onChange={onForcedChange}
/>
}
label="Force Config Update"
control={
<Checkbox
checked={forced}
onChange={onForcedChange}
/>
}
/>
<Tooltip key={`push-config-${vin}`} title={`Push Config Update to "${vin}"`}>
<Link to="#" onClick={() => setShowUploadConfigModal(true)} >
<UploadIcon aria-label={`Push Config Update to "${vin}"`} fontSize="large" />

View File

@@ -2,24 +2,25 @@ jest.mock("../../../Contexts/VehicleContext");
jest.mock("../../../Contexts/StatusContext");
jest.mock("../../../Contexts/UserContext");
import { render, waitFor } from "@testing-library/react";
import { render, screen, waitFor } from "@testing-library/react";
import { BrowserRouter } from "react-router-dom";
import routeData from "react-router";
import { VehicleProvider } from "../../../Contexts/VehicleContext";
import { StatusProvider } from "../../../Contexts/StatusContext";
import { UserProvider, setToken } from "../../../Contexts/UserContext";
import { TEST_AUTH_OBJECT_FISKER }from "../../../../utils/testing";
import { TEST_AUTH_OBJECT_FISKER } from "../../../../utils/testing";
import MainForm from "./index";
import addSnapshotSerializer from "../../../../utils/snapshot";
import * as Roles from "../../../../utils/roles";
const renderVehicleDetailsTab = async () => {
const { container } = render(
<VehicleProvider>
<StatusProvider>
<UserProvider>
<UserProvider >
<BrowserRouter>
<MainForm vin="TESTVIN1234567890"/>
<MainForm vin="TESTVIN1234567890" />
</BrowserRouter>
</UserProvider>
</StatusProvider>
@@ -46,4 +47,23 @@ describe("VehicleDetailsTab", () => {
const container = await renderVehicleDetailsTab();
expect(container).toMatchSnapshot();
});
it("renders update config control when required permission is present.", () => {
const hasRole = jest.spyOn(Roles, 'hasRole');
hasRole.mockReturnValue(true);
render(
<VehicleProvider>
<StatusProvider>
<UserProvider>
<BrowserRouter>
<MainForm vin="TESTVIN1234567890" />
</BrowserRouter>
</UserProvider>
</StatusProvider>
</VehicleProvider>
);
expect(screen.getByLabelText("Force Config Update")).toBeTruthy();
hasRole.mockRestore();
})
});

View File

@@ -168,63 +168,7 @@ exports[`DetailsTab Render 1`] = `
</div>
<div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
>
<label
class="MuiFormControlLabel-root"
>
<span
aria-disabled="false"
class="MuiButtonBase-root MuiIconButton-root PrivateSwitchBase-root-0 MuiCheckbox-root MuiCheckbox-colorSecondary MuiIconButton-colorSecondary"
>
<span
class="MuiIconButton-label"
>
<input
class="PrivateSwitchBase-input-0"
data-indeterminate="false"
type="checkbox"
value=""
/>
<svg
aria-hidden="true"
class="MuiSvgIcon-root"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"
/>
</svg>
</span>
<span
class="MuiTouchRipple-root"
/>
</span>
<span
class="MuiTypography-root MuiFormControlLabel-label MuiTypography-body1"
>
Force Config Update
</span>
</label>
<a
class=""
href="/testroute/TESTVIN1234567890"
title="Push Config Update to \\"TESTVIN1234567890\\""
>
<svg
aria-hidden="true"
aria-label="Push Config Update to \\"TESTVIN1234567890\\""
class="MuiSvgIcon-root MuiSvgIcon-fontSizeLarge css-tzssek-MuiSvgIcon-root"
data-testid="UploadIcon"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M5 20h14v-2H5v2zm0-10h4v6h6v-6h4l-7-7-7 7z"
/>
</svg>
</a>
</div>
/>
<div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
>

View File

@@ -349,63 +349,7 @@ exports[`CarStatus Render 1`] = `
</div>
<div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
>
<label
class="MuiFormControlLabel-root"
>
<span
aria-disabled="false"
class="MuiButtonBase-root MuiIconButton-root PrivateSwitchBase-root-0 MuiCheckbox-root MuiCheckbox-colorSecondary MuiIconButton-colorSecondary"
>
<span
class="MuiIconButton-label"
>
<input
class="PrivateSwitchBase-input-0"
data-indeterminate="false"
type="checkbox"
value=""
/>
<svg
aria-hidden="true"
class="MuiSvgIcon-root"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"
/>
</svg>
</span>
<span
class="MuiTouchRipple-root"
/>
</span>
<span
class="MuiTypography-root MuiFormControlLabel-label MuiTypography-body1"
>
Force Config Update
</span>
</label>
<a
class=""
href="/"
title="Push Config Update to \\"TESTVIN1234567890\\""
>
<svg
aria-hidden="true"
aria-label="Push Config Update to \\"TESTVIN1234567890\\""
class="MuiSvgIcon-root MuiSvgIcon-fontSizeLarge css-tzssek-MuiSvgIcon-root"
data-testid="UploadIcon"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M5 20h14v-2H5v2zm0-10h4v6h6v-6h4l-7-7-7 7z"
/>
</svg>
</a>
</div>
/>
<div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
>

View File

@@ -2,9 +2,9 @@ import React from "react";
import { hasRole } from "../../../utils/roles";
export const RoleWrap = (props) => {
const {groups, rolesPerProvider, providers} = props;
const { groups, rolesPerProvider, providers } = props;
const eitherComponent = props["eitherComponent"] || null;
const eitherComponent = props["eitherComponent"] || null;
if (!hasRole(groups, rolesPerProvider, providers)) {
return eitherComponent != null ? eitherComponent : <></>;

View File

@@ -231,7 +231,7 @@ const MainForm = () => {
icon: <EditIcon aria-label={`Update ${row.name} ${row.version}`} />,
});
}
if (hasRole(groups, Permissions.FiskerMagnaCreate, providers)) {
if (hasRole(groups, Permissions.FiskerUpdateDeploy, providers)) {
actions.push({
tip: `Deploy "${row.name} ${row.version}"`,
link: `/package-deploy/${row.id}`,

View File

@@ -6,6 +6,7 @@ export const Roles = {
DELETE: process.env.REACT_APP_ROLE_DELETE,
CERTIFICATES: process.env.REACT_APP_ROLE_GENERATE_CERTIFICATE,
APPROVESUPPLIERS: process.env.REACT_APP_ROLE_SUPPLIER_APPROVER,
UPDATEDEPLOY: process.env.REACT_APP_ROLE_UPDATE_DEPLOY,
MANUFACTURE: process.env.REACT_APP_ROLE_MANUFACTURE,
MAGNAGROUP: process.env.REACT_APP_MAGNA_GROUP_ID,
MANIFEST_MIGRATION: process.env.REACT_APP_ROLE_MANIFEST_MIGRATION
@@ -81,6 +82,9 @@ export const Permissions = {
[Providers.FISKER_QA]: [Roles.MANUFACTURE],
[Providers.MAGNA]: [Roles.MAGNAGROUP],
},
FiskerUpdateDeploy: {
[Providers.FISKER]: [Roles.UPDATEDEPLOY],
},
Magna: {
[Providers.FISKER_QA]: [Roles.MANUFACTURE],
[Providers.MAGNA]: [Roles.MAGNAGROUP],

View File

@@ -68,6 +68,15 @@ describe("Roles Helper", () => {
).toEqual(true);
});
it("Check FiskerUpdateDeploy permission", () => {
expect(
hasRole([Roles.UPDATEDEPLOY], Permissions.FiskerUpdateDeploy, [Providers.FISKER])
).toEqual(true);
expect(
hasRole([Roles.UPDATEDEPLOY], Permissions.FiskerUpdateDeploy, [Providers.MAGNA])
).toEqual(false);
});
it("Check Magna permission", () => {
expect(
hasRole([Roles.MAGNAGROUP], Permissions.Magna, [Providers.MAGNA])