From cbb45c2cf0e47f637200053d52d09d661145421e Mon Sep 17 00:00:00 2001 From: Samyak Jain Date: Tue, 25 Mar 2025 18:09:34 +0530 Subject: [PATCH 1/3] Updated user details page --- frontend/src/pages/UserDetails.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/UserDetails.tsx b/frontend/src/pages/UserDetails.tsx index 3d3621bb89..161e52c27c 100644 --- a/frontend/src/pages/UserDetails.tsx +++ b/frontend/src/pages/UserDetails.tsx @@ -272,7 +272,7 @@ const UserDetailsPage: React.FC = () => { url={user.url || '#'} > } details={userDetails} From 7d84cb820e02e8e39fb183f18c2dd071670e19c0 Mon Sep 17 00:00:00 2001 From: Samyak Jain Date: Thu, 27 Mar 2025 23:19:59 +0530 Subject: [PATCH 2/3] Added Pull requests to homepage --- .../apps/github/graphql/nodes/pull_request.py | 1 + frontend/__tests__/unit/data/mockHomeData.ts | 20 ++++++ frontend/__tests__/unit/pages/Home.test.tsx | 14 +++++ frontend/src/api/queries/homeQueries.ts | 10 +++ frontend/src/components/ItemCardList.tsx | 5 ++ frontend/src/pages/Home.tsx | 61 +++++++++++++++++-- frontend/src/pages/UserDetails.tsx | 2 +- frontend/src/types/home.ts | 12 ++++ 8 files changed, 119 insertions(+), 6 deletions(-) diff --git a/backend/apps/github/graphql/nodes/pull_request.py b/backend/apps/github/graphql/nodes/pull_request.py index f2819e6c02..8ab673e051 100644 --- a/backend/apps/github/graphql/nodes/pull_request.py +++ b/backend/apps/github/graphql/nodes/pull_request.py @@ -16,6 +16,7 @@ class Meta: fields = ( "created_at", "title", + "author", ) def resolve_url(self, info): diff --git a/frontend/__tests__/unit/data/mockHomeData.ts b/frontend/__tests__/unit/data/mockHomeData.ts index ec62a67334..ca816da480 100644 --- a/frontend/__tests__/unit/data/mockHomeData.ts +++ b/frontend/__tests__/unit/data/mockHomeData.ts @@ -79,6 +79,26 @@ export const mockGraphQLData = { url: 'https://nest.owasp.org/events/event-1', }, ], + recentPullRequests: [ + { + createdAt: '2025-03-25T10:00:00Z', + title: 'Fix authentication bug', + author: { + name: 'John Doe', + avatarUrl: 'https://avatars.githubusercontent.com/u/58754215?v=4', + }, + url: 'https://github.com/example/repo/pull/1', + }, + { + createdAt: '2025-03-24T15:30:00Z', + title: 'Add new feature', + author: { + login: 'jane-smith', + avatarUrl: 'https://avatars.githubusercontent.com/u/58754221?v=4', + }, + url: 'https://github.com/example/repo/pull/2', + }, + ], } export const mockAlgoliaData = { diff --git a/frontend/__tests__/unit/pages/Home.test.tsx b/frontend/__tests__/unit/pages/Home.test.tsx index d5dfbabec2..4e72fc16f9 100644 --- a/frontend/__tests__/unit/pages/Home.test.tsx +++ b/frontend/__tests__/unit/pages/Home.test.tsx @@ -166,4 +166,18 @@ describe('Home', () => { }) }) }) + + test('renders Recent Pull Requests section', async () => { + render() + + await waitFor(() => { + expect(screen.getByText('Recent Pull Requests')).toBeInTheDocument() + mockGraphQLData.recentPullRequests.forEach((pullRequest) => { + expect(screen.getByText(pullRequest.title)).toBeInTheDocument() + expect( + screen.getByText(pullRequest.author.name || pullRequest.author.login) + ).toBeInTheDocument() + }) + }) + }) }) diff --git a/frontend/src/api/queries/homeQueries.ts b/frontend/src/api/queries/homeQueries.ts index 0aa5765b96..1667f8018c 100644 --- a/frontend/src/api/queries/homeQueries.ts +++ b/frontend/src/api/queries/homeQueries.ts @@ -54,6 +54,16 @@ export const GET_MAIN_PAGE_DATA = gql` tagName url } + recentPullRequests(limit: 5) { + author { + avatarUrl + login + name + } + createdAt + title + url + } sponsors { imageUrl name diff --git a/frontend/src/components/ItemCardList.tsx b/frontend/src/components/ItemCardList.tsx index c4fd6ef3c6..2a6dd17f79 100644 --- a/frontend/src/components/ItemCardList.tsx +++ b/frontend/src/components/ItemCardList.tsx @@ -18,6 +18,11 @@ const ItemCardList = ({ commentsCount: number publishedAt: string tagName: string + author: { + avatarUrl: string + login: string + name: string + } }) => JSX.Element }) => ( diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx index 7b82432150..840301c8a8 100644 --- a/frontend/src/pages/Home.tsx +++ b/frontend/src/pages/Home.tsx @@ -269,18 +269,69 @@ export default function Home() { )} /> (
- {formatDate(item.publishedAt)} - - {item.tagName} + {formatDate(item.createdAt)} + {item?.author.name || item?.author.login ? ( + <> + + {item.author.name || item.author.login} + + ) : null}
)} /> + + {data.recentReleases && data.recentReleases.length > 0 ? ( +
+ {data.recentReleases.map((item, index) => ( +
+
+ +
+
+ + {formatDate(item.publishedAt)} + + {item.tagName} +
+
+
+
+ ))} +
+ ) : ( +

No recent releases.

+ )} +
{data.recentPosts.map((post) => ( diff --git a/frontend/src/pages/UserDetails.tsx b/frontend/src/pages/UserDetails.tsx index 161e52c27c..3d3621bb89 100644 --- a/frontend/src/pages/UserDetails.tsx +++ b/frontend/src/pages/UserDetails.tsx @@ -272,7 +272,7 @@ const UserDetailsPage: React.FC = () => { url={user.url || '#'} > } details={userDetails} diff --git a/frontend/src/types/home.ts b/frontend/src/types/home.ts index 65eb4db63a..7d79e8a824 100644 --- a/frontend/src/types/home.ts +++ b/frontend/src/types/home.ts @@ -7,6 +7,7 @@ export type MainPageData = { recentIssues: ProjectIssuesType[] recentReleases: ProjectReleaseType[] upcomingEvents: EventType[] + recentPullRequests: PullRequestsType[] recentChapters: { createdAt: string key: string @@ -45,3 +46,14 @@ export type SponsorType = { sponsorType: string url: string } + +export type PullRequestsType = { + createdAt: string + title: string + url: string + author: { + login: string + avatarUrl: string + name: string + } +} From 6057b0a2a730456509c000e41da1eb2ea1440508 Mon Sep 17 00:00:00 2001 From: Arkadii Yakovets Date: Fri, 28 Mar 2025 20:24:55 -0700 Subject: [PATCH 3/3] Update code --- .../apps/github/graphql/nodes/pull_request.py | 2 +- backend/apps/github/graphql/queries/issue.py | 12 ++++++---- .../github/graphql/queries/pull_request.py | 23 +++++++++++++++++-- .../apps/github/graphql/queries/release.py | 15 ++++++++---- frontend/src/api/queries/homeQueries.ts | 14 +++++------ frontend/src/types/home.ts | 8 +++---- 6 files changed, 51 insertions(+), 23 deletions(-) diff --git a/backend/apps/github/graphql/nodes/pull_request.py b/backend/apps/github/graphql/nodes/pull_request.py index 8ab673e051..2ce4223652 100644 --- a/backend/apps/github/graphql/nodes/pull_request.py +++ b/backend/apps/github/graphql/nodes/pull_request.py @@ -14,9 +14,9 @@ class PullRequestNode(BaseNode): class Meta: model = PullRequest fields = ( + "author", "created_at", "title", - "author", ) def resolve_url(self, info): diff --git a/backend/apps/github/graphql/queries/issue.py b/backend/apps/github/graphql/queries/issue.py index 606ebd204e..3379fb8747 100644 --- a/backend/apps/github/graphql/queries/issue.py +++ b/backend/apps/github/graphql/queries/issue.py @@ -1,6 +1,7 @@ """GraphQL queries for handling GitHub issues.""" import graphene +from django.db.models import OuterRef, Subquery from apps.common.graphql.queries import BaseQuery from apps.github.graphql.nodes.issue import IssueNode @@ -43,12 +44,15 @@ def resolve_recent_issues(root, info, limit=15, distinct=False, login=None): queryset = queryset.filter(author__login=login) if distinct: - queryset = queryset.distinct( - "author_id", - "created_at", + latest_issue_per_author = ( + queryset.filter(author_id=OuterRef("author_id")) + .order_by("-created_at") + .values("id")[:1] + ) + queryset = queryset.filter( + id__in=Subquery(latest_issue_per_author), ).order_by( "-created_at", - "author_id", ) return queryset[:limit] diff --git a/backend/apps/github/graphql/queries/pull_request.py b/backend/apps/github/graphql/queries/pull_request.py index ec60d99dd0..19c01d1e0e 100644 --- a/backend/apps/github/graphql/queries/pull_request.py +++ b/backend/apps/github/graphql/queries/pull_request.py @@ -1,6 +1,7 @@ """Github pull requests GraphQL queries.""" import graphene +from django.db.models import OuterRef, Subquery from apps.common.graphql.queries import BaseQuery from apps.github.graphql.nodes.pull_request import PullRequestNode @@ -13,13 +14,31 @@ class PullRequestQuery(BaseQuery): recent_pull_requests = graphene.List( PullRequestNode, limit=graphene.Int(default_value=6), + distinct=graphene.Boolean(default_value=False), login=graphene.String(required=False), ) - def resolve_recent_pull_requests(root, info, limit, login=None): + def resolve_recent_pull_requests(root, info, limit, distinct=False, login=None): """Resolve recent pull requests.""" - queryset = PullRequest.objects.select_related("author").order_by("-created_at") + queryset = PullRequest.objects.select_related( + "author", + ).order_by( + "-created_at", + ) + if login: queryset = queryset.filter(author__login=login) + if distinct: + latest_pull_request_per_author = ( + queryset.filter(author_id=OuterRef("author_id")) + .order_by("-created_at") + .values("id")[:1] + ) + queryset = queryset.filter( + id__in=Subquery(latest_pull_request_per_author), + ).order_by( + "-created_at", + ) + return queryset[:limit] diff --git a/backend/apps/github/graphql/queries/release.py b/backend/apps/github/graphql/queries/release.py index 56cc85a26f..7be89a1d90 100644 --- a/backend/apps/github/graphql/queries/release.py +++ b/backend/apps/github/graphql/queries/release.py @@ -1,6 +1,7 @@ """GraphQL queries for handling OWASP releases.""" import graphene +from django.db.models import OuterRef, Subquery from apps.common.graphql.queries import BaseQuery from apps.github.graphql.nodes.release import ReleaseNode @@ -31,18 +32,22 @@ def resolve_recent_releases(root, info, limit=15, distinct=False): Queryset containing the filtered list of releases. """ - query = Release.objects.filter( + queryset = Release.objects.filter( is_draft=False, is_pre_release=False, published_at__isnull=False, ).order_by("-published_at") if distinct: - query = query.distinct( - "author_id", - "published_at", + latest_release_per_author = ( + queryset.filter(author_id=OuterRef("author_id")) + .order_by("-published_at") + .values("id")[:1] + ) + queryset = queryset.filter( + id__in=Subquery(latest_release_per_author), ).order_by( "-published_at", ) - return query[:limit] + return queryset[:limit] diff --git a/frontend/src/api/queries/homeQueries.ts b/frontend/src/api/queries/homeQueries.ts index c0d94fa436..cd9ac60500 100644 --- a/frontend/src/api/queries/homeQueries.ts +++ b/frontend/src/api/queries/homeQueries.ts @@ -43,25 +43,25 @@ export const GET_MAIN_PAGE_DATA = gql` name } } - recentReleases(limit: 5, distinct: $distinct) { + recentPullRequests(limit: 5, distinct: $distinct) { author { avatarUrl login name } - name - publishedAt - tagName + createdAt + title url } - recentPullRequests(limit: 5) { + recentReleases(limit: 5, distinct: $distinct) { author { avatarUrl login name } - createdAt - title + name + publishedAt + tagName url } sponsors { diff --git a/frontend/src/types/home.ts b/frontend/src/types/home.ts index 7d79e8a824..8664b9dedb 100644 --- a/frontend/src/types/home.ts +++ b/frontend/src/types/home.ts @@ -48,12 +48,12 @@ export type SponsorType = { } export type PullRequestsType = { - createdAt: string - title: string - url: string author: { - login: string avatarUrl: string + login: string name: string } + createdAt: string + title: string + url: string }