コード例 #1
0
def delete_collection(identifier: str):
    """
    Delete a collection.

    Can be deleted only by an owner or user with DATA_MANAGEMENT permissions.

    Args:
        identifier (str): The collection uuid.
    """
    perm_status = utils.req_check_permissions(["DATA_EDIT"])
    if perm_status != 200:
        flask.abort(status=perm_status)

    entry = utils.req_get_entry("collections", identifier)
    if not entry:
        flask.abort(status=404)

    # permission check
    if (not utils.req_has_permission("DATA_MANAGEMENT")
            and flask.g.current_user["_id"] not in entry["editors"]):
        flask.abort(status=403)

    result = utils.req_commit_to_db("collections", "delete",
                                    {"_id": entry["_id"]})
    if not result.log or not result.data:
        flask.abort(status=500)
    return flask.Response(status=200)
コード例 #2
0
def get_user_data(identifier: str):
    """
    Get information about a user.

    Args:
        identifier (str): The user identifier.

    Returns:
        flask.Response: Information about the user as json.
    """
    perm_status = utils.req_check_permissions(["USER_MANAGEMENT"])
    if perm_status != 200:
        flask.abort(status=perm_status)

    user_info = utils.req_get_entry("users", identifier)
    if not user_info:
        flask.abort(status=404)

    # The hash and salt should never leave the system
    del user_info["api_key"]
    del user_info["api_salt"]

    user_info["permissions"] = utils.prepare_permissions(
        user_info["permissions"])

    return utils.response_json({"user": user_info})
コード例 #3
0
def get_user_actions(identifier: str):
    """
    Get a list of actions (changes) by the user entry with ``identifier``.

    Can be accessed by actual user and USER_MANAGEMENT.

    Args:
        identifier (str): The user identifier.

    Returns:
        flask.Response: Information about the user as json.
    """
    if identifier != (flask.g.current_user["_id"] or None):
        perm_status = utils.req_check_permissions(["USER_MANAGEMENT"])
        if perm_status != 200:
            flask.abort(status=perm_status)

    # only report a list of actions, not the actual data
    user_logs = list(flask.g.db["logs"].find({"user": identifier},
                                             {"user": 0}))

    for entry in user_logs:
        entry["entry_id"] = entry["data"]["_id"]
        del entry["data"]

    return utils.response_json({"logs": user_logs})
コード例 #4
0
def gen_new_api_key(identifier: str = None):
    """
    Generate a new API key for the provided or current user.

    Args:
        identifier (str): The user identifier.

    Returns:
        flask.Response: The new API key
    """
    if identifier != flask.g.current_user["_id"]:
        perm_status = utils.req_check_permissions(["USER_MANAGEMENT"])
        if perm_status != 200:
            flask.abort(status=perm_status)

    user_data = utils.req_get_entry("users", identifier)
    if not user_data:
        flask.abort(status=404)

    apikey = utils.gen_api_key()
    new_hash = utils.gen_api_key_hash(apikey.key, apikey.salt)
    new_values = {"api_key": new_hash, "api_salt": apikey.salt}
    user_data.update(new_values)
    result = flask.g.db["users"].update_one({"_id": identifier},
                                            {"$set": new_values})
    if not result.acknowledged:
        flask.current_app.logger.error("Updating API key for user %s failed",
                                       identifier)
        flask.Response(status=500)
    else:
        utils.make_log("user", "edit", "New API key", user_data)

    return utils.response_json({"key": apikey.key})
コード例 #5
0
def prepare():
    """
    All order request require ``DATA_EDIT``.

    Make sure that the user is logged in and has the required permission.
    """
    perm_status = utils.req_check_permissions(["DATA_EDIT"])
    if perm_status != 200:
        flask.abort(status=perm_status)
