def test_get_asset_nonadmin_access(client):
    """Without being an admin, test correct responses when accessing one asset."""
    with UserContext("*****@*****.**") as prosumer1:
        prosumer1_assets = prosumer1.assets
    with UserContext("*****@*****.**") as prosumer2:
        prosumer2_assets = prosumer2.assets
    headers = {
        "content-type":
        "application/json",
        "Authorization":
        get_auth_token(client, "*****@*****.**", "testtest"),
    }

    # okay to look at own asset
    asset_response = client.get(
        url_for("flexmeasures_api_v2_0.get_asset", id=prosumer2_assets[0].id),
        headers=headers,
        follow_redirects=True,
    )
    assert asset_response.status_code == 200
    # not okay to see assets owned by others
    asset_response = client.get(
        url_for("flexmeasures_api_v2_0.get_asset", id=prosumer1_assets[0].id),
        headers=headers,
        follow_redirects=True,
    )
    assert asset_response.status_code == 403
    # proper 404 for non-existing asset
    asset_response = client.get(
        url_for("flexmeasures_api_v2_0.get_asset", id=8171766575),
        headers=headers,
        follow_redirects=True,
    )
    assert asset_response.status_code == 404
    assert "not found" in asset_response.json["message"]
Esempio n. 2
0
def test_get_asset_nonaccount_access(client, setup_api_test_data):
    """Without being on the same account, test correct responses when accessing one asset."""
    with UserContext("*****@*****.**") as prosumer1:
        prosumer1_assets = prosumer1.account.generic_assets
    with UserContext("*****@*****.**") as supplieruser4:
        supplieruser4_assets = supplieruser4.account.generic_assets
    headers = {
        "content-type": "application/json",
        "Authorization": get_auth_token(
            client, "*****@*****.**", "testtest"
        ),
    }

    # okay to look at assets in own account
    asset_response = client.get(
        url_for("AssetAPI:fetch_one", id=supplieruser4_assets[0].id),
        headers=headers,
        follow_redirects=True,
    )
    assert asset_response.status_code == 200
    # not okay to see assets owned by other accounts
    asset_response = client.get(
        url_for("AssetAPI:fetch_one", id=prosumer1_assets[0].id),
        headers=headers,
        follow_redirects=True,
    )
    assert asset_response.status_code == 403
    # proper 404 for non-existing asset
    asset_response = client.get(
        url_for("AssetAPI:fetch_one", id=8171766575),
        headers=headers,
        follow_redirects=True,
    )
    assert asset_response.status_code == 404
    assert "not found" in asset_response.json["message"]
def test_edit_user(client):
    with UserContext("*****@*****.**") as supplier:
        supplier_auth_token = supplier.get_auth_token()  # supplier is no admin
        supplier_id = supplier.id
    with UserContext("*****@*****.**") as prosumer:
        prosumer_auth_token = prosumer.get_auth_token()  # prosumer is an admin
        prosumer_id = prosumer.id
    # without being the user themselves or an admin, the user cannot be edited
    user_edit_response = client.patch(
        url_for("flexmeasures_api_v2_0.patch_user", id=prosumer_id),
        headers={
            "content-type": "application/json",
            "Authorization": supplier_auth_token,
        },
        json={},
    )
    assert user_edit_response.status_code == 403
    user_edit_response = client.patch(
        url_for("flexmeasures_api_v2_0.patch_user", id=supplier_id),
        headers={"content-type": "application/json"},
        json={},
    )
    assert user_edit_response.status_code == 401
    # admin can deactivate supplier, other changes will be ignored
    # (id is in the Userschema of the API, but we ignore it)
    headers = {
        "content-type": "application/json",
        "Authorization": prosumer_auth_token
    }
    user_edit_response = client.patch(
        url_for("flexmeasures_api_v2_0.patch_user", id=supplier_id),
        headers=headers,
        json={
            "active": False,
            "id": 888
        },
    )
    print("Server responded with:\n%s" % user_edit_response.json)
    assert user_edit_response.status_code == 200
    assert user_edit_response.json["active"] is False
    supplier = find_user_by_email("*****@*****.**")
    assert supplier.active is False
    assert supplier.id == supplier_id
    # admin can edit themselves but not sensitive fields
    headers = {
        "content-type": "application/json",
        "Authorization": prosumer_auth_token
    }
    user_edit_response = client.patch(
        url_for("flexmeasures_api_v2_0.patch_user", id=prosumer_id),
        headers=headers,
        json={"active": False},
    )
    print("Server responded with:\n%s" % user_edit_response.json)
    assert user_edit_response.status_code == 403
