<commit_before>""" Module for interacting with the problems """
import imp
import json

import api.common
import api.user
import api.team

from datetime import datetime
from api.common import validate, APIException, check
from voluptuous import Schema, Length, Required, Range
from pymongo.errors import DuplicateKeyError
from bson import json_util
from os.path import join, isfile

grader_base_path = "./graders"
check_graders_exist = True

submission_schema = Schema({
    Required("tid"): check(
        (0, "This does not look like a valid tid.", [str, Length(max=100)])),
    Required("pid"): check(
        (0, "This does not look like a valid pid.", [str, Length(max=100)])),
    Required("key"): check(
        (0, "This does not look like a valid key.", [str, Length(max=100)]))
})

problem_schema = Schema({
    Required("basescore"): check(
        (0, "Basescore must be a positive integer.", [int, Range(min=0)])),
    Required("category"): check(
        (0, "Category must be a string.", [str])),
    Required("desc"): check(
        (0, "The problem description must be a string.", [str])),
    Required("displayname"): check(
        (0, "The problem's display name must be a string.", [str])),
    Required("grader"): check(
        (0, "A grader does not exist at that path.", [
            lambda grader: not check_graders_exist or
            isfile(join(grader_base_path, grader))])),
    Required("threshold"): check(
        (0, "Threshold must be a positive integer.", [int, Range(min=0)])),

    "disabled": check(
        (0, "A problem's disabled state is either True or False.", [bool])),
    "autogen": check(
        (0, "A problem should either be autogenerated or not, True/False", [bool])),
    "relatedproblems": check(
        (0, "Related problems should be a list of related problems.", [list])),
    "pid": check(
        (0, "The problem's pid should be a string.", [str])),
    "weightmap": check(
        (0, "Weightmap should be a dict.", [dict])),
    "tags": check(
        (0, "Tags must be described as a list.", [list])),
    "hint": check(
        (0, "A hint must be a string.", [str])),

    "_id": check(
        (0, "Your problems should not already have _ids.", [lambda id: False]))
})

def insert_problem(problem):
    """
    Inserts a problem into the database. Does sane validation.

    Args:
        Problem dict.
        basescore: points awarded for completing the problem.
        category: problem's category
        desc: description of the problem.
        grader: path relative to grader_base_path
        threshold: Amount of points necessary for a team to unlock this problem.

        Optional:
        disabled: True or False. Defaults to False.
        hint: hint for completing the problem.
        pid: if you care to manually specify a pid
        tags: list of problem tags.
        relatedproblems: list of related problems.
        weightmap: problem's unlock weightmap
        autogen: Whether or not the problem will be auto generated.
    Returns:
        The newly created problem id.
        """

    db = api.common.get_conn()
    validate(problem_schema, problem)

    problem["disabled"] = problem.get("disabled", False)

    if problem["pid"] is None:
        problem["pid"] = api.common.token()

    if get_problem(name=problem["displayname"]) is not None or get_problem(pid=problem["pid"]) is not None:
        raise APIException(0, None, "Problem with identical displayname or pid already exists.")

    db.problems.insert(problem)

    return problem["pid"]

def remove_problem(pid):
    """
    Removes a problem from the given database.

    Args:
        pid: the pid of the problem to remove.
    Returns:
        The removed problem object.
    """

    db = api.common.get_conn()
    problem = get_problem(pid=pid)

    db.problems.remove({"pid": pid})

    return problem

def set_problem_disabled(pid, disabled):
    """
    Updates a problem's availability.<commit_msg>Small touch ups<commit_after>""" Module for interacting with the problems """
import imp
import json

import api.common
import api.user
import api.team

from datetime import datetime
from api.common import validate, APIException, check
from voluptuous import Schema, Length, Required, Range
from pymongo.errors import DuplicateKeyError
from bson import json_util
from os.path import join, isfile

grader_base_path = "./graders"
check_graders_exist = True

submission_schema = Schema({
    Required("tid"): check(
        (0, "This does not look like a valid tid.", [str, Length(max=100)])),
    Required("pid"): check(
        (0, "This does not look like a valid pid.", [str, Length(max=100)])),
    Required("key"): check(
        (0, "This does not look like a valid key.", [str, Length(max=100)]))
})

problem_schema = Schema({
   Required("basescore"): check(
       (0, "Basescore must be a positive integer.", [int, Range(min=0)])),
   Required("category"): check(
       (0, "Category must be a string.", [str])),
   Required("desc"): check(
       (0, "The problem description must be a string.", [str])),
   Required("displayname"): check(
       (0, "The problem's display name must be a string.", [str])),
   Required("grader"): check(
       (0, "A grader does not exist at that path.", [
           lambda grader: not check_graders_exist or
           isfile(join(grader_base_path, grader))])),
   Required("threshold"): check(
       (0, "Threshold must be a positive integer.", [int, Range(min=0)])),

   "disabled": check(
       (0, "A problem's disabled state is either True or False.", [
           lambda disabled: type(disabled) == bool])),
   "autogen": check(
       (0, "A problem should either be autogenerated or not, True/False", [
           lambda autogen: type(autogen) == bool])),
   "relatedproblems": check(
       (0, "Related problems should be a list of related problems.", [list])),
   "pid": check(
       (0, "The problem's pid should be a string.", [str])),
   "weightmap": check(
       (0, "Weightmap should be a dict.", [dict])),
   "tags": check(
       (0, "Tags must be described as a list.", [list])),
   "hint": check(
       (0, "A hint must be a string.", [str])),

   "_id": check(
       (0, "Your problems should not already have _ids.", [lambda id: False]))
})

def insert_problem(problem):
    """
    Inserts a problem into the database. Does sane validation.

    Args:
        Problem dict.
        basescore: points awarded for completing the problem.
        category: problem's category
        desc: description of the problem.
        grader: path relative to grader_base_path
        threshold: Amount of points necessary for a team to unlock this problem.

        Optional:
        disabled: True or False. Defaults to False.
        hint: hint for completing the problem.
        pid: if you care to manually specify a pid
        tags: list of problem tags.
        relatedproblems: list of related problems.
        weightmap: problem's unlock weightmap
        autogen: Whether or not the problem will be auto generated.
    Returns:
        The newly created problem id.
        """

    db = api.common.get_conn()
    validate(problem_schema, problem)

    problem["disabled"] = problem.get("disabled", False)

    if problem.get("pid", None) is None:
        problem["pid"] = api.common.token()

    #TODO: We should not depend on exceptions for this
    try:
        get_problem(name=problem["displayname"])
        raise APIException(0, None, "Problem with identical displayname already exists.")
    except APIException:
        pass

    try:
        get_problem(pid=problem["pid"])
        raise APIException(0, None, "Problem with identical pid already exists.")
    except APIException:
        pass

    db.problems.insert(problem)

    return problem["pid"]

def remove_problem(pid):
    """
    Removes a problem from the given database.

    Args:
        pid: the pid of the problem to remove.
    Returns:
        The removed problem object.
    """

    db = api.common.get_conn()
    problem = get_problem(pid=pid)

    db.problems.remove({"pid": pid})

    return problem

def set_problem_disabled(pid, disabled):
    """
    Updates a problem's availability.
{'fraction_non_alphanumeric': 0.12046726697493307, 'fraction_numerical': 0.007179362375273789, 'mean_word_length': 2.9419664268585133, 'pattern_counts': {'":': 18, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5586491', 'n_tokens_mistral': 2396, 'n_tokens_neox': 2318, 'n_words': 890}