diff --git a/client/src/components/exercise/lab7/Main.js b/client/src/components/exercise/lab7/Main.js index 70137e34c..9efacc295 100644 --- a/client/src/components/exercise/lab7/Main.js +++ b/client/src/components/exercise/lab7/Main.js @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React from "react"; import { Router } from "@reach/router"; import "../../../assets/stylesheets/main.scss"; @@ -12,31 +12,29 @@ import AlterationStart from "./pages/AlterationActivity/AlterationStart"; import AlterationQuiz from "./pages/AlterationActivity/AlterationQuiz"; import ExerciseEnd from "./pages/ExerciseEnd"; -class Main extends Component { - render() { - return ( -
- - +const Main = () => { + return ( +
+ + - {/* Phase 1: Simulation */} - - - + {/* Phase 1: Simulation */} + + + - {/* Phase 2: Improve AI Code Repair */} - - + {/* Phase 2: Improve AI Code Repair */} + + - {/* Phase 3: Alteration Activity */} - - + {/* Phase 3: Alteration Activity */} + + - - -
- ); - } -} + +
+
+ ); +}; export default Main; diff --git a/client/src/components/exercise/lab7/components/Code.js b/client/src/components/exercise/lab7/components/Code.js index 5d101f66c..ace1f19f6 100644 --- a/client/src/components/exercise/lab7/components/Code.js +++ b/client/src/components/exercise/lab7/components/Code.js @@ -160,14 +160,10 @@ class Code extends Component {
AutoSysAI.js
- {/* psuedocode */} - {/*
- Psuedocode -
*/} + {/* import React, Component from react */}
- {/* import React, Component from react */}
import  React @@ -199,13 +195,15 @@ class Code extends Component {
{/* AI function comment */} - // Here is where you will update the equation to improve the AI‘s accuracy + // Here is where you will update the equation to improve + the AI‘s accuracy
{/* AI function comment */} - // Feel free to add other math operations to improve its accuracy + // Feel free to add other math operations to improve its + accuracy
diff --git a/client/src/components/exercise/lab7/components/Collapsible.js b/client/src/components/exercise/lab7/components/Collapsible.js index 7fa04030a..204d5f795 100644 --- a/client/src/components/exercise/lab7/components/Collapsible.js +++ b/client/src/components/exercise/lab7/components/Collapsible.js @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React, { useState } from "react"; import { FILE_INCORRECT, FILE_INTRUSION, @@ -7,114 +7,97 @@ import { } from "../../../../constants/lab7"; import PropTypes from "prop-types"; -class Collapsible extends Component { - constructor(props) { - super(props); - this.state = { - active: false, - }; - } +const Collapsible = ({ result: { files, threatLvl }, index }) => { + const [active, setActive] = useState(false); /** * Toggle method for dropdown. No dropdown if no intrusions occurred. * * @param numOfIntrusions number of intrusions */ - handleClick = (numOfIntrusions) => { - const { active } = this.state; - if (numOfIntrusions > 0) this.setState({ active: !active }); + const handleClick = (numOfIntrusions) => { + if (numOfIntrusions > 0) setActive(!active); }; - render = () => { - const { active } = this.state; - const { - result: { files, threatLvl }, - index, - } = this.props; - const intrusions = files.filter((file) => file.result === FILE_INTRUSION); - const protectedFiles = files.filter( - (file) => file.result === FILE_PROTECTED - ); - const incorrectFiles = files.filter( - (file) => file.result === FILE_INCORRECT - ); + const intrusions = files.filter((file) => file.result === FILE_INTRUSION); + const protectedFiles = files.filter((file) => file.result === FILE_PROTECTED); + const incorrectFiles = files.filter((file) => file.result === FILE_INCORRECT); - return ( -
- - {active && intrusions.length > 0 && ( -
-
-

List of Intrusions

-
    - {intrusions.map((file, index) => { - const className = - "tw-flex tw-text-left tw-py-3 tw-border-x-0 tw-border-b tw-border-solid "; - return ( -
  • -
    -

    - Filename:{" "} - {file.fileName} -

    -

    - - Sensitivity Level: - {" "} - {file.sensitivityLevel} -

    -

    - Content:{" "} - {file.content} -

    -
    -
    -

    Intrusion Message:

    -

    {file.message}

    -
    -
  • - ); - })} -
-
+ return ( +
+ + {active && intrusions.length > 0 && ( +
+
+

List of Intrusions

+
    + {intrusions.map((file, index) => { + const className = + "tw-flex tw-text-left tw-py-3 tw-border-x-0 tw-border-b tw-border-solid "; + return ( +
  • +
    +

    + Filename:{" "} + {file.fileName} +

    +

    + + Sensitivity Level: + {" "} + {file.sensitivityLevel} +

    +

    + Content:{" "} + {file.content} +

    +
    +
    +

    Intrusion Message:

    +

    {file.message}

    +
    +
  • + ); + })} +
- )} -
- ); - }; -} +
+ )} +
+ ); +}; export default Collapsible; diff --git a/client/src/components/exercise/lab7/components/File.js b/client/src/components/exercise/lab7/components/File.js index 086a6995f..d206dec44 100644 --- a/client/src/components/exercise/lab7/components/File.js +++ b/client/src/components/exercise/lab7/components/File.js @@ -1,55 +1,48 @@ -import React, { Component } from "react"; +import React from "react"; import PropTypes from "prop-types"; import { AI_CORRECT, LOCKED_FILE } from "../../../../constants/lab7"; import LOCKED from "../../../../assets/images/lab7/lock.png"; import OPEN from "../../../../assets/images/lab7/unlock.png"; -class File extends Component { - constructor(props) { - super(props); - } +const File = ({ data }) => { + const image = data.decision === LOCKED_FILE ? LOCKED : OPEN; + const alt = `A .png image of ${ + data.decision === LOCKED_FILE ? "a locked" : "an unlocked" + } lock.`; + const reportClassName = + data.report === AI_CORRECT ? "tw-text-[#2e8540]" : "tw-text-[#e31c3d]"; - render() { - const { data } = this.props; - const image = data.decision === LOCKED_FILE ? LOCKED : OPEN; - const alt = `A .png image of ${ - data.decision === LOCKED_FILE ? "a locked" : "an unlocked" - } lock.`; - const reportClassName = - data.report === AI_CORRECT ? "tw-text-[#2e8540]" : "tw-text-[#e31c3d]"; - - return ( -
-
- {data.report !== undefined && ( -
- {alt} -

{data.decision} FILE

-
- )} -
-

{data.fileName}

-

- Sensitivity Level {data.sensitivityLevel} -

-
-
-

{data.content}

-
-
+ return ( +
+
{data.report !== undefined && ( -
- - {data.report} - +
+ {alt} +

{data.decision} FILE

)} +
+

{data.fileName}

+

+ Sensitivity Level {data.sensitivityLevel} +

+
+
+

{data.content}

+
- ); - } -} + {data.report !== undefined && ( +
+ + {data.report} + +
+ )} +
+ ); +}; export default File; diff --git a/client/src/components/exercise/lab7/components/ProgressBar.js b/client/src/components/exercise/lab7/components/ProgressBar.js index 2c06817af..83d43922e 100644 --- a/client/src/components/exercise/lab7/components/ProgressBar.js +++ b/client/src/components/exercise/lab7/components/ProgressBar.js @@ -1,40 +1,32 @@ -import React, { Component } from "react"; +import React from "react"; import { READ_TIME } from "../../../../constants/lab7"; import PropTypes from "prop-types"; -class ProgressBar extends Component { - constructor(props) { - super(props); - } - +const ProgressBar = ({ text, seconds }) => { /** * Calculates the width of the progress bar, utilizing the current seconds, and the starting seconds. * * @returns {number} width of the progress bar */ - calculateWidth = () => { - const { seconds } = this.props; + const calculateWidth = () => { return (((seconds - 1) * 1000) / (READ_TIME - 1000)) * 100; }; - render() { - const { text, seconds } = this.props; - return ( -
-
-

{text}

-
-
-
-

{seconds - 1}

-
+ return ( +
+
+

{text}

+
+
+
+

{seconds - 1}

- ); - } -} +
+ ); +}; export default ProgressBar; diff --git a/client/src/components/exercise/lab7/components/Simulation.js b/client/src/components/exercise/lab7/components/Simulation.js index 60d6ed3f3..d538c9da4 100644 --- a/client/src/components/exercise/lab7/components/Simulation.js +++ b/client/src/components/exercise/lab7/components/Simulation.js @@ -1,391 +1,392 @@ /* eslint-disable react/prop-types */ -import React, {Component} from "react"; +import React, { Component } from "react"; import UserLabService from "../../../../services/UserLabService"; import "../../../../assets/stylesheets/components/Simulation.scss"; import { - AI_CORRECT, - AI_INCORRECT, - DELAY_TIME, - FILE_INCORRECT, - FILE_INTRUSION, - FILE_PROTECTED, - LAB_ID, - LOCKED_FILE, - MESSAGES, - OPEN_FILE, - READ_TIME, - ROUND_LIMIT, - SCORE_MAP, - THREAT_LEVEL_TEXT, - THREAT_MAX, + AI_CORRECT, + AI_INCORRECT, + DELAY_TIME, + FILE_INCORRECT, + FILE_INTRUSION, + FILE_PROTECTED, + LAB_ID, + LOCKED_FILE, + MESSAGES, + OPEN_FILE, + READ_TIME, + ROUND_LIMIT, + SCORE_MAP, + THREAT_LEVEL_TEXT, + THREAT_MAX, } from "../../../../constants/lab7"; -import {navigate} from "@reach/router"; -import {generateList} from "./data/files"; +import { navigate } from "@reach/router"; +import { generateList } from "./data/files"; import Countdown from "react-countdown-now"; import ProgressBar from "./ProgressBar"; import File from "./File"; -import {connect} from "react-redux"; -import {bindActionCreators} from "redux"; -import {actions as exerciseActions} from "../../../../reducers/lab7/ExerciseReducer"; +import { connect } from "react-redux"; +import { bindActionCreators } from "redux"; +import { actions as exerciseActions } from "../../../../reducers/lab7/ExerciseReducer"; import RepairService from "../../../../services/lab7/RepairService"; class Simulation extends Component { - constructor(props) { - super(props); - this.state = { - files: [], - message: "", - countdownComponent: null, - counter: -1, - }; - } + constructor(props) { + super(props); + this.state = { + files: [], + message: "", + countdownComponent: null, + counter: -1, + }; + } - componentDidMount() { - this.startSimulation(); - } + componentDidMount() { + this.startSimulation(); + } - startSimulation() { - this.startRound(); - } + startSimulation() { + this.startRound(); + } - /** - * Logic handling the transition of rounds. - * - * As long as we have not reached the round limit, calculate a random threat level, - * update the round number, generate a new list of files, update the states accordingly, and - * store them for the summary report. - * - * Otherwise, transition to the simulation summary. - */ - startRound() { - const {roundNumber, handlers, user, repairId} = this.props; - if (roundNumber < ROUND_LIMIT) { - const threatLvl = this.randomizeThreat(); - handlers.startNewRound(); - const files = this.generateFileList(threatLvl); - this.setState({files, counter: 0}); - handlers.addResults({files, threatLvl}); - } else { - UserLabService.complete_exercise(LAB_ID); - if (user?.firstname !== null && user !== null) { - UserLabService.user_complete_exercise(user.userid, LAB_ID); - } - RepairService.updateReport(repairId, this.formatReport()); - navigate("/Lab7/Exercise/SimulationSummary"); - } + /** + * Logic handling the transition of rounds. + * + * As long as we have not reached the round limit, calculate a random threat level, + * update the round number, generate a new list of files, update the states accordingly, and + * store them for the summary report. + * + * Otherwise, transition to the simulation summary. + */ + startRound() { + const { roundNumber, handlers, user, repairId } = this.props; + if (roundNumber < ROUND_LIMIT) { + const threatLvl = this.randomizeThreat(); + handlers.startNewRound(); + const files = this.generateFileList(threatLvl); + this.setState({ files, counter: 0 }); + handlers.addResults({ files, threatLvl }); + } else { + UserLabService.complete_exercise(LAB_ID); + if (user?.firstname !== null && user !== null) { + UserLabService.user_complete_exercise(user.userid, LAB_ID); + } + if (repairId !== null) + RepairService.updateReport(repairId, this.formatReport()); + navigate("/Lab7/Exercise/SimulationSummary"); } + } - formatReport() { - const {results} = this.props; - return results.map(({threatLvl, files}) => { - return { - threatLvl, - intrusions: files.filter((file) => file.result === FILE_INTRUSION) - .length, - protected: files.filter((file) => file.result === FILE_PROTECTED) - .length, - incorrect: files.filter((file) => file.result === FILE_INCORRECT) - .length, - }; - }); - } + formatReport() { + const { results } = this.props; + return results.map(({ threatLvl, files }) => { + return { + threatLvl, + intrusions: files.filter((file) => file.result === FILE_INTRUSION) + .length, + protected: files.filter((file) => file.result === FILE_PROTECTED) + .length, + incorrect: files.filter((file) => file.result === FILE_INCORRECT) + .length, + }; + }); + } - /** - * Calculates a random threat level for the round updates the state. - * - * @returns {number} random threat level - */ - randomizeThreat() { - const {handlers} = this.props; - const threatLvl = Math.floor(Math.random() * THREAT_MAX) + 1; - handlers.updateThreatLevel(threatLvl); - return threatLvl; - } + /** + * Calculates a random threat level for the round updates the state. + * + * @returns {number} random threat level + */ + randomizeThreat() { + const { handlers } = this.props; + const threatLvl = Math.floor(Math.random() * THREAT_MAX) + 1; + handlers.updateThreatLevel(threatLvl); + return threatLvl; + } - makeDecision(threatLvl, file) { - const makeDecisionFunction = - this.props.makeDecision ?? this.defaultMakeDecision.bind(this); - return makeDecisionFunction(threatLvl, file); - } + makeDecision(threatLvl, file) { + const makeDecisionFunction = + this.props.makeDecision ?? this.defaultMakeDecision.bind(this); + return makeDecisionFunction(threatLvl, file); + } - defaultMakeDecision(threatLvl, file) { - return threatLvl >= file.sensitivityLevel ? LOCKED_FILE : OPEN_FILE; - } + defaultMakeDecision(threatLvl, file) { + return threatLvl >= file.sensitivityLevel ? LOCKED_FILE : OPEN_FILE; + } - /** - * Generate a list of random files from existing data. - * - * The utility and AIs decision is calculated. Results are added to the file object and the - * file object is added to the list of files. - * - * @param threatLvl pre-calculated threat level of the round - * @returns {(*&{result: string, decision: string})[]} a list of file objects - */ - generateFileList(threatLvl) { - return generateList().map((file) => { - const decision = this.makeDecision(threatLvl, file); - return { - ...file, - decision, - result: this.evaluateAIDecision(file, decision, threatLvl), - }; - }); - } + /** + * Generate a list of random files from existing data. + * + * The utility and AIs decision is calculated. Results are added to the file object and the + * file object is added to the list of files. + * + * @param threatLvl pre-calculated threat level of the round + * @returns {(*&{result: string, decision: string})[]} a list of file objects + */ + generateFileList(threatLvl) { + return generateList().map((file) => { + const decision = this.makeDecision(threatLvl, file); + return { + ...file, + decision, + result: this.evaluateAIDecision(file, decision, threatLvl), + }; + }); + } - /** - * Evaluates the AIs decision-making based on the utility equation. - * - * @param file current file being evaluated - * @param decision AIs decision based on utility - * @param threatLvl pre-calculated threat level of the round - * @returns {string|string} `FILE_PROTECTED` | `FILE_INCORRECT` | `FILE_INTRUSION` - */ - evaluateAIDecision(file, decision, threatLvl) { - const {sensitivityLevel} = file; - let expected; - switch (threatLvl) { - case 1: - expected = sensitivityLevel === 1 ? LOCKED_FILE : OPEN_FILE; - break; - case 2: - expected = - sensitivityLevel === 2 || sensitivityLevel === 3 - ? LOCKED_FILE - : OPEN_FILE; - break; - case 3: - expected = - sensitivityLevel === 4 || sensitivityLevel === 5 - ? LOCKED_FILE - : OPEN_FILE; - break; - } - if (decision !== expected) - return expected === OPEN_FILE && decision === LOCKED_FILE - ? FILE_INCORRECT - : FILE_INTRUSION; - return FILE_PROTECTED; + /** + * Evaluates the AIs decision-making based on the utility equation. + * + * @param file current file being evaluated + * @param decision AIs decision based on utility + * @param threatLvl pre-calculated threat level of the round + * @returns {string|string} `FILE_PROTECTED` | `FILE_INCORRECT` | `FILE_INTRUSION` + */ + evaluateAIDecision(file, decision, threatLvl) { + const { sensitivityLevel } = file; + let expected; + switch (threatLvl) { + case 1: + expected = sensitivityLevel === 1 ? LOCKED_FILE : OPEN_FILE; + break; + case 2: + expected = + sensitivityLevel === 2 || sensitivityLevel === 3 + ? LOCKED_FILE + : OPEN_FILE; + break; + case 3: + expected = + sensitivityLevel === 4 || sensitivityLevel === 5 + ? LOCKED_FILE + : OPEN_FILE; + break; } + if (decision !== expected) + return expected === OPEN_FILE && decision === LOCKED_FILE + ? FILE_INCORRECT + : FILE_INTRUSION; + return FILE_PROTECTED; + } - /** - * React method that is invoked whenever a state/prop is updated. - * - * @param prevProps values of props prior to update - * @param prevState values of states prior to update - * @param snapshot required for method signature - */ - // eslint-disable-next-line no-unused-vars - componentDidUpdate(prevProps, prevState, snapshot) { - /* Counter was incremented */ - if (prevState.counter !== this.state.counter) { - /* Counter is within range of being incremented again */ - if (this.state.counter < this.state.files.length) { - const {handlers} = this.props; - const {counter, files} = this.state; - switch (files[counter].result) { - case FILE_PROTECTED: - this.handleProtected(); - break; - case FILE_INTRUSION: - this.handleIntrusion(); - break; - case FILE_INCORRECT: - this.handleIncorrect(); - break; - default: - break; - } - handlers.incrementScore(SCORE_MAP[files[counter].result]); - } else { - /* End of round */ - const result = this.handlePerfectScore(); - setTimeout(() => this.startRound(), result ? READ_TIME : 0); - } + /** + * React method that is invoked whenever a state/prop is updated. + * + * @param prevProps values of props prior to update + * @param prevState values of states prior to update + * @param snapshot required for method signature + */ + // eslint-disable-next-line no-unused-vars + componentDidUpdate(prevProps, prevState, snapshot) { + /* Counter was incremented */ + if (prevState.counter !== this.state.counter) { + /* Counter is within range of being incremented again */ + if (this.state.counter < this.state.files.length) { + const { handlers } = this.props; + const { counter, files } = this.state; + switch (files[counter].result) { + case FILE_PROTECTED: + this.handleProtected(); + break; + case FILE_INTRUSION: + this.handleIntrusion(); + break; + case FILE_INCORRECT: + this.handleIncorrect(); + break; + default: + break; } + handlers.incrementScore(SCORE_MAP[files[counter].result]); + } else { + /* End of round */ + const result = this.handlePerfectScore(); + setTimeout(() => this.startRound(), result ? READ_TIME : 0); + } } + } - /** - * Updates `files` and `countdownComponent` states. Invoked for when a message - * needs to be displayed with progress bar. - * - * @param files array of file objects - * @param message text to be displayed - */ - handleCountdownComponent(files, message) { - this.setState({ - files, - message, - countdownComponent: ( - - ), - }); - /* Unmount countdownComponent and message after read time */ - setTimeout( - () => this.setState({countdownComponent: null, message: ""}), - READ_TIME - ); - } + /** + * Updates `files` and `countdownComponent` states. Invoked for when a message + * needs to be displayed with progress bar. + * + * @param files array of file objects + * @param message text to be displayed + */ + handleCountdownComponent(files, message) { + this.setState({ + files, + message, + countdownComponent: ( + + ), + }); + /* Unmount countdownComponent and message after read time */ + setTimeout( + () => this.setState({ countdownComponent: null, message: "" }), + READ_TIME + ); + } - /** - * Logic to award bonus points if all files for a round were correctly protected. - * - * @returns {boolean} whether the files of a round were perfectly protected - */ - handlePerfectScore() { - const {files} = this.state; - const {handlers} = this.props; - const filteredFiles = files.filter( - (file) => file.result === FILE_PROTECTED - ); - if (filteredFiles.length === files.length) { - handlers.incrementScore(SCORE_MAP.PERFECT_SCORE); - this.handleCountdownComponent(files, MESSAGES.Perfect); - return true; - } - return false; + /** + * Logic to award bonus points if all files for a round were correctly protected. + * + * @returns {boolean} whether the files of a round were perfectly protected + */ + handlePerfectScore() { + const { files } = this.state; + const { handlers } = this.props; + const filteredFiles = files.filter( + (file) => file.result === FILE_PROTECTED + ); + if (filteredFiles.length === files.length) { + handlers.incrementScore(SCORE_MAP.PERFECT_SCORE); + this.handleCountdownComponent(files, MESSAGES.Perfect); + return true; } + return false; + } - /** - * Logic for when a file was correctly protected. - */ - handleProtected() { - const {handlers} = this.props; - const {counter, files} = this.state; - files[counter].report = AI_CORRECT; - this.setState({files}); - handlers.incrementProtected(); - this.incrementCounter(); - } + /** + * Logic for when a file was correctly protected. + */ + handleProtected() { + const { handlers } = this.props; + const { counter, files } = this.state; + files[counter].report = AI_CORRECT; + this.setState({ files }); + handlers.incrementProtected(); + this.incrementCounter(); + } - /** - * Logic for when the AIs decision-making resulted in an intrusion. - */ - handleIntrusion() { - const {handlers} = this.props; - const {counter, files} = this.state; - files[counter].report = AI_INCORRECT; - files[counter].message = MESSAGES[files[counter].content]; - handlers.incrementIntrusions(); - this.handleCountdownComponent(files, files[counter].message); - this.incrementCounter(READ_TIME); - } + /** + * Logic for when the AIs decision-making resulted in an intrusion. + */ + handleIntrusion() { + const { handlers } = this.props; + const { counter, files } = this.state; + files[counter].report = AI_INCORRECT; + files[counter].message = MESSAGES[files[counter].content]; + handlers.incrementIntrusions(); + this.handleCountdownComponent(files, files[counter].message); + this.incrementCounter(READ_TIME); + } - /** - * Logic for when the AIs decision-making was incorrect. - */ - handleIncorrect() { - const {handlers} = this.props; - const {counter, files} = this.state; - files[counter].report = AI_INCORRECT; - this.setState({files}); - handlers.incrementIncorrect(); - this.incrementCounter(); - } + /** + * Logic for when the AIs decision-making was incorrect. + */ + handleIncorrect() { + const { handlers } = this.props; + const { counter, files } = this.state; + files[counter].report = AI_INCORRECT; + this.setState({ files }); + handlers.incrementIncorrect(); + this.incrementCounter(); + } - /** - * Updates the pointer to the file array with a delay. - * - * @param delay specified ms delay for updating the counter - */ - incrementCounter(delay = DELAY_TIME) { - setTimeout(() => this.setState({counter: this.state.counter + 1}), delay); - } + /** + * Updates the pointer to the file array with a delay. + * + * @param delay specified ms delay for updating the counter + */ + incrementCounter(delay = DELAY_TIME) { + setTimeout(() => this.setState({ counter: this.state.counter + 1 }), delay); + } - /** - * Callback method for a countdown. Used for progress bar. - * - * @param seconds time left on the countdown - * @param completed whether the countdown is complete - * @returns {JSX.Element} progress bar component - */ - countdownRenderCallback({seconds, completed}) { - const {message} = this.state; - if (completed) return <>; - else return ; - } + /** + * Callback method for a countdown. Used for progress bar. + * + * @param seconds time left on the countdown + * @param completed whether the countdown is complete + * @returns {JSX.Element} progress bar component + */ + countdownRenderCallback({ seconds, completed }) { + const { message } = this.state; + if (completed) return <>; + else return ; + } - render() { - const {roundNumber, intrusions, protect, incorrect, score, threatLvl} = - this.props; - return ( -
- {/* Header */} -
- {/* Round Tracker */} -
-

- Round {roundNumber} of {ROUND_LIMIT} -

-
- {/* Status Report */} -
-
    -
  • Intrusions:
  • -
  • Protected (TP):
  • -
  • Incorrect (FP):
  • -
  • Total Score:
  • -
-
    -
  • {intrusions}
  • -
  • {protect}
  • -
  • {incorrect}
  • -
  • {score}
  • -
-
-
- {/* Body */} -
- {/* Threat Message */} -
-

- {THREAT_LEVEL_TEXT[threatLvl]} threat detected! -

-
- {/* File Display */} -
- {this.state.files.map((file, index) => ( - - ))} -
- {/* Countdown component w/ message */} - {/* When countdown component is not null, it will be rendered */} - {this.state.countdownComponent} -
-
- ); - } + render() { + const { roundNumber, intrusions, protect, incorrect, score, threatLvl } = + this.props; + return ( +
+ {/* Header */} +
+ {/* Round Tracker */} +
+

+ Round {roundNumber} of {ROUND_LIMIT} +

+
+ {/* Status Report */} +
+
    +
  • Intrusions:
  • +
  • Protected (TP):
  • +
  • Incorrect (FP):
  • +
  • Total Score:
  • +
+
    +
  • {intrusions}
  • +
  • {protect}
  • +
  • {incorrect}
  • +
  • {score}
  • +
+
+
+ {/* Body */} +
+ {/* Threat Message */} +
+

+ {THREAT_LEVEL_TEXT[threatLvl]} threat detected! +

+
+ {/* File Display */} +
+ {this.state.files.map((file, index) => ( + + ))} +
+ {/* Countdown component w/ message */} + {/* When countdown component is not null, it will be rendered */} + {this.state.countdownComponent} +
+
+ ); + } } const mapStateToProps = (state) => { - const {roundNumber, intrusions, incorrect, score, threatLvl, results} = - state.exercise7; - const {makeDecision, repairId} = state.repair7; - const {user} = state.main; - return { - makeDecision, - repairId, - user, - roundNumber, - score, - intrusions, - incorrect, - threatLvl, - results, - protect: state.exercise7.protected, - }; + const { roundNumber, intrusions, incorrect, score, threatLvl, results } = + state.exercise7; + const { makeDecision, repairId } = state.repair7; + const { user } = state.main; + return { + makeDecision, + repairId, + user, + roundNumber, + score, + intrusions, + incorrect, + threatLvl, + results, + protect: state.exercise7.protected, + }; }; const mapDispatchToProps = (dispatch) => { - return { - handlers: bindActionCreators({...exerciseActions}, dispatch), - }; + return { + handlers: bindActionCreators({ ...exerciseActions }, dispatch), + }; }; export default connect(mapStateToProps, mapDispatchToProps)(Simulation); diff --git a/client/src/components/exercise/lab7/components/data/files.js b/client/src/components/exercise/lab7/components/data/files.js index 4d561a43d..058ee6c03 100644 --- a/client/src/components/exercise/lab7/components/data/files.js +++ b/client/src/components/exercise/lab7/components/data/files.js @@ -1,4 +1,4 @@ -import {FILE_COUNT} from "../../../../../constants/lab7"; +import { FILE_COUNT } from "../../../../../constants/lab7"; import _ from "lodash"; export const FILES = [ @@ -124,4 +124,4 @@ export const FILES = [ }, ]; -export const generateList = () => _.sampleSize(FILES, FILE_COUNT); \ No newline at end of file +export const generateList = () => _.sampleSize(FILES, FILE_COUNT); diff --git a/client/src/components/exercise/lab7/pages/ExerciseStart.js b/client/src/components/exercise/lab7/pages/ExerciseStart.js index 1b745ec61..d1f6ff56f 100644 --- a/client/src/components/exercise/lab7/pages/ExerciseStart.js +++ b/client/src/components/exercise/lab7/pages/ExerciseStart.js @@ -33,11 +33,15 @@ class ExerciseStart extends Component {
  • - Five files will be displayed on the screen, each of which will have the following: + Five files will be displayed on the screen, each of which + will have the following:
    • A file name
    • Sensitive or nonsensitive content
    • -
    • A level of sensitivity that is dependent on the contents of the file
    • +
    • + A level of sensitivity that is dependent on the contents of + the file +
    • An access status assigned by the system
  • @@ -45,37 +49,44 @@ class ExerciseStart extends Component { The simulation will consist of ten rounds
    • - For each round, a threat level will - be detected in the system + For each round, a threat level will be detected in + the system
    • - The system will restrict file access based on the threat level and - the file‘s sensitivity level: + The system will restrict file access based on the{" "} + threat level and the{" "} + file‘s sensitivity level:
    • -
      - - +
      +
      + - - - + + + - + - + - + - -
      Threat Level Restricted Files
      HighSensitivity Levels 4 and 5 + Sensitivity Levels 4 and 5 +
      MediumSensitivity Levels 2 and 3 + Sensitivity Levels 2 and 3 +
      LowSensitivity Level 1 + Sensitivity Level 1 +
      -
      + + +
  • The simulation will notify you of whether the autonomous system made the correct restriction for each file by @@ -83,8 +94,8 @@ class ExerciseStart extends Component { "AI Incorrect".
  • - The autonomous system's mistakes can be categorized into - two types: + The autonomous system's mistakes can be categorized + into two types:
    • @@ -92,23 +103,24 @@ class ExerciseStart extends Component { should have been restricted.
    • - An incorrect decision, or false positive (FP),{" "} - occurs when a file is restricted when it should have been - accessible. + An incorrect decision, or{" "} + false positive (FP), occurs when a file is + restricted when it should have been accessible.
  • - At the end, a summary report containing all of the information displayed throughout the simulation - will be displayed + At the end, a summary report containing all of the information + displayed throughout the simulation will be displayed
  • - Note: The simulation will be done by the - autonomous system. You will NOT be able to interact with the simulation once it starts. + Note: The simulation will be done by the autonomous system. + You will NOT be able to interact with the simulation once it + starts.

    diff --git a/client/src/components/exercise/lab7/pages/ImproveAICode/AICodeRepair.js b/client/src/components/exercise/lab7/pages/ImproveAICode/AICodeRepair.js index f210b7e26..3fc882df2 100644 --- a/client/src/components/exercise/lab7/pages/ImproveAICode/AICodeRepair.js +++ b/client/src/components/exercise/lab7/pages/ImproveAICode/AICodeRepair.js @@ -1,148 +1,153 @@ -import React, {Component, Fragment} from "react"; +import React, { Component, Fragment } from "react"; import Popup from "../../../shared/Popup"; -import {navigate} from "@reach/router"; +import { navigate } from "@reach/router"; import Code from "../../components/Code"; -import {EXERCISE_PLAYING, LOCKED_FILE, OPEN_FILE,} from "../../../../../constants/lab7"; -import {connect} from "react-redux"; -import {bindActionCreators} from "redux"; -import {actions as repairActions} from "../../../../../reducers/lab7/RepairReducer"; -import {actions as appActions} from "../../../../../reducers/lab7/AppReducer"; -import {actions as exerciseActions} from "../../../../../reducers/lab7/ExerciseReducer"; -import {evaluate} from "mathjs"; +import { + EXERCISE_PLAYING, + LOCKED_FILE, + OPEN_FILE, +} from "../../../../../constants/lab7"; +import { connect } from "react-redux"; +import { bindActionCreators } from "redux"; +import { actions as repairActions } from "../../../../../reducers/lab7/RepairReducer"; +import { actions as appActions } from "../../../../../reducers/lab7/AppReducer"; +import { actions as exerciseActions } from "../../../../../reducers/lab7/ExerciseReducer"; +import { evaluate } from "mathjs"; import PropTypes from "prop-types"; -import {MathComponent} from "mathjax-react"; +import { MathComponent } from "mathjax-react"; class AICodeRepair extends Component { - constructor(props) { - super(props); - this.state = { - componentName: "AICodeRepair", - }; - } + constructor(props) { + super(props); + this.state = { + componentName: "AICodeRepair", + }; + } - componentDidMount() { - const {actions} = this.props; - actions.updateState(EXERCISE_PLAYING); - this.reset(); - } + componentDidMount() { + const { actions } = this.props; + actions.updateState(EXERCISE_PLAYING); + this.reset(); + } - reset() { - const {actions} = this.props; - actions.resetRepair(); - actions.updatePopup(""); - } + reset() { + const { actions } = this.props; + actions.resetRepair(); + actions.updatePopup(""); + } - handleNav() { - const {actions} = this.props; - actions.updateMakeDecision(this.updateMakeDecision.bind(this)); - actions.reset(); - navigate("/Lab7/Exercise/ImprovedAISimulation"); - } + handleNav() { + const { actions } = this.props; + actions.updateMakeDecision(this.updateMakeDecision.bind(this)); + actions.reset(); + navigate("/Lab7/Exercise/ImprovedAISimulation"); + } - updateMakeDecision(threatLvl, file) { - const {rewardValue, costValue} = this.props; - const utility = evaluate(`(${rewardValue}) / (${costValue})`, { - file, - threatLvl, - }); - return utility >= 1 ? LOCKED_FILE : OPEN_FILE; - } + updateMakeDecision(threatLvl, file) { + const { rewardValue, costValue } = this.props; + const utility = evaluate(`(${rewardValue}) / (${costValue})`, { + file, + threatLvl, + }); + return utility >= 1 ? LOCKED_FILE : OPEN_FILE; + } - render() { - const { - repairVisible, - popupMessage, - actions, - repairError, - changesApplied, - } = this.props; + render() { + const { + repairVisible, + popupMessage, + actions, + repairError, + changesApplied, + } = this.props; - return ( -

    - -
    -
    -

    - We have identified the component of the AI that is - impacting its decision-making, let‘s take a look into the - AI and see how it can be improved. -

    -

    - In this part of the exercise, you will have the opportunity to improve the accuracy of - the autonomous file access system. -

    -

    - Your goal should be to implement a utility equation into the autonomous system. The - utility equation is calculated by weighting the reward of a decision and the cost of - making said decision. -

    - -
    -

    - Click the ‘Repair - ‘ button to view and edit the code of the autonomous system. -

    -
    -
    - - - - {repairVisible && } + return ( +
    + +
    +
    +

    + We have identified the component of the AI that is impacting its + decision-making, let‘s take a look into the AI and see how + it can be improved. +

    +

    + In this part of the exercise, you will have the opportunity to + improve the accuracy of the autonomous file access system. +

    +

    + Your goal should be to implement a utility equation into the + autonomous system. The utility equation is calculated by + weighting the reward of a decision and the cost of making said + decision. +

    +
    - ); - } +

    + Click the ‘Repair + ‘ button to view and edit the code of the autonomous system. +

    +
    +
    + + + + {repairVisible && } +
    + ); + } } AICodeRepair.propTypes = { - actions: PropTypes.object, - rewardValue: PropTypes.string, - costValue: PropTypes.string, - popupMessage: PropTypes.string, - repairError: PropTypes.string, - changesApplied: PropTypes.bool, - repairVisible: PropTypes.bool, + actions: PropTypes.object, + rewardValue: PropTypes.string, + costValue: PropTypes.string, + popupMessage: PropTypes.string, + repairError: PropTypes.string, + changesApplied: PropTypes.bool, + repairVisible: PropTypes.bool, }; const mapStateToProps = (state) => { - const {popupMessage} = state.app7; - const {repairError, repairVisible, rewardValue, costValue, changesApplied} = - state.repair7; - return { - popupMessage, - repairError, - repairVisible, - rewardValue, - costValue, - changesApplied, - }; + const { popupMessage } = state.app7; + const { repairError, repairVisible, rewardValue, costValue, changesApplied } = + state.repair7; + return { + popupMessage, + repairError, + repairVisible, + rewardValue, + costValue, + changesApplied, + }; }; const mapDispatchToProps = (dispatch) => { - return { - actions: bindActionCreators( - {...repairActions, ...exerciseActions, ...appActions}, - dispatch - ), - }; + return { + actions: bindActionCreators( + { ...repairActions, ...exerciseActions, ...appActions }, + dispatch + ), + }; }; export default connect(mapStateToProps, mapDispatchToProps)(AICodeRepair); diff --git a/client/src/components/exercise/lab7/pages/Simulation/BadAIExplanation.js b/client/src/components/exercise/lab7/pages/Simulation/BadAIExplanation.js index 126a013a2..0b16e7e3b 100644 --- a/client/src/components/exercise/lab7/pages/Simulation/BadAIExplanation.js +++ b/client/src/components/exercise/lab7/pages/Simulation/BadAIExplanation.js @@ -1,63 +1,63 @@ -import React, {Component} from "react"; -import {navigate} from "@reach/router"; -import {EXERCISE_PLAYING} from "../../../../../constants/lab7"; -import {bindActionCreators} from "redux"; -import {actions as exerciseActions} from "../../../../../reducers/lab7/ExerciseReducer"; -import {connect} from "react-redux"; +import React, { Component } from "react"; +import { navigate } from "@reach/router"; +import { EXERCISE_PLAYING } from "../../../../../constants/lab7"; +import { bindActionCreators } from "redux"; +import { actions as exerciseActions } from "../../../../../reducers/lab7/ExerciseReducer"; +import { connect } from "react-redux"; import PropTypes from "prop-types"; class BadAIExplanation extends Component { - constructor(props) { - super(props); - this.state = {componentName: "BadAIExplanation"}; - } + constructor(props) { + super(props); + this.state = { componentName: "BadAIExplanation" }; + } - componentDidMount() { - const {actions} = this.props; - actions.updateState(EXERCISE_PLAYING); - } + componentDidMount() { + const { actions } = this.props; + actions.updateState(EXERCISE_PLAYING); + } - handleStart() { - const {actions} = this.props; - actions.updateState(EXERCISE_PLAYING); - navigate("/Lab7/Exercise/AICodeRepair"); - } + handleStart() { + const { actions } = this.props; + actions.updateState(EXERCISE_PLAYING); + navigate("/Lab7/Exercise/AICodeRepair"); + } - render() { - return ( -
    -

    - As you can see, the AI made many mistakes when it came to managing - file access when threats were detected in the system. -

    -

    - This is due to the factors of the files that the AI is using to determine in a file‘s - access should be restricted or not. -

    -

    - The AI is currently only using one piece of sensitive information - within the file to determine the sensitivity of the entire file. -

    - -
    - ); - } + render() { + return ( +
    +

    + As you can see, the AI made many mistakes when it came to managing + file access when threats were detected in the system. +

    +

    + This is due to the factors of the files that the AI is using to + determine in a file‘s access should be restricted or not. +

    +

    + The AI is currently only using one piece of sensitive information + within the file to determine the sensitivity of the entire file. +

    + +
    + ); + } } BadAIExplanation.propTypes = { - actions: PropTypes.object, + actions: PropTypes.object, }; const mapDispatchToProps = (dispatch) => { - return { - actions: bindActionCreators({...exerciseActions}, dispatch), - }; + return { + actions: bindActionCreators({ ...exerciseActions }, dispatch), + }; }; export default connect(null, mapDispatchToProps)(BadAIExplanation); diff --git a/client/src/services/lab7/ExerciseService.js b/client/src/services/lab7/ExerciseService.js index 5adf214e3..f70a8ea74 100644 --- a/client/src/services/lab7/ExerciseService.js +++ b/client/src/services/lab7/ExerciseService.js @@ -9,7 +9,7 @@ const endpoints = { const ExerciseService = { submitRepair: (report, userId) => { return API.postWithBody( - process.env.REACT_APP_SERVER_URL + endpoints.SUBMIT_REPORT, + `${process.env.REACT_APP_SERVER_URL}${endpoints.SUBMIT_REPORT}`, { report, userId, diff --git a/client/src/services/lab7/RepairService.js b/client/src/services/lab7/RepairService.js index 23309b87b..b7091fc13 100644 --- a/client/src/services/lab7/RepairService.js +++ b/client/src/services/lab7/RepairService.js @@ -10,13 +10,13 @@ const endpoints = { const RepairService = { submitRepair: (activity, repair) => { return API.postWithBody( - process.env.REACT_APP_SERVER_URL + endpoints.SUBMIT_REPAIR, + `${process.env.REACT_APP_SERVER_URL}${endpoints.SUBMIT_REPAIR}`, { activity, repair } ); }, updateReport: (repairId, report) => { return API.postWithBody( - process.env.REACT_APP_SERVER_URL + endpoints.UPDATE_REPORT, + `${process.env.REACT_APP_SERVER_URL}${endpoints.UPDATE_REPORT}`, { repairId, report } ); },