Exemplo n.º 1
0
def private_leaderboard(event_name):
    """Landing page for the private leaderboard.

    Parameters
    ----------
    event_name : str
        The event name.
    """
    if not flask_login.current_user.is_authenticated:
        return redirect(url_for('auth.login'))
    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 (not is_admin(db.session, event_name, flask_login.current_user.name) and
            (event.closing_timestamp is None or
             event.closing_timestamp > datetime.datetime.utcnow())):
        return redirect(url_for('ramp.problems'))

    if app.config['TRACK_USER_INTERACTION']:
        add_user_interaction(
            db.session,
            interaction='looking at private leaderboard',
            user=flask_login.current_user,
            event=event
        )
    leaderboard_html = event.private_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'

    approved = is_user_signed_up(
        db.session, event_name, flask_login.current_user.name
    )
    asked = approved
    template = render_template(
        'leaderboard.html',
        leaderboard_title='Leaderboard',
        leaderboard=leaderboard_html,
        sorting_column_index=5,
        sorting_direction=sorting_direction,
        event=event,
        private=True,
        admin=admin,
        asked=asked,
        approved=approved
    )

    return template
Exemplo n.º 2
0
def test_check_admin(session_toy_db):
    event_name = 'iris_test'
    user_name = 'test_iris_admin'
    assert is_admin(session_toy_db, event_name, user_name)
    user_name = 'test_user'
    assert not is_admin(session_toy_db, event_name, user_name)
    add_event_admin(session_toy_db, event_name, user_name)
    assert is_admin(session_toy_db, event_name, user_name)
    event_admin = get_event_admin(session_toy_db, event_name, user_name)
    assert event_admin.event.name == event_name
    assert event_admin.admin.name == user_name
    user_name = 'test_user_2'
    assert get_event_admin(session_toy_db, event_name, user_name) is None
