Esempio n. 1
0
def test_hint_team_unlock():
    """Is a user's unlocked hint reflected on other team members"""
    app = create_ctfd(user_mode="teams")
    with app.app_context():
        user = gen_user(app.db)
        second_user = gen_user(app.db, name="user", email='*****@*****.**')
        team = gen_team(app.db)
        user.team_id = team.id
        second_user.team_id = team.id
        team.members.append(user)
        team.members.append(second_user)
        chal = gen_challenge(app.db)
        gen_hint(app.db, chal.id, content="hint", cost=1, type="standard")
        gen_award(app.db, 2, team.id)
        app.db.session.commit()
        with login_as_user(app, name="user_name") as client:
            client.get('/api/v1/hints/1')
            client.post('/api/v1/unlocks', json={"target": 1, "type": "hints"})
            client.get('/api/v1/hints/1')
        with login_as_user(app) as second_client:
            second_client.get('/api/v1/hints/1')
            second_client.post('/api/v1/unlocks',
                               json={
                                   "target": 1,
                                   "type": "hints"
                               })
            r = second_client.get('/api/v1/hints/1')
            assert r.json['data']['content'] == 'hint'
            standings = get_standings()
            assert standings[0][2] == "team_name"
            assert standings[0][3] == 99
    destroy_ctfd(app)
Esempio n. 2
0
def listing():
    standings = get_standings()
    return render_template(
        "scoreboard.html",
        standings=standings,
        score_frozen=config.is_scoreboard_frozen(),
    )
Esempio n. 3
0
def test_challenge_team_submit():
    """Is a user's solved challenge reflected by other team members"""
    app = create_ctfd(user_mode="teams")
    with app.app_context():
        user = gen_user(app.db)
        second_user = gen_user(app.db, name="user", email='*****@*****.**')
        team = gen_team(app.db)
        user.team_id = team.id
        second_user.team_id = team.id
        team.members.append(user)
        team.members.append(second_user)
        gen_challenge(app.db)
        gen_flag(app.db, 1)
        app.db.session.commit()
        with login_as_user(app, name="user_name") as client:
            flag = {"challenge_id": 1, "submission": "flag"}
            client.post('/api/v1/challenges/attempt', json=flag)
        with login_as_user(app) as second_client:
            flag = {"challenge_id": 1, "submission": "flag"}
            r = second_client.post('/api/v1/challenges/attempt', json=flag)
            assert r.json['data']['status'] == 'already_solved'
        standings = get_standings()
        assert standings[0][2] == "team_name"
        assert standings[0][3] == 100
    destroy_ctfd(app)
Esempio n. 4
0
    def get(self):
        challenge_count = Challenges.query.count() or 1
        total_points = (Challenges.query.with_entities(
            db.func.sum(Challenges.value).label("sum")).filter_by(
                state="visible").first().sum) or 0
        # Convert Decimal() to int in some database backends for Python 2
        total_points = int(total_points)

        # Divide score by challenges to get brackets with explicit floor division
        bracket_size = total_points // challenge_count

        # Get standings
        standings = get_standings(admin=True)

        # Iterate over standings and increment the count for each bracket for each standing within that bracket
        bottom, top = 0, bracket_size
        count = 1
        brackets = defaultdict(lambda: 0)
        for t in reversed(standings):
            if ((t.score >= bottom) and (t.score <= top)) or t.score <= 0:
                brackets[top] += 1
            else:
                count += 1
                bottom, top = (bracket_size, (bracket_size * count))
                brackets[top] += 1

        return {"success": True, "data": {"brackets": brackets}}
    def multi_scoreboard(sb=None):
        if sb == None:
            sb = 'Global'
        infos = get_infos()

        if config.is_scoreboard_frozen():
            infos.append("Scoreboard has been frozen")

        if is_admin() is True and scores_visible() is False:
            infos.append("Scores are not currently visible to users")

        standings = get_standings()
        teams = []
        scoreboards = ["Global"]
        for t in Teams.query.all():
            if sb == "Global" and (t.name not in teams):
                teams.append(t.name)
            for f in t.fields:
                if f.name not in scoreboards:
                    scoreboards.append(f.name)
                if f.name == sb and (t.name not in teams):
                    teams.append(t.name)

        if sb not in scoreboards:
            abort(404)

        filtered_standings = [st for st in standings if st[2] in teams]

        return render_template("multi_scoreboard.html",
                               standings=filtered_standings,
                               infos=infos,
                               scoreboards=scoreboards,
                               scoreboard=sb)
