<commit_before>"""
Hackathon API endpoints - create/update/delete/list hackathons+leaderboards
"""

import uuid

import arrow
import flask
import sqlalchemy

from .. import model, util

from . import util as api_util
from .blueprint import web_api


def can_view_hackathon(user_id, hackathon_id, conn):
    is_user_joined = conn.execute(model.hackathon_participants.select(
        (model.hackathon_participants.c.user_id == user_id) &
        (model.hackathon_participants.c.hackathon_id == hackathon_id)
    )).first()

    is_admin = api_util.is_user_admin(user_id, conn=conn)

    return is_user_joined or is_admin


hackathon_query = sqlalchemy.sql.select([
    model.hackathons.c.id,
    model.hackathons.c.title,
    model.hackathons.c.description,
    model.hackathons.c.start_date,
    model.hackathons.c.end_date,
    model.hackathons.c.organization_id,
    model.organizations.c.organization_name,
]).select_from(
    model.hackathons.join(
        model.organizations,
        model.hackathons.c.organization_id == model.organizations.c.id,
        isouter=True,
        )
)


@web_api.route("/hackathon", methods=["GET"])
@api_util.requires_login(accept_key=True, admin=True)
def list_hackathons(*, user_id):
    result = []
    offset, limit = api_util.get_offset_limit()

    with model.engine.connect() as conn:
        hackathons = conn.execute(
            hackathon_query.offset(offset).limit(limit)).fetchall()

        for hackathon in hackathons:
            record = {
                "hackathon_id": hackathon["id"],
                "title": hackathon["title"],
                "description": hackathon["description"],
                "status": api_util.hackathon_status(hackathon["start_date"],
                                                    hackathon["end_date"]),
                "start_date": hackathon["start_date"],
                "end_date": hackathon["end_date"],
                "organization_id": hackathon["organization_id"],
                "organization_name": hackathon["organization_name"],
            }

            result.append(record)

    return flask.jsonify(result)


@web_api.route("/hackathon", methods=["POST"])
@api_util.requires_login(accept_key=True, admin=True)
def create_hackathon(*, user_id):
    title = flask.request.form["title"]
    description = flask.request.form["description"]
    start_date = arrow.get(flask.request.form["start_date"]).datetime
    end_date = arrow.get(flask.request.form["end_date"]).datetime
    organization_id = flask.request.form.get("organization_id")

    if end_date < arrow.now().datetime:
        raise util.APIError(
            400,
            message="End date is in the past!"
        )

    if start_date >= end_date:
        raise util.APIError(
            400,
            message="Start date must be before end date."
        )

    with model.engine.connect() as conn:
        if organization_id is not None:
            organization_id = int(organization_id)
            organization = conn.execute(
                model.organizations.select(
                    model.organizations.c.id == organization_id)
            ).first()

            if not organization:
                raise util.APIError(
                    400,
                    message="Invalid organization ID."
                )

        verification_code = uuid.uuid4().hex
        hackathon_id = conn.execute(model.hackathons.insert().values(
            title=title,
            description=description,
            start_date=start_date,
            end_date=end_date,
            verification_code=verification_code,
            organization_id=organization_id,
        )).inserted_primary_key[0]

        return util.response_success({
            "hackathon_id": hackathon_id,
            "verification_code": verification_code,
        }, status_code=201)


@web_api.route("/hackathon/<int:hackathon_id>", methods=["GET"])
@util.cross_origin(methods=["GET", "PUT"])
@api_util.requires_login(accept_key=True)
def get_hackathon(hackathon_id, *, user_id):
    with model.engine.connect() as conn:
        hackathon = conn.execute(hackathon_query.where(
            model.hackathons.c.id == hackathon_id)).first()

        if (not hackathon or
                not can_view_hackathon(user_id, hackathon["id"], conn)):
            raise util.APIError(404)

        hackathon_users = conn.execute(
            model.hackathon_total_ranked_users_query(hackathon_id)
        ).first()[0]

        return flask.jsonify({
            "hackathon_id": hackathon["id"],
            "title": hackathon["title"],
            "description": hackathon["description"],
            "status": api_util.hackathon_status(hackathon["start_date"],
                                                hackathon["end_date"]),
            "start_date": hackathon["start_date"],
            "end_date": hackathon["end_date"],
            "organization_id": hackathon["organization_id"],
            "organization_name": hackathon["organization_name"],
            "num_participants": hackathon_users,
        })


@web_api.route("/hackathon/<int:hackathon_id>", methods=["PUT"])
@util.cross_origin(methods=["GET", "PUT"])
@api_util.requires_login(admin=True, accept_key=True)
def update_hackathon(hackathon_id, *, user_id):
    values = {}

    if "title" in flask.request.form:
        values["title"] = flask.request.form["title"]

    if "description" in flask.request.form:
        values["description"] = flask.request.form["description"]

    if "organization_id" in flask.request.form:
        values["organization_id"] = int(flask.request.form["organization_id"])

    with model.engine.connect() as conn:
        hackathon = conn.execute(
            model.hackathons.select(model.hackathons.c.id == hackathon_id)
        ).first()

        if not hackathon:
            raise util.APIError(
                404,
                message="Hackathon does not exist."
            )
<commit_msg>Accept JSON or form values for hackathon endpoints<commit_after>"""
Hackathon API endpoints - create/update/delete/list hackathons+leaderboards
"""

import uuid

import arrow
import flask
import sqlalchemy

from .. import model, util

from . import util as api_util
from .blueprint import web_api


