コード例 #1
0
def create_team_action(request):
    """ Create a team for the context's user.
        An administrator can also perform the action on a user's behalf.
    """
    # Create the team.
    now = datetime.utcnow()
    user_id = request.context.user_id
    user = load_user(request.db, user_id)
    # Select a round based on the user's badges.
    round_ids = find_round_ids_with_badges(request.db, user['badges'], now)
    if len(round_ids) == 0:
        # The user does not have access to any open round.
        raise ApiError('not qualified for any open round')
    if len(round_ids) > 1:
        # XXX The case where a user has badges for multiple open rounds
        # is currently handled by picking the first one, which is the
        # one that has the greatest id.  This is unsatisfactory.
        pass
    round_id = round_ids[0]
    round_ = load_round(request.db, round_id, now)
    if not round_['is_registration_open']:
        raise ApiError('registration is closed')
    # Create the team.
    team_id = create_user_team(request.db, user_id, now)
    # Create a participation.
    create_participation(request.db, team_id, round_id, now=now)
    # Ensure the user gets team credentials.
    reset_user_principals(request)
    return {'success': True}
コード例 #2
0
def add_badge_action(request):
    data = request.json_body
    user_id = request.context.user_id
    user = load_user(request.db, user_id)
    foreign_id = user['foreign_id']
    access_token = get_oauth2_token(request, refresh=True)
    params = {
        'badgeUrl': app['requested_badge'],
        'idUser': foreign_id,
        'qualCode': data.get('code')
    }
    headers = {
        'Accept': 'application/json',
        'Authorization': 'Bearer {}'.format(access_token)
    }
    req = requests.post(app['add_badge_uri'],
                        headers=headers,
                        data=params,
                        verify='/etc/ssl/certs/ca-certificates.crt')
    req.raise_for_status()
    result = req.json()
    print("\033[91mresult\033[0m {}".format(result))
    success = result.get('success')
    if not success:
        return {
            'success': False,
            'profileUpdated': False,
            'error': result.get('error', 'undefined')
        }
    profileUpdated = False
    profile = get_user_profile(request, foreign_id)
    if profile is not None:
        update_user(request.db, user['id'], profile)
        profileUpdated = True
    return {'success': True, 'profileUpdated': profileUpdated}
コード例 #3
0
def leave_team(db, user_id, team_id, now):
    """ Remove a user from their team.
    """
    user = load_user(db, user_id, for_update=True)
    team_id = user['team_id']
    # The user must be member of a team.
    if team_id is None:
        raise ModelError('no team')
    team = load_team(db, team_id)
    # Load the participation.
    participation_id = get_team_latest_participation_id(db, team_id)
    participation = load_participation(db, participation_id)
    round_id = participation['round_id']
    round_ = load_round(db, round_id)
    # If the team already has an attempt (is_locked=True), verify
    # that the team remains valid if the user is removed.
    if team['is_locked']:
        if round_['allow_team_changes']:
            validate_team(db, team_id, round_id, without_member=user, now=now)
        else:
            raise ModelError('team is locked')
    # Clear the user's team_id.
    set_user_team_id(db, user_id, None)
    # Delete the team_members row.
    team_members = db.tables.team_members
    tm_query = db.query(team_members) \
        .where(team_members.team_id == team_id) \
        .where(team_members.user_id == user_id)
    (is_creator,) = db.first(
        tm_query.fields(team_members.is_creator))
    db.delete(tm_query)
    # If the user was the team creator, select the earliest member
    # as the new creator.
    if is_creator:
        query = db.query(team_members) \
            .where(team_members.team_id == team_id)
        row = db.first(
            query.fields(team_members.user_id)
                 .order_by(team_members.joined_at),
            for_update=True)
        if row is None:
            # Team has become empty, delete it.
            teams = db.tables.teams
            team_query = db.query(teams) \
                .where(teams.id == team_id)
            db.delete(team_query)
        else:
            # Promote the selected user as the creator.
            new_creator_id = row[0]
            db.update(
                query.where(team_members.user_id == new_creator_id),
                {team_members.is_creator: True})
コード例 #4
0
def create_user_team(db, user_id, now):
    # Check that the user does not already belong to a team.
    user = load_user(db, user_id)
    if user['team_id'] is not None:
        # User is already in a team.
        raise ModelError('already in a team')
    # Create an empty team.
    team_id = create_empty_team(db, now)
    # Create the team_members row.
    add_team_member(
        db, team_id, user_id, now=now,
        is_qualified=True, is_creator=True)
    return team_id
