Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions frontend/src/app/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,9 @@ const useLeadersData = () => {
}, [error1, error2, error3])

const leadersData = [leader1Data?.user, leader2Data?.user, leader3Data?.user]
.filter(Boolean)
.filter((user): user is NonNullable<typeof user> => !!user)
.map((user) => ({
description: leaders[user.login],
description: leaders[user.login as keyof typeof leaders],
memberName: user.name || user.login,
member: user,
}))
Expand Down
22 changes: 15 additions & 7 deletions frontend/src/app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,15 @@ async function checkIfMentor(login: string): Promise<boolean> {
const providers = []

if (IS_GITHUB_AUTH_ENABLED) {
const clientId = process.env.NEXT_SERVER_GITHUB_CLIENT_ID
const clientSecret = process.env.NEXT_SERVER_GITHUB_CLIENT_SECRET
if (!clientId || !clientSecret) {
throw new Error('GitHub OAuth credentials are required when IS_GITHUB_AUTH_ENABLED is true')
}
providers.push(
GitHubProvider({
clientId: process.env.NEXT_SERVER_GITHUB_CLIENT_ID,
clientSecret: process.env.NEXT_SERVER_GITHUB_CLIENT_SECRET,
clientId,
clientSecret,
profile(profile) {
return {
email: profile.email,
Expand Down Expand Up @@ -88,7 +93,7 @@ const authOptions: AuthOptions = {
}

if (trigger === 'update' && session) {
token.isOwaspStaff = (session as ExtendedSession).user.isOwaspStaff || false
token.isOwaspStaff = (session as ExtendedSession).user?.isOwaspStaff || false
}
return token
},
Expand All @@ -97,10 +102,13 @@ const authOptions: AuthOptions = {
;(session as ExtendedSession).accessToken = token.accessToken as string

if (session.user) {
;(session as ExtendedSession).user.login = token.login as string
;(session as ExtendedSession).user.isMentor = token.isMentor as boolean
;(session as ExtendedSession).user.isLeader = token.isLeader as boolean
;(session as ExtendedSession).user.isOwaspStaff = token.isOwaspStaff as boolean
const extendedUser = (session as ExtendedSession).user
if (extendedUser) {
extendedUser.login = token.login as string
extendedUser.isMentor = token.isMentor as boolean
extendedUser.isLeader = token.isLeader as boolean
extendedUser.isOwaspStaff = token.isOwaspStaff as boolean
}
}
return session
},
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/app/board/[year]/candidates/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ type Candidate = {
avatarUrl: string
bio?: string
createdAt?: number
firstOwaspContributionAt?: number
firstOwaspContributionAt?: number | null
id: string
isFormerOwaspStaff?: boolean
isGsocMentor?: boolean
isOwaspBoardMember?: boolean
linkedinPageId?: string
login: string
name: string
}
} | null
}

type MemberSnapshot = {
Expand Down Expand Up @@ -333,7 +333,7 @@ const BoardCandidatesPage = () => {
e.stopPropagation()
e.preventDefault()
window.open(
`https://linkedin.com/in/${candidate.member.linkedinPageId}`,
`https://linkedin.com/in/${candidate.member?.linkedinPageId}`,
'_blank',
'noopener,noreferrer'
)
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/app/chapters/[chapterKey]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export async function generateMetadata({
keywords: ['owasp', 'security', 'chapter', chapterKey, chapter.name],
title: chapter.name,
})
: null
: {
title: 'Not Found',
}
}

export default async function ChapterDetailsLayout({
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/chapters/[chapterKey]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export default function ChapterDetailsPage() {

const details = [
{ label: 'Last Updated', value: formatDate(chapter.updatedAt) },
{ label: 'Location', value: chapter.suggestedLocation },
{ label: 'Location', value: chapter.suggestedLocation || '' },
{ label: 'Region', value: chapter.region },
{
label: 'URL',
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/app/chapters/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const ChaptersPage = () => {
const renderChapterCard = (chapter: Chapter) => {
const params: string[] = ['updatedAt']
const filteredIcons = getFilteredIcons(chapter, params)
const formattedUrls = handleSocialUrls(chapter.relatedUrls)
const formattedUrls = handleSocialUrls(chapter.relatedUrls || [])

const handleButtonClick = () => {
router.push(`/chapters/${chapter.key}`)
Expand All @@ -63,11 +63,11 @@ const ChaptersPage = () => {

return (
<Card
key={chapter.objectID}
cardKey={chapter.objectID}
key={chapter.objectID || chapter.key}
cardKey={chapter.objectID || chapter.key}
title={chapter.name}
url={`/chapters/${chapter.key}`}
summary={chapter.summary}
summary={chapter.summary || ''}
icons={filteredIcons}
topContributors={chapter.topContributors}
button={submitButton}
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/app/committees/[committeeKey]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export async function generateMetadata({
keywords: ['owasp', 'security', 'committee', committeeKey, committee.name],
title: committee.name,
})
: null
: {
title: 'Not Found',
}
}

export default async function CommitteeDetailsLayout({
Expand Down
26 changes: 19 additions & 7 deletions frontend/src/app/committees/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,24 @@ const CommitteesPage = () => {
pageTitle: 'OWASP Committees',
})
const router = useRouter()
const renderCommitteeCard = (committee: Committee) => {
const renderCommitteeCard = (committee: Committee, index: number) => {
const params: string[] = ['updatedAt']
const filteredIcons = getFilteredIcons(committee, params)
const formattedUrls = handleSocialUrls(committee.relatedUrls)
const formattedUrls = handleSocialUrls(committee.relatedUrls || [])

const uniqueKey = committee.objectID ?? committee.key ?? `committee-${index}`
const hasValidUrl = Boolean(committee.key || committee.objectID)
const urlKey = committee.key ?? committee.objectID ?? `committee-${index}`

if (!hasValidUrl) {
// eslint-disable-next-line no-console
console.warn('Invalid committee data:', { index, committee, uniqueKey })
}

const handleButtonClick = () => {
router.push(`/committees/${committee.key}`)
if (hasValidUrl) {
router.push(`/committees/${urlKey}`)
}
}

const submitButton = {
Expand All @@ -37,11 +49,11 @@ const CommitteesPage = () => {

return (
<Card
key={committee.objectID}
cardKey={committee.objectID}
key={uniqueKey}
cardKey={uniqueKey}
title={committee.name}
url={`/committees/${committee.key}`}
summary={committee.summary}
url={hasValidUrl ? `/committees/${urlKey}` : ''}
summary={committee.summary || ''}
icons={filteredIcons}
topContributors={committee.topContributors}
button={submitButton}
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/app/community/snapshots/[id]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ export async function generateMetadata({
keywords: ['owasp', 'snapshot', snapshotKey, snapshot?.title],
title: snapshot?.title,
})
: null
: {
title: 'Not Found',
}
}
export default function SnapshotDetailsLayout({ children }: { children: React.ReactNode }) {
return children
Expand Down
12 changes: 6 additions & 6 deletions frontend/src/app/community/snapshots/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ const SnapshotDetailsPage: React.FC = () => {
return (
<Card
button={submitButton}
cardKey={project.key}
cardKey={project.key || ''}
icons={filteredIcons}
level={level[`${project.level.toLowerCase() as keyof typeof level}`]}
summary={project.summary}
level={level[(project.level || 'incubator').toLowerCase() as keyof typeof level] ?? level.incubator}
summary={project.summary || ''}
title={project.name}
topContributors={project.topContributors}
url={`/projects/${project.key}`}
Expand All @@ -66,7 +66,7 @@ const SnapshotDetailsPage: React.FC = () => {
const renderChapterCard = (chapter: Chapter) => {
const params: string[] = ['updatedAt']
const filteredIcons = getFilteredIcons(chapter, params)
const formattedUrls = handleSocialUrls(chapter.relatedUrls)
const formattedUrls = handleSocialUrls(chapter.relatedUrls || [])

const handleButtonClick = () => {
router.push(`/chapters/${chapter.key}`)
Expand All @@ -81,10 +81,10 @@ const SnapshotDetailsPage: React.FC = () => {
return (
<Card
button={submitButton}
cardKey={chapter.key}
cardKey={chapter.key || ''}
icons={filteredIcons}
social={formattedUrls}
summary={chapter.summary}
summary={chapter.summary || ''}
title={chapter.name}
url={`/chapters/${chapter.key}`}
/>
Expand Down
14 changes: 7 additions & 7 deletions frontend/src/app/contribute/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,26 +41,26 @@ const ContributePage = () => {
}

return (
<React.Fragment key={issue.objectID}>
<React.Fragment key={issue.objectID || index}>
<Card
key={issue.objectID}
cardKey={issue.objectID}
key={issue.objectID || index}
cardKey={issue.objectID || String(index)}
title={issue.title}
url={issue.url}
projectName={issue.projectName}
projectLink={issue.projectUrl}
summary={issue.summary}
summary={issue.summary || ''}
icons={filteredIcons}
button={SubmitButton}
labels={issue.labels}
/>
<DialogComp
key={`modal-${issue.objectID}`}
key={`modal-${issue.objectID || index}`}
isOpen={modalOpenIndex === index}
onClose={() => setModalOpenIndex(null)}
title={issue.title}
summary={issue.summary}
hint={issue.hint}
summary={issue.summary || ''}
hint={issue.hint || ''}
button={viewIssueButton}
description="The issue summary and the recommended steps to address it have been generated by AI"
></DialogComp>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export default function RootLayout({
</BreadcrumbRoot>
</Providers>
</body>
<GoogleAnalytics gaId={GTM_ID} />
<GoogleAnalytics gaId={GTM_ID || ''} />
</html>
)
}
6 changes: 4 additions & 2 deletions frontend/src/app/members/[memberKey]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ export async function generateMetadata({
canonicalPath: `/members/${memberKey}`,
description: user.bio ?? `${title} OWASP community member details.`,
keywords: [user.login, user.name, 'owasp', 'owasp community member'],
title: title,
title: title || '',
})
: null
: {
title: 'Not Found',
}
}

export default async function UserDetailsLayout({
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/app/members/[memberKey]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,10 @@ const UserDetailsPage: React.FC = () => {
recentIssues={issues}
recentMilestones={milestones}
recentReleases={releases}
repositories={topRepositories}
repositories={topRepositories?.map((repo) => ({
...repo,
organization: repo.organization || undefined,
}))}
showAvatar={false}
stats={userStats}
title={user?.name || user?.login}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useParams } from 'next/navigation'
import { useEffect } from 'react'
import { ErrorDisplay, handleAppError } from 'app/global-error'
import { GetProgramAdminsAndModulesDocument } from 'types/__generated__/moduleQueries.generated'
import { Contributor } from 'types/contributor'
import { formatDate } from 'utils/dateFormatter'
import DetailsCard from 'components/CardDetailsPage'
import LoadingSpinner from 'components/LoadingSpinner'
Expand Down Expand Up @@ -69,13 +70,20 @@ const ModuleDetailsPage = () => {

return (
<DetailsCard
admins={admins}
admins={(admins || []) as Contributor[]}
details={moduleDetails}
domains={programModule.domains}
mentors={programModule.mentors}
pullRequests={programModule.recentPullRequests || []}
domains={(programModule.domains || undefined) as string[] | undefined}
mentors={(programModule.mentors || []) as Contributor[]}
programKey={programKey}
projectName={programModule.projectName || undefined}
pullRequests={
programModule.recentPullRequests?.map((pr) => ({
...pr,
author: pr.author || undefined,
})) || []
}
summary={programModule.description}
tags={programModule.tags}
tags={(programModule.tags || undefined) as string[] | undefined}
title={programModule.name}
type="module"
/>
Expand Down
9 changes: 7 additions & 2 deletions frontend/src/app/my/mentorship/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const MyMentorshipPage: React.FC = () => {
const [programs, setPrograms] = useState<Program[]>([])
const [totalPages, setTotalPages] = useState(1)

const debounceSearch = useMemo(() => debounce((q) => setDebouncedQuery(q), 400), [])
const debounceSearch = useMemo(() => debounce((q: string) => setDebouncedQuery(q), 400), [])

useEffect(() => {
debounceSearch(searchQuery)
Expand Down Expand Up @@ -64,7 +64,12 @@ const MyMentorshipPage: React.FC = () => {

useEffect(() => {
if (programData?.myPrograms) {
setPrograms(programData.myPrograms.programs)
setPrograms(
programData.myPrograms.programs.map((p) => ({
...p,
userRole: p.userRole || undefined,
}))
)
setTotalPages(programData.myPrograms.totalPages || 1)
}
}, [programData])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,17 @@ const EditProgramPage = () => {
skip: !programKey,
fetchPolicy: 'network-only',
})
const [formData, setFormData] = useState({
const [formData, setFormData] = useState<{
name: string
description: string
menteesLimit: number
startedAt: string
endedAt: string
tags: string
domains: string
adminLogins?: string
status?: string
}>({
name: '',
description: '',
menteesLimit: 0,
Expand Down Expand Up @@ -104,8 +114,8 @@ const EditProgramPage = () => {
endedAt: formData.endedAt,
tags: parseCommaSeparated(formData.tags),
domains: parseCommaSeparated(formData.domains),
adminLogins: parseCommaSeparated(formData.adminLogins),
status: formData.status,
adminLogins: parseCommaSeparated(formData.adminLogins || ''),
status: (formData.status as ProgramStatusEnum) || ProgramStatusEnum.Draft,
}

const result = await updateProgram({
Expand Down
Loading