def test_approve_sign_up_for_event(client_session): client, session = client_session with login_scope(client, 'test_iris_admin', 'test') as client: # check the redirection if the user or the event does not exist rv = client.get("/events/xxx/sign_up/test_user") session.commit() assert rv.status_code == 302 assert rv.location == "http://localhost/problems" with client.session_transaction() as cs: flash_message = dict(cs['_flashes']) assert flash_message['message'] == 'No event xxx or no user test_user' rv = client.get("/events/iris_test/sign_up/xxxx") session.commit() assert rv.status_code == 302 assert rv.location == "http://localhost/problems" with client.session_transaction() as cs: flash_message = dict(cs['_flashes']) assert flash_message['message'] == 'No event iris_test or no user xxxx' add_user(session, 'zz', 'zz', 'zz', 'zz', 'zz', access_level='user') _, _, event_team = ask_sign_up_team(session, 'iris_test', 'zz') assert not event_team.approved rv = client.get('/events/iris_test/sign_up/zz') assert rv.status_code == 302 assert rv.location == "http://localhost/problems" session.commit() event_team = get_event_team_by_name(session, 'iris_test', 'zz') assert event_team.approved with client.session_transaction() as cs: flash_message = dict(cs['_flashes']) assert "is signed up for Event" in flash_message['Successful sign-up']
def test_sign_up_for_event(client_session): client, session = client_session # trigger that the event does not exist with login_scope(client, 'test_user', 'test') as client: rv = client.get('/events/xxx/sign_up') assert rv.status_code == 302 assert rv.location == 'http://localhost/problems' with client.session_transaction() as cs: flash_message = dict(cs['_flashes']) assert "no event named" in flash_message['message'] # GET: sign-up to a new controlled event add_user(session, 'yy', 'yy', 'yy', 'yy', 'yy', access_level='user') with login_scope(client, 'yy', 'yy') as client: rv = client.get('/events/iris_test/sign_up') assert rv.status_code == 302 assert rv.location == 'http://localhost/problems' with client.session_transaction() as cs: flash_message = dict(cs['_flashes']) assert "Sign-up request is sent" in flash_message['Request sent'] # make sure that the database has been updated for our session session.commit() event_team = get_event_team_by_name(session, 'iris_test', 'yy') assert not event_team.approved # check that we are informing the user that he has to wait for approval rv = client.get('/events/iris_test') assert rv.status_code == 200 assert b'Waiting approval...' in rv.data # GET: sign-up to a new uncontrolled event event = get_event(session, 'boston_housing_test') event.is_controled_signup = False session.commit() with login_scope(client, 'yy', 'yy') as client: rv = client.get('/events/boston_housing_test/sign_up') assert rv.status_code == 302 assert (rv.location == 'http://localhost/events/boston_housing_test/sandbox') with client.session_transaction() as cs: flash_message = dict(cs['_flashes']) assert "is signed up for" in flash_message['Successful sign-up'] # make sure that the database has been updated for our session session.commit() event_team = get_event_team_by_name(session, 'boston_housing_test', 'yy') assert event_team.approved
def my_submissions(event_name): """Landing page of all user's submission information. Parameters ---------- event_name : str The name of the event. """ event = get_event(db.session, event_name) if not is_accessible_event(db.session, event_name, flask_login.current_user.name): return redirect_to_user( '{}: no event named "{}"' .format(flask_login.current_user.firstname, event_name) ) if app.config['TRACK_USER_INTERACTION']: add_user_interaction( db.session, interaction='looking at my_submissions', user=flask_login.current_user, event=event ) if not is_accessible_code(db.session, event_name, flask_login.current_user.name): error_str = ('No access to my submissions for event {}. If you have ' 'already signed up, please wait for approval.' .format(event.name)) return redirect_to_user(error_str) # Doesn't work if team mergers are allowed event_team = get_event_team_by_name(db.session, event_name, flask_login.current_user.name) leaderboard_html = event_team.leaderboard_html failed_leaderboard_html = event_team.failed_leaderboard_html new_leaderboard_html = event_team.new_leaderboard_html admin = is_admin(db.session, event_name, flask_login.current_user.name) if event.official_score_type.is_lower_the_better: sorting_direction = 'asc' else: sorting_direction = 'desc' return render_template('leaderboard.html', leaderboard_title='Trained submissions', leaderboard=leaderboard_html, failed_leaderboard=failed_leaderboard_html, new_leaderboard=new_leaderboard_html, sorting_column_index=4, sorting_direction=sorting_direction, event=event, admin=admin)
def test_approve_users_remove(client_session): client, session = client_session # create 2 new users add_user(session, 'xx', 'xx', 'xx', 'xx', 'xx', access_level='user') add_user(session, 'yy', 'yy', 'yy', 'yy', 'yy', access_level='asked') # ask for sign up for an event for the first user _, _, event_team = ask_sign_up_team(session, 'iris_test', 'xx') with login_scope(client, 'test_iris_admin', 'test') as client: # GET check that we get all new user to be approved rv = client.get('/approve_users') assert rv.status_code == 200 # line for user approval assert b'yy: yy yy - yy' in rv.data # line for the event approval assert b'iris_test - xx' # POST check that we are able to approve a user and event data = ImmutableMultiDict([('submit_button', 'Remove!'), ('approve_users', 'yy'), ('approve_event_teams', str(event_team.id)) ]) rv = client.post('/approve_users', data=data) assert rv.status_code == 302 assert rv.location == 'http://localhost/problems' # ensure that the previous change have been committed within our # session session.commit() user = get_user_by_name(session, 'yy') assert user is None event_team = get_event_team_by_name(session, 'iris_test', 'xx') assert event_team is None with client.session_transaction() as cs: flash_message = dict(cs['_flashes']) print(flash_message) assert re.match( r"Removed users:\nyy\nRemoved event_team:\n" r"Event\(iris_test\)/Team\(.*xx.*\)\n", flash_message['Removed users'])
def problems(): """Landing page showing all the RAMP problems.""" user = (flask_login.current_user if flask_login.current_user.is_authenticated else None) admin = user.access_level == 'admin' if user is not None else False if app.config['TRACK_USER_INTERACTION']: add_user_interaction( db.session, interaction='looking at problems', user=user ) problems = get_problem(db.session, None) for problem in problems: for event in problem.events: # check the state of the event now = datetime.datetime.now() start = event.opening_timestamp start_collab = event.public_opening_timestamp end = event.closing_timestamp if now < start or now >= end: event.state = 'close' elif now >= start and now < start_collab: event.state = 'competitive' elif now >= start and now >= start_collab and now < end: event.state = 'collab' if user: signed = get_event_team_by_name( db.session, event.name, flask_login.current_user.name) if not signed: event.state_user = '******' elif signed.approved: event.state_user = '******' elif signed: event.state_user = '******' else: event.state_user = '******' # problems = Problem.query.order_by(Problem.id.desc()) return render_template('problems.html', problems=problems, admin=admin)
def test_update_leaderboard_functions(session_toy_function): event_name = 'iris_test' user_name = 'test_user' for leaderboard_type in ['public', 'private', 'failed', 'public competition', 'private competition']: leaderboard = get_leaderboard(session_toy_function, leaderboard_type, event_name) assert leaderboard is None leaderboard = get_leaderboard(session_toy_function, 'new', event_name) assert leaderboard event = get_event(session_toy_function, event_name) assert event.private_leaderboard_html is None assert event.public_leaderboard_html_with_links is None assert event.public_leaderboard_html_no_links is None assert event.failed_leaderboard_html is None assert event.public_competition_leaderboard_html is None assert event.private_competition_leaderboard_html is None assert event.new_leaderboard_html event_team = get_event_team_by_name(session_toy_function, event_name, user_name) assert event_team.leaderboard_html is None assert event_team.failed_leaderboard_html is None assert event_team.new_leaderboard_html event_teams = (session_toy_function.query(EventTeam) .filter_by(event=event) .all()) for et in event_teams: assert et.leaderboard_html is None assert et.failed_leaderboard_html is None assert et.new_leaderboard_html # run the dispatcher to process the different submissions config = read_config(database_config_template()) event_config = read_config(ramp_config_template()) dispatcher = Dispatcher( config, event_config, n_workers=-1, hunger_policy='exit' ) dispatcher.launch() session_toy_function.commit() update_leaderboards(session_toy_function, event_name) event = get_event(session_toy_function, event_name) assert event.private_leaderboard_html assert event.public_leaderboard_html_with_links assert event.public_leaderboard_html_no_links assert event.failed_leaderboard_html assert event.public_competition_leaderboard_html assert event.private_competition_leaderboard_html assert event.new_leaderboard_html is None update_user_leaderboards(session_toy_function, event_name, user_name) event_team = get_event_team_by_name(session_toy_function, event_name, user_name) assert event_team.leaderboard_html assert event_team.failed_leaderboard_html assert event_team.new_leaderboard_html is None update_all_user_leaderboards(session_toy_function, event_name) event_teams = (session_toy_function.query(EventTeam) .filter_by(event=event) .all()) for et in event_teams: assert et.leaderboard_html assert et.failed_leaderboard_html assert et.new_leaderboard_html is None
def sandbox(event_name): """Landing page for the user's sandbox. Parameters ---------- event_name : str The event name. """ event = get_event(db.session, event_name) if not is_accessible_event(db.session, event_name, flask_login.current_user.name): return redirect_to_user(u'{}: no event named "{}"'.format( flask_login.current_user.firstname, event_name)) if not is_accessible_code(db.session, event_name, flask_login.current_user.name): error_str = ('No access to sandbox for event {}. If you have ' 'already signed up, please wait for approval.'.format( event.name)) return redirect_to_user(error_str) # setup the webpage when loading # we use the code store in the sandbox to show to the user sandbox_submission = get_submission_by_name(db.session, event_name, flask_login.current_user.name, event.ramp_sandbox_name) event_team = get_event_team_by_name(db.session, event_name, flask_login.current_user.name) # initialize the form for the code # The amount of python magic we have to do for rendering a variable # number of textareas, named and populated at run time, is mind # boggling. # First we need to make sure CodeForm is empty # for name_code in CodeForm.names_codes: # name, _ = name_code # delattr(CodeForm, name) CodeForm.names_codes = [] # Then we create named fields in the CodeForm class for each editable # submission file. They have to be populated when the code_form object # is created, so we also create a code_form_kwargs dictionary and # populate it with the codes. code_form_kwargs = {} for submission_file in sandbox_submission.files: if submission_file.is_editable: f_field = submission_file.name setattr(CodeForm, f_field, StringField(u'Text', widget=TextArea())) code_form_kwargs[f_field] = submission_file.get_code() code_form_kwargs['prefix'] = 'code' code_form = CodeForm(**code_form_kwargs) # Then, to be able to iterate over the files in the sandbox.html # template, we also fill a separate table of pairs (file name, code). # The text areas in the template will then have to be created manually. for submission_file in sandbox_submission.files: if submission_file.is_editable: code_form.names_codes.append( (submission_file.name, submission_file.get_code())) # initialize the submission field and the the uploading form submit_form = SubmitForm(submission_name=event_team.last_submission_name, prefix='submit') upload_form = UploadForm(prefix='upload') admin = is_admin(db.session, event_name, flask_login.current_user.name) if request.method == 'GET': return render_template('sandbox.html', submission_names=sandbox_submission.f_names, code_form=code_form, submit_form=submit_form, upload_form=upload_form, event=event, admin=admin) if request.method == 'POST': if ('code-csrf_token' in request.form and code_form.validate_on_submit()): try: for submission_file in sandbox_submission.files: if submission_file.is_editable: old_code = submission_file.get_code() submission_file.set_code( request.form[submission_file.name]) new_code = submission_file.get_code() diff = '\n'.join( difflib.unified_diff(old_code.splitlines(), new_code.splitlines())) similarity = difflib.SequenceMatcher( a=old_code, b=new_code).ratio() if app.config['TRACK_USER_INTERACTION']: add_user_interaction( db.session, interaction='save', user=flask_login.current_user, event=event, submission_file=submission_file, diff=diff, similarity=similarity) except Exception as e: return redirect_to_sandbox(event, u'Error: {}'.format(e)) return redirect_to_sandbox( event, 'You submission has been saved. You can safely comeback to ' 'your sandbox later.', is_error=False, category='File saved') elif request.files: upload_f_name = secure_filename(request.files['file'].filename) upload_name = upload_f_name.split('.')[0] # TODO: create a get_function upload_workflow_element = WorkflowElement.query.filter_by( name=upload_name, workflow=event.workflow).one_or_none() if upload_workflow_element is None: return redirect_to_sandbox( event, u'{} is not in the file list.'.format(upload_f_name)) # TODO: create a get_function submission_file = SubmissionFile.query.filter_by( submission=sandbox_submission, workflow_element=upload_workflow_element).one() if submission_file.is_editable: old_code = submission_file.get_code() tmp_f_name = os.path.join(tempfile.gettempdir(), upload_f_name) request.files['file'].save(tmp_f_name) file_length = os.stat(tmp_f_name).st_size if (upload_workflow_element.max_size is not None and file_length > upload_workflow_element.max_size): return redirect_to_sandbox( event, u'File is too big: {} exceeds max size {}'.format( file_length, upload_workflow_element.max_size)) if submission_file.is_editable: try: with open(tmp_f_name) as f: code = f.read() submission_file.set_code(code) except Exception as e: return redirect_to_sandbox(event, u'Error: {}'.format(e)) else: # non-editable files are not verified for now dst = os.path.join(sandbox_submission.path, upload_f_name) shutil.copy2(tmp_f_name, dst) logger.info(u'{} uploaded {} in {}'.format( flask_login.current_user.name, upload_f_name, event)) if submission_file.is_editable: new_code = submission_file.get_code() diff = '\n'.join( difflib.unified_diff(old_code.splitlines(), new_code.splitlines())) similarity = difflib.SequenceMatcher(a=old_code, b=new_code).ratio() if app.config['TRACK_USER_INTERACTION']: add_user_interaction(db.session, interaction='upload', user=flask_login.current_user, event=event, submission_file=submission_file, diff=diff, similarity=similarity) else: if app.config['TRACK_USER_INTERACTION']: add_user_interaction(db.session, interaction='upload', user=flask_login.current_user, event=event, submission_file=submission_file) return redirect(request.referrer) # TODO: handle different extensions for the same workflow element # ie: now we let upload eg external_data.bla, and only fail at # submission, without giving a message elif ('submit-csrf_token' in request.form and submit_form.validate_on_submit()): new_submission_name = request.form['submit-submission_name'] if not 4 < len(new_submission_name) < 20: return redirect_to_sandbox( event, 'Submission name should have length between 4 and ' '20 characters.') try: new_submission_name.encode('ascii') except Exception as e: return redirect_to_sandbox(event, u'Error: {}'.format(e)) try: new_submission = add_submission(db.session, event_name, event_team.team.name, new_submission_name, sandbox_submission.path) except DuplicateSubmissionError: return redirect_to_sandbox( event, u'Submission {} already exists. Please change the name.'. format(new_submission_name)) except MissingExtensionError as e: return redirect_to_sandbox(event, 'Missing extension') except TooEarlySubmissionError as e: return redirect_to_sandbox(event, str(e)) logger.info(u'{} submitted {} for {}.'.format( flask_login.current_user.name, new_submission.name, event_team)) if event.is_send_submitted_mails: admin_users = User.query.filter_by(access_level='admin') for admin in admin_users: subject = 'Submission {} sent for training'.format( new_submission.name) body = """A new submission have been submitted: event: {} user: {} submission: {} submission path: {} """.format(event_team.event.name, flask_login.current_user.name, new_submission.name, new_submission.path) send_mail(admin, subject, body) if app.config['TRACK_USER_INTERACTION']: add_user_interaction(db.session, interaction='submit', user=flask_login.current_user, event=event, submission=new_submission) return redirect_to_sandbox(event, u'{} submitted {} for {}'.format( flask_login.current_user.firstname, new_submission.name, event_team), is_error=False, category='Submission') admin = is_admin(db.session, event_name, flask_login.current_user.name) return render_template('sandbox.html', submission_names=sandbox_submission.f_names, code_form=code_form, submit_form=submit_form, upload_form=upload_form, event=event, admin=admin)