Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ensysmod/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

from .endpoints import users, authentication, energy_sources, datasets, energy_commodities, energy_sinks, \
energy_storages, energy_transmissions, energy_conversions, regions, ts_capacity_max, ts_operation_rate_fix, \
ts_operation_rate_max, ts_capacity_fix, energy_models
ts_operation_rate_max, ts_capacity_fix, energy_models, datasets_permissions

api_router = APIRouter()
api_router.include_router(authentication.router, prefix="/auth", tags=["Authentication"])
api_router.include_router(users.router, prefix="/users", tags=["Users"])
api_router.include_router(datasets.router, prefix="/datasets", tags=["Datasets"])
api_router.include_router(datasets_permissions.router, prefix="/datasets/permissions", tags=["Dataset Permissions"])
api_router.include_router(regions.router, prefix="/regions", tags=["Regions"])
api_router.include_router(energy_commodities.router, prefix="/commodities", tags=["Commodities"])
api_router.include_router(energy_conversions.router, prefix="/conversions", tags=["Energy Conversions"])
Expand Down
17 changes: 8 additions & 9 deletions ensysmod/api/endpoints/datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from sqlalchemy.orm import Session

from ensysmod import schemas, model, crud
from ensysmod.api import deps
from ensysmod.api import deps, permissions
from ensysmod.core.file_download import export_data
from ensysmod.core.file_upload import process_dataset_zip_archive
from ensysmod.schemas import FileStatus
Expand All @@ -36,7 +36,6 @@ def get_dataset(dataset_id: int,
"""
Retrieve a dataset.
"""
# TODO Check if user has permission for dataset
return crud.dataset.get(db, dataset_id)


Expand All @@ -48,11 +47,11 @@ def create_dataset(request: schemas.DatasetCreate,
"""
Create a new dataset.
"""
# TODO Check if user has permission for dataset
existing_ds = crud.dataset.get_by_name(db=db, name=request.name)
if existing_ds is not None:
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=f"Dataset {request.name} already exists!")

raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=f"Dataset {request.name} already exists!"
f"Please choose a different name.")
request.ref_created_by = current.id
return crud.dataset.create(db=db, obj_in=request)


Expand All @@ -64,10 +63,10 @@ def update_dataset(dataset_id: int,
"""
Update a dataset.
"""
# TODO Check if user has permission for dataset
dataset = crud.dataset.get(db=db, id=dataset_id)
if dataset is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Dataset {dataset_id} not found!")
permissions.check_modification_permission(db=db, user=current, dataset_id=dataset_id)
return crud.dataset.update(db=db, db_obj=dataset, obj_in=request)


Expand All @@ -78,7 +77,7 @@ def remove_dataset(dataset_id: int,
"""
Delete a dataset.
"""
# TODO Check if user has permission for dataset
permissions.check_modification_permission(db=db, user=current, dataset_id=dataset_id)
# TODO remove all components, commodities, regions, etc.
return crud.dataset.remove(db=db, id=dataset_id)

Expand All @@ -96,7 +95,7 @@ def upload_zip_archive(dataset_id: int,
if dataset is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Dataset {dataset_id} not found!")

# TODO Check if user has permission for dataset
permissions.check_modification_permission(db=db, user=current, dataset_id=dataset_id)

with zipfile.ZipFile(BytesIO(file.file.read()), 'r') as zip_archive:
result = process_dataset_zip_archive(zip_archive, dataset_id, db)
Expand All @@ -118,7 +117,7 @@ def download_zip_archive(dataset_id: int,
if dataset is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Dataset {dataset_id} not found!")

# TODO Check if user has permission for dataset
permissions.check_usage_permission(db=db, user=current, dataset_id=dataset_id)

# create a temporary directory
time_str = datetime.now().strftime("%Y%m%d%H%M%S")
Expand Down
148 changes: 148 additions & 0 deletions ensysmod/api/endpoints/datasets_permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
from typing import List

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session

from ensysmod import schemas, model, crud
from ensysmod.api import deps

router = APIRouter()


@router.get("/", response_model=List[schemas.DatasetPermission])
def all_dataset_permission(db: Session = Depends(deps.get_db),
current: model.User = Depends(deps.get_current_user),
dataset_id: int = 0,
user_id: int = 0,
skip: int = 0,
limit: int = 100) -> List[schemas.DatasetPermission]:
"""
Retrieve all dataset permissions.

If you provide a dataset_id, only the permissions for that dataset will be returned.

If you provide a user_id, only the permissions for that user will be returned.

Otherwise, all of your personal permissions will be returned.
"""
if dataset_id != 0:
if not crud.dataset_permission.is_permission_check_allowed(db=db,
dataset_id=dataset_id,
user_id=current.id):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
detail="You have no permission to check permissions for this dataset.")
return crud.dataset_permission.get_by_dataset_id(db=db, dataset_id=dataset_id, skip=skip, limit=limit)

if user_id != 0:
if user_id != current.id:
# TODO Add admin permission to user, that allow this function
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
detail="You have no permission to check permissions for this user.")
return crud.dataset_permission.get_by_user_id(db=db, user_id=user_id, skip=skip, limit=limit)

return crud.dataset_permission.get_by_user_id(db=db, user_id=current.id, skip=skip, limit=limit)


@router.get("/{permission_id}", response_model=schemas.DatasetPermission)
def get_dataset_permission(permission_id: int,
db: Session = Depends(deps.get_db),
current: model.User = Depends(deps.get_current_user)):
"""
Retrieve a dataset-user permission.
"""
existing_permission = crud.dataset_permission.get(db, permission_id)
if existing_permission is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="Dataset permission not found for id {permission_id}.")

if not crud.dataset_permission.is_permission_check_allowed(db=db,
dataset_id=existing_permission.ref_dataset,
user_id=current.id):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
detail="You have no permission to check permissions for this dataset.")