Exemplo n.º 3
0
def competition_leaderboard(event_name):
    """Landing page for the competition leaderboard for all users.

    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))
    add_user_interaction(db.session,
                         interaction='looking at leaderboard',
                         user=flask_login.current_user,
                         event=event)
    admin = is_admin(db.session, event_name, flask_login.current_user.name)
    leaderboard_html = event.public_competition_leaderboard_html
    leaderboard_kwargs = dict(leaderboard=leaderboard_html,
                              leaderboard_title='Leaderboard',
                              sorting_column_index=0,
                              sorting_direction='asc',
                              event=event,
                              admin=admin)

    return render_template('leaderboard.html', **leaderboard_kwargs)
Exemplo n.º 4
0
def approve_sign_up_for_event(event_name, user_name):
    """Approve a user for a specific event.

    This way of approval is usually used by clicking in an email sent to the
    admin.

    Parameters
    ----------
    event_name : str
        The name of the event.
    user_name : str
        The name of the user.
    """
    event = get_event(db.session, event_name)
    user = User.query.filter_by(name=user_name).one_or_none()
    if not is_admin(db.session, event_name, flask_login.current_user.name):
        return redirect_to_user(
            u'Sorry {}, you do not have admin rights'.format(
                flask_login.current_user.firstname),
            is_error=True)
    if not event or not user:
        return redirect_to_user(u'No event {} or no user {}'.format(
            event_name, user_name),
                                is_error=True)
    sign_up_team(db.session, event.name, user.name)

    subject = ('Signed up for the RAMP event {}'.format(event.name))
    body = ('{}, you have been registered to the RAMP event {}. '
            'You can now proceed to your sandbox and make submission.'
            '\nHave fun!!!'.format(flask_login.current_user.name, event.name))
    send_mail(to=flask_login.current_user.email, subject=subject, body=body)

    return redirect_to_user(u'{} is signed up for {}.'.format(user, event),
                            is_error=False,
                            category='Successful sign-up')
Exemplo n.º 5
0
def user_event(event_name):
    """Landing page for a given event.

    Parameters
    ----------
    event_name : str
        The event name.
    """
    if flask_login.current_user.access_level == 'asked':
        msg = 'Your account has not been approved yet by the administrator'
        logger.error(msg)
        return redirect_to_user(msg)
    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))
    event = get_event(db.session, event_name)
    if event:
        if app.config['TRACK_USER_INTERACTION']:
            add_user_interaction(db.session,
                                 interaction='looking at event',
                                 event=event,
                                 user=flask_login.current_user)
        admin = is_admin(db.session, event_name, flask_login.current_user.name)
        approved = is_user_signed_up(db.session, event_name,
                                     flask_login.current_user.name)
        asked = is_user_sign_up_requested(db.session, event_name,
                                          flask_login.current_user.name)
        return render_template('event.html',
                               event=event,
                               admin=admin,
                               approved=approved,
                               asked=asked)
    return redirect_to_user('Event {} does not exist.'.format(event_name),
                            is_error=True)
Exemplo n.º 6
0
def dashboard_submissions(event_name):
    """Show information about all submissions for a given event.

    Parameters
    ----------
    event_name : str
        The name of the event.
    """
    if not is_admin(db.session, event_name, flask_login.current_user.name):
        return redirect_to_user(
            'Sorry {}, you do not have admin rights'
            .format(flask_login.current_user.firstname),
            is_error=True
        )
    event = get_event(db.session, event_name)
    # Get dates and number of submissions
    submissions = \
        (Submission.query
                   .filter(Event.name == event.name)
                   .filter(Event.id == EventTeam.event_id)
                   .filter(EventTeam.id == Submission.event_team_id)
                   .order_by(Submission.submission_timestamp)
                   .all())
    submissions = [sub for sub in submissions if sub.is_not_sandbox]
    timestamp_submissions = [
        sub.submission_timestamp.strftime('%Y-%m-%d %H:%M:%S')
        for sub in submissions]
    name_submissions = [sub.name for sub in submissions]
    cumulated_submissions = list(range(1, 1 + len(submissions)))
    training_sec = [
        (
            sub.training_timestamp - sub.submission_timestamp
        ).total_seconds() / 60.
        if sub.training_timestamp is not None else 0
        for sub in submissions
    ]
    dashboard_kwargs = {'event': event,
                        'timestamp_submissions': timestamp_submissions,
                        'training_sec': training_sec,
                        'cumulated_submissions': cumulated_submissions,
                        'name_submissions': name_submissions}
    failed_leaderboard_html = event.failed_leaderboard_html
    new_leaderboard_html = event.new_leaderboard_html
    approved = is_user_signed_up(
        db.session, event_name, flask_login.current_user.name
    )
    asked = is_user_sign_up_requested(
        db.session, event_name, flask_login.current_user.name
    )
    return render_template(
        'dashboard_submissions.html',
        failed_leaderboard=failed_leaderboard_html,
        new_leaderboard=new_leaderboard_html,
        admin=True,
        approved=approved,
        asked=asked,
        **dashboard_kwargs)
Exemplo n.º 7
0
def leaderboard(event_name):
    """Landing page showing all user's submissions 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 leaderboard',
            user=flask_login.current_user,
            event=event
        )

    if is_accessible_leaderboard(db.session, event_name,
                                 flask_login.current_user.name):
        leaderboard_html = event.public_leaderboard_html_with_links
    else:
        leaderboard_html = event.public_leaderboard_html_no_links
    if event.official_score_type.is_lower_the_better:
        sorting_direction = 'asc'
    else:
        sorting_direction = 'desc'

    leaderboard_kwargs = dict(
        leaderboard=leaderboard_html,
        leaderboard_title='Leaderboard',
        sorting_column_index=4,
        sorting_direction=sorting_direction,
        event=event
    )

    if is_admin(db.session, event_name, flask_login.current_user.name):
        failed_leaderboard_html = event.failed_leaderboard_html
        new_leaderboard_html = event.new_leaderboard_html
        template = render_template(
            'leaderboard.html',
            failed_leaderboard=failed_leaderboard_html,
            new_leaderboard=new_leaderboard_html,
            admin=True,
            **leaderboard_kwargs
        )
    else:
        template = render_template(
            'leaderboard.html', **leaderboard_kwargs
        )

    return template
Exemplo n.º 8
0
def private_competition_leaderboard(event_name):
    """Landing page for the private competition leaderboard.

    Parameters
    ----------
    event_name : str
        The event name.
    """
    if not flask_login.current_user.is_authenticated:
        return redirect(url_for('auth.login'))
    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_admin(db.session, event_name, flask_login.current_user.name)
            and (event.closing_timestamp is None
                 or event.closing_timestamp > datetime.datetime.utcnow())):
        return redirect(url_for('ramp.problems'))

    if app.config['TRACK_USER_INTERACTION']:
        add_user_interaction(db.session,
                             interaction='looking at private leaderboard',
                             user=flask_login.current_user,
                             event=event)

    admin = is_admin(db.session, event_name, flask_login.current_user.name)
    approved = is_user_signed_up(db.session, event_name,
                                 flask_login.current_user.name)
    asked = approved
    leaderboard_html = event.private_competition_leaderboard_html

    leaderboard_kwargs = dict(leaderboard=leaderboard_html,
                              leaderboard_title='Leaderboard',
                              sorting_column_index=0,
                              sorting_direction='asc',
                              event=event,
                              admin=admin,
                              asked=asked,
                              approved=approved)

    return render_template('leaderboard.html', **leaderboard_kwargs)