コード例 #5
0
def leave_team(db, user_id, team_id, now):
    """ Remove a user from their team.
    """
    user = load_user(db, user_id, for_update=True)
    team_id = user['team_id']
    # The user must be member of a team.
    if team_id is None:
        raise ModelError('no team')
    team = load_team(db, team_id)
    # Load the participation.
    participation_id = get_team_latest_participation_id(db, team_id)
    participation = load_participation(db, participation_id)
    round_id = participation['round_id']
    round_ = load_round(db, round_id)
    # If the team already has an attempt (is_locked=True), verify
    # that the team remains valid if the user is removed.
    if team['is_locked']:
        if round_['allow_team_changes']:
            validate_team(db, team_id, round_id, without_member=user, now=now)
        else:
            raise ModelError('team is locked')
    # Clear the user's team_id.
    set_user_team_id(db, user_id, None)
    # Delete the team_members row.
    team_members = db.tables.team_members
    tm_query = db.query(team_members) \
        .where(team_members.team_id == team_id) \
        .where(team_members.user_id == user_id)
    (is_creator, ) = db.first(tm_query.fields(team_members.is_creator))
    db.delete(tm_query)
    # If the user was the team creator, select the earliest member
    # as the new creator.
    if is_creator:
        query = db.query(team_members) \
            .where(team_members.team_id == team_id)
        row = db.first(query.fields(team_members.user_id).order_by(
            team_members.joined_at),
                       for_update=True)
        if row is None:
            # Team has become empty, delete it.
            teams = db.tables.teams
            team_query = db.query(teams) \
                .where(teams.id == team_id)
            db.delete(team_query)
        else:
            # Promote the selected user as the creator.
            new_creator_id = row[0]
            db.update(query.where(team_members.user_id == new_creator_id),
                      {team_members.is_creator: True})
コード例 #6
0
def create_user_team(db, user_id, now):
    # Check that the user does not already belong to a team.
    user = load_user(db, user_id)
    if user['team_id'] is not None:
        # User is already in a team.
        raise ModelError('already in a team')
    # Create an empty team.
    team_id = create_empty_team(db, now)
    # Create the team_members row.
    add_team_member(db,
                    team_id,
                    user_id,
                    now=now,
                    is_qualified=True,
                    is_creator=True)
    return team_id
コード例 #7
0
def join_team(db, user_id, team_id, now):
    """ Add a user to a team.
        Registration for the team's round must be open.
        Return a boolean indicating if the team member was added.
    """
    # Verify that the user does not already belong to a team.
    user = load_user(db, user_id, for_update=True)
    if user['team_id'] is not None:
        raise ModelError('already in a team')
    # Verify that the team exists.
    team = load_team(db, team_id)
    # Verify that the team is open.
    if not team['is_open']:
        # Team is closed (by its creator).
        raise ModelError('team is closed')
    # Load the participation.
    participation_id = get_team_latest_participation_id(db, team_id)
    participation = load_participation(db, participation_id)
    round_id = participation['round_id']
    # Look up the badges that grant access to the team's round, to
    # figure out whether the user is qualified for that round.
    user_badges = user['badges']
    badges = db.tables.badges
    if len(user_badges) == 0:
        is_qualified = False
    else:
        query = db.query(badges) \
            .where(badges.round_id == round_id) \
            .where(badges.symbol.in_(user_badges)) \
            .where(badges.is_active) \
            .fields(badges.id)
        is_qualified = db.scalar(query) is not None
    # If the team has already accessed a task instance (is_locked=True),
    # verify that the team remains valid if the user is added.
    if team['is_locked']:
        round_ = load_round(round_id)
        if round_['allow_team_changes']:
            user['is_qualified'] = is_qualified
            validate_team(db, team_id, round_id, with_member=user, now=now)
        else:
            raise ModelError('team is locked')
    # Create the team_members row.
    user_id = user['id']
    add_team_member(db, team_id, user_id, now=now, is_qualified=is_qualified)
    # Update the user's team_id.
    set_user_team_id(db, user_id, team_id)