Esempio n. 4
0
def test_alter_an_asset(client, setup_api_test_data, setup_accounts):
    # without being an account-admin, no asset can be created ...
    with UserContext("*****@*****.**") as prosumer1:
        auth_token = prosumer1.get_auth_token()  # not an account admin
    with AccountContext("Test Prosumer Account") as prosumer:
        prosumer_asset = prosumer.generic_assets[0]
    asset_creation_response = client.post(
        url_for("AssetAPI:post"),
        headers={"content-type": "application/json", "Authorization": auth_token},
        json={},
    )
    print(f"Creation Response: {asset_creation_response.json}")
    assert asset_creation_response.status_code == 403
    # ... or deleted ...
    asset_delete_response = client.delete(
        url_for("AssetAPI:delete", id=prosumer_asset.id),
        headers={"content-type": "application/json", "Authorization": auth_token},
        json={},
    )
    print(f"Deletion Response: {asset_delete_response.json}")
    assert asset_delete_response.status_code == 403
    # ... but editing is allowed.
    asset_edit_response = client.patch(
        url_for("AssetAPI:patch", id=prosumer_asset.id),
        headers={"content-type": "application/json", "Authorization": auth_token},
        json={
            "latitude": prosumer_asset.latitude
        },  # we're not changing values to keep other tests clean here
    )
    print(f"Editing Response: {asset_edit_response.json}")
    assert asset_edit_response.status_code == 200
def test_alter_an_asset_wrongauth(client):
    # without admin and owner rights, no asset can be created ...
    with UserContext("*****@*****.**") as prosumer1:
        prosumer1_asset = prosumer1.assets[0]
    with UserContext("*****@*****.**") as prosumer2:
        auth_token = prosumer2.get_auth_token()
        prosumer2_asset = prosumer2.assets[0]
    asset_creation_response = client.post(
        url_for("flexmeasures_api_v2_0.post_assets"),
        headers={
            "content-type": "application/json",
            "Authorization": auth_token
        },
        json={},
    )
    print(f"Response: {asset_creation_response.json}")
    assert asset_creation_response.status_code == 403
    # ... or edited ...
    asset_edit_response = client.patch(
        url_for("flexmeasures_api_v2_0.patch_asset", id=prosumer1_asset.id),
        headers={
            "content-type": "application/json",
            "Authorization": auth_token
        },
        json={},
    )
    assert asset_edit_response.status_code == 403
    # ... or deleted ...
    asset_delete_response = client.delete(
        url_for("flexmeasures_api_v2_0.delete_asset", id=prosumer1_asset.id),
        headers={
            "content-type": "application/json",
            "Authorization": auth_token
        },
        json={},
    )
    assert asset_delete_response.status_code == 403
    # ... which is impossible even if you're the owner
    asset_delete_response = client.delete(
        url_for("flexmeasures_api_v2_0.delete_asset", id=prosumer2_asset.id),
        headers={
            "content-type": "application/json",
            "Authorization": auth_token
        },
        json={},
    )
    assert asset_delete_response.status_code == 403