return crud.dataset_permission.get(db, permission_id)


@router.post("/", response_model=schemas.DatasetPermission,
responses={409: {"description": "Dataset permission for same user already exists."}})
def create_dataset_permission(request: schemas.DatasetPermissionCreate,
db: Session = Depends(deps.get_db),
current: model.User = Depends(deps.get_current_user)):
"""
Create a new dataset_permission.
"""
if not crud.dataset_permission.is_permission_grant_allowed(db=db,
dataset_id=request.ref_dataset,
user_id=current.id):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
detail="You have no permission to grant permissions to other users for this dataset.")

permission = crud.dataset_permission.get_by_user_id(db=db, user_id=request.ref_user, dataset_id=request.ref_dataset)
if permission is not None:
raise HTTPException(status_code=status.HTTP_409_CONFLICT,
detail="Dataset permission for same user already exists.")

return crud.dataset_permission.create(db=db, obj_in=request)


@router.put("/{permission_id}", response_model=schemas.DatasetPermission)
def update_dataset_permission(permission_id: int,
request: schemas.DatasetPermissionUpdate,
db: Session = Depends(deps.get_db),
current: model.User = Depends(deps.get_current_user)):
"""
Update a dataset-user permission.

You can not edit your own permissions.

For editing other permissions, you need grant and revoke permissions.
(Might change in future.)
"""
existing_permission = crud.dataset_permission.get(db, permission_id)
if existing_permission is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="Dataset permission not found for id {permission_id}.")

if existing_permission.ref_user == current.id:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
detail="You cannot edit your own dataset permissions.")

if not crud.dataset_permission.is_permission_grant_allowed(db=db,
dataset_id=existing_permission.ref_dataset,
user_id=current.id):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
detail="You have no permission to grant permissions to other users for this dataset.")

if not crud.dataset_permission.is_permission_revoke_allowed(db=db,
dataset_id=existing_permission.ref_dataset,
user_id=current.id):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
detail="You have no permission to revoke permissions from other users for this dataset.")

return crud.dataset_permission.update(db=db, obj_in=request, permission_id=permission_id)


@router.delete("/{permission_id}", response_model=schemas.DatasetPermission)
def remove_dataset_permission(permission_id: int,
db: Session = Depends(deps.get_db),
current: model.User = Depends(deps.get_current_user)):
"""
Delete a dataset-user permission.
"""
existing_permission = crud.dataset_permission.get(db, permission_id)
if existing_permission is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="Dataset permission not found for id {permission_id}.")

if existing_permission.ref_user == current.id:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
detail="You cannot edit your own dataset permissions.")

if not crud.dataset_permission.is_permission_revoke_allowed(db=db,
dataset_id=existing_permission.ref_dataset,
user_id=current.id):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
detail="You have no permission to revoke permissions from other users for this dataset.")

return crud.dataset_permission.remove(db=db, id=permission_id)
12 changes: 7 additions & 5 deletions ensysmod/api/endpoints/energy_commodities.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from sqlalchemy.orm import Session

from ensysmod import schemas, model, crud
from ensysmod.api import deps
from ensysmod.api import deps, permissions

router = APIRouter()