コード例 #6
0
def delete_dataset(identifier: str):
    """
    Delete a dataset.

    Can be deleted only by editors or user with DATA_MANAGEMENT permissions.

    Args:
        identifier (str): The dataset uuid.
    """
    perm_status = utils.req_check_permissions(["DATA_EDIT"])
    if perm_status != 200:
        flask.abort(status=perm_status)

    ds = utils.req_get_entry("datasets", identifier)
    if not ds:
        flask.abort(status=404)

    # permission check
    order = flask.g.db["orders"].find_one({"datasets": ds["_id"]})
    if not order:
        flask.current_app.logger.error("Dataset without parent order: %s", ds["_id"])
        flask.current_app.logger.error(ds)
    # permission check
    if (
        not utils.req_has_permission("DATA_MANAGEMENT")
        and flask.g.current_user["_id"] not in order["editors"]
    ):
        flask.abort(status=403)

    result = utils.req_commit_to_db("datasets", "delete", {"_id": ds["_id"]})
    if not result.log or not result.data:
        flask.abort(status=500)

    collections = list(flask.g.db["collections"].find({"datasets": ds["_id"]}))
    flask.g.db["collections"].update_many({}, {"$pull": {"datasets": ds["_id"]}})
    for collection in collections:
        collection["datasets"] = [collection["datasets"].remove(ds["_id"])]
        utils.req_make_log_new(
            data_type="collection",
            action="edit",
            comment="Dataset deleted",
            data=collection,
        )

    flask.g.db["orders"].update_many({}, {"$pull": {"datasets": ds["_id"]}})
    order["datasets"].remove(ds["_id"])
    utils.req_make_log_new(
        data_type="order",
        action="edit",
        comment="Dataset deleted",
        data=order,
    )

    return flask.Response(status=200)
コード例 #7
0
def update_dataset(identifier):
    """
    Update a dataset with new values.

    Args:
        identifier (str): uuid for the wanted dataset

    Returns:
        flask.Response: success: 200, failure: 400
    """
    perm_status = utils.req_check_permissions(["DATA_EDIT"])
    if perm_status != 200:
        flask.abort(status=perm_status)

    dataset = utils.req_get_entry("datasets", identifier)
    if not dataset:
        flask.abort(status=404)
    # permissions
    order = flask.g.db["orders"].find_one({"datasets": dataset["_id"]})
    if (
        not utils.req_has_permission("DATA_MANAGEMENT")
        and flask.g.current_user["_id"] not in order["editors"]
    ):
        flask.abort(status=403)

    jsondata = flask.request.json
    if not jsondata or "dataset" not in jsondata or not isinstance(jsondata["dataset"], dict):
        flask.abort(status=400)
    indata = jsondata["dataset"]

    validation = utils.basic_check_indata(indata, dataset, prohibited=("_id"))
    if not validation.result:
        flask.abort(status=validation.status)

    indata = utils.prepare_for_db(indata)

    is_different = False
    for field in indata:
        if indata[field] != dataset[field]:
            is_different = True
            break

    dataset.update(indata)

    if indata and is_different:
        result = utils.req_commit_to_db("datasets", "edit", dataset)
        if not result.log or not result.data:
            flask.abort(status=500)

    return flask.Response(status=200)
コード例 #8
0
def update_user_info(identifier: str):
    """
    Update the information about a user.

    Requires USER_MANAGEMENT.

    Args:
        identifier (str): The uuid of the user to modify.

    Returns:
        flask.Response: Response code.
    """
    perm_status = utils.req_check_permissions(["USER_MANAGEMENT"])
    if perm_status != 200:
        flask.abort(status=perm_status)

    user_data = utils.req_get_entry("users", identifier)
    if not user_data:
        flask.abort(status=404)

    jsondata = flask.request.json
    if not jsondata.get("user") or not isinstance(jsondata["user"], dict):
        flask.abort(status=400)
    indata = jsondata["user"]

    validation = utils.basic_check_indata(
        indata, user_data, ("_id", "api_key", "api_salt", "auth_ids"))
    if not validation.result:
        flask.abort(status=validation.status)

    if "email" in indata:
        old_user = flask.g.db["users"].find_one({"email": indata["email"]})
        if old_user and old_user.get("_id") != user_data["_id"]:
            flask.current_app.logger.debug("User already exists")
            flask.abort(status=409)

    # Avoid "updating" and making log if there are no changes
    is_different = False
    for field in indata:
        if indata[field] != user_data[field]:
            is_different = True
            break
    user_data.update(indata)

    if is_different:
        result = utils.req_commit_to_db("users", "edit", user_data)
        if not result.log or not result.data:
            flask.abort(status=500)

    return flask.Response(status=200)
