Skip to content

Commit 53bf2ae

Browse files
committed
Update to use views and new button
1 parent a7367e1 commit 53bf2ae

File tree

10 files changed

+99
-113
lines changed

10 files changed

+99
-113
lines changed

backend/apps/owasp/api/internal/views/project_health_metrics.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Views for OWASP project health metrics."""
22

3-
from django.http import FileResponse
3+
from django.http import FileResponse, HttpResponseNotFound
44
from django.views.decorators.http import require_GET
55

66
from apps.owasp.models.project_health_metrics import ProjectHealthMetrics
@@ -15,3 +15,14 @@ def generate_overview_pdf(_request):
1515
as_attachment=True,
1616
filename="owasp_project_health_metrics_overview.pdf",
1717
)
18+
19+
20+
@require_GET
21+
def generate_project_health_metrics_pdf(_request, project_key: str):
22+
"""Generate and return a PDF report of project health metrics."""
23+
pdf = ProjectHealthMetrics.generate_latest_metrics_pdf(project_key)
24+
if not pdf:
25+
return HttpResponseNotFound(f"No health metrics found for project with key: {project_key}")
26+
return FileResponse(
27+
pdf, as_attachment=True, filename=f"{project_key}_health_metrics_report.pdf"
28+
)

backend/apps/owasp/api/internal/views/urls.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,20 @@
22

33
from django.urls import path
44

5-
from apps.owasp.api.internal.views.project_health_metrics import generate_overview_pdf
5+
from apps.owasp.api.internal.views.project_health_metrics import (
6+
generate_overview_pdf,
7+
generate_project_health_metrics_pdf,
8+
)
69

710
urlpatterns = [
811
path(
912
"project-health-metrics/overview/pdf/",
1013
generate_overview_pdf,
1114
name="project_health_metrics_overview_pdf",
1215
),
16+
path(
17+
"project-health-metrics/<str:project_key>/pdf/",
18+
generate_project_health_metrics_pdf,
19+
name="project_health_metrics_pdf",
20+
),
1321
]

backend/apps/owasp/api/rest/v1/project_health_metrics.py

Lines changed: 0 additions & 20 deletions
This file was deleted.

backend/apps/owasp/models/project_health_metrics.py

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -189,24 +189,39 @@ def generate_latest_metrics_pdf(project_key: str) -> BytesIO | None:
189189
pdf.drawCentredString(300, 680, f"Health Score: {metrics.score:.2f}")
190190
table_data = [
191191
["Metric", "Value"],
192-
["Project Age (days)", metrics.age_days],
193-
["Last Commit (days)", metrics.last_commit_days],
194-
["Last Commit Requirement (days)", metrics.last_commit_days_requirement],
195-
["Last Pull Request (days)", metrics.last_pull_request_days],
196-
["Last Release (days)", metrics.last_release_days],
197-
["Last Release Requirement (days)", metrics.last_release_days_requirement],
198-
["OWASP Page Last Update (days)", metrics.owasp_page_last_update_days],
199-
["Open Issues", metrics.open_issues_count],
200-
["Total Issues", metrics.total_issues_count],
201-
["Open Pull Requests", metrics.open_pull_requests_count],
202-
["Total Pull Requests", metrics.total_pull_requests_count],
203-
["Recent Releases", metrics.recent_releases_count],
204-
["Total Releases", metrics.total_releases_count],
192+
["Project Age", f"{metrics.age_days}/{metrics.age_days_requirement} days"],
193+
[
194+
"Last Commit",
195+
f"{metrics.last_commit_days}/{metrics.last_commit_days_requirement} days",
196+
],
197+
[
198+
"Last Pull Request",
199+
f"{metrics.last_pull_request_days}/{metrics.last_pull_request_days_requirement} days",
200+
],
201+
[
202+
"Last Release",
203+
f"{metrics.last_release_days}/{metrics.last_release_days_requirement} days",
204+
],
205+
[
206+
"OWASP Page Last Update",
207+
f"{metrics.owasp_page_last_update_days}/{metrics.owasp_page_last_update_days_requirement} days",
208+
],
209+
["Open/Total Issues", f"{metrics.open_issues_count}/{metrics.total_issues_count}"],
210+
[
211+
"Open/Total Pull Requests",
212+
f"{metrics.open_pull_requests_count}/{metrics.total_pull_requests_count}",
213+
],
214+
[
215+
"Recent/Total Releases",
216+
f"{metrics.recent_releases_count}/{metrics.total_releases_count}",
217+
],
205218
["Forks", metrics.forks_count],
206219
["Stars", metrics.stars_count],
220+
[
221+
"Unassigned/Unanswered Issues",
222+
f"{metrics.unassigned_issues_count}/{metrics.unanswered_issues_count}",
223+
],
207224
["Contributors", metrics.contributors_count],
208-
["Unassigned Issues", metrics.unassigned_issues_count],
209-
["Unanswered Issues", metrics.unanswered_issues_count],
210225
[
211226
"Has funding policy issues",
212227
"No" if metrics.is_funding_requirements_compliant else "Yes",

backend/tests/apps/owasp/api/rest/v1/urls_test.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from apps.owasp.api.rest.v1.committee import router as committee_router
55
from apps.owasp.api.rest.v1.event import router as event_router
66
from apps.owasp.api.rest.v1.project import router as project_router
7-
from apps.owasp.api.rest.v1.project_health_metrics import router as project_health_metrics_router
87
from apps.owasp.api.rest.v1.urls import router as main_router
98

109

@@ -16,7 +15,6 @@ class TestRouterRegistration:
1615
"/committees": committee_router,
1716
"/events": event_router,
1817
"/projects": project_router,
19-
"/project-health-metrics": project_health_metrics_router,
2018
}
2119

2220
def test_all_routers_are_registered(self):

frontend/src/app/projects/dashboard/metrics/[projectKey]/page.tsx

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,16 @@ import {
1212
faStar,
1313
faTags,
1414
} from '@fortawesome/free-solid-svg-icons'
15-
import { Button } from '@heroui/button'
1615
import { useParams } from 'next/navigation'
1716
import { FC, useState, useEffect } from 'react'
1817
import { handleAppError } from 'app/global-error'
19-
import { fetchMetricsPDF } from 'server/fetchMetricsPDF'
2018
import { GET_PROJECT_HEALTH_METRICS_DETAILS } from 'server/queries/projectsHealthDashboardQueries'
2119
import { HealthMetricsProps } from 'types/healthMetrics'
2220
import BarChart from 'components/BarChart'
2321
import GeneralCompliantComponent from 'components/GeneralCompliantComponent'
2422
import LineChart from 'components/LineChart'
2523
import LoadingSpinner from 'components/LoadingSpinner'
24+
import MetricsPDFButton from 'components/MetricsPDFButton'
2625
import MetricsScoreCircle from 'components/MetricsScoreCircle'
2726
const ProjectHealthMetricsDetails: FC = () => {
2827
const { projectKey } = useParams()
@@ -64,19 +63,13 @@ const ProjectHealthMetricsDetails: FC = () => {
6463
{metricsList && metricsLatest ? (
6564
<>
6665
<div className="flex items-center justify-between">
67-
<h1 className="text-2xl font-bold">{metricsLatest.projectName}</h1>
68-
<Button
69-
variant="solid"
70-
color="primary"
71-
onPress={async () => {
72-
await fetchMetricsPDF(
73-
`owasp/project-health-metrics/${projectKey}/pdf`,
74-
`${projectKey}-health-metrics.pdf`
75-
)
76-
}}
77-
>
78-
Download PDF
79-
</Button>
66+
<div className="flex justify-start">
67+
<h1 className="text-2xl font-bold">{metricsLatest.projectName}</h1>
68+
<MetricsPDFButton
69+
path={`${projectKey}/pdf`}
70+
fileName={`${projectKey}-health-metrics.pdf`}
71+
/>
72+
</div>
8073
<div className="flex items-center gap-2">
8174
<MetricsScoreCircle score={metricsLatest.score} />
8275
<GeneralCompliantComponent

frontend/src/app/projects/dashboard/page.tsx

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,19 @@ import {
1111
faCodeBranch,
1212
faChartColumn,
1313
faHeart,
14-
faFileArrowDown,
1514
} from '@fortawesome/free-solid-svg-icons'
16-
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
17-
import { Tooltip } from '@heroui/tooltip'
1815
import millify from 'millify'
1916
import { useState, useEffect, FC } from 'react'
2017
import { handleAppError } from 'app/global-error'
21-
import { fetchMetricsOverviewPDF } from 'server/fetchMetricsOverviewPDF'
2218
import { GET_PROJECT_HEALTH_STATS } from 'server/queries/projectsHealthDashboardQueries'
2319
import type { ProjectHealthStats } from 'types/projectHealthStats'
2420
import DashboardCard from 'components/DashboardCard'
2521
import DonutBarChart from 'components/DonutBarChart'
2622
import LineChart from 'components/LineChart'
2723
import LoadingSpinner from 'components/LoadingSpinner'
24+
import MetricsPDFButton from 'components/MetricsPDFButton'
2825
import ProjectTypeDashboardCard from 'components/ProjectTypeDashboardCard'
26+
2927
const ProjectsDashboardPage: FC = () => {
3028
const [stats, setStats] = useState<ProjectHealthStats>()
3129
const [isLoading, setIsLoading] = useState<boolean>(true)
@@ -100,20 +98,10 @@ const ProjectsDashboardPage: FC = () => {
10098
<>
10199
<div className="mb-4 flex items-center justify-start">
102100
<h1 className="font-semibold">Project Health Dashboard Overview</h1>
103-
<Tooltip
104-
content="Download PDF"
105-
className="ml-2"
106-
placement="top"
107-
delay={100}
108-
closeDelay={100}
109-
showArrow
110-
>
111-
<FontAwesomeIcon
112-
icon={faFileArrowDown}
113-
className="ml-2 h-7 w-7 cursor-pointer text-gray-500 transition-colors duration-200 hover:text-gray-700"
114-
onClick={async () => await fetchMetricsOverviewPDF()}
115-
/>
116-
</Tooltip>
101+
<MetricsPDFButton
102+
path="overview/pdf"
103+
fileName="owasp-project-health-metrics-overview.pdf"
104+
/>
117105
</div>
118106
<div className="mt-4 grid grid-cols-1 gap-4 md:grid-cols-3">
119107
{projectsCardsItems.map((item) => (
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use client'
2+
3+
import { faFileArrowDown } from '@fortawesome/free-solid-svg-icons'
4+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
5+
import { Tooltip } from '@heroui/tooltip'
6+
import { FC } from 'react'
7+
import { fetchMetricsPDF } from 'server/fetchMetricsPDF'
8+
9+
const MetricsPDFButton: FC<{
10+
path: string
11+
fileName: string
12+
}> = ({ path, fileName }) => {
13+
return (
14+
<Tooltip
15+
content="Download PDF"
16+
className="ml-2"
17+
placement="top"
18+
delay={100}
19+
closeDelay={100}
20+
showArrow
21+
>
22+
<FontAwesomeIcon
23+
icon={faFileArrowDown}
24+
className="ml-2 h-7 w-7 cursor-pointer text-gray-500 transition-colors duration-200 hover:text-gray-700"
25+
onClick={async () => await fetchMetricsPDF(path, fileName)}
26+
/>
27+
</Tooltip>
28+
)
29+
}
30+
31+
export default MetricsPDFButton

frontend/src/server/fetchMetricsOverviewPDF.ts

Lines changed: 0 additions & 37 deletions
This file was deleted.

frontend/src/server/fetchMetricsPDF.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { handleAppError } from 'app/global-error'
2-
import { API_URL } from 'utils/credentials'
2+
import { VIEWS_URL } from 'utils/credentials'
33
export const fetchMetricsPDF = async (path: string, fileName: string): Promise<void> => {
4-
const response = await fetch(`${API_URL}${path}`, {
4+
const response = await fetch(`${VIEWS_URL}owasp/project-health-metrics/${path}`, {
55
method: 'GET',
6-
credentials: 'include',
76
headers: {
8-
'Content-Type': 'application/pdf',
7+
accept: 'application/pdf',
98
},
109
})
1110
if (!response.ok) {

0 commit comments

Comments
 (0)