Esempio n. 6
0
    def get(self):
        standings = get_standings()
        response = []
        mode = get_config("user_mode")

        if mode == TEAMS_MODE:
            team_ids = []
            for team in standings:
                team_ids.append(team.account_id)
            teams = Teams.query.filter(Teams.id.in_(team_ids)).all()
            teams = [next(t for t in teams if t.id == id) for id in team_ids]

        for i, x in enumerate(standings):
            entry = {
                "pos": i + 1,
                "account_id": x.account_id,
                "oauth_id": x.oauth_id,
                "name": x.name,
                "score": int(x.score),
            }

            if mode == TEAMS_MODE:
                members = []
                for member in teams[i].members:
                    members.append({
                        "id": member.id,
                        "oauth_id": member.oauth_id,
                        "name": member.name,
                        "score": int(member.score),
                    })

                entry["members"] = members

            response.append(entry)
        return {"success": True, "data": response}
Esempio n. 7
0
    def get(self):
        standings = get_standings()
        response = []
        mode = get_config('user_mode')

        if mode == TEAMS_MODE:
            team_ids = []
            for team in standings:
                team_ids.append(team.account_id)
            teams = Teams.query.filter(Teams.id.in_(team_ids)).all()
            teams = [next(t for t in teams if t.id == id) for id in team_ids]

        for i, x in enumerate(standings):
            entry = {
                'pos': i + 1,
                'account_id': x.account_id,
                'oauth_id': x.oauth_id,
                'name': x.name,
                'score': int(x.score)
            }

            if mode == TEAMS_MODE:
                members = []
                for member in teams[i].members:
                    members.append({
                        'id': member.id,
                        'oauth_id': member.oauth_id,
                        'name': member.name,
                        'score': int(member.score)
                    })

                entry['members'] = members

            response.append(entry)
        return {'success': True, 'data': response}
Esempio n. 8
0
def listing():
    infos = get_infos()

    if config.is_scoreboard_frozen():
        infos.append("Scoreboard has been frozen")

    standings = get_standings()
    return render_template("scoreboard.html", standings=standings, infos=infos)
Esempio n. 9
0
def test_hint_team_unlock():
    """Is a user's unlocked hint reflected on other team members"""
    app = create_ctfd(user_mode="teams")
    with app.app_context():
        user = gen_user(app.db)
        second_user = gen_user(app.db,
                               name="user",
                               email="*****@*****.**")
        team = gen_team(app.db)
        user.team_id = team.id
        second_user.team_id = team.id
        team.members.append(user)
        team.members.append(second_user)
        chal = gen_challenge(app.db)
        gen_hint(app.db, chal.id, content="hint", cost=1, type="standard")
        # Give the points to the user that doesn't unlock
        # Users that unlock hints should be able to unlock but cost their team points
        gen_award(app.db, user_id=3, team_id=team.id)
        app.db.session.commit()
        with login_as_user(app, name="user_name") as client:
            # Assert that we don't see a hint
            r = client.get("/api/v1/hints/1")
            assert r.get_json()["data"].get("content") is None

            # Unlock the hint
            client.post("/api/v1/unlocks", json={"target": 1, "type": "hints"})

            # Assert that we see a hint
            r = client.get("/api/v1/hints/1")
            assert r.get_json()["data"].get("content")
        with login_as_user(app) as second_client:
            # Assert that we see a hint
            r = second_client.get("/api/v1/hints/1")
            assert r.get_json()["data"].get("content")

            # Assert that we can't double unlock
            r = second_client.post("/api/v1/unlocks",
                                   json={
                                       "target": 1,
                                       "type": "hints"
                                   })
            assert r.status_code == 400
            assert (r.get_json()["errors"]["target"] ==
                    "You've already unlocked this this target")

            # Assert that we see a hint
            r = second_client.get("/api/v1/hints/1")
            assert r.json["data"]["content"] == "hint"

            # Verify standings
            # We start with 100 points from the award.
            # We lose a point because we unlock successfully once
            standings = get_standings()
            assert standings[0][2] == "team_name"
            assert standings[0][3] == 99
    destroy_ctfd(app)
