def reverify(self): problem = problemlib.load_problem(self.competition) changes = 0 for group in self.competition.groups: if group.input: for output in group.input.outputs: old_status = output.ground_truth input_file = StringIO( group.input.data.file.read().decode("utf-8")) output_file = StringIO( output.data.file.read().decode("utf-8")) try: problem.verify_output(input_file, output_file) except problemlib.VerificationError as e: output.ground_truth = VerificationStatus.rejected print("{} rejected because: {}".format(output, e)) except Exception as e: output.ground_truth = VerificationStatus.waiting print("Verifier module failed on {}: {}".format( output, e)) else: output.ground_truth = VerificationStatus.accepted if old_status != output.ground_truth: print("{} changed ground truth from {} to {}".format( output, old_status, output.ground_truth)) changes += 1 DBSession.flush() print("{} ground truths changed".format(changes))
def authenticate(self, environ, identity): try: ticket = identity['login'] except KeyError: return None if identity['identifier'] != 'mpapi': return None r = requests.post(self.mpapi_fetch, data={'tkt': ticket}) r.raise_for_status() data = r.json() if data['result'] != 'success': raise ValueError('MPAPI Failure') username = data['uid'] identity['user'] = User.from_username(username) if identity['user']: return username else: user = user_from_mpapi_attributes(data['attributes']) DBSession.add(user) DBSession.flush() transaction.commit() return username
def reverify(self): verif_mod = self.competition.output_verifier.module changes = 0 for group in self.competition.groups: if group.input: for output in group.input.outputs: old_status = output.ground_truth try: verif_mod.verify(group.input.data.file, output.data.file) except verif_mod.VerificationError as e: output.ground_truth = VerificationStatus.rejected print("{} rejected because: {}".format(output, e)) except Exception as e: output.ground_truth = VerificationStatus.waiting print("Verifier module failed on {}: {}".format( output, e)) else: output.ground_truth = VerificationStatus.accepted if old_status != output.ground_truth: print("{} changed ground truth from {} to {}".format( output, old_status, output.ground_truth)) changes += 1 DBSession.flush() print("{} ground truths changed".format(changes))
def automatic_verification(self): outputs = (DBSession .query(Output) .join(Output.input) .filter(Input.group_id == self.group.id)) for output in outputs: output.verification = output.ground_truth DBSession.add(output) DBSession.flush()
def input_upload(self, input_upload=None, team_name=None): user = request.identity['user'] if not user.admin and not self.group.competition.input_upload_open: abort(403, "Sorry, input upload stage is closed.") if hasattr(input_upload, "file"): try: contents = input_upload.file.read().decode("utf-8") except UnicodeDecodeError: flash('Your input contains invalid characters. ' 'Please correct and try uploading again.', 'danger') redirect(self.base_url) problem = problemlib.load_problem(self.group.competition) try: input = problem.parse_input(StringIO(contents)) except problemlib.FileFormatError as e: flash( f"Your input is not valid: {e}. Please correct and upload again.", "danger", ) redirect(self.base_url) reformatted_contents = StringIO() input.write(reformatted_contents) f = FileIntent( BytesIO(reformatted_contents.getvalue().encode('utf-8')), 'input_group{}.txt'.format(self.group.id), 'application/octet-stream') if self.group.input is None: iput = Input(data=f, group=self.group) DBSession.add(iput) else: self.group.input.data = f DBSession.flush() if team_name is not None: if len(team_name) >= 100: flash('Your team name has been rejected, as it is too long.', 'danger') redirect(self.base_url) if not team_name: flash('You must set a team name.', 'danger') redirect(self.base_url) self.group.name = team_name flash('Thank you. Please return here for output upload on {}' .format(ftime(self.group.competition.output_upload_begins)), 'success') redirect(self.base_url)
def input_upload(self, input_upload=None, team_name=None): user = request.identity['user'] if not user.admin and not self.group.competition.input_upload_open: abort(403, "Sorry, input upload stage is closed.") if hasattr(input_upload, "file"): try: contents = file_normalize(input_upload.file.read()) except UnicodeDecodeError: flash( 'Your input contains invalid characters. ' 'Please correct and try uploading again.', 'danger') redirect(self.base_url) if len(contents) > 1E6: abort(400, "Your input exceeds the maxiumum size.") verif_mod = self.group.competition.input_verifier.module try: verif_mod.verify(StringIO(contents)) except verif_mod.VerificationError as e: flash( 'Your input has been rejected for the following reason: ' '{}. Please correct and try uploading again.'.format(e), 'danger') redirect(self.base_url) f = FileIntent(BytesIO(contents.encode('utf-8')), 'input_group{}.txt'.format(self.group.id), 'application/octet-stream') if self.group.input is None: iput = Input(data=f, group=self.group) DBSession.add(iput) else: self.group.input.data = f DBSession.flush() if team_name is not None: if len(team_name) >= 100: flash('Your team name has been rejected, as it is too long.', 'danger') redirect(self.base_url) if not team_name: flash('You must set a team name.', 'danger') redirect(self.base_url) self.group.name = team_name flash( 'Thank you. Please return here for output upload on {}'.format( ftime(self.group.competition.output_upload_begins)), 'success') redirect(self.base_url)
def authenticate(self, environ, identity): try: ticket = identity['login'] except KeyError: return None if identity['identifier'] != 'mpapi': return None r = requests.post(self.mpapi_fetch, data={'tkt': ticket}) r.raise_for_status() data = r.json() if data['result'] != 'success': raise ValueError('MPAPI Failure') username = data['uid'] attributes = data['attributes'] uid = attributes['uidNumber'] full_name = '{} {}'.format(attributes['first'], attributes['sn']) email = attributes['mail'] user = DBSession.query(User).filter(User.id == uid).one_or_none() if user: # Update attributes in case of username/full name change user.username = username user.full_name = full_name user.email = email else: user = User(id=uid, username=username, full_name=full_name, email=email) DBSession.add(user) DBSession.flush() transaction.commit() return username
def submit_output(self, to_group, output_file=None): user = request.identity['user'] to_group = DBSession.query(Group).get(to_group) if not to_group: abort(404, "No such group") if to_group.competition_id != self.group.competition_id: abort(400, "Cannot submit to a group in another competition") if not hasattr(output_file, "file"): abort(400, "Must include file in submission") comp = self.group.competition existing = (DBSession.query(Output) .filter(Output.group_id == self.group.id) .filter(Output.input_id == to_group.input.id) .filter(Output.active == True) .one_or_none()) if not (user.admin or comp.output_upload_open or (comp.resolution_open and existing is not None and not existing.use_ground_truth)): abort(403, "Forbidden to upload this output at this time") try: contents = output_file.file.read().decode("utf-8") except UnicodeDecodeError: return {'status': 'error', 'msg': 'Output contains invalid characters.'} problem = problemlib.load_problem(comp) try: output = problem.parse_output(to_group.input.data.file, StringIO(contents)) except problemlib.FileFormatError as e: return { "status": "error", "msg": f"Output has formatting errors: {e}", } new_contents = StringIO() output.write(new_contents) f = FileIntent( BytesIO(new_contents.getvalue().encode("utf-8")), 'output_from_{}_to_{}.txt'.format(self.group.id, to_group.id), 'application/octet-stream') try: output.verify() except problemlib.VerificationError: ground_truth = VerificationStatus.rejected except Exception: ground_truth = VerificationStatus.waiting else: ground_truth = VerificationStatus.accepted use_ground_truth = ( not comp.verification_begins or datetime.datetime.now() >= comp.verification_begins ) if existing: if comp.resolution_open: existing.active = False else: DBSession.delete(existing) db_output = Output( data=f, group=self.group, input=to_group.input, score=output.score, original=comp.output_upload_open, ground_truth=ground_truth, use_ground_truth=use_ground_truth, ) DBSession.add(db_output) DBSession.flush() return {'status': 'success', 'url': db_output.data.url}
def submit_output(self, to_group, output_file=None): user = request.identity['user'] to_group = DBSession.query(Group).get(to_group) if not to_group: abort(404, "No such group") if to_group.competition_id != self.group.competition_id: abort(400, "Cannot submit to a group in another competition") if not hasattr(output_file, "file"): abort(400, "Must include file in submission") comp = self.group.competition existing = (DBSession.query(Output).filter( Output.group_id == self.group.id).filter( Output.input_id == to_group.input.id).filter( Output.active == True).one_or_none()) if not (user.admin or comp.output_upload_open or (comp.resolution_open and existing is not None and not existing.use_ground_truth)): abort(403, "Forbidden to upload this output at this time") try: contents = file_normalize(output_file.file.read()) except UnicodeDecodeError: return { 'status': 'error', 'msg': 'Output contains invalid characters.' } if len(contents) > 1E6: return {'status': 'error', 'msg': 'Output exceeds maximum size.'} try: score, _, _ = contents.partition('\n') score = int(score) except ValueError: return { 'status': 'error', 'msg': 'First line must only contain an integer.' } f = FileIntent( BytesIO(contents.encode('utf-8')), 'output_from_{}_to_{}.txt'.format(self.group.id, to_group.id), 'application/octet-stream') if existing: if comp.resolution_open: existing.active = False else: DBSession.delete(existing) output = Output(data=f, group=self.group, input=to_group.input, score=score, original=comp.output_upload_open) verif_mod = self.group.competition.output_verifier.module try: verif_mod.verify(to_group.input.data.file, StringIO(contents)) except verif_mod.VerificationError: output.ground_truth = VerificationStatus.rejected except Exception: output.ground_truth = VerificationStatus.waiting else: output.ground_truth = VerificationStatus.accepted if comp.resolution_open or not comp.verification_begins: output.use_ground_truth = True DBSession.add(output) DBSession.flush() return {'status': 'success', 'url': output.data.url}