コード例 #9
0
def add_user():
    """
    Add a user.

    Returns:
        flask.Response: Information about the user as json.
    """
    perm_status = utils.req_check_permissions(["USER_ADD"])
    if perm_status != 200:
        flask.abort(status=perm_status)

    new_user = structure.user()
    jsondata = flask.request.json
    if not jsondata.get("user") or not isinstance(jsondata["user"], dict):
        flask.abort(status=400)
    indata = jsondata["user"]

    validation = utils.basic_check_indata(
        indata, new_user, ("_id", "api_key", "api_salt", "auth_ids"))
    if not validation.result:
        flask.abort(status=validation.status)

    indata = utils.prepare_for_db(indata)
    if not indata:
        flask.abort(status=400)

    if "email" not in indata:
        flask.current_app.logger.debug("Email must be set")
        flask.abort(status=400)

    old_user = flask.g.db["users"].find_one({"email": indata["email"]})
    if old_user:
        flask.current_app.logger.debug("User already exists")
        flask.abort(status=400)

    if not utils.req_has_permission(
            "USER_MANAGEMENT") and "permissions" in indata:
        flask.current_app.logger.debug(
            "USER_MANAGEMENT required for permissions")
        flask.abort(403)

    new_user.update(indata)

    new_user["auth_ids"] = [new_user["email"]]

    result = utils.req_commit_to_db("users", "add", new_user)
    if not result.log or not result.data:
        flask.abort(status=500)

    return utils.response_json({"_id": result.ins_id})
コード例 #10
0
def list_users():
    """List all users."""
    perm_status = utils.req_check_permissions(["USER_SEARCH"])
    if perm_status != 200:
        flask.abort(status=perm_status)

    fields = {"api_key": 0, "api_salt": 0}

    if not utils.req_has_permission("USER_MANAGEMENT"):
        fields["auth_ids"] = 0
        fields["permissions"] = 0

    result = tuple(flask.g.db["users"].find(projection=fields))

    return utils.response_json({"users": result})
コード例 #11
0
def add_collection():
    """
    Add a collection.

    Returns:
        flask.Response: Json structure with the ``_id`` of the collection.
    """
    perm_status = utils.req_check_permissions(["DATA_EDIT"])
    if perm_status != 200:
        flask.abort(status=perm_status)

    # create new collection
    collection = structure.collection()

    jsondata = flask.request.json
    if not jsondata or "collection" not in jsondata or not isinstance(
            jsondata["collection"], dict):
        flask.abort(status=400)
    indata = jsondata["collection"]

    # indata validation
    validation = utils.basic_check_indata(indata,
                                          collection,
                                          prohibited=["_id"])
    if not validation.result:
        flask.abort(status=validation.status)

    if not indata.get("editors"):
        indata["editors"] = [flask.g.current_user["_id"]]
    # add current user if missing and only DATA_EDIT
    elif (not utils.req_has_permission("DATA_MANAGEMENT")
          and str(flask.g.current_user["_id"]) not in indata["editors"]):
        indata["editors"].append(flask.g.current_user["_id"])

    indata = utils.prepare_for_db(indata)

    collection.update(indata)

    # add to db
    result = utils.req_commit_to_db("collections", "add", collection)
    if not result.log or not result.data:
        flask.abort(status=500)

    return utils.response_json({"_id": result.ins_id})
コード例 #12
0
def get_dataset_log(identifier: str = None):
    """
    Get change logs for the user entry with uuid ``identifier``.

    Can be accessed by editors with DATA_EDIT and admin (DATA_MANAGEMENT).

    Logs for deleted datasets cannot be accessed.

    Args:
        identifier (str): The uuid of the dataset.

    Returns:
        flask.Response: Logs as json.
    """
    perm_status = utils.req_check_permissions(["DATA_EDIT"])
    if perm_status != 200:
        flask.abort(status=perm_status)

    dataset = utils.req_get_entry("datasets", identifier)
    if not dataset:
        flask.abort(status=404)

    order_data = flask.g.db["orders"].find_one({"datasets": dataset["_id"]})
    if not order_data:
        flask.current_app.logger.error("Dataset without parent order: %s", dataset["_id"])
        flask.abort(500)

    if (
        not utils.req_has_permission("DATA_MANAGEMENT")
        and flask.g.current_user["_id"] not in order_data["editors"]
    ):
        flask.abort(403)

    dataset_logs = list(
        flask.g.db["logs"].find({"data_type": "dataset", "data._id": dataset["_id"]})
    )
    for log in dataset_logs:
        del log["data_type"]

    utils.incremental_logs(dataset_logs)

    return utils.response_json(
        {"entry_id": dataset["_id"], "data_type": "dataset", "logs": dataset_logs}
    )