def can_view_hackathon(user_id, hackathon_id, conn):
    """
    Validate whether a given user is allowed to view a given hackathon.
    :param user_id:
    :param hackathon_id:
    :param conn:
    :return: True if the user can view the hackathon; False otherwise
    """
    is_user_joined = conn.execute(model.hackathon_participants.select(
        (model.hackathon_participants.c.user_id == user_id) &
        (model.hackathon_participants.c.hackathon_id == hackathon_id)
    )).first()

    is_admin = api_util.is_user_admin(user_id, conn=conn)

    return is_user_joined or is_admin


hackathon_query = sqlalchemy.sql.select([
    model.hackathons.c.id,
    model.hackathons.c.title,
    model.hackathons.c.description,
    model.hackathons.c.start_date,
    model.hackathons.c.end_date,
    model.hackathons.c.organization_id,
    model.organizations.c.organization_name,
]).select_from(
    model.hackathons.join(
        model.organizations,
        model.hackathons.c.organization_id == model.organizations.c.id,
        isouter=True,
        )
)


@web_api.route("/hackathon", methods=["GET"])
@api_util.requires_login(accept_key=True, admin=True)
def list_hackathons(*, user_id):
    result = []
    offset, limit = api_util.get_offset_limit()

    with model.engine.connect() as conn:
        hackathons = conn.execute(
            hackathon_query.offset(offset).limit(limit)).fetchall()

        for hackathon in hackathons:
            record = {
                "hackathon_id": hackathon["id"],
                "title": hackathon["title"],
                "description": hackathon["description"],
                "status": api_util.hackathon_status(hackathon["start_date"],
                                                    hackathon["end_date"]),
                "start_date": hackathon["start_date"],
                "end_date": hackathon["end_date"],
                "organization_id": hackathon["organization_id"],
                "organization_name": hackathon["organization_name"],
            }

            result.append(record)

    return flask.jsonify(result)


@web_api.route("/hackathon", methods=["POST"])
@api_util.requires_login(accept_key=True, admin=True)
def create_hackathon(*, user_id):
    # Accept JSON if possible; fall back to form-encoded data
    hackathon_body = flask.request.get_json()
    if not hackathon_body:
        hackathon_body = flask.request.form

    title = hackathon_body["title"]
    description = hackathon_body["description"]
    start_date = arrow.get(hackathon_body["start_date"]).datetime
    end_date = arrow.get(hackathon_body["end_date"]).datetime
    organization_id = hackathon_body.get("organization_id", None)

    if end_date < arrow.now().datetime:
        raise util.APIError(
            400,
            message="End date is in the past!"
        )

    if start_date >= end_date:
        raise util.APIError(
            400,
            message="Start date must be before end date."
        )

    with model.engine.connect() as conn:
        if organization_id is not None:
            organization_id = int(organization_id)
            organization = conn.execute(
                model.organizations.select(
                    model.organizations.c.id == organization_id)
            ).first()

            if not organization:
                raise util.APIError(
                    400,
                    message="Invalid organization ID."
                )

        verification_code = uuid.uuid4().hex
        hackathon_id = conn.execute(model.hackathons.insert().values(
            title=title,
            description=description,
            start_date=start_date,
            end_date=end_date,
            verification_code=verification_code,
            organization_id=organization_id,
        )).inserted_primary_key[0]

        return util.response_success({
            "hackathon_id": hackathon_id,
            "verification_code": verification_code,
        }, status_code=201)


@web_api.route("/hackathon/<int:hackathon_id>", methods=["GET"])
@util.cross_origin(methods=["GET", "PUT"])
@api_util.requires_login(accept_key=True)
def get_hackathon(hackathon_id, *, user_id):
    with model.engine.connect() as conn:
        hackathon = conn.execute(hackathon_query.where(
            model.hackathons.c.id == hackathon_id)).first()

        if (not hackathon or
                not can_view_hackathon(user_id, hackathon["id"], conn)):
            raise util.APIError(404)

        hackathon_users = conn.execute(
            model.hackathon_total_ranked_users_query(hackathon_id)
        ).first()[0]

        return flask.jsonify({
            "hackathon_id": hackathon["id"],
            "title": hackathon["title"],
            "description": hackathon["description"],
            "status": api_util.hackathon_status(hackathon["start_date"],
                                                hackathon["end_date"]),
            "start_date": hackathon["start_date"],
            "end_date": hackathon["end_date"],
            "organization_id": hackathon["organization_id"],
            "organization_name": hackathon["organization_name"],
            "num_participants": hackathon_users,
        })


@web_api.route("/hackathon/<int:hackathon_id>", methods=["PUT"])
@util.cross_origin(methods=["GET", "PUT"])
@api_util.requires_login(admin=True, accept_key=True)
def update_hackathon(hackathon_id, *, user_id):
    values = {}
    hackathon_body = flask.request.get_form()
    if not hackathon_body:
        hackathon_body = flask.request.form

    if "title" in hackathon_body:
        values["title"] = hackathon_body["title"]

    if "description" in hackathon_body:
        values["description"] = hackathon_body["description"]

    if "organization_id" in hackathon_body:
        values["organization_id"] = int(hackathon_body["organization_id"])

    with model.engine.connect() as conn:
        hackathon = conn.execute(
            model.hackathons.select(model.hackathons.c.id == hackathon_id)
        ).first()

        if not hackathon:
            raise util.APIError(
                404,
                message="Hackathon does not exist."
            )

{'fraction_non_alphanumeric': 0.1155083655083655, 'fraction_numerical': 0.0033783783783783786, 'mean_word_length': 2.549243505566657, 'pattern_counts': {'":': 38, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2631056', 'n_tokens_mistral': 3807, 'n_tokens_neox': 3641, 'n_words': 634}