Exemplo n.º 9
0
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)
Exemplo n.º 10
0
def user_event(event_name):
    """Landing page for a given event.

    Parameters
    ----------
    event_name : str
        The event name.
    """
    if flask_login.current_user.access_level == 'asked':
        msg = 'Your account has not been approved yet by the administrator'
        logger.error(msg)
        return redirect_to_user(msg)
    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))
    event = get_event(db.session, event_name)
    if event:
        if app.config['TRACK_USER_INTERACTION']:
            add_user_interaction(db.session, interaction='looking at event',
                                 event=event, user=flask_login.current_user)
        description_f_name = os.path.join(
            event.problem.path_ramp_kit,
            '{}_starting_kit.html'.format(event.problem.name)
        )
        with codecs.open(description_f_name, 'r', 'utf-8') as description_file:
            description = description_file.read()
        admin = is_admin(db.session, event_name, flask_login.current_user.name)
        approved = is_user_signed_up(
            db.session, event_name, flask_login.current_user.name
        )
        asked = approved
        return render_template('event.html',
                               description=description,
                               event=event,
                               admin=admin,
                               approved=approved,
                               asked=asked)
    return redirect_to_user('Event {} does not exist.'
                            .format(event_name), is_error=True)
Exemplo n.º 11
0
def update_event(event_name):
    """Update the parameters of an event.

    Parameters
    ----------
    event_name : str
        The name of the event.
    """
    if not is_admin(db.session, event_name, flask_login.current_user.name):
        return redirect_to_user(
            'Sorry {}, you do not have admin rights'
            .format(flask_login.current_user.firstname),
            is_error=True
        )
    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)
        )
    logger.info('{} is updating event {}'
                .format(flask_login.current_user.name, event.name))
    admin = is_admin(db.session, event_name, flask_login.current_user.name)
    # We assume here that event name has the syntax <problem_name>_<suffix>
    suffix = event.name[len(event.problem.name) + 1:]

    h = event.min_duration_between_submissions // 3600
    m = event.min_duration_between_submissions // 60 % 60
    s = event.min_duration_between_submissions % 60
    form = EventUpdateProfileForm(
        suffix=suffix, title=event.title,
        is_send_trained_mails=event.is_send_trained_mails,
        is_send_submitted_mails=event.is_send_submitted_mails,
        is_public=event.is_public,
        is_controled_signup=event.is_controled_signup,
        is_competitive=event.is_competitive,
        min_duration_between_submissions_hour=h,
        min_duration_between_submissions_minute=m,
        min_duration_between_submissions_second=s,
        opening_timestamp=event.opening_timestamp,
        closing_timestamp=event.closing_timestamp,
        public_opening_timestamp=event.public_opening_timestamp,
    )
    if form.validate_on_submit():
        try:
            if form.suffix.data == '':
                event.name = event.problem.name
            else:
                event.name = event.problem.name + '_' + form.suffix.data
            event.title = form.title.data
            event.is_send_trained_mails = form.is_send_trained_mails.data
            event.is_send_submitted_mails = form.is_send_submitted_mails.data
            event.is_public = form.is_public.data
            event.is_controled_signup = form.is_controled_signup.data
            event.is_competitive = form.is_competitive.data
            event.min_duration_between_submissions = (
                form.min_duration_between_submissions_hour.data * 3600 +
                form.min_duration_between_submissions_minute.data * 60 +
                form.min_duration_between_submissions_second.data)
            event.opening_timestamp = form.opening_timestamp.data
            event.closing_timestamp = form.closing_timestamp.data
            event.public_opening_timestamp = form.public_opening_timestamp.data
            db.session.commit()

        except IntegrityError as e:
            db.session.rollback()
            message = ''
            existing_event = get_event(db.session, event.name)
            if existing_event is not None:
                message += 'event name is already in use'
            # # try:
            # #     User.query.filter_by(email=email).one()
            # #     if len(message) > 0:
            # #         message += ' and '
            # #     message += 'email is already in use'
            # except NoResultFound:
            #     pass
            if message:
                e = NameClashError(message)
            flash('{}'.format(e), category='Update event error')
            return redirect(url_for('update_event', event_name=event.name))

        return redirect(url_for('ramp.problems'))

    approved = is_user_signed_up(
        db.session, event_name, flask_login.current_user.name
    )
    asked = approved
    return render_template(
        'update_event.html',
        form=form,
        event=event,
        admin=admin,
        asked=asked,
        approved=approved
    )
