Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sample requests #8

Merged
merged 7 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
__pycache__

api_keys.json
.vscode/*
31 changes: 22 additions & 9 deletions src/api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
from pathlib import Path
from typing import Annotated, AsyncGenerator, Iterable

from fastapi import Depends, FastAPI, Security
from fastapi import Depends, FastAPI, HTTPException, Security
from pydantic.functional_validators import AfterValidator
from sqlalchemy.exc import IntegrityError
from sqlmodel import Session, SQLModel, create_engine
from sqlmodel import Session, SQLModel, create_engine, select

from api.security import ApiKey, validate_api_key, validate_permissions
from models.member import Member
from models.person import Person
from models.project import InputProject, Project
from models.role import prepopulate_roles
from models.services import ResearchDriveService, Services
from models.services import ResearchDriveService

# Ensure driveoff directory is created
(Path.home() / ".driveoff").mkdir(exist_ok=True)
Expand Down Expand Up @@ -106,9 +106,7 @@ async def set_drive_info(
ResearchDriveService.model_validate(drive)
for drive in input_project.services.research_drive
]
stored_services = Services(research_drive=drives)
# Add the validated services and members into the project
project.services = stored_services
project.research_drives = drives
project.members = members
# Upsert the project.
session.merge(project)
Expand All @@ -135,15 +133,30 @@ async def append_drive_info(
@app.get(ENDPOINT_PREFIX + "/resdriveinfo")
async def get_drive_info(
drive_id: ResearchDriveID,
# session: SessionDep,
session: SessionDep,
api_key: ApiKey = Security(validate_api_key),
) -> dict[str, str]:
"""Retrieve information about the specified Research Drive."""

validate_permissions("GET", api_key)

code_query = select(ResearchDriveService).where(
ResearchDriveService.name == drive_id
)
drive_found = session.exec(code_query).first()
if drive_found is None:
raise HTTPException(
status_code=404,
detail=f"Research Drive ID {drive_id} not found in local database.",
)
projects = drive_found.projects
if len(projects) == 0:
raise HTTPException(
status_code=404,
detail=f"No Projects associated with {drive_id} in local database",
)
return {
"drive_id": drive_id,
"ro_crate": "TODO: Make RO-Crate",
"manifest": "TODO: Make manifest",
"ro_crate": "TODO: Make RO-Crate from: " + str(projects),
"manifest": "TODO: Make Manifest",
}
1 change: 0 additions & 1 deletion src/models/person.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ class InputIdentity(SQLModel):
class InputIdentityResultItems(SQLModel):
"""The set of result items from Project DB API."""

href: str
items: list[InputIdentity]


Expand Down
12 changes: 9 additions & 3 deletions src/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
from sqlmodel import Field, Relationship, SQLModel

from models.person import InputPerson
from models.services import InputServices, Services
from models.services import (
InputServices,
ResearchDriveProjectLink,
ResearchDriveService,
)

# Only import Member during typechecking to prevent circular dependency error.
if TYPE_CHECKING:
Expand Down Expand Up @@ -52,9 +56,11 @@ class Project(BaseProject, table=True):
"""Project model for data stored in database"""

id: Optional[int] = Field(default=None, primary_key=True)
services_id: int | None = Field(default=None, foreign_key="services.id")
# services_id: int | None = Field(default=None, foreign_key="services.id")
codes: list[Code] = Relationship(link_model=ProjectCodeLink)
services: Services = Relationship()
research_drives: list[ResearchDriveService] = Relationship(
link_model=ResearchDriveProjectLink, back_populates="projects"
)
members: list["Member"] = Relationship(
# cascade_delete enabled so session.merge() works for project save.
back_populates="project",
Expand Down
37 changes: 17 additions & 20 deletions src/models/services.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
"""Data models representing CeR services."""

from datetime import datetime
from typing import Optional
from typing import TYPE_CHECKING, Optional

from sqlmodel import Field, Relationship, SQLModel

if TYPE_CHECKING:
from models.project import Project


class ResearchDriveProjectLink(SQLModel, table=True):
"""Linking table between research drive service and a project's service."""

project_id: int | None = Field(
default=None, foreign_key="project.id", primary_key=True
)
research_drive_id: int | None = Field(
default=None, foreign_key="researchdriveservice.id", primary_key=True
)


class ResearchDriveService(SQLModel, table=True):
"""Object describing a research drive service."""
Expand All @@ -18,29 +32,12 @@ class ResearchDriveService(SQLModel, table=True):
name: str
percentage_used: float
used_gb: float


class ResearchDriveServicesLink(SQLModel, table=True):
"""Linking table between research drive service and a project's service."""

service_id: int | None = Field(
default=None, foreign_key="services.id", primary_key=True
)
research_drive_id: int | None = Field(
default=None, foreign_key="researchdriveservice.id", primary_key=True
projects: list["Project"] = Relationship(
link_model=ResearchDriveProjectLink, back_populates="research_drives"
)


class InputServices(SQLModel):
"""Input object describing relevant storage services."""

research_drive: list[ResearchDriveService]


class Services(SQLModel, table=True):
"""Object describing relevant storage services."""

id: Optional[int] = Field(default=None, primary_key=True)
research_drive: list[ResearchDriveService] = Relationship(
link_model=ResearchDriveServicesLink
)
142 changes: 142 additions & 0 deletions tests/test-requests.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@

# Test requests for the driveoff webserver
#
# Intended to be used with the VS Code "REST Client" extension, which defines the syntax used here.
#
# NOTE: need to set an environment variable with your API key.
# Add something like this to VS Code's settings.json:
#
# "rest-client.environmentVariables": {
# "$shared": {
# "api_key": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
# },
# }
#

@server_url = http://localhost:8000
@drive_id = reslig202200001-Tītoki-metabolomics
###

# GET {{server_url}}/api/v1/resdriveinfo
# ?drive_id={{drive_id}}
# &api-key={{api_key}}

###

GET {{server_url}}/api/v1/resdriveinfo
?drive_id={{drive_id}}
x-api-key: {{api_key}}

###

POST {{server_url}}/api/v1/resdriveinfo
x-api-key: {{api_key}}

{
"id": 100,
"title": "Tītoki metabolomics",
"description": "Stress in plants could be defined as any change in growth condition(s) that disrupts metabolic homeostasis and requires an adjustment of metabolic pathways in a process that is usually referred to as acclimation. Metabolomics could contribute significantly to the study of stress biology in plants and other organisms by identifying different compounds, such as by-products of stress metabolism, stress signal transduction molecules or molecules that are part of the acclimation response of plants.",
"start_date": "2022-01-01",
"end_date": "2024-11-04",
"division": "Liggins Institute",
"codes": [
{
"code": "uoa00001",
"id": 550
},
{
"code": "reslig202200001",
"id": 630
}
],
"services": {
"research_drive": [
{
"allocated_gb": 25600.0,
"archived": 0,
"date": "2024-10-13",
"deleted": 0,
"first_day": "2022-01-09",
"free_gb": 24004.5,
"id": 22001,
"last_day": null,
"name": "reslig202200001-Tītoki-metabolomics",
"num_files": 50102,
"percentage_used": 2.75578,
"project_code": "reslig202200001",
"used_gb": 1596.0
}
],
"uoaivm": [],
"vis": [],
"vm": []
},
"members": [
{
"id": 1421,
"person.email": "s.nicholas@test.auckland.ac.nz",
"person.full_name": "Samina Nicholas",
"person.identities": {
"items": [
{
"username": "snic021"
}
]
},
"role": {
"id": 1,
"name": "Project Owner"
},
"notes": ""
},
{
"id": 330,
"person.email": "z.luther@test.auckland.ac.nz",
"person.full_name": "Zach Luther",
"person.identities": {
"items": [
{
"username": "zlut014"
}
]
},
"role": {
"id": 3,
"name": "Project Team Member"
},
"notes": ""
},
{
"id": 188,
"person.email": "j.hossam@test.auckland.ac.nz",
"person.full_name": "Jarrod Hossam",
"person.identities": {
"items": [
{
"username": "jhos225"
}
]
},
"role": {
"id": 3,
"name": "Project Team Member"
}
},
{
"id": 44,
"person.email": "m.edric@test.auckland.ac.nz",
"person.full_name": "Melisa Edric",
"person.identities": {
"items": [
{
"username": "medr894"
}
]
},
"role": {
"id": 3,
"name": "Project Team Member"
}
}
]
}