def create_dataset():
    """Create a new dataset.

    **Example request**:

    .. sourcecode:: json

        {
            "name": "Mood",
            "description": "Dataset for mood classification.",
            "public": true,
            "classes": [
                {
                    "name": "Happy",
                    "description": "Recordings that represent happiness.",
                    "recordings": ["770cc467-8dde-4d22-bc4c-a42f91e"]
                },
                {
                    "name": "Sad"
                }
            ]
        }

    :reqheader Content-Type: *application/json*
    :<json string name: *Required.* Name of the dataset.
    :<json string description: *Optional.* Description of the dataset.
    :<json boolean public: *Optional.* ``true`` to make dataset public, ``false`` to make it private. New datasets are
        public by default.
    :<json array classes: *Optional.* Array of objects containing information about classes to add into new dataset. For
        example:

        .. sourcecode:: json

            {
                "name": "Happy",
                "description": "Recordings that represent happiness.",
                "recordings": ["770cc467-8dde-4d22-bc4c-a42f91e"]
            }


    :resheader Content-Type: *application/json*
    :>json boolean success: ``True`` on successful creation.
    :>json string dataset_id: ID (UUID) of newly created dataset.
    """
    dataset_dict = request.get_json()
    if not dataset_dict:
        raise api_exceptions.APIBadRequest("Data must be submitted in JSON format.")
    if "public" not in dataset_dict:
        dataset_dict["public"] = True
    if "classes" not in dataset_dict:
        dataset_dict["classes"] = []
    try:
        dataset_id = db.dataset.create_from_dict(dataset_dict, current_user.id)
    except dataset_validator.ValidationException as e:
        raise api_exceptions.APIBadRequest(e.message)

    return jsonify(
        success=True,
        dataset_id=dataset_id,
    )
Esempio n. 2
0
def submit_low_level(mbid):
    """Endpoint for submitting low-level information to AcousticBrainz."""
    raw_data = request.get_data()
    try:
        data = json.loads(raw_data.decode("utf-8"))
    except ValueError as e:
        raise exceptions.APIBadRequest("Cannot parse JSON document: %s" % e)

    try:
        submit_low_level_data(mbid, data, 'mbid')
    except BadDataException as e:
        raise exceptions.APIBadRequest("%s" % e)
    return jsonify({"message": "ok"})
Esempio n. 3
0
def delete_class(dataset_id):
    """Delete class and all of its recordings from a dataset.

    **Example request**:

    .. sourcecode:: json

        {
            "name": "Sad"
        }

    :reqheader Content-Type: *application/json*
    :<json string name: *Required.* Name of the class.

    :resheader Content-Type: *application/json*
    """
    ds = get_check_dataset(dataset_id, write=True)
    class_dict = request.get_json()

    try:
        dataset_validator.validate_class(class_dict, recordings_required=False)
    except dataset_validator.ValidationException as e:
        raise api_exceptions.APIBadRequest(e.error)

    db.dataset.delete_class(ds["id"], class_dict)
    return jsonify(success=True, message="Class deleted.")
Esempio n. 4
0
def update_dataset_details(dataset_id):
    """Update dataset details.

    If one of the fields is not specified, it will not be updated.

    **Example request**:

    .. sourcecode:: json

        {
            "name": "Not Mood",
            "description": "Dataset for mood misclassification.",
            "public": true
        }

    :reqheader Content-Type: *application/json*
    :<json string name: *Optional.* Name of the dataset.
    :<json string description: *Optional.* Description of the dataset.
    :<json boolean public: *Optional.* ``true`` to make dataset public, ``false`` to make it private.

    :resheader Content-Type: *application/json*
    """
    ds = get_check_dataset(dataset_id, write=True)
    dataset_data = request.get_json()

    try:
        dataset_validator.validate_dataset_update(dataset_data)
    except dataset_validator.ValidationException as e:
        raise api_exceptions.APIBadRequest(e.error)

    db.dataset.update_dataset_meta(ds["id"], dataset_data)
    return jsonify(success=True, message="Dataset updated.")
Esempio n. 5
0
def submit_low_level(mbid):
    """Endpoint for submitting low-level information to AcousticBrainz."""
    raw_data = request.get_data()
    try:
        data = json.loads(raw_data.decode("utf-8"))
    except ValueError as e:
        raise exceptions.APIBadRequest("Cannot parse JSON document: %s" % e)

    max_duplicate_submissions = current_app.config.get(
        'MAX_NUMBER_DUPLICATE_SUBMISSIONS', None)

    try:
        submit_low_level_data(mbid, data, 'mbid', max_duplicate_submissions)
    except BadDataException as e:
        raise exceptions.APIBadRequest("%s" % e)
    return jsonify({"message": "ok"})
