Skip to content

Commit

Permalink
feat: add analysis and image hub eps with models
Browse files Browse the repository at this point in the history
  • Loading branch information
brucetony committed Mar 11, 2024
1 parent d6d5204 commit 1670fc0
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 15 deletions.
3 changes: 3 additions & 0 deletions gateway/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ async def make_request(
query = {}

async with httpx.AsyncClient(headers=headers) as client:
print(url)
print(query)
print(data)
r = await client.request(url=url, method=method, params=query, data=data)
resp_data = r.json()
return resp_data, r.status_code
Expand Down
80 changes: 76 additions & 4 deletions gateway/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Models for API."""
import datetime
import uuid
from enum import Enum
from typing import Optional
from uuid import UUID

Expand Down Expand Up @@ -169,18 +170,89 @@ class ImageDataResponse(BaseModel):


# Hub Models
class ProjectResponse(BaseModel):
"""Single project response model."""
## String Models
class IncludeNode(BaseModel):
"""Include node."""
include: str = "node"


class ApprovalStatus(Enum):
"""Status of project possibilities."""
approved: str = "approved"
rejected: str = "rejected"


## Response Models
class BaseHubResponse(BaseModel):
"""Common attributes of Hub responses."""
id: uuid.UUID
name: str
analyses: int
created_at: datetime.datetime
updated_at: datetime.datetime


class MasterImage(BaseHubResponse):
"""Master image details."""
path: str
virtual_path: str
group_virtual_path: str
name: str
command: str | None = None
command_arguments: str | None = None


class ProjectResponse(BaseHubResponse):
"""Single project response model."""
name: str
analyses: int
realm_id: uuid.UUID
user_id: uuid.UUID
master_image_id: uuid.UUID | None = None
master_image: MasterImage | None = None


class AllProjects(BaseModel):
"""List of all projects."""
data: list[ProjectResponse]


class NodeDetails(BaseHubResponse):
"""Node details."""
external_name: str | None = None
name: str
hidden: bool
type: str
online: bool
registry_id: uuid.UUID | None = None
registry_project_id: uuid.UUID | None = None
robot_id: uuid.UUID
realm_id: uuid.UUID


class AnalysisOrProjectNodeResponse(BaseHubResponse):
"""Single project or analysis by node."""

approval_status: ApprovalStatus
comment: str | None = None
project_id: uuid.UUID | None = None
project_realm_id: uuid.UUID | None = None
node_id: uuid.UUID | None = None
node_realm_id: uuid.UUID | None = None


class ListAnalysisOrProjectNodeResponse(BaseModel):
data: list[AnalysisOrProjectNodeResponse]


class AnalysisNodeResponse(AnalysisOrProjectNodeResponse):
"""Node analysis response model."""
run_status: str | None = None
index: int
artifact_tag: str | None = None
artifact_digest: str | None = None
analysis_id: uuid.UUID
analysis_realm_id: uuid.UUID
node: NodeDetails | None = None


class ListAnalysisNodeResponse(BaseModel):
data: list[AnalysisNodeResponse]
174 changes: 164 additions & 10 deletions gateway/routers/hub.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
"""EPs for Hub provided information."""
import uuid
from typing import Annotated

from fastapi import APIRouter, Security
from fastapi import APIRouter, Security, Query, Body, Path
from starlette import status
from starlette.requests import Request
from starlette.responses import Response

from gateway.auth import hub_oauth2_scheme
from gateway.conf import gateway_settings
from gateway.core import route
from gateway.models import ImageDataResponse, ContainerResponse, ProjectResponse, AllProjects
from gateway.models import ImageDataResponse, ContainerResponse, ProjectResponse, AllProjects, \
ApprovalStatus, AnalysisOrProjectNodeResponse, ListAnalysisNodeResponse, ListAnalysisOrProjectNodeResponse

hub_router = APIRouter(
# dependencies=[Security(oauth2_scheme)],
dependencies=[Security(hub_oauth2_scheme)],
tags=["Hub"],
responses={404: {"description": "Not found"}},
)
Expand Down Expand Up @@ -91,13 +93,21 @@ async def get_vault_status():
status_code=status.HTTP_200_OK,
service_url=gateway_settings.HUB_SERVICE_URL,
response_model=AllProjects,
dependencies=[
Security(hub_oauth2_scheme) # TODO: move to router definition
]
query_params=["filter_id", "filter_realm_id", "filter_user_id", "include"],
)
async def list_all_projects(
request: Request,
response: Response,
include: Annotated[
str | None,
Query(
description="Whether to include additional data. Can only be 'master_image' or null",
pattern="^master_image$", # Must be "master_image",
),
] = None,
filter_id: Annotated[uuid.UUID, Query(description="Filter by object UUID.")] = None,
filter_realm_id: Annotated[uuid.UUID, Query(description="Filter by realm UUID.")] = None,
filter_user_id: Annotated[uuid.UUID, Query(description="Filter by user UUID.")] = None,
):
"""List all projects."""
pass
Expand All @@ -109,14 +119,158 @@ async def list_all_projects(
status_code=status.HTTP_200_OK,
service_url=gateway_settings.HUB_SERVICE_URL,
response_model=ProjectResponse,
dependencies=[
Security(hub_oauth2_scheme) # TODO: move to router definition
]
)
async def list_specific_project(
project_id: uuid.UUID,
project_id: Annotated[uuid.UUID, Path(description="Project UUID.")],
request: Request,
response: Response,
):
"""List project for a given UUID."""
pass


@route(
request_method=hub_router.get,
path="/project-nodes",
status_code=status.HTTP_200_OK,
service_url=gateway_settings.HUB_SERVICE_URL,
response_model=ListAnalysisOrProjectNodeResponse,
query_params=["filter_id", "filter_approval_status", "filter_project_id", "filter_project_realm_id",
"filter_node_id", "filter_node_realm_id"],
)
async def list_project_node(
request: Request,
response: Response,
filter_id: Annotated[
uuid.UUID | None,
Query(
description="Filter by ID of returned object.",
),
] = None,
filter_approval_status: Annotated[
uuid.UUID | None,
Query(
description="Filter by approval status of project.",
),
] = None,
filter_project_id: Annotated[
uuid.UUID | None,
Query(
description="Filter by project UUID.",
),
] = None,
filter_project_realm_id: Annotated[
uuid.UUID | None,
Query(
description="Filter by project realm UUID.",
),
] = None,
filter_node_id: Annotated[
uuid.UUID | None,
Query(
description="Filter by node UUID.",
),
] = None,
filter_node_realm_id: Annotated[
uuid.UUID | None,
Query(
description="Filter by node realm UUID.",
),
] = None,
):
"""List project for a node."""
pass


@route(
request_method=hub_router.post,
path="/project-nodes",
status_code=status.HTTP_200_OK,
service_url=gateway_settings.HUB_SERVICE_URL,
response_model=AnalysisOrProjectNodeResponse,
body_params=["project_id", "node_id"],
query_params=["approval_status"],
)
async def create_project_node(
request: Request,
response: Response,
project_id: Annotated[uuid.UUID, Body(description="Project ID as UUID")],
node_id: Annotated[uuid.UUID, Body(description="Node ID as UUID")],
approval_status: Annotated[ApprovalStatus, Query(
description="Set the approval status of project for the node. Either 'rejected' or 'approved'"
)],
):
"""Create a project at a specific node and set the approval status."""
pass


@route(
request_method=hub_router.get,
path="/analysis-nodes",
status_code=status.HTTP_200_OK,
service_url=gateway_settings.HUB_SERVICE_URL,
response_model=ListAnalysisNodeResponse,
query_params=["filter_id", "filter_approval_status", "filter_project_id", "filter_project_realm_id",
"filter_node_id", "filter_node_realm_id", "include"],
)
async def list_analyses_of_node(
request: Request,
response: Response,
include: Annotated[
str | None,
Query(
description="Whether to include additional data for the given parameter",
pattern="^node$", # Must be "node",
),
] = None,
filter_id: Annotated[
uuid.UUID | None,
Query(
description="Filter by ID of returned object.",
),
] = None,
filter_approval_status: Annotated[
uuid.UUID | None,
Query(
description="Filter by approval status of project.",
),
] = None,
filter_project_id: Annotated[
uuid.UUID | None,
Query(
description="Filter by project UUID.",
),
] = None,
filter_project_realm_id: Annotated[
uuid.UUID | None,
Query(
description="Filter by project realm UUID.",
),
] = None,
filter_node_id: Annotated[
uuid.UUID | None,
Query(
description="Filter by node UUID.",
),
] = None,
filter_node_realm_id: Annotated[
uuid.UUID | None,
Query(
description="Filter by node realm UUID.",
),
] = None,
filter_analysis_id: Annotated[
uuid.UUID | None,
Query(
description="Filter by analysis UUID.",
),
] = None,
filter_analysis_realm_id: Annotated[
uuid.UUID | None,
Query(
description="Filter by analysis realm UUID.",
),
] = None,
):
"""List analyses for a node."""
pass
11 changes: 10 additions & 1 deletion gateway/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ async def unzip_query_params(

for key in necessary_params:
value = all_params.get(key)

if not value: # if value is None, then skip
continue

if key.startswith("filter_"): # convert filter_some_param -> filter[some_param] for hub
filter_kw, filter_param = key.split("_", 1)
key = f"{filter_kw}[{filter_param}]"

serialized_dict = await serialize_query_content(key=key, value=value)
response_query_params.update(serialized_dict)

Expand All @@ -58,7 +66,8 @@ async def unzip_body_object(
for key in specified_params:
value = additional_params.get(key)
_body_dict = await serialize_response(response_content=value)
response_body_dict.update(_body_dict)
# response_body_dict.update(_body_dict)
response_body_dict[key] = _body_dict

return response_body_dict

Expand Down

0 comments on commit 1670fc0

Please sign in to comment.