Skip to content

Commit

Permalink
Merge pull request #18 from UoA-eResearch/IDS-966-submit-changes-to-b…
Browse files Browse the repository at this point in the history
…ackend

IDS-966 submit project information changes to backend
  • Loading branch information
uoa-noel authored Dec 15, 2024
2 parents d5f3d02 + 9963e3d commit 12a2065
Show file tree
Hide file tree
Showing 28 changed files with 910 additions and 17 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/frontend-gh-pages-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ name: Deploy frontend to Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["main", "IDS-914-create-prototype-for-frontend"]
branches: ["main"]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
Expand Down Expand Up @@ -42,6 +42,9 @@ jobs:
- name: Build
run: npm run build
working-directory: web
env:
VITE_API_KEY: ${{ vars.FRONTEND_API_KEY }}
VITE_API_BASE_URL: ${{ vars.FRONTEND_API_BASE_URL }}
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload artifact
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ __pycache__
api_keys.json
.vscode/*
.coverage

# Ignored local configuration files to keep secrets safe.
*.local
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,13 @@ Prototype for research drive offboarding and archiving, from IDS team.
web - JavaScript web frontend.
Project-Archive-RoCrate-Profile - ROCrate profile that this prototype will create.
```
## Modes
Both the FastAPI backend (`src/api`) and web frontend (`web`) read configuration dotenv files from the `modes` directory. There are currently two modes specified - `development` and `production`. More modes (e.g. for staging deployments) can be added.

There are two files for each mode - `.env.[mode]` and `.env.[mode].local`. The .local files are ignored in `.gitignore`, and are suitable for storing secrets such as API keys and passwords.

For both web frontend and FastAPI backend, an explicitly set environment variable will override values in dotenv files.

Web frontend: Vite has been configured to read from `modes` directory - see `web/vite.config.ts`. Read more at the [Vite env variables page](https://vite.dev/guide/env-and-mode.html#env-variables-and-modes).

FastAPI backend: See `src/config.py` and [pydantic-settings page](https://docs.pydantic.dev/latest/concepts/pydantic_settings/).
2 changes: 2 additions & 0 deletions modes/.env.development
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
VITE_API_BASE_URL=http://localhost:8000
CORS_ALLOW_HOST='["http://localhost:5173"]'
1 change: 1 addition & 0 deletions modes/.env.production
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CORS_ALLOW_HOST='["https://uoa-eresearch.github.io/driveoff/"]'
22 changes: 21 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ rocrate = "^0.11.0"
orjson = "^3.10"
factory-boy = "^3.3.1"
mock = "^5.1.0"
pydantic-settings = "^2.6.1"


[tool.poetry.group.dev.dependencies]
isort = "^5.13.2"
Expand Down
8 changes: 8 additions & 0 deletions src/api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# API server for offboarding

## Setting a mode
By default, the API server runs in development mode. To change to production mode and use production env variables (e.g. API keys, etc), set `MODE=production`. e.g.:

```
MODE=production fastapi run src/api/main.py
```
21 changes: 21 additions & 0 deletions src/api/cors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Module for CORS-related functionality."""

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from config import get_settings


def add_cors_middleware(app: FastAPI) -> None:
"""Adds CORS middleware to the server app.
Args:
app (FastAPI): The FastAPI app to add middleware to.
"""
app.add_middleware(
CORSMiddleware,
allow_origins=get_settings().cors_allow_host,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
4 changes: 3 additions & 1 deletion src/api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from sqlalchemy.exc import IntegrityError
from sqlmodel import Session, SQLModel, create_engine, select

from api.cors import add_cors_middleware
from api.manifests import bag_directory, create_manifests_directory, generate_manifest
from api.security import ApiKey, validate_api_key, validate_permissions
from crate.ro_builder import ROBuilder
Expand Down Expand Up @@ -69,6 +70,8 @@ async def lifespan(_: FastAPI) -> AsyncGenerator[None, None]:

app = FastAPI(lifespan=lifespan)

# Send CORS headers to enable frontend to contact API.
add_cors_middleware(app)

RESEARCH_DRIVE_REGEX = re.compile(r"res[a-z]{3}[0-9]{9}-[a-zA-Z0-9-_]+")

Expand Down Expand Up @@ -127,7 +130,6 @@ async def set_drive_info(
# Upsert the project.
session.merge(project)
session.commit()
print(project.codes)
return project


Expand Down
41 changes: 41 additions & 0 deletions src/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""Module for reading configuration files."""

import os
from functools import lru_cache
from pathlib import Path

from pydantic_settings import BaseSettings, SettingsConfigDict


def get_env_file() -> list[Path]:
"""Given the mode this app should run in, return the dotenv files
that should be used. If no file matching mode exists, raises a ValueError.
Returns:
list[Path]: The list of dotenv files.
"""
mode = "development"
if "MODE" in os.environ:
mode = os.environ["MODE"]
mode_dir = Path("modes")
all_env_files = [mode_dir / f".env.{mode}", mode_dir / f".env.{mode}.local"]
files_that_exist = [file for file in all_env_files if file.is_file()]
if len(files_that_exist) == 0:
raise ValueError("No matching dotenv file exists for specified mode.")
return files_that_exist


class Settings(BaseSettings):
"""
Configurations for Driveoff. Use get_settings() for a cached version of the settings.
"""

cors_allow_host: list[str] = []

model_config = SettingsConfigDict(env_file=get_env_file(), extra="ignore")


@lru_cache
def get_settings() -> Settings:
"""Returns a cached version of the Settings."""
return Settings()
1 change: 0 additions & 1 deletion web/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ node_modules
dist
dist-ssr
coverage
*.local

/cypress/videos/
/cypress/screenshots/
Expand Down
15 changes: 14 additions & 1 deletion web/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
# driveoff-web

This template should help get you started developing with Vue 3 in Vite.
Frontend service for drive offboarding. Built with Vue.

## Generate API client
This project uses heyapi to generate client code and TypeScript types based on OpenAPI specification that's produced by Pydantic/FastAPI. When models and endpoints change, the client code needs to be regenerated. To do this:
1. Run the fastapi server. `fastapi dev src/api/main.py`
2. In the `web/` directory, run `npm run openapi-ts`. It will retrieve the OpenAPI specification from FastAPI server running on localhost, generate API client code and types, and place them in `web/src/client`.
3. Add and commit the generated code.

Do not manually edit code in `web/src/client`, they will be overwritten next time the types are regenerated.

## GitHub Pages deployment
This frontend is deployed to [GitHub Pages](https://uoa-eresearch.github.io/driveoff/).

During build, the API key and API base URL are set through environment variables. See `.github/frontend-gh-pages-build.yaml` and [Store information in variables GitHub Action documentation](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#using-the-vars-context-to-access-configuration-variable-values).

## Recommended IDE Setup

Expand Down
7 changes: 7 additions & 0 deletions web/openapi-ts.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { defineConfig } from '@hey-api/openapi-ts';

export default defineConfig({
client: '@hey-api/client-fetch',
input: 'http://localhost:8000/openapi.json',
output: 'src/client',
});
Loading

0 comments on commit 12a2065

Please sign in to comment.