def test_edit_user(client):
    with UserContext("*****@*****.**") as user2:
        user2_auth_token = user2.get_auth_token()  # user2 is no admin
        user2_id = user2.id
    with UserContext("*****@*****.**") as admin:
        admin_auth_token = admin.get_auth_token()
        admin_id = admin.id
    # without being the user themselves or an admin, the user cannot be edited
    user_edit_response = client.patch(
        url_for("UserAPI:patch", id=admin_id),
        headers={
            "content-type": "application/json",
            "Authorization": user2_auth_token,
        },
        json={},
    )
    assert user_edit_response.status_code == 403
    user_edit_response = client.patch(
        url_for("UserAPI:patch", id=user2_id),
        headers={"content-type": "application/json"},
        json={},
    )
    assert user_edit_response.status_code == 401
    # admin can deactivate user2
    admin_headers = {
        "content-type": "application/json",
        "Authorization": admin_auth_token,
    }
    user_edit_response = client.patch(
        url_for("UserAPI:patch", id=user2_id),
        headers=admin_headers,
        json={"active": False},
    )
    print("Server responded with:\n%s" % user_edit_response.json)
    assert user_edit_response.status_code == 200
    assert user_edit_response.json["active"] is False
    user2 = find_user_by_email("*****@*****.**")
    assert user2.active is False
    assert user2.id == user2_id
    # admin can edit themselves but not sensitive fields
    user_edit_response = client.patch(
        url_for("UserAPI:patch", id=admin_id),
        headers=admin_headers,
        json={"active": False},
    )
    print("Server responded with:\n%s" % user_edit_response.json)
    assert user_edit_response.status_code == 403
def test_edit_user_with_unexpected_fields(client):
    """Sending unexpected fields (not in Schema) is an Unprocessible Entity error."""
    with UserContext("*****@*****.**") as supplier:
        supplier_id = supplier.id
    with UserContext("*****@*****.**") as prosumer:
        prosumer_auth_token = prosumer.get_auth_token()  # prosumer is an admin
    user_edit_response = client.patch(
        url_for("flexmeasures_api_v2_0.patch_user", id=supplier_id),
        headers={
            "content-type": "application/json",
            "Authorization": prosumer_auth_token,
        },
        json={
            "active": False,
            "password": "******"
        },
    )
    print("Server responded with:\n%s" % user_edit_response.json)
    assert user_edit_response.status_code == 422
def test_edit_user_with_unexpected_fields(client, unexpected_fields: dict):
    """Sending unexpected fields (not in Schema) is an Unprocessable Entity error."""
    with UserContext("*****@*****.**") as user2:
        user2_id = user2.id
    with UserContext("*****@*****.**") as admin:
        admin_auth_token = admin.get_auth_token()
    user_edit_response = client.patch(
        url_for("UserAPI:patch", id=user2_id),
        headers={
            "content-type": "application/json",
            "Authorization": admin_auth_token,
        },
        json={
            **{
                "active": False
            },
            **unexpected_fields
        },
    )
    print("Server responded with:\n%s" % user_edit_response.json)
    assert user_edit_response.status_code == 422
def test_post_an_asset_with_existing_name(client):
    """Catch DB error (Unique key violated) correctly"""
    with UserContext("*****@*****.**") as prosumer:
        auth_token = prosumer.get_auth_token()
    with UserContext("*****@*****.**") as prosumer:
        test_prosumer_id = prosumer.id
        existing_asset = prosumer.assets[0]
    post_data = get_asset_post_data()
    post_data["name"] = existing_asset.name
    post_data["owner_id"] = test_prosumer_id
    asset_creation = client.post(
        url_for("flexmeasures_api_v2_0.post_assets"),
        json=post_data,
        headers={
            "content-type": "application/json",
            "Authorization": auth_token
        },
    )
    assert asset_creation.status_code == 422
    assert "already exists" in asset_creation.json["message"]["json"]["name"][
        0]
Esempio n. 10
0
def test_post_an_asset_with_nonexisting_field(client, setup_api_test_data):
    """Posting a field that is unexpected leads to a 422"""
    with UserContext("*****@*****.**") as prosumer:
        auth_token = prosumer.get_auth_token()
    post_data = get_asset_post_data()
    post_data["nnname"] = "This field does not exist"
    asset_creation = client.post(
        url_for("AssetAPI:post"),
        json=post_data,
        headers={"content-type": "application/json", "Authorization": auth_token},
    )
    assert asset_creation.status_code == 422
    assert asset_creation.json["message"]["json"]["nnname"][0] == "Unknown field."