Esempio n. 10
0
def test_admin_standings():
    app = create_ctfd(user_mode="teams")

    with app.app_context():
        setup_app(app)

        standings = get_standings(admin=True)

        assert standings[0].name == "team1"
        assert standings[0].score == 100
Esempio n. 11
0
def listing():
    infos = get_infos()

    if config.is_scoreboard_frozen():
        infos.append("Результаты заморожены")

    if is_admin() is True and scores_visible() is False:
        infos.append("Результаты сейчас не отображаются для участников")

    standings = get_standings()
    return render_template("scoreboard.html", standings=standings, infos=infos)
Esempio n. 12
0
def listing():
    infos = get_infos()

    if config.is_scoreboard_frozen():
        infos.append("Scoreboard has been frozen")

    if is_admin() is True and scores_visible() is False:
        infos.append("Scores are not currently visible to users")

    standings = get_standings()
    return render_template("scoreboard.html", standings=standings, infos=infos)
Esempio n. 13
0
def test_standings():
    app = create_ctfd(user_mode="teams")

    with app.app_context():
        setup_app(app)

        standings = get_standings()

        assert standings[0].name == "team2"
        assert standings[0].score == 100

    destroy_ctfd(app)
Esempio n. 14
0
    def get(self, count):
        response = {}

        standings = get_standings(count=count)

        team_ids = [team.account_id for team in standings]

        solves = Solves.query.filter(Solves.account_id.in_(team_ids))
        awards = Awards.query.filter(Awards.account_id.in_(team_ids))

        freeze = get_config('freeze')

        if freeze:
            solves = solves.filter(Solves.date < unix_time_to_utc(freeze))
            awards = awards.filter(Awards.date < unix_time_to_utc(freeze))

        solves = solves.all()
        awards = awards.all()

        for i, team in enumerate(team_ids):
            response[i + 1] = {
                'id': standings[i].account_id,
                'name': standings[i].name,
                'solves': []
            }
            for solve in solves:
                if solve.account_id == team:
                    response[i + 1]['solves'].append({
                        'challenge_id': solve.challenge_id,
                        'account_id': solve.account_id,
                        'team_id': solve.team_id,
                        'user_id': solve.user_id,
                        'value': solve.challenge.value,
                        'date': isoformat(solve.date)
                    })
            for award in awards:
                if award.account_id == team:
                    response[i + 1]['solves'].append({
                        'challenge_id': None,
                        'account_id': award.account_id,
                        'team_id': award.team_id,
                        'user_id': award.user_id,
                        'value': award.value,
                        'date': isoformat(award.date)
                    })
            response[i + 1]['solves'] = sorted(response[i + 1]['solves'], key=lambda k: k['date'])

        return {
            'success': True,
            'data': response
        }
