Merge pull request #23 from neharanadee/main
Fixes security vulnerabilites and adds html-react parser package
This commit is contained in:
Коммит
68036f6b09
|
@ -17,5 +17,7 @@ namespace Assessment.App.Database.Model
|
|||
public List<string> Options { get; set; }
|
||||
|
||||
public int Answer { get; set; }
|
||||
|
||||
public string TextType{get;set;}
|
||||
}
|
||||
}
|
|
@ -10,5 +10,7 @@ namespace Assessment.App.Functions.Student.Dto
|
|||
public string Description { get; set; }
|
||||
public List<string> Options { get; set; }
|
||||
public int ChosenOption { get; set; }
|
||||
|
||||
public string TextType{get;set;}
|
||||
}
|
||||
}
|
|
@ -131,6 +131,7 @@ namespace Assessment.App.Functions.Student
|
|||
Description = item.Description,
|
||||
Options = item.Options,
|
||||
ChosenOption = chosenOption,
|
||||
TextType=item.TextType
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -180,6 +180,8 @@ namespace Assessment.App.Functions.Teacher
|
|||
Name = questionItem.Name,
|
||||
Options = questionItem.Options,
|
||||
LastModified = DateTime.UtcNow,
|
||||
TextType = questionItem.TextType
|
||||
|
||||
});
|
||||
return new OkObjectResult(new CreateQuestionResponse() {Id = id});
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -16,12 +16,16 @@
|
|||
"fast-xml-parser": "^4.0.1",
|
||||
"file-saver": "^2.0.5",
|
||||
"gift-pegjs": "^0.2.1",
|
||||
"html-react-parser": "^1.4.6",
|
||||
"nth-check": "^2.0.1",
|
||||
"react": "^17.0.2",
|
||||
"react-countdown-circle-timer": "^2.5.4",
|
||||
"react-dev-utils": "^12.0.0",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-grid-system": "^7.3.1",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-router-dom": "^5.3.0",
|
||||
"resolve-url-loader": "^5.0.0",
|
||||
"typescript": "^4.4.2",
|
||||
"web-vitals": "^2.1.0"
|
||||
},
|
||||
|
@ -32,13 +36,14 @@
|
|||
"@testing-library/react": "^12.0.0",
|
||||
"@testing-library/user-event": "^13.2.1",
|
||||
"@types/file-saver": "^2.0.3",
|
||||
"@types/html-to-text": "^8.0.1",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/react-helmet": "^6.1.2",
|
||||
"@types/react-router-dom": "^5.1.8",
|
||||
"@types/selenium-webdriver": "^4.0.15",
|
||||
"azure-functions-core-tools": "^3.0.3904",
|
||||
"concurrently": "^6.4.0",
|
||||
"react-scripts": "^4.0.3",
|
||||
"react-scripts": "^5.0.0",
|
||||
"selenium-webdriver": "^4.0.0-rc-1"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import React from "react";
|
||||
import {
|
||||
ChoiceGroup,
|
||||
IChoiceGroupOption,
|
||||
|
@ -15,6 +14,9 @@ import {Col, Container, Row} from "react-grid-system";
|
|||
const optionRootClass = mergeStyles({display: 'flex', alignItems: 'baseline'});
|
||||
const textFieldStyles: Partial<ITextFieldStyles> = {fieldGroup: {width: 350}};
|
||||
|
||||
|
||||
|
||||
|
||||
interface EditQuestionComponentProps {
|
||||
question: Question;
|
||||
setQuestion: (f: (oldValue: Question) => Question) => void;
|
||||
|
@ -100,6 +102,24 @@ export const EditQuestionComponent = (
|
|||
setQuestion(q => ({...q, description: newValue || ''}))
|
||||
}
|
||||
/>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
<br/>
|
||||
<Row>
|
||||
<Col md={2}>
|
||||
<Label style={{textAlign: "left"}}>Text format</Label>
|
||||
</Col>
|
||||
<Col md={6}>
|
||||
<TextField
|
||||
id="textType-input"
|
||||
rows={1}
|
||||
value={question.textType}
|
||||
onChange={(_: any, newValue?: string) =>
|
||||
setQuestion(q => ({...q, textType: newValue || ''}))
|
||||
}
|
||||
/>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
<br/>
|
||||
|
|
|
@ -3,12 +3,23 @@ import {StudentQuestion} from '../model/StudentQuestion';
|
|||
import {ChoiceGroup, IChoiceGroupOption} from '@fluentui/react/lib/ChoiceGroup';
|
||||
import { Label } from "@fluentui/react";
|
||||
import { getTheme } from '@fluentui/react';
|
||||
import parse from 'html-react-parser';
|
||||
|
||||
interface StudentQuestionComponentProps {
|
||||
question: StudentQuestion;
|
||||
selectedOption: number;
|
||||
setSelectedOption: (choice: number) => void;
|
||||
}
|
||||
var getDisplay = (x:string, texttype:string)=> {
|
||||
console.log("text type is");
|
||||
console.log(texttype);
|
||||
if (texttype === "html" || texttype === "text/html"){
|
||||
x = x.replaceAll('\\n','<br>')
|
||||
return parse(x)
|
||||
}
|
||||
// Need to handle case where texttype is markdown
|
||||
return x
|
||||
}
|
||||
|
||||
export const StudentQuestionComponent = (
|
||||
{question, selectedOption, setSelectedOption}: StudentQuestionComponentProps
|
||||
|
@ -31,7 +42,8 @@ export const StudentQuestionComponent = (
|
|||
<br/>
|
||||
<div style={{margin: '30px', textAlign: 'left'}}>
|
||||
<Label style={{textAlign: 'left', fontSize: '25px'}}>Question</Label>
|
||||
<p>{question.description}</p>
|
||||
<p>{getDisplay(question.description, question.textType)}</p>
|
||||
{console.log(question)}
|
||||
<ChoiceGroup
|
||||
selectedKey={selectedOption.toString()}
|
||||
onChange={(_: any, option) => {
|
||||
|
|
|
@ -188,6 +188,7 @@ export class FakeRepository implements IRepository {
|
|||
lastModified: new Date(),
|
||||
options: ["True", "False"],
|
||||
answer: 0,
|
||||
textType:"text",
|
||||
},
|
||||
'1': {
|
||||
id: '1',
|
||||
|
@ -200,6 +201,7 @@ export class FakeRepository implements IRepository {
|
|||
"Deep learning is used in robots",
|
||||
],
|
||||
answer: 1,
|
||||
textType:"text"
|
||||
},
|
||||
'2': {
|
||||
id: '2',
|
||||
|
@ -212,6 +214,7 @@ export class FakeRepository implements IRepository {
|
|||
"Both of the above",
|
||||
],
|
||||
answer: 2,
|
||||
textType:"text"
|
||||
},
|
||||
'3': {
|
||||
id: '3',
|
||||
|
@ -225,6 +228,7 @@ export class FakeRepository implements IRepository {
|
|||
"All of the above",
|
||||
],
|
||||
answer: 3,
|
||||
textType:"text"
|
||||
},
|
||||
'4': {
|
||||
id: '4',
|
||||
|
@ -238,6 +242,7 @@ export class FakeRepository implements IRepository {
|
|||
"Software Models",
|
||||
],
|
||||
answer: 1,
|
||||
textType:"text"
|
||||
},
|
||||
'5': {
|
||||
id: '5',
|
||||
|
@ -251,6 +256,7 @@ export class FakeRepository implements IRepository {
|
|||
"5",
|
||||
],
|
||||
answer: 2,
|
||||
textType:"text"
|
||||
},
|
||||
'6': {
|
||||
id: '6',
|
||||
|
@ -264,6 +270,7 @@ export class FakeRepository implements IRepository {
|
|||
"Self-regulation",
|
||||
],
|
||||
answer: 0,
|
||||
textType:"text"
|
||||
},
|
||||
'7': {
|
||||
id: '7',
|
||||
|
@ -277,6 +284,7 @@ export class FakeRepository implements IRepository {
|
|||
"All of the above",
|
||||
],
|
||||
answer: 3,
|
||||
textType:"text"
|
||||
},
|
||||
'8': {
|
||||
id: '8',
|
||||
|
@ -290,6 +298,7 @@ export class FakeRepository implements IRepository {
|
|||
"All of the above",
|
||||
],
|
||||
answer: 3,
|
||||
textType:"text"
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,4 +5,5 @@ export interface Question {
|
|||
lastModified: Date,
|
||||
options: string[],
|
||||
answer: number,
|
||||
textType:string,
|
||||
}
|
||||
|
|
|
@ -4,4 +4,5 @@ export interface StudentQuestion {
|
|||
description: string,
|
||||
options: string[],
|
||||
chosenOption: number,
|
||||
textType:string,
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ import { parse, GIFTQuestion, TextChoice, TextFormat } from "gift-pegjs";
|
|||
import { ParsedQuestionBank } from "./ParsedQuestionBank";
|
||||
import { AssessmentAppParser } from "./Parser";
|
||||
import { Question } from "../Question";
|
||||
import * as React from "react";
|
||||
|
||||
// Currently only parses in MCQs and TFs
|
||||
export class GiftParser extends AssessmentAppParser{
|
||||
|
@ -40,6 +39,7 @@ export class GiftParser extends AssessmentAppParser{
|
|||
lastModified: new Date (),
|
||||
options: answerTexts,
|
||||
answer: correctAnswer,
|
||||
textType:stem.format
|
||||
}
|
||||
questions.push(question);
|
||||
|
||||
|
@ -51,10 +51,11 @@ export class GiftParser extends AssessmentAppParser{
|
|||
const question: Question = {
|
||||
id: "",
|
||||
name: this.removeTags(stem.text),
|
||||
description: this.removeTags(stem.text),
|
||||
description: stem.text,
|
||||
lastModified: new Date (),
|
||||
options: ["True", "False"],
|
||||
answer: ans? 0:1,
|
||||
textType:stem.format
|
||||
}
|
||||
questions.push(question);
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@ export class MicrosoftOSCParser extends AssessmentAppParser{
|
|||
var answerTexts = Array();
|
||||
var correctAnswer = 0;
|
||||
var counter = 0;
|
||||
console.log("Read a new question");
|
||||
console.log(question.questionText);
|
||||
for (let option of question.answerOptions){
|
||||
answerTexts.push(option.answerText)
|
||||
if (option.isCorrect == "true"){
|
||||
|
@ -35,6 +33,7 @@ export class MicrosoftOSCParser extends AssessmentAppParser{
|
|||
lastModified: new Date (),
|
||||
options: answerTexts,
|
||||
answer: correctAnswer,
|
||||
textType:"text"
|
||||
}
|
||||
questions.push(questionToSave);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ export class OriginalAppParser extends AssessmentAppParser{
|
|||
lastModified: new Date (),
|
||||
options: rawQuestion.options,
|
||||
answer: rawQuestion.answer,
|
||||
textType: rawQuestion.textType
|
||||
}
|
||||
questions.push(question);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ export class QTIParser extends AssessmentAppParser{
|
|||
continue; // As we currently only support MCQs
|
||||
}
|
||||
var questionText = currQuestion['presentation']['material']['mattext']['#text'];
|
||||
questionText = this.removeTags(questionText); // Clean any html tags
|
||||
questionText = questionText.split('\n')[1];
|
||||
|
||||
// Get all options
|
||||
|
@ -48,6 +47,7 @@ export class QTIParser extends AssessmentAppParser{
|
|||
lastModified: new Date (),
|
||||
options: answerTexts,
|
||||
answer: correctAnswer,
|
||||
textType:currQuestion['presentation']['material']['mattext']['@_texttype'],
|
||||
}
|
||||
questions.push(question);
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ export const NewQuestionPage = () => {
|
|||
lastModified: new Date(),
|
||||
options: ['', ''],
|
||||
answer: -1,
|
||||
textType:""
|
||||
});
|
||||
const {bankId} = useParams<NewQuestionPageParams>();
|
||||
const repositoryContext = React.useContext(RepositoryContext);
|
||||
|
|
|
@ -23,6 +23,7 @@ export const QuestionPage = () => {
|
|||
lastModified: new Date(),
|
||||
options: ['', ''],
|
||||
answer: -1,
|
||||
textType:"text"
|
||||
});
|
||||
const [savedQuestion, setSavedQuestion] = useState<Question>({
|
||||
id: "",
|
||||
|
@ -31,6 +32,7 @@ export const QuestionPage = () => {
|
|||
lastModified: new Date(),
|
||||
options: ['', ''],
|
||||
answer: -1,
|
||||
textType:"text"
|
||||
})
|
||||
const {id} = useParams<QuestionPageParams>();
|
||||
const repositoryContext = React.useContext(RepositoryContext);
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"lockfileVersion": 1
|
||||
}
|
Загрузка…
Ссылка в новой задаче