def displayWork(form): """ Provides the student-requested view of previously submitted work. """ tamarin.printHeader() try: # Validate that this person is really capable of seeing this stuff # (throws exception if not) tamarin.authenticate(form.getfirst('user'), form.getfirst('pass')) if 'submission' in form: #wants to see a specific submission print('<br>') core_view.displaySubmission(form.getfirst('submission')) else: #show them all their work #start form print('<form action="' + tamarin.CGI_URL + 'view.py" ' 'method="post">') print('<input type="hidden" name="user" value="' + form.getfirst('user') + '">') print('<input type="hidden" name="pass" value="' + form.getfirst('pass') + '">') print('<div class="logout">[Close your browser to logout]</div>') core_view.displayUser(form.getfirst('user'), brief=True) print('</form>') except tamarin.TamarinError as err: tamarin.printError(err) except: tamarin.printError('UNHANDLED_ERROR') finally: tamarin.printFooter()
def main(form=None): if not form: form = cgi.FieldStorage() tamarin.printHeader("Submission and Grading Results") print("<h2>Submission and Grading Results</h2>") try: print("<p>") # check that submitted form was correct with all needed details if "uploaded" not in form: raise TamarinError("BAD_SUBMITTED_FORM", "Missing uploaded field.") # validate filename format, printing username and assignment filename = form.getfirst("uploaded") match = re.match(tamarin.UPLOADED_RE, filename) if not match: raise TamarinError("BAD_SUBMITTED_FORM", "Wrong filename format.") print("<b>Username:</b> " + match.group(1) + "<br>") print("<b>Assignment:</b> " + match.group(2) + "<br>") # check that uploaded file really exists uploadedFilename = os.path.join(tamarin.UPLOADED_ROOT, filename) if not os.path.exists(uploadedFilename): raise TamarinError("NO_UPLOADED_FILE") # create submitted filename and move uploaded file to submitted folder currentStamp = tamarin.convertTimeToTimestamp() submittedFilename = filename.replace(".", "-" + currentStamp + ".", 1) submittedFilename = os.path.join(tamarin.SUBMITTED_ROOT, submittedFilename) shutil.move(uploadedFilename, submittedFilename) print("<b>File submitted at:</b> " + currentStamp + "<br>") # Yay! Submission is successful, and user is DONE print("<i>--Submission completed successfully--</i>") print("</p>") # now start grading... # (In future, might have option to grade in real time. For now, # just start the grade pipe and print results.) startGradePipe() except TamarinError as err: tamarin.printError(err) print("<p>") print( "Due to the above error, your file was <i>not</i> successfully " "submitted. You may want to try again or else contact your " "Tamarin administrator " ) if tamarin.ADMIN_EMAIL: print("(" + tamarin.ADMIN_EMAIL + ")") print(" with the details of the error you encountered.") print("</p>") except: tamarin.printError("UNHANDLED_ERROR") finally: tamarin.printFooter()
def testPrintPage(self): """ printHeader and printFooter work. """ printHeader() print("<p>Hello World.</p>") printFooter() #print(sys.stdout.getvalue(), file=sys.__stdout__) output = sys.stdout.getvalue() self.assertIn('<html>', output) self.assertIn('</html>', output) self.assertIn('Hello', output)
def main(): """ Displays current time, grading method, gradepipe status, number of uploaded (but unsubmitted files), and the submitted queue. """ tamarin.printHeader("Tamarin Status") try: print('<h2>Tamarin Status</h2>') # current time # (Printed in two different formats as a way for users # to learn how to make sense of Tamarin timestamp format) print('<p><b>Current System Time:</b> ') now = datetime.datetime.now() print(tamarin.convertTimeToTimestamp(now)) print(' (<i>' + now.isoformat(' ') + '</i>)') print('</p>') # uploaded file count print('<p><b>Uploaded (but not submitted) file count:</b> ') uploaded = glob.glob(os.path.join(tamarin.UPLOADED_ROOT, '*')) print(len(uploaded)) # grade pipe status print('<p><b>Gradepipe:</b> ') if os.path.exists(tamarin.GRADEPIPE_ACTIVE): print('<small>RUNNING</small>') else: print('<small>OFF</small>') if os.path.exists(tamarin.GRADEPIPE_DISABLED): print(' <small>(DISABLED)</small>') print('</p>') # grading queue contents print('<p><b>Submitted (but not yet graded) queue:</b> ') submitted = tamarin.getSubmittedFilenames() if len(submitted) == 0: print('[empty]') else: print('<br>') for s in submitted: print('<span class="gradequeue">' + os.path.basename(s) + '</span><br>') print('</p>') except: tamarin.printError('UNHANDLED_ERROR') finally: tamarin.printFooter()
def main(form=None): """ Determine whether to show view login form, show all the user's work, or show a single given submission. """ if not form: form = cgi.FieldStorage() if not form: # no values passed displayLogin() elif ('user' in form) and ('pass' in form): displayWork(form) else: tamarin.printHeader('File Upload Error') tamarin.printError('BAD_SUBMITTED_FORM') tamarin.printFooter()
def displayLogin(): """ Displays the login form to be used to view submissions. """ tamarin.printHeader('View Submissions') print(""" <h2>View Submissions</h2> <form class="html" action="/cgi-bin/view.py" method="post" enctype="multipart/form-data"> <table> <tr><td>Username:</td><td><input type="text" name="user"></td></tr> <tr><td>Password:</td><td><input type="password" name="pass"></td></tr> <tr><td colspan="2" style="text-align: center;"> <input type="submit" value="View my submissions"></td></tr> </table> </form> """) tamarin.printFooter()
def displayUploadForm(): """ Displays the form to be used to upload a file. """ printHeader('File Upload') print(""" <h2>File Upload</h2> <form class="html" action="/cgi-bin/upload.py" method="post" enctype="multipart/form-data"> <table> <tr><td>File (<code><i>Username</i>A##.<i>ext</i></code>):</td> <td><input type="file" name="file"></td></tr> <tr><td>Your password:</td> <td><input type="password" name="pass"></td></tr> <tr><td colspan="2" style="text-align: center;"> <input type="submit" value="Upload this file for grading"></td></tr> </table> </form> """) printFooter()
def main(form=None): """ Determine which mode to run in: are we displaying the upload page, or processing a submission, or was there an error? """ if form is None: form = cgi.FieldStorage() if not form: displayUploadForm() elif 'pass' in form and 'file' in form: validateUploadedFile(form) else: # XXX: You'll get this error if a binary file is uploaded and # Tamarin is running on Windows because, for some reason, the # pass field is then not submitted correctly. printHeader('File Upload Error') printError('BAD_SUBMITTED_FORM') #print(form); printFooter()
def main(form=None): if not form: form = cgi.FieldStorage() try: if not form: tamarin.printHeader('Tamarin Masterview') displayForm() elif 'modify' in form: # modify a submission's grade if 'submission' not in form or 'grade' not in form: # may have a comment too, but that can be blank tamarin.printHeader('Masterview: Modify error') raise TamarinError('BAD_SUBMITTED_FORM') tamarin.printHeader("Masterview: Modified " + form.getfirst('submission')) modifySubmission(form.getfirst('submission'), form.getfirst('grade'), form.getfirst('verify'), form.getfirst('comment')) core_view.displaySubmission(form.getfirst('submission'), master=True) elif 'deleteComment' in form: # delete a comment from a submission if 'submission' not in form: tamarin.printHeader('Masterview: Delete comment error') raise TamarinError('BAD_SUBMITTED_FORM') tamarin.printHeader('Masterview: Deleted comment #' + form.getfirst('deleteComment')) deleteComment(form.getfirst('submission'), form.getfirst('deleteComment')) print('<br>') core_view.displaySubmission(form.getfirst('submission'), master=True) elif 'submission' in form: # view a single specific submission # (without modify or deleteComment, caught above) tamarin.printHeader('Masterview: ' + form.getfirst('submission')) print('<br>') core_view.modifySubmission(form.getfirst('submission')) elif 'user' in form: # view all of a user's submissions tamarin.printHeader('Masterview: ' + form.getfirst('user')) core_view.displayUser(form.getfirst('user'), assignment=form.getfirst('assignment'), brief=form.getfirst('brief'), master=True) elif 'assignment' in form: # without user given, or would have been caught above tamarin.printHeader('Masterview: ' + form.getfirst('assignment')) core_view.displayAssignment(form.getfirst('assignment'), form.getfirst('brief'), master=True) elif 'strip' in form: tamarin.printHeader('Masterview: Stripping ' + form.getfirst('strip')) stripFiles(form.getfirst('strip'), form.getfirst('only')) elif 'verifyAll' in form: tamarin.printHeader('Masterview: Verifying ' + form.getfirst('verifyAll')) markAllAsVerified(form.getfirst('verifyAll')) elif 'startGrader' in form: tamarin.printHeader('Masterview: Start grading pipeline') started = submit.startGradePipe(printStatus=False) if started: print('<p><br>Grading pipeline started.</p>') else: print('<p><br>Grader pipeline <b>not</b> started.') print('This is either because it is disabled or is already ' 'running.') print('<p>See <a href="' + tamarin.CGI_URL + 'status.py">status</a> ' + 'for more.</p>') elif 'gradesheet' in form: print("Content-Type: text/plain") print() displayGradeSheet(form.getfirst('comma')) else: tamarin.printHeader('Masterview: No valid option submitted') raise TamarinError('BAD_SUBMITTED_FORM') except TamarinError as err: tamarin.printError(err) except: tamarin.printError('UNHANDLED_ERROR') finally: if not (form and 'gradesheet' in form): tamarin.printFooter()
def validateUploadedFile(form): """ Processes a file upload. Assumes the passed form is a valid query submission. On an error, reports what went wrong to the user. Otherwise confirms that the user wants to submit the uploaded file for grading. """ printHeader("File Upload Results") try: print('<h2>File Upload Results</h2>') print('<p>') # get filename and check that file was properly uploaded assert 'file' in form and 'pass' in form, "Invalid form submission" filename = form['file'].filename if not filename: raise TamarinError('NO_FILE_UPLOADED') else: print('<!--Original filename: ' + filename + '-->') filename = stripFilename(filename) #defined below print('<b>Filename:</b> ' + filename + '<br>') filecontents = form.getfirst('file') if not filecontents: raise TamarinError('EMPTY_FILE') # validate filename checkFilename(filename) # authenticate user match = re.match(tamarin.UPLOADED_RE, filename) assert match #because filename is valid from above username = match.group(1) username = username.lower() #for any initial uppercase letter assignmentName = match.group(2) extension = match.group(3) password = form.getfirst('pass') print('<b>Username:</b> ' + username + '<br>') print('<b>Password:</b> ', end='') if password: print('*' * len(password) + '<br>') else: print('[missing]<br>') tamarin.authenticate(username, password) # validate that assignment exists print('<b>Assignment:</b> ' + assignmentName) #... no <br> yet assignment = Assignment(assignmentName) #may throw TamarinError # confirm any type-specific requirements... # right extension? if extension != assignment.type.fileExt: raise TamarinError('WRONG_EXTENSION', 'Your file is .' + extension + ' but this assignment requires .' + assignment.type.fileExt) # initial cap? if assignment.type.initialCap and not re.match(r"^[A-Z]", filename): raise TamarinError('NO_INITIAL_CAP', filename) # check that file contents are plain text (if necessary) if assignment.type.encoding: try: # convert bytes to str filecontents = filecontents.decode( encoding=assignment.type.encoding) # files often uploaded in binary form from various OSs, # so adjust line-endings # XXX: Still need this in Python3? filecontents = filecontents.replace('\r\n', '\r') # \n comes out properly as 0D0A on Windows filecontents = filecontents.replace('\r', '\n') except UnicodeError as err: # this problem is often due to a copy-and-paste thing from a # different encoding where a couple odd characters (like quotes # and such) come from a word processor. So this will help # students track down where their bad chars are in this most # common non-ASCII case lineCount = 1 charCount = 1 for char in filecontents: if char > 128: print("<p><b>First non-ASCII character:</b>: ") print("line " + str(lineCount) + ", char " + str(charCount) + "<br>") break elif char == '\n': # NOTE: line count only correct for Unix and Windows; # not old Mac, etc lineCount += 1 charCount = 1 else: charCount += 1 raise TamarinError('BINARY_FILE', "This assignment requires " "plain text files using the " + assignment.type.encoding + " (or compatible) encoding, but: " + str(err)) # Ready to accept based on submission itself. # Now see if late or already submitted (for warnings) or verified # Reuse filename (without extension) from above wildFilename = filename.replace('.', '*.', 1) alreadySubmitted = glob.glob(os.path.join(tamarin.SUBMITTED_ROOT, wildFilename)) alreadyGraded = glob.glob(os.path.join(assignment.path, wildFilename)) # but not all files in graded == a graded submission file if submitted # ext is same as grader output file ext, so remove grader output files for ag in alreadyGraded[:]: if re.match(tamarin.GRADED_RE, os.path.basename(ag)): alreadyGraded.remove(ag) # determine lateness, so can print it here if assignment.isLate(): print(' (<i>Late: </i>' + assignment.getLateOffset() + ')') if assignment.isTooLate(): raise TamarinError('SUBMISSION_TOO_LATE') if not tamarin.MAY_RESUBMIT_LATE and \ (alreadySubmitted or alreadyGraded): raise 'RESUBMISSION_LATE' # has a human already verified a previous submission? if not tamarin.MAY_RESUMBIT_AFTER_HUMAN and alreadyGraded: # check if a graded file has also been verified for f in alreadyGraded: gradedF = GradedFile(os.path.basename(f)) if gradedF.humanVerified: # oops for student: already verified raise TamarinError('PREVIOUS_SUBMISSION_VERIFIED') # display file contents (if appropriate) print('<p><b>Uploaded Code:</b></p>') print('<pre ' if assignment.type.preformatted else '<div ') print('class="code">') if not assignment.type.encoding: print('[ <i>binary file format: ' 'cannot display contents here</i> ]') else: # prevent disappearing code due to code test looking like html tags if assignment.type.preformatted: print(html.escape(filecontents)) else: print(html.escape(filecontents).replace('\n', '<br>\n')) print('</pre>' if assignment.type.preformatted else '</div>') # Done! # write file (could result in an io error, handed as UNHANDLED below) uploadedFilename = os.path.join(tamarin.UPLOADED_ROOT, filename) overwrite = glob.glob(uploadedFilename) #see if file already exists outfile = open(uploadedFilename, 'w' if assignment.type.encoding else 'wb') outfile.write(filecontents) outfile.close() # give success message print('<p>') print('Your code (as shown above) has been uploaded to Tamarin. ') if overwrite: print('(Doing so overwrote a previously uploaded ' 'but unsubmitted file of the same name.) ') print('<i>It has not yet been submitted.</i> ') # warn if already submitted (and/or graded) this assignment if alreadySubmitted or alreadyGraded: print('<p><b><i>Warning:</i></b> You already have ') if alreadySubmitted: print(str(len(alreadySubmitted)) + ' file(s) submitted ' '(but not yet graded) ') if alreadyGraded: print('and ') if alreadyGraded: print(str(len(alreadyGraded)) + ' file(s) graded ') print('for this ' + str(assignment) + ' assignment. ') submitCount = len(alreadySubmitted) + len(alreadyGraded) if tamarin.RESUBMISSION_PENALTY: print('If you submit this uploaded file, it will be a ' + '(resubmission * ' + str(submitCount) + '), ') print('and so its final score will be reduced by ' + str(round(submitCount * tamarin.RESUBMISSION_PENALTY, tamarin.GRADE_PRECISION)) + '.</p>') # provide submit button print("<p>If you are ready to officially submit this uploaded file " "for grading, click the button below. </p>") print() print('<form action="' + tamarin.CGI_URL + 'submit.py" ' 'method="post" class="html">') print('<input type="hidden" name="uploaded" value="' + filename + '">') print('<input type="submit" value="Submit this file" ' 'class="centered">') print('</form>') except TamarinError as err: printError(err) print('<p>') print('Due to the above error, your uploaded file was not saved. ' 'Please <a href="' + tamarin.CGI_URL + 'upload.py' + '">return to the upload page</a> and try again.') print('</p>') except: printError('UNHANDLED_ERROR') finally: printFooter()