Esempio n. 15
0
    def get(self):
        standings = get_standings()
        response = []
        mode = get_config("user_mode")
        account_type = get_mode_as_word()

        if mode == TEAMS_MODE:
            r = db.session.execute(
                select([
                    Users.id,
                    Users.name,
                    Users.oauth_id,
                    Users.team_id,
                    Users.hidden,
                    Users.banned,
                ]).where(Users.team_id.isnot(None)))
            users = r.fetchall()
            membership = defaultdict(dict)
            for u in users:
                if u.hidden is False and u.banned is False:
                    membership[u.team_id][u.id] = {
                        "id": u.id,
                        "oauth_id": u.oauth_id,
                        "name": u.name,
                        "score": 0,
                    }

            # Get user_standings as a dict so that we can more quickly get member scores
            user_standings = get_user_standings()
            for u in user_standings:
                membership[u.team_id][u.user_id]["score"] = int(u.score)

        for i, x in enumerate(standings):
            entry = {
                "pos": i + 1,
                "account_id": x.account_id,
                "account_url": generate_account_url(account_id=x.account_id),
                "account_type": account_type,
                "oauth_id": x.oauth_id,
                "name": x.name,
                "score": int(x.score),
            }

            if mode == TEAMS_MODE:
                entry["members"] = list(membership[x.account_id].values())

            response.append(entry)
        return {"success": True, "data": response}
Esempio n. 16
0
def listing():
    infos = get_infos()

    if config.is_scoreboard_frozen():
        infos.append("Scoreboard has been frozen")

    if is_admin() is True and scores_visible() is False:
        infos.append("Scores are not currently visible to users")

    standings = get_standings()
    standings_interne = [s for s in standings if s.fields != True]
    standings_externe = [s for s in standings if s.fields == True]
    return render_template("scoreboard.html",
                           standings_interne=standings_interne,
                           standings_externe=standings_externe,
                           infos=infos)
Esempio n. 17
0
    def get(self):
        response = {'tasks': [], 'standings': []}

        mode = get_config("user_mode")
        freeze = get_config("freeze")

        # Get Challenges
        challenges = Challenges.query.filter(
            and_(Challenges.state != 'hidden',
                 Challenges.state != 'locked')).order_by(
                     Challenges.value).all()

        challenges_ids = {}
        for i, x in enumerate(challenges):
            response['tasks'].append(unicode_safe(x.name) + " " + str(x.value))
            challenges_ids[x.id] = unicode_safe(x.name) + " " + str(x.value)

        # Get Standings
        if mode == TEAMS_MODE:
            standings = get_standings()
            team_ids = [team.account_id for team in standings]
        else:
            abort(501, "CTFTime only accepts team scores.")

        solves = Solves.query.filter(Solves.account_id.in_(team_ids))
        if freeze:
            solves = solves.filter(Solves.date < unix_time_to_utc(freeze))

        for i, team in enumerate(team_ids):
            team_standing = {
                'pos': i + 1,
                'team': unicode_safe(standings[i].name),
                'score': float(standings[i].score),
                'taskStats': {}
            }
            team_solves = solves.filter(
                Solves.account_id == standings[i].account_id)
            for solve in team_solves:
                chall_name = challenges_ids[solve.challenge_id]
                team_standing["taskStats"][chall_name] = {
                    "points": solve.challenge.value,
                    "time": unix_time(solve.date),
                }
            response['standings'].append(team_standing)
        return response
Esempio n. 18
0
def test_scoreboard_team_score():
    """Is a user's submitted flag reflected on the team's score on /scoreboard"""
    app = create_ctfd(user_mode="teams")
    with app.app_context():
        user = gen_user(app.db, name="user")
        team = gen_team(app.db)
        user.team_id = team.id
        team.members.append(user)
        gen_challenge(app.db)
        gen_flag(app.db, 1)
        app.db.session.commit()
        with login_as_user(app) as client:
            flag = {"challenge_id": 1, "submission": "flag"}
            client.post("/api/v1/challenges/attempt", json=flag)
        standings = get_standings()
        assert standings[0][2] == "team_name"
        assert standings[0][3] == 100
    destroy_ctfd(app)
Esempio n. 19
0
def static_html(route):
    """
    Route in charge of routing users to Pages.
    :param route:
    :return:
    """
    page = get_page(route)
    if page is None:
        abort(404)
    else:
        if route == 'index':
            try:
                highscore = str(get_standings()[0][3]).rjust(6, '0')
            except:
                highscore = '000000'
            return render_template('index.html', highscore=highscore)
        elif page.auth_required and authed() is False:
            return redirect(url_for('auth.login', next=request.full_path))

        return render_template("page.html", content=markdown(page.content))
