Skip to content

Commit 6b35eaa

Browse files
committed
bug fixes + edit transactions
1 parent b8cde91 commit 6b35eaa

File tree

6 files changed

+243
-11
lines changed

6 files changed

+243
-11
lines changed

api/api.js

+1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ const main = async () => {
123123
app.post('/v1/adminSettings/', misc.adminSettings)
124124
app.get('/v1/submissions', submissions.submissions);
125125
app.post('/v1/submissions/new', submissions.newSubmission);
126+
app.post('/v1/submissions/edit', submissions.editSubmission);
126127
app.post('/v1/submissions/delete', submissions.deleteSubmission);
127128
app.get('/v1/about', misc.about);
128129
app.post('/v1/profile/upload', misc.profileUpload)

api/controllers/Scoreboard.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const scoreboard = async (req, res, next) => {
99
if (req.app.get("adminShowDisable")) {
1010
for (let i = 0; i < transactionsCache.length; i++) {
1111
const current = transactionsCache[i]
12-
const document = { points: current.points, challenge: current.challenge, timestamp: current.timestamp, challengeID: current.challengeID }
12+
const document = {_id: current._id, points: current.points, challenge: current.challenge, timestamp: current.timestamp, challengeID: current.challengeID }
1313

1414
if (checkUsernamePerms(current.author) !== 2) {
1515
if (current.author in changes) changes[current.author].changes.push(document)
@@ -21,7 +21,7 @@ const scoreboard = async (req, res, next) => {
2121
else {
2222
for (let i = 0; i < transactionsCache.length; i++) {
2323
const current = transactionsCache[i]
24-
const document = { points: current.points, challenge: current.challenge, timestamp: current.timestamp, challengeID: current.challengeID }
24+
const document = {_id: current._id, points: current.points, challenge: current.challenge, timestamp: current.timestamp, challengeID: current.challengeID }
2525

2626

2727
if (current.author in changes) changes[current.author].changes.push(document)

api/controllers/Submissions.js

+55-3
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const newSubmission = async (req, res, next) => {
3333
points: req.body.points
3434
}
3535
if (req.body.type === "hint") {
36-
insertDoc.hint_id = req.body.hint_id-1
36+
insertDoc.hint_id = req.body.hint_id - 1
3737
}
3838
else {
3939
insertDoc.correct = req.body.correct
@@ -59,6 +59,58 @@ const newSubmission = async (req, res, next) => {
5959
}
6060
}
6161

62+
const editSubmission = async (req, res, next) => {
63+
const collections = Connection.collections
64+
try {
65+
if (res.locals.perms < 2) throw new Error('Permissions');
66+
let latestSolveSubmissionID = req.app.get("latestSolveSubmissionID")
67+
latestSolveSubmissionID += 1
68+
req.app.set("latestSolveSubmissionID", latestSolveSubmissionID)
69+
let updateDoc = {
70+
author: req.body.author,
71+
challenge: req.body.challenge,
72+
challengeID: MongoDB.ObjectID(req.body.challengeID),
73+
type: req.body.type,
74+
lastChallengeID: latestSolveSubmissionID,
75+
points: req.body.points
76+
}
77+
if (req.body.type === "hint") {
78+
updateDoc.hint_id = req.body.hint_id - 1
79+
}
80+
else {
81+
updateDoc.correct = req.body.correct
82+
updateDoc.submission = req.body.submission
83+
}
84+
await collections.transactions.updateOne({ _id: MongoDB.ObjectID(req.body.id) }, { $set: updateDoc })
85+
let transactionsCache = req.app.get("transactionsCache")
86+
let time = null
87+
for (let i = 0; i < transactionsCache.length; i++) {
88+
if (transactionsCache[i]._id.toString() === req.body.id) {
89+
time = transactionsCache[i].timestamp
90+
for (key in updateDoc) {
91+
transactionsCache[i][key] = updateDoc[key]
92+
}
93+
break
94+
}
95+
}
96+
req.app.set("transactionsCache", transactionsCache)
97+
98+
99+
broadCastNewSolve([{
100+
_id: req.body.id,
101+
username: req.body.author,
102+
timestamp: time,
103+
points: req.body.points,
104+
lastChallengeID: latestSolveSubmissionID
105+
}])
106+
res.send({ success: true })
107+
}
108+
catch (err) {
109+
console.error(err)
110+
next(err);
111+
}
112+
}
113+
62114
const deleteSubmission = async (req, res, next) => {
63115
const collections = Connection.collections
64116
try {
@@ -71,7 +123,7 @@ const deleteSubmission = async (req, res, next) => {
71123
else {
72124
delReq = delReq.value
73125
//const challengeID = MongoDB.ObjectID(delReq.challengeID.toString())
74-
const challDoc = await collections.challs.findOne({ _id: delReq.challengeID})
126+
const challDoc = await collections.challs.findOne({ _id: delReq.challengeID })
75127
if (delReq.type === "hint") {
76128
const hints = challDoc.hints
77129
const hintsArray = hints[delReq.hint_id].purchased
@@ -120,4 +172,4 @@ const deleteSubmission = async (req, res, next) => {
120172
}
121173
}
122174

123-
module.exports = { submissions, newSubmission, deleteSubmission }
175+
module.exports = { submissions, newSubmission, deleteSubmission, editSubmission }

client/src/AdminPanel/adminChallenges.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
EyeOutlined,
1111
EyeInvisibleOutlined,
1212
RedoOutlined,
13-
SearchOutlined
13+
SearchOutlined,
1414
} from '@ant-design/icons';
1515
import AdminChallengeCreate from "./adminChallengeCreate.js";
1616
import AdminChallengeEdit from "./adminChallengeEdit.js";
@@ -527,7 +527,7 @@ class AdminChallenges extends React.Component {
527527
title=""
528528
key="edit"
529529
render={(text, record) => (
530-
<Button icon={<EditOutlined />} onClick={() => { this.setState({ editChallenge: true, id: record._id }, this.props.history.push("/Admin/Challenges/Edit")) }}> Edit</Button>
530+
<Button icon={<EditOutlined />} onClick={() => { this.setState({ editChallenge: true, id: record._id }); this.props.history.push("/Admin/Challenges/Edit") }}> Edit</Button>
531531
)}
532532
/>
533533
</Table>

client/src/AdminPanel/adminSubmissions.js

+182-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import {
77
FileOutlined,
88
UserOutlined,
99
DeleteOutlined,
10-
ExclamationCircleOutlined
10+
ExclamationCircleOutlined,
11+
EditOutlined
1112
} from '@ant-design/icons';
1213
import { orderBy } from "lodash";
1314
import { Ellipsis } from 'react-spinners-css';
@@ -165,6 +166,165 @@ const CreateT = (props) => {
165166
);
166167
};
167168

169+
const EditT = (props) => {
170+
const [isHint, setIsHint] = useState(false)
171+
const [isNonZero, setNonZero] = useState(false)
172+
const [correctValue, setCorrectValue] = useState(true)
173+
const [form] = Form.useForm();
174+
175+
176+
177+
if (typeof form.getFieldValue("author") === "undefined") {
178+
let initialData = JSON.parse(JSON.stringify(props.initialData))
179+
initialData.challenge = ["", [props.initialData.challenge, props.initialData.challengeID]]
180+
if (initialData.type === "hint") setIsHint(true)
181+
if (initialData.points !== 0) setNonZero(true)
182+
form.setFieldsValue(initialData)
183+
}
184+
185+
186+
return (
187+
<Form
188+
form={form}
189+
onFinish={async (values) => {
190+
// must use correctValue state value instead
191+
await fetch(window.ipAddress + "/v1/submissions/edit", {
192+
method: 'post',
193+
headers: { 'Content-Type': 'application/json', "Authorization": window.IRSCTFToken },
194+
body: JSON.stringify({
195+
"id": props.initialData._id,
196+
"author": values.author,
197+
"challenge": values.challenge[1][0],
198+
"challengeID": values.challenge[1][1],
199+
"type": values.type,
200+
"points": values.points,
201+
"correct": correctValue,
202+
"submission": values.submission,
203+
"hint_id": values.hint_id
204+
})
205+
}).then((results) => {
206+
return results.json(); //return data in JSON (since its JSON data)
207+
}).then((data) => {
208+
if (data.success === true) {
209+
message.success({ content: "Edited transaction successfully!" })
210+
setNonZero(false)
211+
setCorrectValue(false)
212+
setIsHint(false)
213+
props.setState({ editTModal: false })
214+
props.refresh()
215+
form.resetFields()
216+
}
217+
else {
218+
message.error({ content: "Oops. Unknown error" })
219+
}
220+
221+
222+
}).catch((error) => {
223+
console.log(error)
224+
message.error({ content: "Oops. There was an issue connecting with the server" });
225+
})
226+
}}
227+
>
228+
<h4>Select an Account</h4>
229+
<Form.Item
230+
name="author"
231+
rules={[{ required: true, message: 'Please enter an author' }]}
232+
>
233+
<Input allowClear prefix={<UserOutlined />} placeholder="Account which this transaction will belong to" />
234+
</Form.Item>
235+
236+
<h4>Select a Challenge</h4>
237+
<Form.Item
238+
name="challenge"
239+
rules={[{ required: true, message: 'Please select a challenge' }]}
240+
>
241+
<Cascader
242+
options={props.challengeList}
243+
allowClear
244+
showSearch
245+
placeholder="Select an existing challenge which this transaction will belong to" />
246+
</Form.Item>
247+
248+
<h4>Select a Type</h4>
249+
<Form.Item
250+
name="type"
251+
rules={[{ required: true, message: 'Please select the type of transaction' }]}
252+
initialValue="submission"
253+
>
254+
<Select onSelect={(type) => { type === "hint" ? setIsHint(true) : setIsHint(false) }}>
255+
<Option value="submission">Submission</Option>
256+
<Option value="hint">Hint</Option>
257+
<Option value="blocked_submission">Blocked Submission</Option>
258+
</Select>
259+
260+
</Form.Item>
261+
262+
<h4>Input Amount of Points</h4>
263+
<Form.Item
264+
name="points"
265+
rules={[{ required: true, message: 'Please input the amount of points' }]}
266+
initialValue={0}
267+
>
268+
<InputNumber onChange={(value) => {
269+
if (value !== 0) {
270+
setNonZero(true)
271+
setCorrectValue(true)
272+
}
273+
else setNonZero(false)
274+
}} min={-100000} max={100000} ></InputNumber>
275+
276+
</Form.Item>
277+
278+
{!isHint ?
279+
<div>
280+
281+
282+
<h4>Choose whether this is a "Correct" submission</h4>
283+
<Form.Item
284+
name="correct"
285+
rules={[{ required: true, message: 'Please select whether it is correct' }]}
286+
initialValue={true}
287+
valuePropName={correctValue}
288+
>
289+
<Select value={correctValue} onSelect={(value) => setCorrectValue(value)} disabled={isNonZero}>
290+
<Option value={true}>Correct</Option>
291+
<Option value={false}>Wrong</Option>
292+
</Select>
293+
294+
</Form.Item>
295+
296+
<h4>Enter a Submission</h4>
297+
<Form.Item
298+
name="submission"
299+
rules={[{ required: true, message: 'Please enter a submission' }]}
300+
>
301+
<Input allowClear placeholder="The user's flag input" />
302+
</Form.Item>
303+
</div>
304+
:
305+
<div>
306+
<h4>Enter a hint ID (hint number of the challenge from <code>1-n</code>)</h4>
307+
<Form.Item
308+
name="hint_id"
309+
rules={[{ required: true, message: 'Please enter a hint ID' }]}
310+
initialValue={1}
311+
>
312+
<InputNumber min={-100000} max={100000}></InputNumber>
313+
314+
</Form.Item>
315+
</div>}
316+
317+
318+
<Form.Item>
319+
<div style={{ display: "flex", justifyContent: "space-between" }}>
320+
<Button style={{ marginRight: "1.5vw" }} onClick={() => { props.setState({ editTModal: false }) }}>Cancel</Button>
321+
<Button type="primary" htmlType="submit" className="login-form-button" style={{ marginBottom: "1.5vh" }}>Edit Transaction</Button>
322+
</div>
323+
</Form.Item>
324+
</Form>
325+
);
326+
};
327+
168328
class AdminSubmissions extends React.Component {
169329
constructor(props) {
170330
super(props);
@@ -175,7 +335,9 @@ class AdminSubmissions extends React.Component {
175335
createTModal: false,
176336
challengeList: [],
177337
selectedTableKeys: [],
178-
disableEditButtons: true
338+
disableEditButtons: true,
339+
editTModal: false,
340+
initialData: {}
179341
}
180342
}
181343

@@ -324,6 +486,17 @@ class AdminSubmissions extends React.Component {
324486
<CreateT refresh={this.refresh.bind(this)} challengeList={this.state.challengeList} setState={this.setState.bind(this)}></CreateT>
325487
</Modal>
326488

489+
<Modal
490+
title="Edit Transaction"
491+
visible={this.state.editTModal}
492+
footer={null}
493+
destroyOnClose
494+
onCancel={() => { this.setState({ editTModal: false }) }}
495+
>
496+
497+
<EditT initialData={this.state.initialData} refresh={this.refresh.bind(this)} challengeList={this.state.challengeList} setState={this.setState.bind(this)}></EditT>
498+
</Modal>
499+
327500
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
328501
<div style={{ display: "flex", alignItems: "center", height: "2ch" }}>
329502
<Button type="primary" style={{ marginBottom: "2vh", marginRight: "1ch" }} icon={<FileOutlined />} onClick={() => { this.setState({ createTModal: true }) }}>Create New Transaction</Button>
@@ -419,6 +592,13 @@ class AdminSubmissions extends React.Component {
419592
<Column title="Points Awarded" dataIndex="points" key="points" sorter={(a, b) => a.points - b.points} />
420593
<Column title="Flag Submitted" dataIndex="submission" key="submission" />
421594
<Column title="Correct" dataIndex="correct" key="correct" filters={[{ text: "True", value: "True" }, { text: "False", value: "False" }]} onFilter={(value, record) => { return value === record.correct }} />
595+
<Column
596+
title=""
597+
key="edit"
598+
render={(text, record) => (
599+
<Button icon={<EditOutlined />} onClick={() => { this.setState({ editTModal: true, initialData: record }) }}> Edit</Button>
600+
)}
601+
/>
422602
</Table>
423603
</Layout >
424604
);

client/src/Scoreboard/Scoreboard.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,7 @@ class Scoreboard extends React.Component {
142142
changes.users.push({ _id: payload.username, changes: [{ points: payload.points, timestamp: payload.timestamp, _id: payload._id }] })
143143
}
144144
}
145-
146-
145+
147146
window.scoreboardData = changes
148147
window.lastChallengeID = payloadArray[0].lastChallengeID
149148
this.sortPlotRenderData(JSON.parse(JSON.stringify(changes)))

0 commit comments

Comments
 (0)