Esempio n. 6
0
def delete_recordings(dataset_id):
    """Delete recordings from a class in a dataset.

    **Example request**:

    .. sourcecode:: json

        {
            "class_name": "Happy",
            "recordings": ["770cc467-8dde-4d22-bc4c-a42f91e"]
        }

    :reqheader Content-Type: *application/json*
    :<json string class_name: *Required.* Name of the class.
    :<json array recordings: *Required.* Array of recoding MBIDs (``string``) that need be deleted from a class.

    :resheader Content-Type: *application/json*
    """
    ds = get_check_dataset(dataset_id, write=True)
    class_dict = request.get_json()
    try:
        dataset_validator.validate_recordings_add_delete(class_dict)
    except dataset_validator.ValidationException as e:
        raise api_exceptions.APIBadRequest(e.error)

    unique_mbids = list(set(class_dict["recordings"]))
    class_dict["recordings"] = unique_mbids

    try:
        db.dataset.delete_recordings(ds["id"], class_dict["class_name"],
                                     class_dict["recordings"])
    except db.exceptions.NoDataFoundException as e:
        # NoDataFoundException is raised if the class name doesn't exist in this dataset.
        # We treat this as a bad request, because it's based on data in the request body,
        # and not the url
        raise api_exceptions.APIBadRequest(str(e))

    return jsonify(success=True, message="Recordings deleted.")
Esempio n. 7
0
def update_class(dataset_id):
    """Update class in a dataset.

    If one of the fields is not specified, it will not be updated.

    **Example request**:

    .. sourcecode:: json

        {
            "name": "Very happy",
            "new_name": "Recordings that represent ultimate happiness."
        }

    :reqheader Content-Type: *application/json*
    :<json string name: *Required.* Current name of the class.
    :<json string new_name: *Optional.* New name of the class. Must be unique within a dataset.
    :<json string description: *Optional.* Description of the class.

    :resheader Content-Type: *application/json*
    """
    ds = get_check_dataset(dataset_id, write=True)
    class_data = request.get_json()

    try:
        dataset_validator.validate_class_update(class_data)
    except dataset_validator.ValidationException as e:
        raise api_exceptions.APIBadRequest(e.error)

    try:
        db.dataset.update_class(ds["id"], class_data["name"], class_data)
    except db.exceptions.NoDataFoundException as e:
        # NoDataFoundException is raised if the class name doesn't exist in this dataset.
        # We treat this as a bad request, because it's based on data in the request body,
        # and not the url
        raise api_exceptions.APIBadRequest(str(e))

    return jsonify(success=True, message="Class updated.")
Esempio n. 8
0
def _validate_data_arguments(mbid, offset):
    """Validate the mbid and offset. If the mbid is not a valid uuid, raise 404.
    If the offset is None, return 0, otherwise interpret it as a number. If it is
    not a number, raise 400."""
    try:
        mbid = str(uuid.UUID(mbid))
    except ValueError:
        # an invalid uuid is 404
        raise exceptions.APINotFound("Not found")

    if offset:
        try:
            offset = int(offset)
        except ValueError:
            raise exceptions.APIBadRequest("Offset must be an integer value")
    else:
        offset = 0

    return mbid, offset
Esempio n. 9
0
def add_class(dataset_id):
    """Add a class to a dataset.

    The data can include an optional list of recording ids. If these are included,
    the recordings are also added to the list. Duplicate recording ids are ignored.

    If a class with the given name already exists, the recordings (if provided) will
    be added to the existing class.

    **Example request**:

    .. sourcecode:: json

        {
            "name": "Not Mood",
            "description": "Dataset for mood misclassification.",
            "recordings": ["770cc467-8dde-4d22-bc4c-a42f91e"]
        }

    :reqheader Content-Type: *application/json*
    :<json string name: *Required.* Name of the class. Must be unique within a dataset.
    :<json string description: *Optional.* Description of the class.
    :<json array recordings: *Optional.* Array of recording MBIDs (``string``) to add into that class. For example:
        ``["770cc467-8dde-4d22-bc4c-a42f91e"]``.


    :resheader Content-Type: *application/json*
    """
    ds = get_check_dataset(dataset_id, write=True)
    class_dict = request.get_json()

    try:
        dataset_validator.validate_class(class_dict, recordings_required=False)
    except dataset_validator.ValidationException as e:
        raise api_exceptions.APIBadRequest(e.error)

    if "recordings" in class_dict:
        unique_mbids = list(set(class_dict["recordings"]))
        class_dict["recordings"] = unique_mbids

    db.dataset.add_class(ds["id"], class_dict)
    return jsonify(success=True, message="Class added.")
Esempio n. 10
0
def get_jobs():
    """Return a list of jobs related to the current user.
       Identify the current user by being logged in or by passing a Token for authentication.

       :query status: *Required.* Status of jobs to be returned. Possible values: "pending"
       :query location: *Required.* Location that the user wants to evaluate jobs. Possible values: "remote"

       **Example Response**:

       .. sourcecode:: json

       {
           'username': '******'
           'jobs': [
               {
                   'dataset_name': 'test_dataset',
                   'created': 'Wed, 08 Jun 2016 21:41:58 GMT',
                   'job_id': '0fc553b6-f3a8-4e24-af39-56ac02276ed9'
               }
           ]
       }

    :reqheader Content-Type: *application/json*
    :<json string username:  MusicBrainz username of the user.
    :<json array jobs:       Jobs which match the query.
    """

    location = request.args.get("location")
    status = request.args.get("status")
    # TODO: This endpoint can be used in the future to get any type of job,
    #       but for now we only use it for pending/remote.
    if location != db.dataset_eval.EVAL_REMOTE or status != db.dataset_eval.STATUS_PENDING:
        raise exceptions.APIBadRequest(
            "parameter location must be 'remote' and status 'pending'")

    jobs = db.dataset_eval.get_remote_pending_jobs_for_user(current_user.id)
    return jsonify(username=current_user.musicbrainz_id, jobs=jobs)