Esempio n. 20
0
def scoreboard_listing():
    infos = get_infos()

    if config.is_scoreboard_frozen():
        infos.append("Scoreboard has been frozen")

    if is_admin() is True and scores_visible() is False:
        infos.append("Scores are not currently visible to users")

    Model = get_model()
    standings = get_standings(fields=[Model.email])

    category_standings = get_category_standings()

    return render_template(
        "scoreboard.html",
        standings=standings,
        category_standings=category_standings,
        infos=infos,
        email_group_asset=email_group_asset,
    )
    def view_single_rank():
        # override templates
        dir_path = os.path.dirname(os.path.realpath(__file__))
        template_path = os.path.join(dir_path, 'assets')
        template_path = os.path.join(template_path, 'scoreboard.html')
        override_template("scoreboard.html", open(template_path).read())

        # get categories
        categories = get_all_categories()

        # load scores
        standings = get_standings()

        ranks = []
        for index1, category in enumerate(categories):
            ranks.append([])
            for standing in standings:
                account_id = standing.account_id
                name = standing.name
                oauth_id = standing.oauth_id
                score = get_user_scores_for_each_category(
                    standing.account_id, categories)[index1]
                ranks[index1].append([account_id, name, oauth_id, score])
            ranks[index1] = sorted(ranks[index1],
                                   key=(lambda x: x[3]),
                                   reverse=True)

        # rank[0] account_id
        # rank[1] name
        # rank[2] oauth_id
        # rank[3] score

        return render_template("scoreboard.html",
                               categories=categories,
                               enumerate=enumerate,
                               ranks=ranks,
                               standings=standings,
                               score_frozen=config.is_scoreboard_frozen())
Esempio n. 22
0
def scoreboard_listing():
    standings = get_standings(admin=True)
    user_standings = get_user_standings(admin=True) if is_teams_mode() else None
    return render_template(
        "admin/scoreboard.html", standings=standings, user_standings=user_standings
    )
Esempio n. 23
0
    def get(self, count):
        response = {}

        standings = get_standings(count=count)

        team_ids = [team.account_id for team in standings]

        solves = Solves.query.filter(Solves.account_id.in_(team_ids))
        awards = Awards.query.filter(Awards.account_id.in_(team_ids))

        freeze = get_config("freeze")

        if freeze:
            solves = solves.filter(Solves.date < unix_time_to_utc(freeze))
            awards = awards.filter(Awards.date < unix_time_to_utc(freeze))

        solves = solves.all()
        awards = awards.all()

        for i, team in enumerate(team_ids):
            response[i + 1] = {
                "id": standings[i].account_id,
                "name": standings[i].name,
                "solves": [],
            }
            for solve in solves:
                if solve.account_id == team:
                    response[i + 1]["solves"].append({
                        "challenge_id":
                        solve.challenge_id,
                        "account_id":
                        solve.account_id,
                        "team_id":
                        solve.team_id,
                        "user_id":
                        solve.user_id,
                        "value":
                        solve.challenge.value,
                        "date":
                        isoformat(solve.date),
                    })
            for award in awards:
                if award.account_id == team:
                    response[i + 1]["solves"].append({
                        "challenge_id":
                        None,
                        "account_id":
                        award.account_id,
                        "team_id":
                        award.team_id,
                        "user_id":
                        award.user_id,
                        "value":
                        award.value,
                        "date":
                        isoformat(award.date),
                    })
            response[i + 1]["solves"] = sorted(response[i + 1]["solves"],
                                               key=lambda k: k["date"])

        return {"success": True, "data": response}
