Skip to content

Commit

Permalink
Get component with rhdl tag from RHDL
Browse files Browse the repository at this point in the history
Change-Id: I59166d4a237f50d83c06540d044e5d80ea4c8b8a
  • Loading branch information
rh-gvincent committed Dec 4, 2024
1 parent b89c0e3 commit 5826fb6
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 73 deletions.
4 changes: 2 additions & 2 deletions dci/api/v1/analytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from dci.analytics import query_es_dsl as qed
from dci.api.v1 import api
from dci.api.v1 import base
from dci.api.v1 import export_control
from dci.api.v1 import permissions
from dci.common import exceptions as dci_exc
from dci.common.schemas import (
analytics_task_duration_cumulated,
Expand Down Expand Up @@ -60,7 +60,7 @@ def tasks_duration_cumulated(user):
if user.is_not_super_admin() and user.is_not_epm() and user.is_not_read_only_user():
if remoteci.team_id not in user.teams_ids:
raise dci_exc.Unauthorized()
export_control.verify_access_to_topic(user, topic)
permissions.verify_access_to_topic(user, topic)

query = "q=topic_id:%s AND remoteci_id:%s" % (args["topic_id"], args["remoteci_id"])
offset, limit = handle_pagination(args)
Expand Down
70 changes: 18 additions & 52 deletions dci/api/v1/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@

from dci.api.v1 import api, notifications
from dci.api.v1 import base
from dci.api.v1 import export_control
from dci.api.v1 import permissions
from dci.api.v1 import utils as v1_utils
from dci.api.v2 import components as components_v2
from dci import decorators
from dci.common import exceptions as dci_exc
from dci.common.schemas import (
Expand All @@ -47,42 +48,6 @@
logger = logging.getLogger(__name__)


def get_components_access_teams_ids(teams_ids):
components_access_teams_ids = []
JTCA = models2.JOIN_TEAMS_COMPONENTS_ACCESS
for team_id in teams_ids:
query = flask.g.session.query(JTCA)
query = query.filter(JTCA.c.team_id == team_id)
teams_components_access = query.all()
if teams_components_access:
for tca in teams_components_access:
components_access_teams_ids.append(tca.access_team_id)
return components_access_teams_ids


def _verify_component_and_topic_access(user, component):
component_team_id = component.team_id
if component_team_id is not None:
if user.is_not_in_team(component_team_id):
components_access_teams_ids = get_components_access_teams_ids(
user.teams_ids
)
if component_team_id not in components_access_teams_ids:
raise dci_exc.Unauthorized()
else:
topic = base.get_resource_orm(models2.Topic, component.topic_id)
export_control.verify_access_to_topic(user, topic)


def _verify_component_access_and_role(user, component):
component_team_id = component.team_id
if component_team_id is not None:
if user.is_not_in_team(component_team_id):
dci_exc.Unauthorized()
elif user.is_not_super_admin() and user.is_not_feeder() and user.is_not_epm():
raise dci_exc.Unauthorized()


@api.route("/components", methods=["POST"])
@decorators.login_required
def create_components(user):
Expand Down Expand Up @@ -135,7 +100,7 @@ def update_components(user, c_id):
if_match_etag = utils.check_and_get_etag(flask.request.headers)
component = base.get_resource_orm(models2.Component, c_id, if_match_etag)

_verify_component_and_topic_access(user, component)
permissions.verify_access_to_component(user, component)

initial_component_state = component.state

Expand Down Expand Up @@ -180,7 +145,9 @@ def get_all_components(user, topics_ids):
)

if user.is_not_super_admin() and user.is_not_feeder() and user.is_not_epm():
components_access_teams_ids = get_components_access_teams_ids(user.teams_ids)
components_access_teams_ids = permissions.get_components_access_teams_ids(
user.teams_ids
)
query = query.filter(
sql.or_(
models2.Component.team_id.in_(user.teams_ids),
Expand All @@ -201,7 +168,7 @@ def get_all_components(user, topics_ids):
@api.route("/components", methods=["GET"])
@decorators.login_required
def get_components(user):
topics_ids = export_control.get_user_topic_ids(user)
topics_ids = permissions.get_user_topic_ids(user)
return get_all_components(user, topics_ids)


Expand All @@ -211,7 +178,7 @@ def get_component_by_id(user, c_id):
component = base.get_resource_orm(
models2.Component, c_id, options=[sa_orm.selectinload("files")]
)
_verify_component_and_topic_access(user, component)
permissions.verify_access_to_component(user, component)

component_jobs_query = (
flask.g.session.query(models2.Job)
Expand Down Expand Up @@ -242,7 +209,7 @@ def get_component_by_id(user, c_id):
def delete_component_by_id(user, c_id):
if_match_etag = utils.check_and_get_etag(flask.request.headers)
component = base.get_resource_orm(models2.Component, c_id, if_match_etag)
_verify_component_access_and_role(user, component)
permissions.can_delete_component(user, component)
base.update_resource_orm(component, {"state": "archived"})

return flask.Response(None, 204, content_type="application/json")
Expand All @@ -252,7 +219,7 @@ def delete_component_by_id(user, c_id):
@decorators.login_required
def list_components_files(user, c_id):
component = base.get_resource_orm(models2.Component, c_id)
_verify_component_and_topic_access(user, component)
permissions.verify_access_to_component(user, component)
args = check_and_get_args(flask.request.args.to_dict())

query = flask.g.session.query(models2.Componentfile)
Expand All @@ -278,8 +245,9 @@ def list_components_files(user, c_id):
@decorators.login_required
def get_component_file_from_s3(user, c_id, filepath):
component = base.get_resource_orm(models2.Component, c_id)
_verify_component_and_topic_access(user, component)

permissions.verify_access_to_component(user, component)
if component.tags and "rhdl" in component.tags:
return components_v2.get_component_file_from_rhdl(filepath, component)
normalized_filepath = os.path.normpath("/" + filepath).lstrip("/")
normalized_component_id_filepath = os.path.join(str(c_id), normalized_filepath)
component_id_filepath = os.path.join(str(c_id), filepath)
Expand All @@ -302,19 +270,17 @@ def get_component_file_from_s3(user, c_id, filepath):
@decorators.login_required
def get_component_file_by_id(user, c_id, f_id):
component = base.get_resource_orm(models2.Component, c_id)
_verify_component_and_topic_access(user, component)
permissions.verify_access_to_component(user, component)

componentfile = base.get_resource_orm(models2.Componentfile, f_id)

res = flask.jsonify({"component_file": componentfile.serialize()})
return res
return flask.jsonify({"component_file": componentfile.serialize()})


@api.route("/components/<uuid:c_id>/files/<uuid:f_id>/content", methods=["GET"])
@decorators.login_required
def download_component_file(user, c_id, f_id):
component = base.get_resource_orm(models2.Component, c_id)
_verify_component_and_topic_access(user, component)
permissions.verify_access_to_component(user, component)

store = flask.g.store

Expand All @@ -332,7 +298,7 @@ def download_component_file(user, c_id, f_id):
@decorators.login_required
def upload_component_file(user, c_id):
component = base.get_resource_orm(models2.Component, c_id)
_verify_component_and_topic_access(user, component)
permissions.verify_access_to_component(user, component)

if str(component.topic_id) not in v1_utils.user_topic_ids(flask.g.session, user):
raise dci_exc.Unauthorized()
Expand Down Expand Up @@ -370,7 +336,7 @@ def upload_component_file(user, c_id):
def delete_component_file(user, c_id, f_id):
if_match_etag = utils.check_and_get_etag(flask.request.headers)
component = base.get_resource_orm(models2.Component, c_id)
_verify_component_access_and_role(user, component)
permissions.can_delete_component(user, component)
componentfile = base.get_resource_orm(models2.Componentfile, f_id, if_match_etag)
base.update_resource_orm(componentfile, {"state": "archived"})

Expand Down
8 changes: 4 additions & 4 deletions dci/api/v1/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
from dci.db import models2

from dci.api.v1 import files
from dci.api.v1 import export_control
from dci.api.v1 import permissions
from dci.api.v1 import jobstates


Expand Down Expand Up @@ -97,7 +97,7 @@ def internal_create_jobs(user, values, components_ids=None):
if topic.state != "active":
msg = "Topic %s:%s not active." % (topic_id, topic.name)
raise dci_exc.DCIException(msg, status_code=412)
export_control.verify_access_to_topic(user, topic)
permissions.verify_access_to_topic(user, topic)

previous_job_id = values.get("previous_job_id")
if previous_job_id:
Expand All @@ -119,7 +119,7 @@ def internal_create_jobs(user, values, components_ids=None):
"previous_job_id": previous_job_id,
}
)
components_access_teams_ids = components.get_components_access_teams_ids(
components_access_teams_ids = permissions.get_components_access_teams_ids(
user.teams_ids
)
# schedule
Expand Down Expand Up @@ -392,7 +392,7 @@ def add_component_to_job(user, job_id):
j = base.get_resource_orm(models2.Job, job_id)
component = base.get_resource_orm(models2.Component, values["id"])

components_access_teams_ids = components.get_components_access_teams_ids(
components_access_teams_ids = permissions.get_components_access_teams_ids(
user.teams_ids
)

Expand Down
39 changes: 39 additions & 0 deletions dci/api/v1/export_control.py → dci/api/v1/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,42 @@ def get_user_topic_ids(user):
if user.has_not_pre_release_access():
filters.append(models2.Topic.export_control == True) # noqa
return [t.id for t in base.get_resources_orm(models2.Topic, filters)]


def get_components_access_teams_ids(teams_ids):
"""A team can allow another team to see its components.
This method returns the list of teams ids that allowed teams_ids to see theirs components.
"""
components_access_teams_ids = []
JTCA = models2.JOIN_TEAMS_COMPONENTS_ACCESS
for team_id in teams_ids:
query = flask.g.session.query(JTCA)
query = query.filter(JTCA.c.team_id == team_id)
teams_components_access = query.all()
if teams_components_access:
for tca in teams_components_access:
components_access_teams_ids.append(tca.access_team_id)
return components_access_teams_ids


def verify_access_to_component(user, component):
component_team_id = component.team_id
if component_team_id is not None:
if user.is_not_in_team(component_team_id):
components_access_teams_ids = get_components_access_teams_ids(
user.teams_ids
)
if component_team_id not in components_access_teams_ids:
raise dci_exc.Unauthorized()
else:
topic = base.get_resource_orm(models2.Topic, component.topic_id)
verify_access_to_topic(user, topic)


def can_delete_component(user, component):
component_team_id = component.team_id
if component_team_id is not None:
if user.is_not_in_team(component_team_id):
dci_exc.Unauthorized()
elif user.is_not_super_admin() and user.is_not_feeder() and user.is_not_epm():
raise dci_exc.Unauthorized()
16 changes: 8 additions & 8 deletions dci/api/v1/topics.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from dci.api.v1 import api
from dci.api.v1 import base
from dci.api.v1 import components
from dci.api.v1 import export_control
from dci.api.v1 import permissions
from dci.api.v1 import utils as v1_utils
from dci import decorators
from dci.common import exceptions as dci_exc
Expand Down Expand Up @@ -78,7 +78,7 @@ def get_topic_by_id(user, topic_id):
and user.is_not_feeder()
and user.is_not_read_only_user()
):
export_control.verify_access_to_topic(user, topic)
permissions.verify_access_to_topic(user, topic)

return flask.Response(
json.dumps({"topic": topic_serialized}),
Expand All @@ -100,7 +100,7 @@ def get_all_topics(user):
)

if user.is_not_super_admin() and user.is_not_read_only_user() and user.is_not_epm():
product_ids = export_control.get_user_product_ids(user)
product_ids = permissions.get_user_product_ids(user)
q = q.filter(models2.Topic.product_id.in_(product_ids))
if user.has_not_pre_release_access():
q = q.filter(models2.Topic.export_control == True) # noqa
Expand Down Expand Up @@ -166,21 +166,21 @@ def delete_topic_by_id(user, topic_id):
@decorators.login_required
def get_topics_components(user, topic_id):
topic = base.get_resource_orm(models2.Topic, topic_id)
export_control.verify_access_to_topic(user, topic)
permissions.verify_access_to_topic(user, topic)
return components.get_all_components(user, [topic_id])


@api.route("/topics/<uuid:topic_id>/notifications", methods=["POST"])
@decorators.login_required
def subscribe_user_to_topic(user, topic_id):
t = base.get_resource_orm(models2.Topic, topic_id)
export_control.verify_access_to_topic(user, t)
ut = base.create_resource_orm(
topic = base.get_resource_orm(models2.Topic, topic_id)
permissions.verify_access_to_topic(user, topic)
user_topic = base.create_resource_orm(
models2.UserTopic, {"user_id": user.id, "topic_id": topic_id}
)

return flask.Response(
json.dumps(ut),
json.dumps(user_topic),
201,
content_type="application/json",
)
Expand Down
18 changes: 11 additions & 7 deletions dci/api/v2/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

from dci.api.v2 import api
from dci.api.v1 import base
from dci.api.v1.components import _verify_component_and_topic_access
from dci.api.v1 import permissions
from dci import decorators
from dci.common import exceptions as dci_exc
from dci.dci_config import CONFIG
Expand All @@ -33,12 +33,7 @@
logger = logging.getLogger(__name__)


@api.route("/components/<uuid:c_id>/files/<path:filepath>", methods=["GET", "HEAD"])
@decorators.login_required
def get_component_file_from_rhdl(user, c_id, filepath):
component = base.get_resource_orm(models2.Component, c_id)
_verify_component_and_topic_access(user, component)

def get_component_file_from_rhdl(filepath, component):
if filepath == "dci_files_list.json":
filepath = "rhdl_files_list.json"
normalized_filepath = os.path.normpath("/" + filepath).lstrip("/")
Expand Down Expand Up @@ -72,3 +67,12 @@ def get_component_file_from_rhdl(user, c_id, filepath):
)

return flask.Response(None, 302, headers={"Location": redirect.headers["Location"]})


@api.route("/components/<uuid:c_id>/files/<path:filepath>", methods=["GET", "HEAD"])
@decorators.login_required
def get_component_file_from_rhdl_endpoint(user, c_id, filepath):
component = base.get_resource_orm(models2.Component, c_id)
permissions.verify_access_to_component(user, component)

return get_component_file_from_rhdl(filepath, component)

0 comments on commit 5826fb6

Please sign in to comment.