Expand All @@ -31,7 +31,6 @@ def get_commodity(commodity_id: int,
"""
Retrieve a energy commodity.
"""
# TODO Check if user has permission for dataset and commodity
return crud.energy_commodity.get(db, commodity_id)


Expand All @@ -47,7 +46,7 @@ def create_commodity(request: schemas.EnergyCommodityCreate,
if dataset is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Dataset {request.ref_dataset} not found!")

# TODO Check if user has permission for dataset
permissions.check_modification_permission(db, user=current, dataset_id=request.ref_dataset)

existing = crud.energy_commodity.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, name=request.name)
if existing is not None:
Expand All @@ -65,10 +64,10 @@ def update_commodity(commodity_id: int,
"""
Update a energy commodity.
"""
# TODO Check if user has permission for commodity
commodity = crud.energy_commodity.get(db=db, id=commodity_id)
if commodity is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"EnergyCommodity {commodity_id} not found!")
permissions.check_modification_permission(db, user=current, dataset_id=commodity.ref_dataset)
return crud.energy_commodity.update(db=db, db_obj=commodity, obj_in=request)


Expand All @@ -79,5 +78,8 @@ def remove_commodity(commodity_id: int,
"""
Delete a energy commodity.
"""
# TODO Check if user has permission for dataset
commodity = crud.energy_commodity.get(db=db, id=commodity_id)
if commodity is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"EnergyCommodity {commodity_id} not found!")
permissions.check_modification_permission(db, user=current, dataset_id=commodity.ref_dataset)
return crud.energy_commodity.remove(db=db, id=commodity_id)
4 changes: 2 additions & 2 deletions ensysmod/api/endpoints/energy_conversions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from sqlalchemy.orm import Session

from ensysmod import schemas, model, crud
from ensysmod.api import deps
from ensysmod.api import deps, permissions

router = APIRouter()

Expand Down Expand Up @@ -33,7 +33,7 @@ def create_conversion(request: schemas.EnergyConversionCreate,
if dataset is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Dataset {request.ref_dataset} not found!")

# TODO Check if user has permission for dataset
permissions.check_modification_permission(db, user=current, dataset_id=request.ref_dataset)

existing = crud.energy_conversion.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, name=request.name)
if existing is not None:
Expand Down
18 changes: 9 additions & 9 deletions ensysmod/api/endpoints/energy_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from sqlalchemy.orm import Session

from ensysmod import schemas, model, crud
from ensysmod.api import deps
from ensysmod.api import deps, permissions
from ensysmod.core.fine_esm import generate_esm_from_model, optimize_esm

router = APIRouter()
Expand Down Expand Up @@ -33,7 +33,6 @@ def get_model(model_id: int,
"""
Retrieve a energy model.
"""
# TODO Check if user has permission for dataset and model
return crud.energy_model.get(db, id=model_id)


Expand All @@ -49,7 +48,7 @@ def create_model(request: schemas.EnergyModelCreate,
if dataset is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Dataset {request.ref_dataset} not found!")

# TODO Check if user has permission for dataset
permissions.check_usage_permission(db, user=current, dataset_id=request.ref_dataset)

existing = crud.energy_model.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, name=request.name)
if existing is not None:
Expand All @@ -67,10 +66,10 @@ def update_model(model_id: int,
"""
Update a energy model.
"""
# TODO Check if user has permission for model
energy_model = crud.energy_model.get(db=db, id=model_id)
if energy_model is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"EnergyModel {model_id} not found!")
permissions.check_usage_permission(db, user=current, dataset_id=energy_model.ref_dataset)
return crud.energy_model.update(db=db, db_obj=energy_model, obj_in=request)


Expand All @@ -81,7 +80,10 @@ def remove_model(model_id: int,
"""
Delete a energy model.
"""
# TODO Check if user has permission for dataset
energy_model = crud.energy_model.get(db=db, id=model_id)
if energy_model is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"EnergyModel {model_id} not found!")
permissions.check_usage_permission(db, user=current, dataset_id=energy_model.ref_dataset)
return crud.energy_model.remove(db=db, id=model_id)


Expand All @@ -95,12 +97,11 @@ def validate_model(model_id: int,
Might take a while.
And return errors if dataset is not valid.
"""
# TODO Check if user has permission for dataset
energy_model = crud.energy_model.get(db=db, id=model_id)
if energy_model is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"EnergyModel {model_id} not found!")

# TODO Check if user has permission for dataset
permissions.check_usage_permission(db, user=current, dataset_id=energy_model.ref_dataset)

generate_esm_from_model(db=db, model=energy_model)
return energy_model
Expand All @@ -116,12 +117,11 @@ def optimize_model(model_id: int,
Might take a while.
And return errors if dataset is not valid.
"""
# TODO Check if user has permission for dataset
energy_model = crud.energy_model.get(db=db, id=model_id)
if energy_model is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"EnergyModel {model_id} not found!")

# TODO Check if user has permission for dataset
permissions.check_usage_permission(db, user=current, dataset_id=energy_model.ref_dataset)

esM = generate_esm_from_model(db=db, model=energy_model)
result_file_path = optimize_esm(esM=esM)
Expand Down
4 changes: 2 additions & 2 deletions ensysmod/api/endpoints/energy_sinks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from sqlalchemy.orm import Session

from ensysmod import schemas, model, crud
from ensysmod.api import deps
from ensysmod.api import deps, permissions

router = APIRouter()

Expand Down Expand Up @@ -33,7 +33,7 @@ def create_sink(request: schemas.EnergySinkCreate,
if dataset is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Dataset {request.ref_dataset} not found!")

# TODO Check if user has permission for dataset
permissions.check_modification_permission(db, user=current, dataset_id=request.ref_dataset)

existing = crud.energy_sink.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, name=request.name)
if existing is not None:
Expand Down
Loading