Esempio n. 24
0
    def get(self):
        standings = get_standings()
        response = []
        mode = get_config("user_mode")
        account_type = get_mode_as_word()

        if mode == TEAMS_MODE:
            team_ids = []
            for team in standings:
                team_ids.append(team.account_id)

            # Get team objects with members explicitly loaded in
            teams = (Teams.query.options(joinedload(Teams.members)).filter(
                Teams.id.in_(team_ids)).all())

            # Sort according to team_ids order
            teams = [next(t for t in teams if t.id == id) for id in team_ids]

            # Get user_standings as a dict so that we can more quickly get member scores
            user_standings = get_user_standings()
            users = {}
            for u in user_standings:
                users[u.user_id] = u

        for i, x in enumerate(standings):
            entry = {
                "pos": i + 1,
                "account_id": x.account_id,
                "account_url": generate_account_url(account_id=x.account_id),
                "account_type": account_type,
                "oauth_id": x.oauth_id,
                "name": x.name,
                "score": int(x.score),
            }

            if mode == TEAMS_MODE:
                members = []

                # This code looks like it would be slow
                # but it is faster than accessing each member's score individually
                for member in teams[i].members:
                    user = users.get(member.id)
                    if user:
                        members.append({
                            "id": user.user_id,
                            "oauth_id": user.oauth_id,
                            "name": user.name,
                            "score": int(user.score),
                        })
                    else:
                        if member.hidden is False and member.banned is False:
                            members.append({
                                "id": member.id,
                                "oauth_id": member.oauth_id,
                                "name": member.name,
                                "score": 0,
                            })

                entry["members"] = members

            response.append(entry)
        return {"success": True, "data": response}
Esempio n. 25
0
    def get(self, count):
        response = {}

        standings = get_standings(count=count)

        team_ids = [team.account_id for team in standings]

        solves = Solves.query.filter(Solves.account_id.in_(team_ids))
        awards = Awards.query.filter(Awards.account_id.in_(team_ids))
        hints_name_list = db.session.query(
            db.func.concat("Hint ", Hints.id).label("hints_name")).count()
        if hints_name_list > 0:
            hints_name = db.func.concat("Hint ", Hints.id).label("hints_name")
            awards = db.session.query(
                Awards.account_id.label('account_id'),
                Awards.team_id.label('team_id'),
                Awards.user_id.label('user_id'),
                Awards.value.label('value'),
                Awards.date.label('date'),
            ) \
                .join(Hints, Awards.name == hints_name) \
                .join(Solves, (Awards.account_id == Solves.account_id) & (Hints.challenge_id == Solves.challenge_id)) \
                .filter(Awards.value != 0) \
                .filter(Awards.account_id.in_(team_ids))

            awards_by_admin = db.session.query(
                Awards.account_id.label('account_id'),
                Awards.team_id.label('team_id'),
                Awards.user_id.label('user_id'),
                Awards.value.label('value'),
                Awards.date.label('date'),
            ) \
                .filter(Awards.account_id.in_(team_ids)) \
                .filter(Awards.value > 0)

            awards = awards.union(awards_by_admin)

        freeze = get_config('freeze')

        if freeze:
            solves = solves.filter(Solves.date < unix_time_to_utc(freeze))
            awards = awards.filter(Awards.date < unix_time_to_utc(freeze))

        solves = solves.all()
        awards = awards.all()

        for i, team in enumerate(team_ids):
            response[i + 1] = {
                'id': standings[i].account_id,
                'name': standings[i].name,
                'solves': []
            }
            for solve in solves:
                if solve.account_id == team:
                    response[i + 1]['solves'].append({
                        'challenge_id':
                        solve.challenge_id,
                        'account_id':
                        solve.account_id,
                        'team_id':
                        solve.team_id,
                        'user_id':
                        solve.user_id,
                        'value':
                        solve.challenge.value,
                        'date':
                        isoformat(solve.date)
                    })
            for award in awards:
                if award.account_id == team:
                    response[i + 1]['solves'].append({
                        'challenge_id':
                        None,
                        'account_id':
                        award.account_id,
                        'team_id':
                        award.team_id,
                        'user_id':
                        award.user_id,
                        'value':
                        award.value,
                        'date':
                        isoformat(award.date)
                    })
            response[i + 1]['solves'] = sorted(response[i + 1]['solves'],
                                               key=lambda k: k['date'])

        return {'success': True, 'data': response}