コード例 #8
0
def join_team(db, user_id, team_id, now):
    """ Add a user to a team.
        Registration for the team's round must be open.
        Return a boolean indicating if the team member was added.
    """
    # Verify that the user does not already belong to a team.
    user = load_user(db, user_id, for_update=True)
    if user['team_id'] is not None:
        raise ModelError('already in a team')
    # Verify that the team exists.
    team = load_team(db, team_id)
    # Verify that the team is open.
    if not team['is_open']:
        # Team is closed (by its creator).
        raise ModelError('team is closed')
    # Load the participation.
    participation_id = get_team_latest_participation_id(db, team_id)
    participation = load_participation(db, participation_id)
    round_id = participation['round_id']
    # Look up the badges that grant access to the team's round, to
    # figure out whether the user is qualified for that round.
    user_badges = user['badges']
    badges = db.tables.badges
    if len(user_badges) == 0:
        is_qualified = False
    else:
        query = db.query(badges) \
            .where(badges.round_id == round_id) \
            .where(badges.symbol.in_(user_badges)) \
            .where(badges.is_active) \
            .fields(badges.id)
        is_qualified = db.scalar(query) is not None
    # If the team has already accessed a task instance (is_locked=True),
    # verify that the team remains valid if the user is added.
    if team['is_locked']:
        round_ = load_round(round_id)
        if round_['allow_team_changes']:
            user['is_qualified'] = is_qualified
            validate_team(db, team_id, round_id, with_member=user, now=now)
        else:
            raise ModelError('team is locked')
    # Create the team_members row.
    user_id = user['id']
    add_team_member(db, team_id, user_id, now=now, is_qualified=is_qualified)
    # Update the user's team_id.
    set_user_team_id(db, user_id, team_id)
コード例 #9
0
def update_team_action(request):
    user_id = request.context.user_id
    user = load_user(request.db, user_id)
    team_id = user['team_id']
    if team_id is None:
        raise ApiError('no team')
    # If the user is not an admin, they must be the team's creator.
    if request.by_admin:
        if user_id != get_team_creator(request.db, team_id):
            raise ApiError('not team creator')
        # The creator can only change some settings.
        allowed_keys = ['is_open']
        body = request.json_body
        settings = {key: body[key] for key in allowed_keys}
    else:
        # Admins can change all settings.
        settings = request.json_body
    update_team(request.db, team_id, settings)
    return {'success': True}
