Skip to content

Commit

Permalink
Merge pull request #667 from Health-Informatics-UoN/feat/649/django-r…
Browse files Browse the repository at this point in the history
…evproxy

Add Django proxy for Nextjs
  • Loading branch information
AndyRae authored Apr 8, 2024
2 parents d4e4389 + 8ee89a5 commit 4d91898
Show file tree
Hide file tree
Showing 17 changed files with 96 additions and 19 deletions.
6 changes: 5 additions & 1 deletion .vscode/carrot.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
"name": "app/react-client-app",
"path": "../app/react-client-app"
},
{
"name": "app/next-client-app",
"path": "../app/next-client-app"
},
],
"extensions": {
"recommendations": [
Expand All @@ -28,4 +32,4 @@
"settings": {
"debug.internalConsoleOptions": "neverOpen"
}
}
}
4 changes: 4 additions & 0 deletions app/api/api/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
"rest_framework.authtoken",
"corsheaders",
"test",
"proxy",
"revproxy",
]

MIDDLEWARE = [
Expand Down Expand Up @@ -171,3 +173,5 @@
NLP_API_KEY = os.getenv("NLP_API_KEY")

SESSION_COOKIE_AGE = 86400 # session length is 24 hours

NEXTJS_URL = os.environ.get("NEXTJS_URL", "http://localhost:3000")
11 changes: 10 additions & 1 deletion app/api/api/urls.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import os

from django.contrib import admin
from django.urls import path, include
from django.urls import include, path

urlpatterns = [
(
path("", include("proxy.urls"))
if os.environ.get("ENABLE_PROXY", "False").lower() == "true"
else None
),
path("", include("mapping.urls")),
path("admin/", admin.site.urls),
path("accounts/", include("django.contrib.auth.urls")),
]

urlpatterns = [url for url in urlpatterns if url is not None]
2 changes: 1 addition & 1 deletion app/api/mapping/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
)

routers.register(r"users", views.UserViewSet, basename="users")
routers.register(r"usersfilter", views.UserFilterViewSet, basename="users")
routers.register(r"usersfilter", views.UserFilterViewSet, basename="usersfilter")

routers.register(r"scanreports", views.ScanReportListViewSet, basename="scanreports")
routers.register(
Expand Down
33 changes: 24 additions & 9 deletions app/api/poetry.lock

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

Empty file added app/api/proxy/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions app/api/proxy/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class ProxyConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "proxy"
16 changes: 16 additions & 0 deletions app/api/proxy/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from api import settings
from django.urls import re_path
from revproxy.views import ProxyView

# A set of urls that will override any root paths requested, and proxy them to the Next.js app.
urlpatterns = [
re_path(
"scanreports/?(?P<path>.*)$",
ProxyView.as_view(upstream=f"{settings.NEXTJS_URL}/scanreports"),
name="scan-report-list",
),
re_path(
"_next/(?P<path>.*)$",
ProxyView.as_view(upstream=f"{settings.NEXTJS_URL}/_next"),
),
]
1 change: 1 addition & 0 deletions app/api/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ drf-dynamic-fields = "0.4.0"
django-cors-headers = "3.11.0"
python-dotenv = "1.0.0"
pytest-django = "^4.8.0"
django-revproxy = "^0.12.0"

[build-system]
requires = ["poetry-core"]
Expand Down
11 changes: 11 additions & 0 deletions app/next-client-app/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": "0.0.1",
"configurations": [
{
"name": "Next.js: debug",
"type": "node-terminal",
"request": "launch",
"command": "npm run dev",
}
]
}
11 changes: 11 additions & 0 deletions app/next-client-app/api/request.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { apiUrl as apiUrl } from "@/constants";
import { ApiError } from "./error";
import { cookies } from "next/headers";

interface RequestOptions {
method?: string;
Expand All @@ -11,8 +12,18 @@ interface RequestOptions {
}

const request = async <T>(url: string, options: RequestOptions = {}) => {
// Auth with Django session
const cookieStore = cookies();
const session = cookieStore.get("sessionid")?.value;

const headers: HeadersInit = {
Cookie: `sessionid=${session}`,
...(options.headers || {}),
};

const response = await fetch(`${apiUrl}/api/${url}`, {
method: options.method || "GET",
headers: headers,
body: options.body,
cache: options.cache,
next: options.next,
Expand Down
3 changes: 1 addition & 2 deletions app/next-client-app/api/scan-reports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ const fetchKeys = {

export async function getScanReports(): Promise<ScanReport[]> {
try {
// return await request<ScanReport[]>(fetchKeys.list);
return scanReports;
return await request<ScanReport[]>(fetchKeys.list);
} catch (error) {
console.warn("Failed to fetch data.");
return [];
Expand Down
4 changes: 2 additions & 2 deletions app/next-client-app/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ function NavMenu({ options, children }: NavMenuProps) {
<DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger>
<DropdownMenuContent>
{options.map((option, index) => (
<>
<div key={option.name}>
<DropdownMenuItem key={index}>
<a className="text-lg w-full h-full" href={option.link}>
{option.name}
</a>
</DropdownMenuItem>
{!(index >= options.length - 1) && <DropdownMenuSeparator />}
</>
</div>
))}
</DropdownMenuContent>
</DropdownMenu>
Expand Down
6 changes: 3 additions & 3 deletions app/next-client-app/components/data-table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ export function DataTable<TData, TValue>({
<div>
<div className="flex items-center py-4">
<Input
placeholder="Filter emails..."
value={(table.getColumn("email")?.getFilterValue() as string) ?? ""}
placeholder="Filter reports..."
value={(table.getColumn("name")?.getFilterValue() as string) ?? ""}
onChange={(event) =>
table.getColumn("email")?.setFilterValue(event.target.value)
table.getColumn("name")?.setFilterValue(event.target.value)
}
className="max-w-sm"
/>
Expand Down
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Please append a line to the changelog for each change made.
- Extract Azure function ProcessQueue, into UploadQueue and CreateConcepts. Moving the upload to be standalone, and creating concepts and reusing them to when the user sets the Person ID and Date Event per table.
- Updated the CSV export function - reordered the columns and added new columns (class, concept, validity and vocabulary).
- Update the Azure functions to use Python 3.11
- Add `django-revproxy` to reverse proxy the Next.js frontend.
### Bugfixes
- Bug fixed in `find_existing_scan_report_concepts()` which was causing some `SRConcepts` to be processed multiple times. This didn't cause any issues, but was misleading and wasteful.
- Fixed hardcoded `content_type` id used in the backend, client, and workers.
Expand Down

0 comments on commit 4d91898

Please sign in to comment.