Esempio n. 11
0
def test_posting_multiple_assets(client, setup_api_test_data):
    """We can only send one at a time"""
    with UserContext("*****@*****.**") as prosumer:
        auth_token = prosumer.get_auth_token()
    post_data1 = get_asset_post_data()
    post_data2 = get_asset_post_data()
    post_data2["name"] = "Test battery 3"
    asset_creation = client.post(
        url_for("AssetAPI:post"),
        json=[post_data1, post_data2],
        headers={"content-type": "application/json", "Authorization": auth_token},
    )
    print(f"Response: {asset_creation.json}")
    assert asset_creation.status_code == 422
    assert asset_creation.json["message"]["json"]["_schema"][0] == "Invalid input type."
Esempio n. 12
0
def test_delete_an_asset(client, db):
    with UserContext("*****@*****.**") as prosumer:
        existing_asset_id = prosumer.assets[0].id

    auth_token = get_auth_token(client, "*****@*****.**", "testtest")
    delete_asset_response = client.delete(
        url_for("flexmeasures_api_v2_0.delete_asset", id=existing_asset_id),
        headers={
            "content-type": "application/json",
            "Authorization": auth_token
        },
    )
    assert delete_asset_response.status_code == 204
    deleted_asset = Asset.query.filter_by(id=existing_asset_id).one_or_none()
    assert deleted_asset is None
Esempio n. 13
0
def test_post_an_asset_with_existing_name(client, setup_api_test_data):
    """Catch DB error (Unique key violated) correctly"""
    with UserContext("*****@*****.**") as admin_user:
        auth_token = admin_user.get_auth_token()
    with AccountContext("Test Prosumer Account") as prosumer:
        prosumer_id = prosumer.id
        existing_asset = prosumer.generic_assets[0]
    post_data = get_asset_post_data()
    post_data["name"] = existing_asset.name
    post_data["account_id"] = prosumer_id
    asset_creation_response = client.post(
        url_for("AssetAPI:post"),
        json=post_data,
        headers={"content-type": "application/json", "Authorization": auth_token},
    )
    print(f"Creation Response: {asset_creation_response.json}")
    assert asset_creation_response.status_code == 422
    assert (
        "already exists" in asset_creation_response.json["message"]["json"]["name"][0]
    )
Esempio n. 14
0
def test_edit_an_asset(client, db):
    with UserContext("*****@*****.**") as prosumer:
        existing_asset = prosumer.assets[1]

    post_data = dict(latitude=10, id=999)  # id will be ignored
    auth_token = get_auth_token(client, "*****@*****.**", "testtest")
    edit_asset_response = client.patch(
        url_for("flexmeasures_api_v2_0.patch_asset", id=existing_asset.id),
        json=post_data,
        headers={
            "content-type": "application/json",
            "Authorization": auth_token
        },
    )
    assert edit_asset_response.status_code == 200
    updated_asset = Asset.query.filter_by(id=existing_asset.id).one_or_none()
    assert updated_asset.latitude == 10  # changed value
    assert updated_asset.longitude == existing_asset.longitude
    assert updated_asset.capacity_in_mw == existing_asset.capacity_in_mw
    assert updated_asset.name == existing_asset.name
Esempio n. 15
0
def test_post_an_asset_with_invalid_data(client, db):
    """
    Add an asset with some fields having invalid data and one field missing.
    The right error messages should be in the response and the number of assets has not increased.
    """
    with UserContext("*****@*****.**") as prosumer:
        num_assets_before = len(prosumer.assets)

    auth_token = get_auth_token(client, "*****@*****.**", "testtest")

    post_data = get_asset_post_data()
    post_data["latitude"] = 70.4
    post_data["longitude"] = 300.9
    post_data["capacity_in_mw"] = -100
    post_data["min_soc_in_mwh"] = 10
    post_data["max_soc_in_mwh"] = 5
    del post_data["unit"]

    post_asset_response = client.post(
        url_for("flexmeasures_api_v2_0.post_assets"),
        json=post_data,
        headers={
            "content-type": "application/json",
            "Authorization": auth_token
        },
    )
    print("Server responded with:\n%s" % post_asset_response.json)
    assert post_asset_response.status_code == 422

    assert (
        "Must be greater than or equal to 0"
        in post_asset_response.json["message"]["json"]["capacity_in_mw"][0])
    assert ("greater than or equal to -180 and less than or equal to 180"
            in post_asset_response.json["message"]["json"]["longitude"][0])
    assert "required field" in post_asset_response.json["message"]["json"][
        "unit"][0]
    assert ("must be equal or higher than the minimum soc"
            in post_asset_response.json["message"]["json"]["max_soc_in_mwh"])

    assert Asset.query.filter_by(
        owner_id=prosumer.id).count() == num_assets_before