コード例 #10
0
ファイル: views.py プロジェクト: France-ioi/alkindi-backend
def view_requesting_user(
        db, user_id=None, participation_id=None, attempt_id=None,
        is_admin=False):

    now = datetime.utcnow()
    view = {
        'now': now,
        'is_admin': is_admin
    }
    if user_id is None:
        return view

    #
    # Add the user.
    #
    user = load_user(db, user_id)
    if user is None:
        return view
    view['user_id'] = user_id
    view['user'] = view_user(user)
    team_id = user['team_id']

    #
    # Quick return path when the user has no team.
    #
    if team_id is None:
        # If the user has no team, we look for a round to which a
        # badge grants access.
        badges = user['badges']
        round_ids = find_round_ids_with_badges(db, badges, now)
        if len(round_ids) > 0:
            # TODO: resolve this somehow, for example by returning
            # the round views to the user and letting them choose.
            # For now, pick the first one (which has the greatest id).
            round_id = round_ids[0]
            round_ = load_round(db, round_id, now)
            view['round'] = view_round(round_)
        return view

    #
    # Add the team and team members.
    #
    team = load_team(db, team_id)
    members = load_team_members(db, team['id'], users=True)
    team_view = view['team'] = view_team(team, members)

    #
    # Add the team's participations.
    #
    participations = load_team_participations(db, team_id)
    round_ids = set()
    for participation in participations:
        round_ids.add(participation['round_id'])
    rounds = load_rounds(db, round_ids, now)
    view['participations'] = [
        view_team_participation(
            participation,
            rounds[participation['round_id']])
        for participation in participations
    ]
    if len(participations) == 0:
        return view

    # Mark the lastest (or selected) participation as current.
    if participation_id is None:
        participation = participations[-1]
    else:
        participation = get_by_id(participations, participation_id)
        if participation is None:
            return view
    view['participation_id'] = participation['id']
    for pview in view['participations']:
        if pview['id'] == participation['id']:
            pview['is_current'] = True

    #
    # Add the current participation's round.
    #
    round_id = participation['round_id']
    round_ = rounds[round_id]
    view['round'] = view_round(round_)

    #
    # Add the tasks for the current round.
    #
    round_tasks = load_round_tasks(db, round_id)
    view['round']['task_ids'] = [str(rt['id']) for rt in round_tasks]
    round_task_views = view['round_tasks'] = {
        str(rt['id']): view_round_task(rt) for rt in round_tasks
    }

    region_id = team['region_id']

    if round_['status'] == 'closed' and team['region_id'] is not None:
        region = load_region(db, region_id)
        national_count = count_teams_in_round(db, round_id)
        big_region_count = count_teams_in_round_big_region(
            db, round_id, region['big_region_code'])
        region_count = count_teams_in_round_region(db, round_id, region_id)
        view['ranking'] = {
            'national': {
                'rank': participation['rank_national'],
                'count': national_count
            },
            'big_region': {
                'name': region['big_region_name'],
                'rank': participation['rank_big_regional'],
                'count': big_region_count
            },
            'region': {
                'name': region['name'],
                'rank': participation['rank_regional'],
                'count': region_count
            }
        }

    # XXX A team's validity should be checked against settings for a
    #     competition rather than a round.
    causes = validate_members_for_round(members, round_)
    team_view['round_access'] = list(causes.keys())
    team_view['is_invalid'] = len(causes) != 0

    # Do not return attempts if the team is invalid.
    if team_view['is_invalid']:
        return view

    # Load the participation attempts.
    attempts = load_participation_attempts(db, participation['id'], now)
    view_task_attempts(attempts, round_task_views)
    print("attempts {} {}".format(attempt_id, attempts))

    # Find the requested attempt.
    current_attempt = get_by_id(attempts, attempt_id)
    if current_attempt is None:
        return view
    view['attempt_id'] = attempt_id

    # Focus on the current attempt.
    current_round_task = round_task_views[str(current_attempt['round_task_id'])]
    current_attempt_view = None
    for attempt_view in current_round_task['attempts']:
        if attempt_id == attempt_view.get('id'):
            current_attempt_view = attempt_view
    view['attempt'] = current_attempt_view
    view['round_task'] = current_round_task  # XXX duplicates attempts :(

    if False:  # Access codes are disabled
        members_view = view['team']['members']
        access_codes = load_unlocked_access_codes(db, attempt_id)
        add_members_access_codes(members_view, access_codes)
        if current_attempt['is_training']:
            needs_codes = not have_one_code(members_view)
        else:
            needs_codes = not have_code_majority(members_view)
        current_attempt_view['needs_codes'] = needs_codes

    # Add task instance data, if available.
    try:
        # XXX Previously load_task_instance_team_data which did not parse
        #     full_data.
        # /!\ task contains sensitive data
        # XXX If the round is closed, load and pass full_data?
        task_instance = load_user_task_instance(db, attempt_id)
    except ModelError:
        return view

    # If the round has a time limit, return the countdown.
    if round_['duration'] is not None:
        started_at = participation['started_at']
        if started_at is not None:
            duration = timedelta(minutes=round_['duration'])
            countdown = started_at + duration
            view['countdown'] = started_at + duration
            if countdown < now:
                return view

    view['team_data'] = task_instance['team_data']

    # Add a list of the workspace revisions for this attempt.
    add_revisions(db, view, attempt_id)

    # Give the user the id of their latest revision for the
    # current attempt, to be loaded into the crypto tab on
    # first access.
    revision_id = load_user_latest_revision_id(
        db, user_id, attempt_id)
    view['my_latest_revision_id'] = revision_id

    return view