Exemplo n.º 12
0
def view_model(submission_hash, f_name):
    """Rendering submission codes using templates/submission.html.

    The code of f_name is displayed in the left panel, the list of submissions
    files is in the right panel. Clicking on a file will show that file (using
    the same template). Clicking on the name on the top will download the file
    itself (managed in the template). Clicking on "Archive" will zip all the
    submission files and download them (managed here).

    Parameters
    ----------
    submission_hash : str
        The hash_ of the submission.
    f_name : tr
        The name of the submission file.
    """
    submission = (Submission.query.filter_by(
        hash_=submission_hash).one_or_none())
    if (submission is None or not is_accessible_code(
            db.session, submission.event.name, flask_login.current_user.name,
            submission.name)):
        error_str = u'Missing submission: {}'.format(submission_hash)
        return redirect_to_user(error_str)
    event = submission.event_team.event
    team = submission.event_team.team
    workflow_element_name = f_name.split('.')[0]
    workflow_element = \
        (WorkflowElement.query.filter_by(name=workflow_element_name,
                                         workflow=event.workflow)
                              .one_or_none())
    if workflow_element is None:
        error_str = (u'{} is not a valid workflow element by {} '.format(
            workflow_element_name, flask_login.current_user.name))
        error_str += u'in {}/{}/{}/{}'.format(event, team, submission, f_name)
        return redirect_to_user(error_str)
    submission_file = \
        (SubmissionFile.query.filter_by(submission=submission,
                                        workflow_element=workflow_element)
                             .one_or_none())
    if submission_file is None:
        error_str = (u'No submission file by {} in {}/{}/{}/{}'.format(
            flask_login.current_user.name, event, team, submission, f_name))
        return redirect_to_user(error_str)

    # superfluous, perhaps when we'll have different extensions?
    f_name = submission_file.f_name

    submission_abspath = os.path.abspath(submission.path)
    if not os.path.exists(submission_abspath):
        error_str = (u'{} does not exist by {} in {}/{}/{}/{}'.format(
            submission_abspath, flask_login.current_user.name, event, team,
            submission, f_name))
        return redirect_to_user(error_str)

    if app.config['TRACK_USER_INTERACTION']:
        add_user_interaction(db.session,
                             interaction='looking at submission',
                             user=flask_login.current_user,
                             event=event,
                             submission=submission,
                             submission_file=submission_file)

    logger.info(u'{} is looking at {}/{}/{}/{}'.format(
        flask_login.current_user.name, event, team, submission, f_name))

    # Downloading file if it is not editable (e.g., external_data.csv)
    if not workflow_element.is_editable:
        # archive_filename = f_name  + '.zip'
        # with changedir(submission_abspath):
        #    with ZipFile(archive_filename, 'w') as archive:
        #        archive.write(f_name)
        if app.config['TRACK_USER_INTERACTION']:
            add_user_interaction(db.session,
                                 interaction='download',
                                 user=flask_login.current_user,
                                 event=event,
                                 submission=submission,
                                 submission_file=submission_file)

        return send_from_directory(submission_abspath,
                                   f_name,
                                   as_attachment=True,
                                   attachment_filename=u'{}_{}'.format(
                                       submission.hash_[:6], f_name),
                                   mimetype='application/octet-stream')

    # Importing selected files into sandbox
    choices = [(f, f) for f in submission.f_names]
    import_form = ImportForm()
    import_form.selected_f_names.choices = choices
    if import_form.validate_on_submit():
        sandbox_submission = get_submission_by_name(
            db.session, event.name, flask_login.current_user.name,
            event.ramp_sandbox_name)
        for filename in import_form.selected_f_names.data:
            logger.info(u'{} is importing {}/{}/{}/{}'.format(
                flask_login.current_user.name, event, team, submission,
                filename))

            # TODO: deal with different extensions of the same file
            src = os.path.join(submission.path, filename)
            dst = os.path.join(sandbox_submission.path, filename)
            shutil.copy2(src, dst)  # copying also metadata
            logger.info(u'Copying {} to {}'.format(src, dst))

            workflow_element = WorkflowElement.query.filter_by(
                name=filename.split('.')[0], workflow=event.workflow).one()
            submission_file = SubmissionFile.query.filter_by(
                submission=submission,
                workflow_element=workflow_element).one()
            if app.config['TRACK_USER_INTERACTION']:
                add_user_interaction(db.session,
                                     interaction='copy',
                                     user=flask_login.current_user,
                                     event=event,
                                     submission=submission,
                                     submission_file=submission_file)

        return redirect(u'/events/{}/sandbox'.format(event.name))

    with open(os.path.join(submission.path, f_name)) as f:
        code = f.read()
    admin = is_admin(db.session, event.name, flask_login.current_user.name)
    return render_template('submission.html',
                           event=event,
                           code=code,
                           submission=submission,
                           f_name=f_name,
                           import_form=import_form,
                           admin=admin)
Exemplo n.º 13
0
def credit(submission_hash):
    """The landing page to credit other submission when a user submit is own.

    Parameters
    ----------
    submission_hash : str
        The submission hash of the current submission.
    """
    submission = (Submission.query.filter_by(
        hash_=submission_hash).one_or_none())
    access_code = is_accessible_code(db.session,
                                     submission.event_team.event.name,
                                     flask_login.current_user.name,
                                     submission.name)
    if submission is None or not access_code:
        error_str = u'Missing submission: {}'.format(submission_hash)
        return redirect_to_user(error_str)
    event_team = submission.event_team
    event = event_team.event
    source_submissions = get_source_submissions(db.session, submission.id)

    def get_s_field(source_submission):
        return u'{}/{}/{}'.format(source_submission.event_team.event.name,
                                  source_submission.event_team.team.name,
                                  source_submission.name)

    # Make sure that CreditForm is empty
    CreditForm.name_credits = []
    credit_form_kwargs = {}
    for source_submission in source_submissions:
        s_field = get_s_field(source_submission)
        setattr(CreditForm, s_field, StringField(u'Text'))
    credit_form = CreditForm(**credit_form_kwargs)
    sum_credit = 0
    # new = True
    for source_submission in source_submissions:
        s_field = get_s_field(source_submission)
        submission_similaritys = \
            (SubmissionSimilarity.query
                                 .filter_by(
                                     type='target_credit',
                                     user=flask_login.current_user,
                                     source_submission=source_submission,
                                     target_submission=submission)
                                 .all())
        if not submission_similaritys:
            submission_credit = 0
        else:
            # new = False
            # find the last credit (in case crediter changes her mind)
            submission_similaritys.sort(key=lambda x: x.timestamp,
                                        reverse=True)
            submission_credit = int(
                round(100 * submission_similaritys[0].similarity))
            sum_credit += submission_credit
        credit_form.name_credits.append(
            (s_field, str(submission_credit), source_submission.link))
    # This doesnt work, not sure why
    # if not new:
    #    credit_form.self_credit.data = str(100 - sum_credit)
    if credit_form.validate_on_submit():
        try:
            sum_credit = int(credit_form.self_credit.data)
            logger.info(sum_credit)
            for source_submission in source_submissions:
                s_field = get_s_field(source_submission)
                sum_credit += int(getattr(credit_form, s_field).data)
            if sum_credit != 100:
                return redirect_to_credit(
                    submission_hash,
                    'Error: The total credit should add up to 100')
        except Exception as e:
            return redirect_to_credit(submission_hash, u'Error: {}'.format(e))
        for source_submission in source_submissions:
            s_field = get_s_field(source_submission)
            similarity = int(getattr(credit_form, s_field).data) / 100.
            submission_similarity = \
                (SubmissionSimilarity.query
                                     .filter_by(
                                         type='target_credit',
                                         user=flask_login.current_user,
                                         source_submission=source_submission,
                                         target_submission=submission)
                                     .all())
            # if submission_similarity is not empty, we need to
            # add zero to cancel previous credits explicitly
            if similarity > 0 or submission_similarity:
                add_submission_similarity(db.session,
                                          credit_type='target_credit',
                                          user=flask_login.current_user,
                                          source_submission=source_submission,
                                          target_submission=submission,
                                          similarity=similarity,
                                          timestamp=datetime.datetime.utcnow())

        if app.config['TRACK_USER_INTERACTION']:
            add_user_interaction(db.session,
                                 interaction='giving credit',
                                 user=flask_login.current_user,
                                 event=event,
                                 submission=submission)

        return redirect(u'/events/{}/sandbox'.format(event.name))

    admin = is_admin(db.session, event.name, flask_login.current_user.name)
    return render_template('credit.html',
                           submission=submission,
                           source_submissions=source_submissions,
                           credit_form=credit_form,
                           event=event,
                           admin=admin)
Exemplo n.º 14
0
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)