Skip to content
Snippets Groups Projects
Commit 29c623f2 authored by RABijl's avatar RABijl
Browse files

merges approve shortcut with pregrading

parents f5db63ff 94c32299
No related branches found
No related tags found
1 merge request!28combine precise positioning with pregrading
...@@ -30,6 +30,7 @@ class Grade extends React.Component { ...@@ -30,6 +30,7 @@ class Grade extends React.Component {
// update the tooltips for the associated widgets (in render()). // update the tooltips for the associated widgets (in render()).
this.props.bindShortcut(['left', 'h'], this.prev) this.props.bindShortcut(['left', 'h'], this.prev)
this.props.bindShortcut(['right', 'l'], this.next) this.props.bindShortcut(['right', 'l'], this.next)
this.props.bindShortcut(['a'], this.approve)
this.props.bindShortcut(['shift+left', 'shift+h'], (event) => { this.props.bindShortcut(['shift+left', 'shift+h'], (event) => {
event.preventDefault() event.preventDefault()
this.prevUngraded() this.prevUngraded()
...@@ -153,6 +154,20 @@ class Grade extends React.Component { ...@@ -153,6 +154,20 @@ class Grade extends React.Component {
}) })
} }
approve = () => {
const exam = this.props.exam
const problem = exam.problems[this.state.pIndex]
const optionURI = this.state.examID + '/' +
exam.submissions[this.state.sIndex].id + '/' +
problem.id
api.put('solution/approve/' + optionURI, {
graderID: this.props.graderID
})
.then(result => {
this.props.updateSubmission(this.state.sIndex)
})
}
toggleFullPage = (event) => { toggleFullPage = (event) => {
this.setState({ this.setState({
fullPage: event.target.checked fullPage: event.target.checked
......
...@@ -8,7 +8,7 @@ from .students import Students ...@@ -8,7 +8,7 @@ from .students import Students
from .submissions import Submissions from .submissions import Submissions
from .problems import Problems from .problems import Problems
from .feedback import Feedback from .feedback import Feedback
from .solutions import Solutions from .solutions import Solutions, Approve
from .widgets import Widgets from .widgets import Widgets
from .emails import EmailTemplate, RenderedEmailTemplate, Email from .emails import EmailTemplate, RenderedEmailTemplate, Email
from .mult_choice import MultipleChoice from .mult_choice import MultipleChoice
...@@ -50,11 +50,12 @@ api.add_resource(RenderedEmailTemplate, ...@@ -50,11 +50,12 @@ api.add_resource(RenderedEmailTemplate,
api.add_resource(Email, api.add_resource(Email,
'/email/<int:exam_id>', '/email/<int:exam_id>',
'/email/<int:exam_id>/<int:student_id>') '/email/<int:exam_id>/<int:student_id>')
api.add_resource(Approve,
'/solution/approve/<int:exam_id>/<int:submission_id>/<int:problem_id>')
api.add_resource(MultipleChoice, api.add_resource(MultipleChoice,
'/mult-choice/<int:id>', '/mult-choice/<int:id>',
'/mult-choice/') '/mult-choice/')
# Other resources that don't return JSON # Other resources that don't return JSON
# It is possible to get flask_restful to work with these, but not # It is possible to get flask_restful to work with these, but not
# very idiomatic. # very idiomatic.
......
...@@ -9,7 +9,10 @@ from flask_restful import Resource, reqparse ...@@ -9,7 +9,10 @@ from flask_restful import Resource, reqparse
from werkzeug.datastructures import FileStorage from werkzeug.datastructures import FileStorage
from sqlalchemy.orm import selectinload from sqlalchemy.orm import selectinload
from ..pdf_generation import PAGE_FORMATS, generate_pdfs, output_pdf_filename_format, join_pdfs, page_is_size
from ..pdf_generation import PAGE_FORMATS, generate_pdfs, output_pdf_filename_format
from ..pdf_generation import join_pdfs, page_is_size, make_pages_even
from ..database import db, Exam, ExamWidget, Submission from ..database import db, Exam, ExamWidget, Submission
...@@ -280,10 +283,9 @@ class Exams(Resource): ...@@ -280,10 +283,9 @@ class Exams(Resource):
exam_dir = _get_exam_dir(exam.id) exam_dir = _get_exam_dir(exam.id)
pdf_path = os.path.join(exam_dir, 'exam.pdf') pdf_path = os.path.join(exam_dir, 'exam.pdf')
os.makedirs(exam_dir, exist_ok=True) os.makedirs(exam_dir, exist_ok=True)
pdf_data.save(pdf_path) make_pages_even(pdf_path, args['pdf'])
print(f"Added exam {exam.id} (name: {exam_name}, token: {exam.token}) to database") print(f"Added exam {exam.id} (name: {exam_name}, token: {exam.token}) to database")
......
...@@ -147,3 +147,43 @@ class Solutions(Resource): ...@@ -147,3 +147,43 @@ class Solutions(Resource):
db.session.commit() db.session.commit()
return {'state': state} return {'state': state}
class Approve(Resource):
""" add just a grader to a specifc problem on an exam """
put_parser = reqparse.RequestParser()
put_parser.add_argument('graderID', type=int, required=True)
def put(self, exam_id, submission_id, problem_id):
"""Takes an existing feedback checks if it is valid then gives the current graders id to the solution this is
usefull for approving pre graded solutions
Parameters
----------
graderID: int
Returns
-------
state: boolean
"""
args = self.put_parser.parse_args()
grader = Grader.query.get(args.graderID)
sub = Submission.query.filter(Submission.exam_id == exam_id,
Submission.copy_number == submission_id).one_or_none()
if sub is None:
return dict(status=404, message='Submission does not exist.'), 404
solution = Solution.query.filter(Solution.submission_id == sub.id,
Solution.problem_id == problem_id).one_or_none()
if solution is None:
return dict(status=404, message='Solution does not exist.'), 404
graded = len(solution.feedback)
if graded:
solution.graded_at = datetime.now()
solution.graded_by = grader
return {'state': graded}
...@@ -402,3 +402,19 @@ def page_is_size(exam_pdf_file, shape, tolerance=0): ...@@ -402,3 +402,19 @@ def page_is_size(exam_pdf_file, shape, tolerance=0):
pass pass
return not invalid return not invalid
def make_pages_even(output_filename, exam_pdf_file):
exam_pdf = PdfReader(exam_pdf_file)
new = PdfWriter()
new.addpages(exam_pdf.pages)
pagecount = len(exam_pdf.pages)
if (pagecount % 2 == 1):
blank = PageMerge()
box = exam_pdf.pages[0].MediaBox
blank.mbox = box
blank = blank.render()
new.addpage(blank)
new.write(output_filename)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment