Skip to content
13 changes: 13 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: '3.8'
services:
cache:
image: redis:6.2-alpine
restart: always
ports:
- '6379:6379'
command: redis-server --save 20 1 --loglevel warning
volumes:
- cache:/data
volumes:
cache:
driver: local
8 changes: 6 additions & 2 deletions src/app/api/auth/forceLogout/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ export async function GET(req: NextRequest) {
// should be provided that is not needed as the user is not fully logged
// in at this point.
const url = new URL(AUTH0_ISSUER_BASE_URL + "/oidc/logout")
const redirectURI = req.nextUrl.protocol + "//" + req.nextUrl.host
const host = req.headers.get('host')
const redirectURI = req.nextUrl.protocol + "//" + host
url.searchParams.append("post_logout_redirect_uri", redirectURI)
return NextResponse.redirect(url)

const response = NextResponse.redirect(url)
response.cookies.delete("appSession")
return response
}
20 changes: 17 additions & 3 deletions src/app/api/github/blob/[owner]/[repository]/[...path]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,26 @@ interface GetBlobParams {
}

export async function GET(req: NextRequest, { params }: { params: GetBlobParams }) {
const path = params.path.join("/")
const item = await gitHubClient.getRepositoryContent({
repositoryOwner: params.owner,
repositoryName: params.repository,
path: params.path.join("/"),
ref: req.nextUrl.searchParams.get("ref") || undefined
path: path,
ref: req.nextUrl.searchParams.get("ref") ?? undefined
})
const url = new URL(item.downloadURL)
return NextResponse.redirect(url)
const imageRegex = /\.(jpg|jpeg|png|webp|avif|gif)$/;

if (new RegExp(imageRegex).exec(path)) {
const file = await fetch(url).then(r => r.blob());
const headers = new Headers();
const cacheExpirationInSeconds = 60 * 60 * 24 * 30; // 30 days

headers.set("Content-Type", "image/*");
headers.set("cache-control", `stale-while-revalidate=${cacheExpirationInSeconds}`);

return new NextResponse(file, { status: 200, statusText: "OK", headers })
} else {
return NextResponse.redirect(url)
}
}
15 changes: 9 additions & 6 deletions src/app/api/hooks/github/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ const {
GITHUB_WEBHOK_REPOSITORY_DISALLOWLIST
} = process.env

const allowedRepositoryNames = (GITHUB_WEBHOK_REPOSITORY_ALLOWLIST || "")
.split(",")
.map(e => e.trim())
const disallowedRepositoryNames = (GITHUB_WEBHOK_REPOSITORY_DISALLOWLIST || "")
.split(",")
.map(e => e.trim())
const listFromCommaSeparatedString = (str?: string) => {
if (!str) {
return []
}
return str.split(",").map(e => e.trim())
}

const allowedRepositoryNames = listFromCommaSeparatedString(GITHUB_WEBHOK_REPOSITORY_ALLOWLIST)
const disallowedRepositoryNames = listFromCommaSeparatedString(GITHUB_WEBHOK_REPOSITORY_DISALLOWLIST)

const hookHandler = new GitHubHookHandler({
secret: GITHUB_WEBHOOK_SECRET,
Expand Down
9 changes: 9 additions & 0 deletions src/common/theme/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ const theme = () => createTheme({
disableRipple: true
}
}
},
breakpoints: {
values: {
xs: 0,
sm: 600,
md: 900,
lg: 1200,
xl: 1536,
}
}
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,30 @@ export default class RepositoryNameCheckingPullRequestEventHandler implements IP
}