コード例 #13
0
def get_collection_log(identifier: str = None):
    """
    Get change logs for the collection matching ``identifier``.

    Can be accessed by editors (with DATA_EDIT) and admin (DATA_MANAGEMENT).

    Deleted entries cannot be accessed.

    Args:
        identifier (str): The uuid of the collection.

    Returns:
        flask.Response: Logs as json.
    """
    perm_status = utils.req_check_permissions(["DATA_EDIT"])
    if perm_status != 200:
        flask.abort(status=perm_status)

    collection = utils.req_get_entry("collections", identifier)
    if not collection:
        flask.abort(status=404)
    if (not utils.req_has_permission("DATA_MANAGEMENT")
            and flask.g.current_user["_id"] not in collection["editors"]):
        flask.abort(403)

    collection_logs = list(flask.g.db["logs"].find({
        "data_type":
        "collection",
        "data._id":
        collection["_id"]
    }))

    for log in collection_logs:
        del log["data_type"]

    utils.incremental_logs(collection_logs)

    return utils.response_json({
        "entry_id": collection["_id"],
        "data_type": "collection",
        "logs": collection_logs,
    })
コード例 #14
0
def delete_user(identifier: str):
    """
    Delete a user.

    Args:
        identifier (str): The user identifier.

    Returns:
        flask.Response: Response code.
    """
    perm_status = utils.req_check_permissions(["USER_MANAGEMENT"])
    if perm_status != 200:
        flask.abort(status=perm_status)

    user_info = utils.req_get_entry("users", identifier)
    if not user_info:
        flask.abort(status=404)

    result = utils.req_commit_to_db("users", "delete", {"_id": identifier})
    if not result.log or not result.data:
        flask.abort(status=500)

    return flask.Response(status=200)
コード例 #15
0
def get_user_log(identifier: str):
    """
    Get change logs for the user entry with uuid ``identifier``.

    Can be accessed by actual user and admin (USER_MANAGEMENT).

    Args:
        identifier (str): The user identifier.

    Returns:
        flask.Response: Information about the user as json.
    """
    if identifier != (flask.g.current_user["_id"] or None):
        perm_status = utils.req_check_permissions(["USER_MANAGEMENT"])
        if perm_status != 200:
            flask.abort(status=perm_status)

    user_logs = list(flask.g.db["logs"].find({
        "data_type": "user",
        "data._id": identifier
    }))

    for log in user_logs:
        del log["data_type"]

    utils.incremental_logs(user_logs)
    for i in range(len(user_logs)):
        for key in ("api_key", "api_salt"):
            if key in user_logs[i]["data"]:
                user_logs[i]["data"][key] = "<hidden>"

    return utils.response_json({
        "entry_id": identifier,
        "data_type": "user",
        "logs": user_logs
    })
コード例 #16
0
def update_collection(identifier):
    """
    Update a collection.

    Args:
        identifier (str): The collection uuid.

    Returns:
        flask.Response: Status code.
    """
    perm_status = utils.req_check_permissions(["DATA_EDIT"])
    if perm_status != 200:
        flask.abort(status=perm_status)

    collection = utils.req_get_entry("collections", identifier)
    if not collection:
        flask.abort(status=404)

    jsondata = flask.request.json
    if not jsondata or "collection" not in jsondata or not isinstance(
            jsondata["collection"], dict):
        flask.abort(status=400)
    indata = jsondata["collection"]

    # permission check
    if (not utils.req_has_permission("DATA_MANAGEMENT")
            and flask.g.current_user["_id"] not in collection["editors"]):
        flask.current_app.logger.debug(
            "Unauthorized update attempt (collection %s, user %s)",
            collection["_id"],
            flask.g.current_user["_id"],
        )
        flask.abort(status=403)

    # indata validation
    validation = utils.basic_check_indata(indata,
                                          collection,
                                          prohibited=["_id"])
    if not validation.result:
        flask.abort(status=validation.status)

    # DATA_EDIT may not delete itself from editors
    if (not utils.req_has_permission("DATA_MANAGEMENT")
            and indata.get("editors")
            and str(flask.g.current_user["_id"]) not in indata["editors"]):
        flask.abort(status=400)

    indata = utils.prepare_for_db(indata)

    is_different = False
    for field in indata:
        if indata[field] != collection[field]:
            is_different = True
            break

    if indata and is_different:
        collection.update(indata)
        result = utils.req_commit_to_db("collections", "edit", collection)
        if not result.log or not result.data:
            flask.abort(status=500)

    return flask.Response(status=200)