コード例 #11
0
def view_requesting_user(db,
                         user_id=None,
                         participation_id=None,
                         attempt_id=None,
                         is_admin=False):

    now = datetime.utcnow()
    view = {'now': now, 'is_admin': is_admin}
    if user_id is None:
        return view

    #
    # Add the user.
    #
    user = load_user(db, user_id)
    if user is None:
        return view
    view['user_id'] = user_id
    view['user'] = view_user(user)
    team_id = user['team_id']

    #
    # Quick return path when the user has no team.
    #
    if team_id is None:
        # If the user has no team, we look for a round to which a
        # badge grants access.
        badges = user['badges']
        round_ids = find_round_ids_with_badges(db, badges, now)
        if len(round_ids) > 0:
            # TODO: resolve this somehow, for example by returning
            # the round views to the user and letting them choose.
            # For now, pick the first one (which has the greatest id).
            round_id = round_ids[0]
            round_ = load_round(db, round_id, now)
            view['round'] = view_round(round_)
        return view

    #
    # Add the team and team members.
    #
    team = load_team(db, team_id)
    members = load_team_members(db, team['id'], users=True)
    team_view = view['team'] = view_team(team, members)

    #
    # Add the team's participations.
    #
    participations = load_team_participations(db, team_id)
    round_ids = set()
    for participation in participations:
        round_ids.add(participation['round_id'])
    rounds = load_rounds(db, round_ids, now)
    view['participations'] = [
        view_team_participation(participation,
                                rounds[participation['round_id']])
        for participation in participations
    ]
    if len(participations) == 0:
        return view

    # Mark the lastest (or selected) participation as current.
    if participation_id is None:
        participation = participations[-1]
    else:
        participation = get_by_id(participations, participation_id)
        if participation is None:
            return view
    view['participation_id'] = participation['id']
    for pview in view['participations']:
        if pview['id'] == participation['id']:
            pview['is_current'] = True

    #
    # Add the current participation's round.
    #
    round_id = participation['round_id']
    round_ = rounds[round_id]
    view['round'] = view_round(round_)

    #
    # Add the tasks for the current round.
    #
    round_tasks = load_round_tasks(db, round_id)
    view['round']['task_ids'] = [str(rt['id']) for rt in round_tasks]
    round_task_views = view['round_tasks'] = {
        str(rt['id']): view_round_task(rt)
        for rt in round_tasks
    }

    region_id = team['region_id']

    if round_['status'] == 'closed' and team['region_id'] is not None:
        region = load_region(db, region_id)
        national_count = count_teams_in_round(db, round_id)
        big_region_count = count_teams_in_round_big_region(
            db, round_id, region['big_region_code'])
        region_count = count_teams_in_round_region(db, round_id, region_id)
        view['ranking'] = {
            'national': {
                'rank': participation['rank_national'],
                'count': national_count
            },
            'big_region': {
                'name': region['big_region_name'],
                'rank': participation['rank_big_regional'],
                'count': big_region_count
            },
            'region': {
                'name': region['name'],
                'rank': participation['rank_regional'],
                'count': region_count
            }
        }

    # XXX A team's validity should be checked against settings for a
    #     competition rather than a round.
    causes = validate_members_for_round(members, round_)
    team_view['round_access'] = list(causes.keys())
    team_view['is_invalid'] = len(causes) != 0

    # Do not return attempts if the team is invalid.
    if team_view['is_invalid']:
        return view

    # Load the participation attempts.
    attempts = load_participation_attempts(db, participation['id'], now)
    view_task_attempts(attempts, round_task_views)
    print("attempts {} {}".format(attempt_id, attempts))

    # Find the requested attempt.
    current_attempt = get_by_id(attempts, attempt_id)
    if current_attempt is None:
        return view
    view['attempt_id'] = attempt_id

    # Focus on the current attempt.
    current_round_task = round_task_views[str(
        current_attempt['round_task_id'])]
    current_attempt_view = None
    for attempt_view in current_round_task['attempts']:
        if attempt_id == attempt_view.get('id'):
            current_attempt_view = attempt_view
    view['attempt'] = current_attempt_view
    view['round_task'] = current_round_task  # XXX duplicates attempts :(

    if False:  # Access codes are disabled
        members_view = view['team']['members']
        access_codes = load_unlocked_access_codes(db, attempt_id)
        add_members_access_codes(members_view, access_codes)
        if current_attempt['is_training']:
            needs_codes = not have_one_code(members_view)
        else:
            needs_codes = not have_code_majority(members_view)
        current_attempt_view['needs_codes'] = needs_codes

    # Add task instance data, if available.
    try:
        # XXX Previously load_task_instance_team_data which did not parse
        #     full_data.
        # /!\ task contains sensitive data
        # XXX If the round is closed, load and pass full_data?
        task_instance = load_user_task_instance(db, attempt_id)
    except ModelError:
        return view

    # If the round has a time limit, return the countdown.
    if round_['duration'] is not None:
        started_at = participation['started_at']
        if started_at is not None:
            duration = timedelta(minutes=round_['duration'])
            countdown = started_at + duration
            view['countdown'] = started_at + duration
            if countdown < now:
                return view

    view['team_data'] = task_instance['team_data']

    # Add a list of the workspace revisions for this attempt.
    add_revisions(db, view, attempt_id)

    # Give the user the id of their latest revision for the
    # current attempt, to be loaded into the crypto tab on
    # first access.
    revision_id = load_user_latest_revision_id(db, user_id, attempt_id)
    view['my_latest_revision_id'] = revision_id

    return view