def test_user_reset_password(app, client, sender):
    """
    Reset the password of supplier.
    Only the prosumer is allowed to do that (as admin).
    """
    with UserContext("*****@*****.**") as supplier:
        supplier_id = supplier.id
        old_password = supplier.password
    headers = {"content-type": "application/json"}
    if sender != "":
        headers["Authorization"] = (get_auth_token(client, sender,
                                                   "testtest"), )
    with app.mail.record_messages() as outbox:
        pwd_reset_response = client.patch(
            url_for("flexmeasures_api_v2_0.reset_user_password",
                    id=supplier_id),
            query_string={},
            headers=headers,
        )
        print("Server responded with:\n%s" % pwd_reset_response.json)

        if sender == "":
            assert pwd_reset_response.status_code == 401
            return

        if sender == "*****@*****.**":
            assert pwd_reset_response.status_code == 403
            return

        assert pwd_reset_response.status_code == 200

        supplier = find_user_by_email("*****@*****.**")
        assert len(outbox) == 2
        assert "has been reset" in outbox[0].subject
        pwd_reset_instructions = outbox[1]
        assert old_password != supplier.password
        assert "reset instructions" in pwd_reset_instructions.subject
        assert ("reset your password:\n\n%sreset/" % request.host_url
                in pwd_reset_instructions.body)
def test_user_reset_password(app, client, setup_inactive_user, sender):
    """
    Reset the password of User 2.
    Only the admin user and User 2 themselves are allowed to do that.
    """
    with UserContext("*****@*****.**") as user2:
        user2_id = user2.id
        old_password = user2.password
    headers = {"content-type": "application/json"}
    if sender != "":
        headers["Authorization"] = (get_auth_token(client, sender, "testtest"),)
    with app.mail.record_messages() as outbox:
        pwd_reset_response = client.patch(
            url_for("UserAPI:reset_user_password", id=user2_id),
            query_string={},
            headers=headers,
        )
        print("Server responded with:\n%s" % pwd_reset_response.json)

        if sender in ("", "*****@*****.**"):
            assert pwd_reset_response.status_code == 401
            return
        if sender == "*****@*****.**":
            assert pwd_reset_response.status_code == 403
            return

        assert pwd_reset_response.status_code == 200

        user2 = find_user_by_email("*****@*****.**")
        assert len(outbox) == 2
        assert "has been reset" in outbox[0].subject
        pwd_reset_instructions = outbox[1]
        assert old_password != user2.password
        assert "reset instructions" in pwd_reset_instructions.subject
        assert (
            "reset your password:\n\n%sreset/" % request.host_url
            in pwd_reset_instructions.body
        )
Esempio n. 18
0
def test_post_an_asset_with_invalid_data(client, setup_api_test_data):
    """
    Add an asset with some fields having invalid data and one field missing.
    The right error messages should be in the response and the number of assets has not increased.
    """
    with UserContext("*****@*****.**") as prosumer:
        num_assets_before = len(prosumer.assets)

    auth_token = get_auth_token(client, "*****@*****.**", "testtest")

    post_data = get_asset_post_data()
    post_data["name"] = "Something new"
    post_data["longitude"] = 300.9
    del post_data["generic_asset_type_id"]

    post_asset_response = client.post(
        url_for("AssetAPI:post"),
        json=post_data,
        headers={"content-type": "application/json", "Authorization": auth_token},
    )
    print("Server responded with:\n%s" % post_asset_response.json)
    assert post_asset_response.status_code == 422

    assert (
        "exceeds the maximum longitude"
        in post_asset_response.json["message"]["json"]["longitude"][0]
    )
    assert (
        "required field"
        in post_asset_response.json["message"]["json"]["generic_asset_type_id"][0]
    )

    assert (
        GenericAsset.query.filter_by(account_id=prosumer.id).count()
        == num_assets_before
    )