async pullRequestOpened(event: IPullRequestOpenedEvent): Promise<void> {
if (!event.repositoryName.match(/-openapi$/)) {
if (!this.repositoryNameHasExpectedSuffix(event.repositoryName)) {
return
}
if (
this.allowedRepositoryNames.length != 0 &&
!this.allowedRepositoryNames.includes(event.repositoryName)
) {
if (!this.isAllowedRepositoryName(event.repositoryName)) {
return
}
if (this.disallowedRepositoryNames.includes(event.repositoryName)) {
if (this.isDisallowedRepositoryName(event.repositoryName)) {
return
}
return await this.eventHandler.pullRequestOpened(event)
}

private repositoryNameHasExpectedSuffix(repositoryName: string) {
return repositoryName.match(/-openapi$/)
}

private isAllowedRepositoryName(repositoryName: string) {
if (this.allowedRepositoryNames.length == 0) {
return true
}
return this.allowedRepositoryNames.includes(repositoryName)
}

private isDisallowedRepositoryName(repositoryName: string) {
return this.disallowedRepositoryNames.includes(repositoryName)
}
}
43 changes: 43 additions & 0 deletions src/features/projects/view/MobileToolbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Stack } from "@mui/material"
import Project from "../domain/Project"
import Version from "../domain/Version"
import OpenApiSpecification from "../domain/OpenApiSpecification"
import VersionSelector from "./docs/VersionSelector"
import SpecificationSelector from "./docs/SpecificationSelector"

const MobileToolbar = ({
project,
version,
specification,
onSelectVersion,
onSelectSpecification
}: {
project: Project
version: Version
specification: OpenApiSpecification
onSelectVersion: (versionId: string) => void,
onSelectSpecification: (specificationId: string) => void
}) => {
return (
<Stack
direction="column"
spacing={1}
sx={{ display: { sm: "block", md: "none" } }}
>
<VersionSelector
versions={project.versions}
selection={version.id}
onSelect={onSelectVersion}
sx={{ width: "100%" }}
/>
<SpecificationSelector
specifications={version.specifications}
selection={specification.id}
onSelect={onSelectSpecification}
sx={{ width: "100%" }}
/>
</Stack>
)
}

export default MobileToolbar
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ProjectPageStateContainer, ProjectPageState } from "../domain/ProjectPa
import ProjectErrorContent from "./ProjectErrorContent"
import DocumentationViewer from "./docs/DocumentationViewer"

const ProjectsPageSecondaryContent = ({
const ProjectsPageContent = ({
stateContainer
}: {
stateContainer: ProjectPageStateContainer
Expand All @@ -24,4 +24,4 @@ const ProjectsPageSecondaryContent = ({
}
}

export default ProjectsPageSecondaryContent
export default ProjectsPageContent
66 changes: 0 additions & 66 deletions src/features/projects/view/ProjectsPageTrailingToolbarItem.tsx

This file was deleted.

97 changes: 97 additions & 0 deletions src/features/projects/view/TrailingToolbarItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { SxProps } from "@mui/system"
import { Stack, IconButton, Typography, Link } from "@mui/material"
import Project from "../domain/Project"
import Version from "../domain/Version"
import OpenApiSpecification from "../domain/OpenApiSpecification"
import VersionSelector from "./docs/VersionSelector"
import SpecificationSelector from "./docs/SpecificationSelector"
import EditIcon from "@mui/icons-material/Edit"

const TrailingToolbarItem = ({
project,
version,
specification,
onSelectVersion,
onSelectSpecification
}: {
project: Project
version: Version
specification: OpenApiSpecification
onSelectVersion: (versionId: string) => void,
onSelectSpecification: (specificationId: string) => void
}) => {
return (
<>
<Stack
direction="row"
alignItems="center"
sx={{ display: { sm: "flex", md: "none" } }}
>
<ProjectName text={project.name} url={version.url} />
</Stack>
<Stack
direction="row"
alignItems="center"
sx={{ display: { xs: "none", sm: "none", md: "flex" } }}
>
<ProjectName text={project.name} url={version.url} sx={{ marginRight: 1 }} />
<Typography variant="h6" sx={{ marginRight: 1 }}>/</Typography>
<VersionSelector
versions={project.versions}
selection={version.id}
onSelect={onSelectVersion}
sx={{ marginRight: 1 }}
/>
<Typography variant="h6" sx={{ marginRight: 1 }}>/</Typography>
<SpecificationSelector
specifications={version.specifications}
selection={specification.id}
onSelect={onSelectSpecification}
sx={{ marginRight: 1 }}
/>
{specification.editURL &&
<IconButton
href={specification.editURL}
target="_blank"
edge="end"
>
<EditIcon/>
</IconButton>
}
</Stack>
</>
)
}

export default TrailingToolbarItem

const ProjectName = ({
url,
text,
sx
}: {
url?: string
text: string
sx?: SxProps
}) => {
if (url) {
return (
<Link
variant="body1"
color="inherit"
underline="hover"
href={url}
target="_blank"
sx={sx}
>
{text}
</Link>
)
} else {
return (
<Typography variant="body1">
{text}
</Typography>
)
}
}
Loading