Esempio n. 26
0
    def get(self, count):
        response = {}

        standings = get_standings(count=count)

        team_ids = [team.account_id for team in standings]

        solves = Solves.query.filter(Solves.account_id.in_(team_ids))
        awards = Awards.query.filter(Awards.account_id.in_(team_ids))

        freeze = get_config("freeze")

        if freeze:
            solves = solves.filter(Solves.date < unix_time_to_utc(freeze))
            awards = awards.filter(Awards.date < unix_time_to_utc(freeze))

        solves = solves.all()
        awards = awards.all()

        # Build a mapping of accounts to their solves and awards
        solves_mapper = defaultdict(list)
        for solve in solves:
            solves_mapper[solve.account_id].append({
                "challenge_id":
                solve.challenge_id,
                "account_id":
                solve.account_id,
                "team_id":
                solve.team_id,
                "user_id":
                solve.user_id,
                "value":
                solve.challenge.value,
                "date":
                isoformat(solve.date),
            })

        for award in awards:
            solves_mapper[award.account_id].append({
                "challenge_id":
                None,
                "account_id":
                award.account_id,
                "team_id":
                award.team_id,
                "user_id":
                award.user_id,
                "value":
                award.value,
                "date":
                isoformat(award.date),
            })

        # Sort all solves by date
        for team_id in solves_mapper:
            solves_mapper[team_id] = sorted(solves_mapper[team_id],
                                            key=lambda k: k["date"])

        for i, team in enumerate(team_ids):
            response[i + 1] = {
                "id": standings[i].account_id,
                "name": standings[i].name,
                "solves": solves_mapper.get(standings[i].account_id, []),
            }
        return {"success": True, "data": response}
Esempio n. 27
0
def dump_scoreboard_csv():
    # TODO: Add fields to scoreboard data
    temp = StringIO()
    writer = csv.writer(temp)

    standings = get_standings()

    # Get all user fields in a specific order
    user_fields = UserFields.query.all()
    user_field_ids = [f.id for f in user_fields]
    user_field_names = [f.name for f in user_fields]

    if is_teams_mode():
        team_fields = TeamFields.query.all()
        team_field_ids = [f.id for f in team_fields]
        team_field_names = [f.name for f in team_fields]

        header = ([
            "place",
            "team",
            "team id",
            "score",
            "member name",
            "member id",
            "member email",
            "member score",
        ] + user_field_names + team_field_names)
        writer.writerow(header)

        for i, standing in enumerate(standings):
            team = Teams.query.filter_by(id=standing.account_id).first()

            # Build field entries using the order of the field values
            team_field_entries = {
                f.field_id: f.value
                for f in team.field_entries
            }
            team_field_values = [
                team_field_entries.get(f_id, "") for f_id in team_field_ids
            ]
            team_row = [
                i + 1,
                team.name,
                team.id,
                standing.score,
                "",
                "",
            ] + team_field_values

            writer.writerow(team_row)

            for member in team.members:
                user_field_entries = {
                    f.field_id: f.value
                    for f in member.field_entries
                }
                user_field_values = [
                    user_field_entries.get(f_id, "") for f_id in user_field_ids
                ]
                user_row = [
                    "",
                    "",
                    "",
                    "",
                    member.name,
                    member.id,
                    member.email,
                    member.score,
                ] + user_field_values
                writer.writerow(user_row)
    elif is_users_mode():
        header = ["place", "user", "score"] + user_field_names
        writer.writerow(header)

        for i, standing in enumerate(standings):
            user = Users.query.filter_by(id=standing.account_id).first()

            # Build field entries using the order of the field values
            user_field_entries = {
                f.field_id: f.value
                for f in user.field_entries
            }
            user_field_values = [
                user_field_entries.get(f_id, "") for f_id in user_field_ids
            ]
            user_row = [i + 1, user.name, standing.score] + user_field_values
            writer.writerow(user_row)

    # In Python 3 send_file requires bytes
    output = BytesIO()
    output.write(temp.getvalue().encode("utf-8"))
    output.seek(0)
    temp.close()

    return output