Skip to content

Commit

Permalink
feat: Add /suggestSource endpoint for external use (#300)
Browse files Browse the repository at this point in the history
  • Loading branch information
kouloumos authored Oct 9, 2024
1 parent 25e257b commit b5a7258
Show file tree
Hide file tree
Showing 13 changed files with 475 additions and 205 deletions.
6 changes: 5 additions & 1 deletion .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ GITHUB_SECRET = ""
NEXT_PUBLIC_APP_QUEUE_BASE_URL = ""
NEXTAUTH_URL = ""
NEXTAUTH_SECRET = ""
NEXT_PUBLIC_VERCEL_ENV = "" # development | production
NEXT_PUBLIC_VERCEL_ENV = "" # development | production
# For 'Suggest a Source for Transcription' GitHub App
GITHUB_CURATOR_APP_ID = ""
GITHUB_CURATOR_PRIVATE_KEY_BASE64 = ""
GITHUB_CURATOR_INSTALLATION_ID = ""
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
"@chakra-ui/react": "^2.8.0",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@octokit/auth-app": "^7.1.1",
"@octokit/core": "^5.0.0",
"@octokit/rest": "^21.0.2",
"@splidejs/react-splide": "^0.7.12",
"@splidejs/splide": "^4.1.4",
"@tanstack/react-query": "^4.32.6",
Expand Down
44 changes: 16 additions & 28 deletions src/pages/api/github/fork.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,21 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { Octokit } from "@octokit/core";

import { auth } from "../auth/[...nextauth]";
import { getOctokit } from "@/utils/getOctokit";
import { withGithubErrorHandler } from "@/utils/githubApiErrorHandler";

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// Check if the user is authenticated
const session = await auth(req, res);
if (!session || !session.accessToken || !session.user?.githubUsername) {
return res.status(401).json({ message: "Unauthorized" });
}
async function handler(req: NextApiRequest, res: NextApiResponse) {
const { octokit, owner } = await getOctokit(req, res);
const { repo } = req.body;

const { owner, repo } = req.body;

// Initialize Octokit with the user's access token
const octokit = new Octokit({ auth: session.accessToken });

try {
// Fork the repository
const result = await octokit.request("POST /repos/{owner}/{repo}/forks", {
owner,
repo,
});
res.status(200).json(result.data);
} catch (error) {
console.error("fork failed");
console.error(error);
res.status(500).json({ message: "Error occurred while creating fork" });
}
// Fork the repository
const result = await octokit.request("POST /repos/{owner}/{repo}/forks", {
owner,
repo,
});
res.status(200).json(result.data);
}

export default withGithubErrorHandler(
handler,
"Error occurred while creating fork"
);
56 changes: 22 additions & 34 deletions src/pages/api/github/newBranch.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { upstreamOwner } from "@/config/default";
import { Octokit } from "@octokit/core";
import { Octokit } from "@octokit/rest";
import { NextApiRequest, NextApiResponse } from "next";
import { auth } from "../auth/[...nextauth]";
import { getOctokit } from "@/utils/getOctokit";
import { withGithubErrorHandler } from "@/utils/githubApiErrorHandler";

type NewBranchArgs = {
octokit: InstanceType<typeof Octokit>;
octokit: Octokit;
upstreamRepo: string;
baseBranch: string;
branchName: string;
Expand Down Expand Up @@ -50,38 +51,25 @@ export async function createNewBranch({
});
}

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// Check if the user is authenticated
const session = await auth(req, res);
if (!session || !session.accessToken || !session.user?.githubUsername) {
return res.status(401).json({ message: "Unauthorized" });
}

async function handler(req: NextApiRequest, res: NextApiResponse) {
const { octokit, owner } = await getOctokit(req, res);
const { upstreamRepo, baseBranch, branchName } = req.body;

// Initialize Octokit with the user's access token
const octokit = new Octokit({ auth: session.accessToken });

try {
// Call the createNewBranch function
const result = await createNewBranch({
octokit,
upstreamRepo,
baseBranch,
branchName,
owner: session.user.githubUsername,
});
const result = await createNewBranch({
octokit,
upstreamRepo,
baseBranch,
branchName,
owner,
});

res.status(200).json({
message: "succesfully created a new branch",
...result,
});
} catch (error: any) {
res.status(500).json({
message: error?.message ?? "Error occurred while creating new branch",
});
}
res.status(200).json({
message: "successfully created a new branch",
...result,
});
}

export default withGithubErrorHandler(
handler,
"Error occurred while creating new branch"
);
55 changes: 20 additions & 35 deletions src/pages/api/github/pr.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,26 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { Octokit } from "@octokit/core";

import { createPullRequest } from "@/utils/github";
import { auth } from "../auth/[...nextauth]";

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// Check if the user is authenticated
const session = await auth(req, res);
if (!session || !session.accessToken || !session.user?.githubUsername) {
return res.status(401).json({ message: "Unauthorized" });
}
import { getOctokit } from "@/utils/getOctokit";
import { withGithubErrorHandler } from "@/utils/githubApiErrorHandler";

// Initialize Octokit with the user's access token
const octokit = new Octokit({ auth: session.accessToken });
async function handler(req: NextApiRequest, res: NextApiResponse) {
const { octokit, owner } = await getOctokit(req, res);
const { repo, title, body, head, base } = req.body;

const { owner, repo, title, body, head, base } = req.body;
const prResult = await createPullRequest({
octokit,
owner,
repo,
title,
body,
head,
base,
});

try {
const prResult = await createPullRequest({
octokit,
owner,
repo,
title,
body,
head,
base,
});

return res.status(200).json(prResult.data);
} catch (error: any) {
console.error(error);
res.status(500).json({
message:
error?.message ?? "Error occurred while creating the Pull Request",
});
}
return res.status(200).json(prResult.data);
}

export default withGithubErrorHandler(
handler,
"Error occurred while creating the Pull Request"
);
74 changes: 28 additions & 46 deletions src/pages/api/github/save.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { Octokit } from "@octokit/core";

import { getFileSha, updateOrCreateFile } from "@/utils/github";
import { auth } from "../auth/[...nextauth]";
import { getOctokit } from "@/utils/getOctokit";
import { withGithubErrorHandler } from "@/utils/githubApiErrorHandler";

export const config = {
api: {
Expand All @@ -14,51 +14,33 @@ export const config = {
},
};

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// Check if the user is authenticated
const session = await auth(req, res);
if (
!session ||
!session.accessToken ||
!session.user?.jwt ||
!session.user?.githubUsername
) {
return res.status(401).json({ message: "Unauthorized" });
}

// Initialize Octokit with the user's access token
const octokit = new Octokit({ auth: session.accessToken });
async function handler(req: NextApiRequest, res: NextApiResponse) {
const { octokit, owner } = await getOctokit(req, res);

const { repo, filePath, fileContent, branch } = req.body;

try {
const fileSha = await getFileSha({
octokit,
owner: session.user.githubUsername,
repo,
path: filePath,
branch,
});

await updateOrCreateFile({
octokit,
owner: session.user.githubUsername,
repo,
path: filePath,
fileContent,
branch,
sha: fileSha,
});

res.status(200).json({ message: "Successfully saved edits" });
} catch (error: any) {
console.error(error);
const errMessage = error?.message;
res
.status(500)
.json({ message: errMessage ?? "Error occurred while saving fork" });
}
const fileSha = await getFileSha({
octokit,
owner,
repo,
path: filePath,
branch,
});

await updateOrCreateFile({
octokit,
owner,
repo,
path: filePath,
fileContent,
branch,
sha: fileSha,
});

res.status(200).json({ message: "Successfully saved edits" });
}

export default withGithubErrorHandler(
handler,
"Error occurred while creating the Pull Request"
);
88 changes: 88 additions & 0 deletions src/pages/api/github/suggestSource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import type { NextApiRequest, NextApiResponse } from "next";
import yaml from "js-yaml";
import { getOctokit } from "@/utils/getOctokit";
import { upstreamOwner, upstreamRepo } from "@/config/default";
import { deriveFileSlug } from "@/utils";
import { createNewBranch } from "./newBranch";
import { withGithubErrorHandler } from "@/utils/githubApiErrorHandler";

async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "POST") {
return res.status(405).json({ message: "Method not allowed" });
}

const { octokit, owner } = await getOctokit(req, res, {
allowAppFallback: true,
});
const { title, media, targetRepository } = req.body;

if (owner !== upstreamOwner) {
// Fork the main repository
await octokit.request("POST /repos/{owner}/{repo}/forks", {
owner: upstreamOwner,
repo: upstreamRepo,
});
}

// Create new branch
const timeInSeconds = Math.floor(Date.now() / 1000);
const fileName = deriveFileSlug(title);
const branchName = `${timeInSeconds}-${fileName}`;
await createNewBranch({
octokit,
upstreamRepo,
baseBranch:
process.env.NEXT_PUBLIC_VERCEL_ENV === "production"
? "master"
: "staging",
branchName,
owner,
});

// Save file
const transcriptMarkdown =
`---\n` +
yaml.dump(
{
title,
media,
needs: "transcript",
},
{
forceQuotes: true,
}
) +
"---\n";

await octokit.request("PUT /repos/{owner}/{repo}/contents/{path}", {
owner,
repo: upstreamRepo,
path: `misc/${fileName}.md`,
message: `curate(transcript): "${title}"`,
content: Buffer.from(transcriptMarkdown).toString("base64"),
branch: branchName,
});

// Open PR with user's suggestion
const prResult = await octokit.request("POST /repos/{owner}/{repo}/pulls", {
owner: targetRepository === "user" ? owner : upstreamOwner,
repo: upstreamRepo,
title: `curate(transcript): "${title}"`,
body: `This PR is a suggestion for the transcription of [${title}](${media}).`,
head: `${owner}:${branchName}`,
base:
process.env.NEXT_PUBLIC_VERCEL_ENV === "production"
? "master"
: "staging",
});

res.status(200).json({
message: "Suggestion submitted successfully",
pr_url: prResult.data.html_url,
});
}

export default withGithubErrorHandler(
handler,
"Error occurred while submitting suggestion"
);
Loading

0 comments on commit b5a7258

Please sign in to comment.