diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2021-07-07 20:45:06 +0200 |
|---|---|---|
| committer | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2021-07-08 10:53:25 +0200 |
| commit | 5ec19973eb3d23046d874b097275857a58c23082 (patch) | |
| tree | a601cd975f8917fb2d4af28e8a3fb228e0cb769e /opendc-web/opendc-web-api/opendc | |
| parent | 02a2f0f89cb1f39a5f8856bca1971a4e1b12374f (diff) | |
api: Add endpoints for accessing project relations
This change adds additional endpoints to the REST API to access the
project relations, the portfolios and topologies that belong to a
project.
Diffstat (limited to 'opendc-web/opendc-web-api/opendc')
| -rw-r--r-- | opendc-web/opendc-web-api/opendc/api/portfolios.py | 14 | ||||
| -rw-r--r-- | opendc-web/opendc-web-api/opendc/api/projects.py | 27 | ||||
| -rw-r--r-- | opendc-web/opendc-web-api/opendc/auth.py | 5 | ||||
| -rw-r--r-- | opendc-web/opendc-web-api/opendc/exts.py | 7 | ||||
| -rw-r--r-- | opendc-web/opendc-web-api/opendc/models/portfolio.py | 7 | ||||
| -rw-r--r-- | opendc-web/opendc-web-api/opendc/models/scenario.py | 6 | ||||
| -rw-r--r-- | opendc-web/opendc-web-api/opendc/models/topology.py | 7 |
7 files changed, 64 insertions, 9 deletions
diff --git a/opendc-web/opendc-web-api/opendc/api/portfolios.py b/opendc-web/opendc-web-api/opendc/api/portfolios.py index eea82289..4d8f54fd 100644 --- a/opendc-web/opendc-web-api/opendc/api/portfolios.py +++ b/opendc-web/opendc-web-api/opendc/api/portfolios.py @@ -103,6 +103,20 @@ class PortfolioScenarios(Resource): """ method_decorators = [requires_auth] + def get(self, portfolio_id): + """ + Get all scenarios belonging to a portfolio. + """ + portfolio = PortfolioModel.from_id(portfolio_id) + + portfolio.check_exists() + portfolio.check_user_access(current_user['sub'], True) + + scenarios = Scenario.get_for_portfolio(portfolio_id) + + data = ScenarioSchema().dump(scenarios, many=True) + return {'data': data} + def post(self, portfolio_id): """ Add a new scenario to this portfolio diff --git a/opendc-web/opendc-web-api/opendc/api/projects.py b/opendc-web/opendc-web-api/opendc/api/projects.py index 05f02a84..2b47c12e 100644 --- a/opendc-web/opendc-web-api/opendc/api/projects.py +++ b/opendc-web/opendc-web-api/opendc/api/projects.py @@ -132,6 +132,18 @@ class ProjectTopologies(Resource): """ method_decorators = [requires_auth] + def get(self, project_id): + """Get all topologies belonging to the project.""" + project = ProjectModel.from_id(project_id) + + project.check_exists() + project.check_user_access(current_user['sub'], True) + + topologies = Topology.get_for_project(project_id) + data = TopologySchema().dump(topologies, many=True) + + return {'data': data} + def post(self, project_id): """Add a new Topology to the specified project and return it""" schema = ProjectTopologies.PutSchema() @@ -170,6 +182,18 @@ class ProjectPortfolios(Resource): """ method_decorators = [requires_auth] + def get(self, project_id): + """Get all portfolios belonging to the project.""" + project = ProjectModel.from_id(project_id) + + project.check_exists() + project.check_user_access(current_user['sub'], True) + + portfolios = Portfolio.get_for_project(project_id) + data = PortfolioSchema().dump(portfolios, many=True) + + return {'data': data} + def post(self, project_id): """Add a new Portfolio for this Project.""" schema = ProjectPortfolios.PutSchema() @@ -190,7 +214,8 @@ class ProjectPortfolios(Resource): project.obj['portfolioIds'].append(portfolio.get_id()) project.update() - return {'data': portfolio.obj} + data = PortfolioSchema().dump(portfolio.obj) + return {'data': data} class PutSchema(Schema): """ diff --git a/opendc-web/opendc-web-api/opendc/auth.py b/opendc-web/opendc-web-api/opendc/auth.py index 6db06fb1..d5da6ee5 100644 --- a/opendc-web/opendc-web-api/opendc/auth.py +++ b/opendc-web/opendc-web-api/opendc/auth.py @@ -40,10 +40,7 @@ def get_token(): parts = auth.split() if parts[0].lower() != "bearer": - raise AuthError({ - "code": "invalid_header", - "description": "Authorization header must start with Bearer" - }, 401) + raise AuthError({"code": "invalid_header", "description": "Authorization header must start with Bearer"}, 401) if len(parts) == 1: raise AuthError({"code": "invalid_header", "description": "Token not found"}, 401) if len(parts) > 2: diff --git a/opendc-web/opendc-web-api/opendc/exts.py b/opendc-web/opendc-web-api/opendc/exts.py index 17dacd5e..3ee8babb 100644 --- a/opendc-web/opendc-web-api/opendc/exts.py +++ b/opendc-web/opendc-web-api/opendc/exts.py @@ -83,10 +83,9 @@ def requires_scope(required_scope): @wraps(f) def decorated(*args, **kwargs): if not has_scope(required_scope): - raise AuthError({ - "code": "Unauthorized", - "description": "You don't have access to this resource" - }, 403) + raise AuthError({"code": "Unauthorized", "description": "You don't have access to this resource"}, 403) return f(*args, **kwargs) + return decorated + return decorator diff --git a/opendc-web/opendc-web-api/opendc/models/portfolio.py b/opendc-web/opendc-web-api/opendc/models/portfolio.py index 1643e23e..eb016947 100644 --- a/opendc-web/opendc-web-api/opendc/models/portfolio.py +++ b/opendc-web/opendc-web-api/opendc/models/portfolio.py @@ -1,5 +1,7 @@ +from bson import ObjectId from marshmallow import Schema, fields +from opendc.exts import db from opendc.models.project import Project from opendc.models.model import Model @@ -38,3 +40,8 @@ class Portfolio(Model): """ project = Project.from_id(self.obj['projectId']) project.check_user_access(user_id, edit_access) + + @classmethod + def get_for_project(cls, project_id): + """Get all portfolios for the specified project id.""" + return db.fetch_all({'projectId': ObjectId(project_id)}, cls.collection_name) diff --git a/opendc-web/opendc-web-api/opendc/models/scenario.py b/opendc-web/opendc-web-api/opendc/models/scenario.py index 0fb6c453..63160448 100644 --- a/opendc-web/opendc-web-api/opendc/models/scenario.py +++ b/opendc-web/opendc-web-api/opendc/models/scenario.py @@ -1,5 +1,6 @@ from datetime import datetime +from bson import ObjectId from marshmallow import Schema, fields from opendc.exts import db @@ -65,6 +66,11 @@ class Scenario(Model): """ return cls(db.fetch_all({'simulation.state': 'QUEUED'}, cls.collection_name)) + @classmethod + def get_for_portfolio(cls, portfolio_id): + """Get all scenarios for the specified portfolio id.""" + return db.fetch_all({'portfolioId': ObjectId(portfolio_id)}, cls.collection_name) + def update_state(self, new_state, results=None): """Atomically update the state of the Scenario. """ diff --git a/opendc-web/opendc-web-api/opendc/models/topology.py b/opendc-web/opendc-web-api/opendc/models/topology.py index 71d2cade..7d2349ab 100644 --- a/opendc-web/opendc-web-api/opendc/models/topology.py +++ b/opendc-web/opendc-web-api/opendc/models/topology.py @@ -1,5 +1,7 @@ +from bson import ObjectId from marshmallow import Schema, fields +from opendc.exts import db from opendc.models.project import Project from opendc.models.model import Model @@ -93,3 +95,8 @@ class Topology(Model): """ project = Project.from_id(self.obj['projectId']) project.check_user_access(user_id, edit_access) + + @classmethod + def get_for_project(cls, project_id): + """Get all topologies for the specified project id.""" + return db.fetch_all({'projectId': ObjectId(project_id)}, cls.collection_name) |
