feat(pull_requests): add base code for pullRequest details system
+ 917
- 9
app/controllers/index.ts
@@ -2,6 +2,7 @@ export { AuthController } from "./auth";
 export { HomeController } from "./home";
 export { OrganizationController } from "./organization";
 export { RepositoryController } from "./repository";
+export { RepositoryPullRequestsController } from "./repositoryPullRequests";
 export { SyntaxHighlightController } from "./syntaxHighlight";
 export { ThemeController } from "./theme";
 export { UserController } from "./user";

app/controllers/repository/index.ts
@@ -5,12 +5,9 @@ import { default as getRepositoryCreateView } from "./getRepositoryCreateView";
 import { default as getRepositoryDetailsView } from "./getRepositoryDetailsView";
 import { default as getRepositoryExploreView } from "./getRepositoryExploreView";
 import { default as getRepositoryForkView } from "./getRepositoryForkView";
-import { default as getRepositoryPullRequestCreateView } from "./getRepositoryPullRequestCreateView";
-import { default as getRepositoryPullRequestsView } from "./getRepositoryPullRequestsView";
 import { default as getRepositoryShowObjectView } from "./getRepositoryShowObjectView";
 import { default as postRepositoryCreateAction } from "./postRepositoryCreateAction";
 import { default as postRepositoryForkAction } from "./postRepositoryForkAction";
-import { default as postRepositoryPullRequestCreateAction } from "./postRepositoryPullRequestCreateAction";
 
 export const RepositoryController = {
   getRepositoryBrowserView,

...
@@ -20,10 +17,7 @@ export const RepositoryController = {
   getRepositoryDetailsView,
   getRepositoryExploreView,
   getRepositoryForkView,
-  getRepositoryPullRequestCreateView,
-  getRepositoryPullRequestsView,
   getRepositoryShowObjectView,
   postRepositoryCreateAction,
   postRepositoryForkAction,
-  postRepositoryPullRequestCreateAction,
 };

new file
app/controllers/repositoryPullRequests/getRepositoryPullRequestCloseAction.ts
@@ -0,0 +1,69 @@
+// 1st-party
+import type { ReqHandler } from "@ethicdevs/react-monolith";
+import { ResourceVisibility } from "@prisma/client";
+// app
+import { AppRoute, AppRoutesParams } from "../../routes";
+// app services
+import { makeOrganizationService } from "../../services/organization";
+import { makePullRequestService } from "../../services/pullRequest";
+import { makeRepositoryService } from "../../services/repository";
+import { makeUsersService } from "../../services/user";
+// app views
+import RepositoryPullRequestsView, {
+  RepositoryPullRequestsViewProps,
+} from "../../views/repository/RepositoryPullRequestsView";
+
+const getRepositoryPullRequestCloseAction: ReqHandler = async (
+  request,
+  reply
+) => {
+  const { orgSlug, repoSlug } =
+    request.params as AppRoutesParams[AppRoute.REPOSITORY_PULL_REQUESTS]["params"];
+
+  const orgService = makeOrganizationService({ request });
+  const prService = makePullRequestService({ request });
+  const repoService = makeRepositoryService({ request });
+  const usersService = makeUsersService({ request });
+
+  const currentUser =
+    request.session.data.authenticated &&
+    request.session.data.curr_user_uid != null
+      ? await usersService.getUserById(request.session.data.curr_user_uid)
+      : null;
+
+  const parentOrg = await orgService.getOrganizationBySlug(orgSlug);
+
+  if (parentOrg == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  const repo = await repoService.getRepository(orgSlug, repoSlug);
+
+  if (repo == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  if (repo.visibility === ResourceVisibility.PRIVATE) {
+    if (currentUser == null) {
+      return reply.status(404).callNotFound();
+    } else if (
+      (await repoService.canUserAccessRepository(currentUser, repo)) === false
+    ) {
+      return reply.status(404).callNotFound();
+    }
+  }
+
+  const pullRequests = await prService.getPullRequestsInRepository(repo);
+
+  const reqHandler = reply.makeRequestHandler(request, reply);
+  return reqHandler<RepositoryPullRequestsViewProps>(
+    RepositoryPullRequestsView.name,
+    {
+      parentOrg,
+      pullRequests,
+      repo,
+    }
+  );
+};
+
+export default getRepositoryPullRequestCloseAction;

new file
app/controllers/repositoryPullRequests/getRepositoryPullRequestCommentCreateAction.ts
@@ -0,0 +1,69 @@
+// 1st-party
+import type { ReqHandler } from "@ethicdevs/react-monolith";
+import { ResourceVisibility } from "@prisma/client";
+// app
+import { AppRoute, AppRoutesParams } from "../../routes";
+// app services
+import { makeOrganizationService } from "../../services/organization";
+import { makePullRequestService } from "../../services/pullRequest";
+import { makeRepositoryService } from "../../services/repository";
+import { makeUsersService } from "../../services/user";
+// app views
+import RepositoryPullRequestsView, {
+  RepositoryPullRequestsViewProps,
+} from "../../views/repository/RepositoryPullRequestsView";
+
+const getRepositoryPullRequestCommentCreateAction: ReqHandler = async (
+  request,
+  reply
+) => {
+  const { orgSlug, repoSlug } =
+    request.params as AppRoutesParams[AppRoute.REPOSITORY_PULL_REQUESTS]["params"];
+
+  const orgService = makeOrganizationService({ request });
+  const prService = makePullRequestService({ request });
+  const repoService = makeRepositoryService({ request });
+  const usersService = makeUsersService({ request });
+
+  const currentUser =
+    request.session.data.authenticated &&
+    request.session.data.curr_user_uid != null
+      ? await usersService.getUserById(request.session.data.curr_user_uid)
+      : null;
+
+  const parentOrg = await orgService.getOrganizationBySlug(orgSlug);
+
+  if (parentOrg == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  const repo = await repoService.getRepository(orgSlug, repoSlug);
+
+  if (repo == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  if (repo.visibility === ResourceVisibility.PRIVATE) {
+    if (currentUser == null) {
+      return reply.status(404).callNotFound();
+    } else if (
+      (await repoService.canUserAccessRepository(currentUser, repo)) === false
+    ) {
+      return reply.status(404).callNotFound();
+    }
+  }
+
+  const pullRequests = await prService.getPullRequestsInRepository(repo);
+
+  const reqHandler = reply.makeRequestHandler(request, reply);
+  return reqHandler<RepositoryPullRequestsViewProps>(
+    RepositoryPullRequestsView.name,
+    {
+      parentOrg,
+      pullRequests,
+      repo,
+    }
+  );
+};
+
+export default getRepositoryPullRequestCommentCreateAction;

new file
app/controllers/repositoryPullRequests/getRepositoryPullRequestCommentDeleteAction.ts
@@ -0,0 +1,69 @@
+// 1st-party
+import type { ReqHandler } from "@ethicdevs/react-monolith";
+import { ResourceVisibility } from "@prisma/client";
+// app
+import { AppRoute, AppRoutesParams } from "../../routes";
+// app services
+import { makeOrganizationService } from "../../services/organization";
+import { makePullRequestService } from "../../services/pullRequest";
+import { makeRepositoryService } from "../../services/repository";
+import { makeUsersService } from "../../services/user";
+// app views
+import RepositoryPullRequestsView, {
+  RepositoryPullRequestsViewProps,
+} from "../../views/repository/RepositoryPullRequestsView";
+
+const getRepositoryPullRequestCommentDeleteAction: ReqHandler = async (
+  request,
+  reply
+) => {
+  const { orgSlug, repoSlug } =
+    request.params as AppRoutesParams[AppRoute.REPOSITORY_PULL_REQUESTS]["params"];
+
+  const orgService = makeOrganizationService({ request });
+  const prService = makePullRequestService({ request });
+  const repoService = makeRepositoryService({ request });
+  const usersService = makeUsersService({ request });
+
+  const currentUser =
+    request.session.data.authenticated &&
+    request.session.data.curr_user_uid != null
+      ? await usersService.getUserById(request.session.data.curr_user_uid)
+      : null;
+
+  const parentOrg = await orgService.getOrganizationBySlug(orgSlug);
+
+  if (parentOrg == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  const repo = await repoService.getRepository(orgSlug, repoSlug);
+
+  if (repo == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  if (repo.visibility === ResourceVisibility.PRIVATE) {
+    if (currentUser == null) {
+      return reply.status(404).callNotFound();
+    } else if (
+      (await repoService.canUserAccessRepository(currentUser, repo)) === false
+    ) {
+      return reply.status(404).callNotFound();
+    }
+  }
+
+  const pullRequests = await prService.getPullRequestsInRepository(repo);
+
+  const reqHandler = reply.makeRequestHandler(request, reply);
+  return reqHandler<RepositoryPullRequestsViewProps>(
+    RepositoryPullRequestsView.name,
+    {
+      parentOrg,
+      pullRequests,
+      repo,
+    }
+  );
+};
+
+export default getRepositoryPullRequestCommentDeleteAction;

new file
app/controllers/repositoryPullRequests/getRepositoryPullRequestCommentUpdateAction.ts
@@ -0,0 +1,69 @@
+// 1st-party
+import type { ReqHandler } from "@ethicdevs/react-monolith";
+import { ResourceVisibility } from "@prisma/client";
+// app
+import { AppRoute, AppRoutesParams } from "../../routes";
+// app services
+import { makeOrganizationService } from "../../services/organization";
+import { makePullRequestService } from "../../services/pullRequest";
+import { makeRepositoryService } from "../../services/repository";
+import { makeUsersService } from "../../services/user";
+// app views
+import RepositoryPullRequestsView, {
+  RepositoryPullRequestsViewProps,
+} from "../../views/repository/RepositoryPullRequestsView";
+
+const getRepositoryPullRequestCommentUpdateAction: ReqHandler = async (
+  request,
+  reply
+) => {
+  const { orgSlug, repoSlug } =
+    request.params as AppRoutesParams[AppRoute.REPOSITORY_PULL_REQUESTS]["params"];
+
+  const orgService = makeOrganizationService({ request });
+  const prService = makePullRequestService({ request });
+  const repoService = makeRepositoryService({ request });
+  const usersService = makeUsersService({ request });
+
+  const currentUser =
+    request.session.data.authenticated &&
+    request.session.data.curr_user_uid != null
+      ? await usersService.getUserById(request.session.data.curr_user_uid)
+      : null;
+
+  const parentOrg = await orgService.getOrganizationBySlug(orgSlug);
+
+  if (parentOrg == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  const repo = await repoService.getRepository(orgSlug, repoSlug);
+
+  if (repo == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  if (repo.visibility === ResourceVisibility.PRIVATE) {
+    if (currentUser == null) {
+      return reply.status(404).callNotFound();
+    } else if (
+      (await repoService.canUserAccessRepository(currentUser, repo)) === false
+    ) {
+      return reply.status(404).callNotFound();
+    }
+  }
+
+  const pullRequests = await prService.getPullRequestsInRepository(repo);
+
+  const reqHandler = reply.makeRequestHandler(request, reply);
+  return reqHandler<RepositoryPullRequestsViewProps>(
+    RepositoryPullRequestsView.name,
+    {
+      parentOrg,
+      pullRequests,
+      repo,
+    }
+  );
+};
+
+export default getRepositoryPullRequestCommentUpdateAction;

app/controllers/repository/getRepositoryPullRequestCreateView.ts -> app/controllers/repositoryPullRequests/getRepositoryPullRequestCreateView.ts
new file
app/controllers/repositoryPullRequests/getRepositoryPullRequestDeleteAction.ts
@@ -0,0 +1,69 @@
+// 1st-party
+import type { ReqHandler } from "@ethicdevs/react-monolith";
+import { ResourceVisibility } from "@prisma/client";
+// app
+import { AppRoute, AppRoutesParams } from "../../routes";
+// app services
+import { makeOrganizationService } from "../../services/organization";
+import { makePullRequestService } from "../../services/pullRequest";
+import { makeRepositoryService } from "../../services/repository";
+import { makeUsersService } from "../../services/user";
+// app views
+import RepositoryPullRequestsView, {
+  RepositoryPullRequestsViewProps,
+} from "../../views/repository/RepositoryPullRequestsView";
+
+const getRepositoryPullRequestDeleteAction: ReqHandler = async (
+  request,
+  reply
+) => {
+  const { orgSlug, repoSlug } =
+    request.params as AppRoutesParams[AppRoute.REPOSITORY_PULL_REQUESTS]["params"];
+
+  const orgService = makeOrganizationService({ request });
+  const prService = makePullRequestService({ request });
+  const repoService = makeRepositoryService({ request });
+  const usersService = makeUsersService({ request });
+
+  const currentUser =
+    request.session.data.authenticated &&
+    request.session.data.curr_user_uid != null
+      ? await usersService.getUserById(request.session.data.curr_user_uid)
+      : null;
+
+  const parentOrg = await orgService.getOrganizationBySlug(orgSlug);
+
+  if (parentOrg == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  const repo = await repoService.getRepository(orgSlug, repoSlug);
+
+  if (repo == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  if (repo.visibility === ResourceVisibility.PRIVATE) {
+    if (currentUser == null) {
+      return reply.status(404).callNotFound();
+    } else if (
+      (await repoService.canUserAccessRepository(currentUser, repo)) === false
+    ) {
+      return reply.status(404).callNotFound();
+    }
+  }
+
+  const pullRequests = await prService.getPullRequestsInRepository(repo);
+
+  const reqHandler = reply.makeRequestHandler(request, reply);
+  return reqHandler<RepositoryPullRequestsViewProps>(
+    RepositoryPullRequestsView.name,
+    {
+      parentOrg,
+      pullRequests,
+      repo,
+    }
+  );
+};
+
+export default getRepositoryPullRequestDeleteAction;

new file
app/controllers/repositoryPullRequests/getRepositoryPullRequestDetailsView.ts
@@ -0,0 +1,69 @@
+// 1st-party
+import type { ReqHandler } from "@ethicdevs/react-monolith";
+import { ResourceVisibility } from "@prisma/client";
+// app
+import { AppRoute, AppRoutesParams } from "../../routes";
+// app services
+import { makeOrganizationService } from "../../services/organization";
+import { makePullRequestService } from "../../services/pullRequest";
+import { makeRepositoryService } from "../../services/repository";
+import { makeUsersService } from "../../services/user";
+// app views
+import RepositoryPullRequestsView, {
+  RepositoryPullRequestsViewProps,
+} from "../../views/repository/RepositoryPullRequestsView";
+
+const getRepositoryPullRequestDetailsView: ReqHandler = async (
+  request,
+  reply
+) => {
+  const { orgSlug, repoSlug } =
+    request.params as AppRoutesParams[AppRoute.REPOSITORY_PULL_REQUESTS]["params"];
+
+  const orgService = makeOrganizationService({ request });
+  const prService = makePullRequestService({ request });
+  const repoService = makeRepositoryService({ request });
+  const usersService = makeUsersService({ request });
+
+  const currentUser =
+    request.session.data.authenticated &&
+    request.session.data.curr_user_uid != null
+      ? await usersService.getUserById(request.session.data.curr_user_uid)
+      : null;
+
+  const parentOrg = await orgService.getOrganizationBySlug(orgSlug);
+
+  if (parentOrg == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  const repo = await repoService.getRepository(orgSlug, repoSlug);
+
+  if (repo == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  if (repo.visibility === ResourceVisibility.PRIVATE) {
+    if (currentUser == null) {
+      return reply.status(404).callNotFound();
+    } else if (
+      (await repoService.canUserAccessRepository(currentUser, repo)) === false
+    ) {
+      return reply.status(404).callNotFound();
+    }
+  }
+
+  const pullRequests = await prService.getPullRequestsInRepository(repo);
+
+  const reqHandler = reply.makeRequestHandler(request, reply);
+  return reqHandler<RepositoryPullRequestsViewProps>(
+    RepositoryPullRequestsView.name,
+    {
+      parentOrg,
+      pullRequests,
+      repo,
+    }
+  );
+};
+
+export default getRepositoryPullRequestDetailsView;

new file
app/controllers/repositoryPullRequests/getRepositoryPullRequestMergeAction.ts
@@ -0,0 +1,69 @@
+// 1st-party
+import type { ReqHandler } from "@ethicdevs/react-monolith";
+import { ResourceVisibility } from "@prisma/client";
+// app
+import { AppRoute, AppRoutesParams } from "../../routes";
+// app services
+import { makeOrganizationService } from "../../services/organization";
+import { makePullRequestService } from "../../services/pullRequest";
+import { makeRepositoryService } from "../../services/repository";
+import { makeUsersService } from "../../services/user";
+// app views
+import RepositoryPullRequestsView, {
+  RepositoryPullRequestsViewProps,
+} from "../../views/repository/RepositoryPullRequestsView";
+
+const getRepositoryPullRequestMergeAction: ReqHandler = async (
+  request,
+  reply
+) => {
+  const { orgSlug, repoSlug } =
+    request.params as AppRoutesParams[AppRoute.REPOSITORY_PULL_REQUESTS]["params"];
+
+  const orgService = makeOrganizationService({ request });
+  const prService = makePullRequestService({ request });
+  const repoService = makeRepositoryService({ request });
+  const usersService = makeUsersService({ request });
+
+  const currentUser =
+    request.session.data.authenticated &&
+    request.session.data.curr_user_uid != null
+      ? await usersService.getUserById(request.session.data.curr_user_uid)
+      : null;
+
+  const parentOrg = await orgService.getOrganizationBySlug(orgSlug);
+
+  if (parentOrg == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  const repo = await repoService.getRepository(orgSlug, repoSlug);
+
+  if (repo == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  if (repo.visibility === ResourceVisibility.PRIVATE) {
+    if (currentUser == null) {
+      return reply.status(404).callNotFound();
+    } else if (
+      (await repoService.canUserAccessRepository(currentUser, repo)) === false
+    ) {
+      return reply.status(404).callNotFound();
+    }
+  }
+
+  const pullRequests = await prService.getPullRequestsInRepository(repo);
+
+  const reqHandler = reply.makeRequestHandler(request, reply);
+  return reqHandler<RepositoryPullRequestsViewProps>(
+    RepositoryPullRequestsView.name,
+    {
+      parentOrg,
+      pullRequests,
+      repo,
+    }
+  );
+};
+
+export default getRepositoryPullRequestMergeAction;

new file
app/controllers/repositoryPullRequests/getRepositoryPullRequestUpdateAction.ts
@@ -0,0 +1,69 @@
+// 1st-party
+import type { ReqHandler } from "@ethicdevs/react-monolith";
+import { ResourceVisibility } from "@prisma/client";
+// app
+import { AppRoute, AppRoutesParams } from "../../routes";
+// app services
+import { makeOrganizationService } from "../../services/organization";
+import { makePullRequestService } from "../../services/pullRequest";
+import { makeRepositoryService } from "../../services/repository";
+import { makeUsersService } from "../../services/user";
+// app views
+import RepositoryPullRequestsView, {
+  RepositoryPullRequestsViewProps,
+} from "../../views/repository/RepositoryPullRequestsView";
+
+const getRepositoryPullRequestUpdateAction: ReqHandler = async (
+  request,
+  reply
+) => {
+  const { orgSlug, repoSlug } =
+    request.params as AppRoutesParams[AppRoute.REPOSITORY_PULL_REQUESTS]["params"];
+
+  const orgService = makeOrganizationService({ request });
+  const prService = makePullRequestService({ request });
+  const repoService = makeRepositoryService({ request });
+  const usersService = makeUsersService({ request });
+
+  const currentUser =
+    request.session.data.authenticated &&
+    request.session.data.curr_user_uid != null
+      ? await usersService.getUserById(request.session.data.curr_user_uid)
+      : null;
+
+  const parentOrg = await orgService.getOrganizationBySlug(orgSlug);
+
+  if (parentOrg == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  const repo = await repoService.getRepository(orgSlug, repoSlug);
+
+  if (repo == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  if (repo.visibility === ResourceVisibility.PRIVATE) {
+    if (currentUser == null) {
+      return reply.status(404).callNotFound();
+    } else if (
+      (await repoService.canUserAccessRepository(currentUser, repo)) === false
+    ) {
+      return reply.status(404).callNotFound();
+    }
+  }
+
+  const pullRequests = await prService.getPullRequestsInRepository(repo);
+
+  const reqHandler = reply.makeRequestHandler(request, reply);
+  return reqHandler<RepositoryPullRequestsViewProps>(
+    RepositoryPullRequestsView.name,
+    {
+      parentOrg,
+      pullRequests,
+      repo,
+    }
+  );
+};
+
+export default getRepositoryPullRequestUpdateAction;

app/controllers/repository/getRepositoryPullRequestsView.ts -> app/controllers/repositoryPullRequests/getRepositoryPullRequestsView.ts
new file
app/controllers/repositoryPullRequests/index.ts
+ 25
- 0
@@ -0,0 +1,25 @@
+import { default as getRepositoryPullRequestCloseAction } from "./getRepositoryPullRequestCloseAction";
+import { default as getRepositoryPullRequestCommentCreateAction } from "./getRepositoryPullRequestCommentCreateAction";
+import { default as getRepositoryPullRequestCommentUpdateAction } from "./getRepositoryPullRequestCommentUpdateAction";
+import { default as getRepositoryPullRequestCommentDeleteAction } from "./getRepositoryPullRequestCommentDeleteAction";
+import { default as getRepositoryPullRequestCreateView } from "./getRepositoryPullRequestCreateView";
+import { default as postRepositoryPullRequestCreateAction } from "./postRepositoryPullRequestCreateAction";
+import { default as getRepositoryPullRequestDeleteAction } from "./getRepositoryPullRequestDeleteAction";
+import { default as getRepositoryPullRequestDetailsView } from "./getRepositoryPullRequestDetailsView";
+import { default as getRepositoryPullRequestMergeAction } from "./getRepositoryPullRequestMergeAction";
+import { default as getRepositoryPullRequestUpdateAction } from "./getRepositoryPullRequestUpdateAction";
+import { default as getRepositoryPullRequestsView } from "./getRepositoryPullRequestsView";
+
+export const RepositoryPullRequestsController = {
+  getRepositoryPullRequestCloseAction,
+  getRepositoryPullRequestCommentCreateAction,
+  getRepositoryPullRequestCommentUpdateAction,
+  getRepositoryPullRequestCommentDeleteAction,
+  getRepositoryPullRequestCreateView,
+  getRepositoryPullRequestDeleteAction,
+  getRepositoryPullRequestDetailsView,
+  getRepositoryPullRequestMergeAction,
+  getRepositoryPullRequestUpdateAction,
+  getRepositoryPullRequestsView,
+  postRepositoryPullRequestCreateAction,
+};

app/controllers/repository/postRepositoryPullRequestCreateAction.ts -> app/controllers/repositoryPullRequests/postRepositoryPullRequestCreateAction.ts
@@ -17,6 +17,7 @@ import {
   HomeController,
   OrganizationController,
   RepositoryController,
+  RepositoryPullRequestsController,
   SyntaxHighlightController,
   ThemeController,
   UserController,

...
@@ -42,8 +43,16 @@ export enum AppRoute {
   REPOSITORY_EXPLORE = "repository.explore",
   REPOSITORY_FORK = "repository.fork",
   REPOSITORY_FORK_ACTION = "repository.fork.action",
+  REPOSITORY_PULL_REQUEST_CLOSE_ACTION = "repository.pull_request.close.action",
+  REPOSITORY_PULL_REQUEST_COMMENT_CREATE_ACTION = "repository.pull_request.comment.create.action",
+  REPOSITORY_PULL_REQUEST_COMMENT_DELETE_ACTION = "repository.pull_request.comment.delete.action",
+  REPOSITORY_PULL_REQUEST_COMMENT_UPDATE_ACTION = "repository.pull_request.comment.update.action",
   REPOSITORY_PULL_REQUEST_CREATE = "repository.pull_request.create",
   REPOSITORY_PULL_REQUEST_CREATE_ACTION = "repository.pull_request.create.action",
+  REPOSITORY_PULL_REQUEST_DELETE_ACTION = "repository.pull_request.delete.action",
+  REPOSITORY_PULL_REQUEST_DETAILS = "repository.pull_request.details",
+  REPOSITORY_PULL_REQUEST_MERGE_ACTION = "repository.pull_request.merge.action",
+  REPOSITORY_PULL_REQUEST_UPDATE_ACTION = "repository.pull_request.update.action",
   REPOSITORY_PULL_REQUESTS = "repository.pull_requests",
   REPOSITORY_SHOW_OBJECT = "repository.show_object",
   SYNTAX_HIGHLIGHT_HIGHLIGHT_CODE_ACTION = "syntax_highlight.highlight_code.action",

...
@@ -147,6 +156,41 @@ export interface AppRoutesParams extends IRouteParams {
       target_repo_visibility: ResourceVisibility;
     };
   };
+  [AppRoute.REPOSITORY_PULL_REQUEST_CLOSE_ACTION]: {
+    params: {
+      orgSlug: string;
+      repoSlug: string;
+      pullUid: string;
+    };
+    body: {
+      reason_message: string;
+    };
+  };
+  [AppRoute.REPOSITORY_PULL_REQUEST_COMMENT_CREATE_ACTION]: {
+    params: {
+      orgSlug: string;
+      repoSlug: string;
+      pullUid: number;
+    };
+    body: {}; // TODO: define this object shape
+  };
+  [AppRoute.REPOSITORY_PULL_REQUEST_COMMENT_DELETE_ACTION]: {
+    params: {
+      orgSlug: string;
+      repoSlug: string;
+      pullUid: number;
+      commentId: string;
+    };
+  };
+  [AppRoute.REPOSITORY_PULL_REQUEST_COMMENT_UPDATE_ACTION]: {
+    params: {
+      orgSlug: string;
+      repoSlug: string;
+      pullUid: number;
+      commentId: string;
+    };
+    body: {}; // TODO: define this object shape
+  };
   [AppRoute.REPOSITORY_PULL_REQUEST_CREATE]: {
     params: {
       orgSlug: string;

...
@@ -174,6 +218,39 @@ export interface AppRoutesParams extends IRouteParams {
       target_repository_dest_branch: string;
     };
   };
+  [AppRoute.REPOSITORY_PULL_REQUEST_DELETE_ACTION]: {
+    params: {
+      orgSlug: string;
+      repoSlug: string;
+      pullUid: string;
+    };
+  };
+  [AppRoute.REPOSITORY_PULL_REQUEST_DETAILS]: {
+    params: {
+      orgSlug: string;
+      repoSlug: string;
+      pullUid: string;
+    };
+  };
+  [AppRoute.REPOSITORY_PULL_REQUEST_MERGE_ACTION]: {
+    params: {
+      orgSlug: string;
+      repoSlug: string;
+      pullUid: string;
+    };
+    body: {
+      merge_summary: string;
+      merge_message: string;
+    };
+  };
+  [AppRoute.REPOSITORY_PULL_REQUEST_UPDATE_ACTION]: {
+    params: {
+      orgSlug: string;
+      repoSlug: string;
+      pullUid: string;
+    };
+    body: {}; // TODO: define this object shape
+  };
   [AppRoute.REPOSITORY_PULL_REQUESTS]: {
     params: {
       orgSlug: string;

...
@@ -461,6 +538,80 @@ export const AppRoutesSchemas: Record<AppRoute, undefined | FastifySchema> = {
       },
     },
   },
+  [AppRoute.REPOSITORY_PULL_REQUEST_CLOSE_ACTION]: {
+    params: {
+      type: "object",
+      required: ["orgSlug", "repoSlug", "pullUid"],
+      additionalProperties: false,
+      properties: {
+        orgSlug: {
+          type: "string",
+        },
+        repoSlug: {
+          type: "string",
+        },
+        pullUid: {
+          type: "number",
+        },
+      },
+    },
+  },
+  [AppRoute.REPOSITORY_PULL_REQUEST_COMMENT_CREATE_ACTION]: {
+    params: {
+      type: "object",
+      required: ["orgSlug", "repoSlug", "pullUid"],
+      additionalProperties: false,
+      properties: {
+        orgSlug: {
+          type: "string",
+        },
+        repoSlug: {
+          type: "string",
+        },
+        pullUid: {
+          type: "number",
+        },
+      },
+    },
+    // body: {}, // TODO: define this object shape
+  },
+  [AppRoute.REPOSITORY_PULL_REQUEST_COMMENT_DELETE_ACTION]: {
+    params: {
+      type: "object",
+      required: ["orgSlug", "repoSlug", "pullUid"],
+      additionalProperties: false,
+      properties: {
+        orgSlug: {
+          type: "string",
+        },
+        repoSlug: {
+          type: "string",
+        },
+        pullUid: {
+          type: "number",
+        },
+      },
+    },
+  },
+  [AppRoute.REPOSITORY_PULL_REQUEST_COMMENT_UPDATE_ACTION]: {
+    params: {
+      type: "object",
+      required: ["orgSlug", "repoSlug", "pullUid"],
+      additionalProperties: false,
+      properties: {
+        orgSlug: {
+          type: "string",
+        },
+        repoSlug: {
+          type: "string",
+        },
+        pullUid: {
+          type: "number",
+        },
+      },
+    },
+    // body: {}, // TODO: define this object shape
+  },
   [AppRoute.REPOSITORY_PULL_REQUEST_CREATE]: {
     params: {
       type: "object",

...
@@ -549,6 +700,91 @@ export const AppRoutesSchemas: Record<AppRoute, undefined | FastifySchema> = {
       },
     },
   },
+  [AppRoute.REPOSITORY_PULL_REQUEST_DELETE_ACTION]: {
+    params: {
+      type: "object",
+      required: ["orgSlug", "repoSlug", "pullUid"],
+      additionalProperties: false,
+      properties: {
+        orgSlug: {
+          type: "string",
+        },
+        repoSlug: {
+          type: "string",
+        },
+        pullUid: {
+          type: "number",
+        },
+      },
+    },
+  },
+  [AppRoute.REPOSITORY_PULL_REQUEST_DETAILS]: {
+    params: {
+      type: "object",
+      required: ["orgSlug", "repoSlug", "pullUid"],
+      additionalProperties: false,
+      properties: {
+        orgSlug: {
+          type: "string",
+        },
+        repoSlug: {
+          type: "string",
+        },
+        pullUid: {
+          type: "number",
+        },
+      },
+    },
+  },
+  [AppRoute.REPOSITORY_PULL_REQUEST_MERGE_ACTION]: {
+    params: {
+      type: "object",
+      required: ["orgSlug", "repoSlug", "pullUid"],
+      additionalProperties: false,
+      properties: {
+        orgSlug: {
+          type: "string",
+        },
+        repoSlug: {
+          type: "string",
+        },
+        pullUid: {
+          type: "number",
+        },
+      },
+    },
+    body: {
+      type: "object",
+      required: ["merge_summary"],
+      additionalProperties: false,
+      properties: {
+        merge_summary: {
+          type: "string",
+        },
+        merge_message: {
+          type: "string",
+        },
+      },
+    },
+  },
+  [AppRoute.REPOSITORY_PULL_REQUEST_UPDATE_ACTION]: {
+    params: {
+      type: "object",
+      required: ["orgSlug", "repoSlug", "pullUid"],
+      additionalProperties: false,
+      properties: {
+        orgSlug: {
+          type: "string",
+        },
+        repoSlug: {
+          type: "string",
+        },
+        pullUid: {
+          type: "number",
+        },
+      },
+    },
+  },
   [AppRoute.REPOSITORY_PULL_REQUESTS]: {
     params: {
       type: "object",

...
@@ -776,13 +1012,63 @@ const RootAppRouter: AppRouter = () => {
           preHandler={loggedOrLoginRedirect}
           handler={RepositoryController.postRepositoryForkAction}
         />
+        <Router.Route
+          name={AppRoute.REPOSITORY_PULL_REQUEST_CLOSE_ACTION}
+          method={"POST"}
+          path={"/:orgSlug/:repoSlug/pulls/:pullUid/close"}
+          schema={
+            AppRoutesSchemas[AppRoute.REPOSITORY_PULL_REQUEST_CLOSE_ACTION]
+          }
+          preHandler={loggedOrLoginRedirect}
+          handler={
+            RepositoryPullRequestsController.getRepositoryPullRequestCloseAction
+          }
+        />
+        <Router.Route
+          name={AppRoute.REPOSITORY_PULL_REQUEST_CREATE_ACTION}
+          method={"POST"}
+          path={"/:orgSlug/:repoSlug/pulls/:pullUid/comment"}
+          schema={
+            AppRoutesSchemas[AppRoute.REPOSITORY_PULL_REQUEST_CREATE_ACTION]
+          }
+          preHandler={loggedOrLoginRedirect}
+          handler={
+            RepositoryPullRequestsController.getRepositoryPullRequestCommentCreateAction
+          }
+        />
+        <Router.Route
+          name={AppRoute.REPOSITORY_PULL_REQUEST_UPDATE_ACTION}
+          method={"POST"}
+          path={"/:orgSlug/:repoSlug/pulls/:pullUid/comment/edit"}
+          schema={
+            AppRoutesSchemas[AppRoute.REPOSITORY_PULL_REQUEST_UPDATE_ACTION]
+          }
+          preHandler={loggedOrLoginRedirect}
+          handler={
+            RepositoryPullRequestsController.getRepositoryPullRequestCommentUpdateAction
+          }
+        />
+        <Router.Route
+          name={AppRoute.REPOSITORY_PULL_REQUEST_DELETE_ACTION}
+          method={"POST"}
+          path={"/:orgSlug/:repoSlug/pulls/:pullUid/comment/delete"}
+          schema={
+            AppRoutesSchemas[AppRoute.REPOSITORY_PULL_REQUEST_DELETE_ACTION]
+          }
+          preHandler={loggedOrLoginRedirect}
+          handler={
+            RepositoryPullRequestsController.getRepositoryPullRequestCommentDeleteAction
+          }
+        />
         <Router.Route
           name={AppRoute.REPOSITORY_PULL_REQUEST_CREATE}
           method={"GET"}
           path={"/:orgSlug/:repoSlug/pulls/new"}
           schema={AppRoutesSchemas[AppRoute.REPOSITORY_PULL_REQUEST_CREATE]}
           preHandler={loggedOrLoginRedirect}
-          handler={RepositoryController.getRepositoryPullRequestCreateView}
+          handler={
+            RepositoryPullRequestsController.getRepositoryPullRequestCreateView
+          }
         />
         <Router.Route
           name={AppRoute.REPOSITORY_PULL_REQUEST_CREATE_ACTION}

...
@@ -792,14 +1078,64 @@ const RootAppRouter: AppRouter = () => {
             AppRoutesSchemas[AppRoute.REPOSITORY_PULL_REQUEST_CREATE_ACTION]
           }
           preHandler={loggedOrLoginRedirect}
-          handler={RepositoryController.postRepositoryPullRequestCreateAction}
+          handler={
+            RepositoryPullRequestsController.postRepositoryPullRequestCreateAction
+          }
+        />
+        <Router.Route
+          name={AppRoute.REPOSITORY_PULL_REQUEST_DELETE_ACTION}
+          method={"POST"}
+          path={"/:orgSlug/:repoSlug/pulls/:pullUid/delete"}
+          schema={
+            AppRoutesSchemas[AppRoute.REPOSITORY_PULL_REQUEST_DELETE_ACTION]
+          }
+          preHandler={loggedOrLoginRedirect}
+          handler={
+            RepositoryPullRequestsController.getRepositoryPullRequestDeleteAction
+          }
+        />
+        <Router.Route
+          name={AppRoute.REPOSITORY_PULL_REQUEST_DETAILS}
+          method={"GET"}
+          path={"/:orgSlug/:repoSlug/pulls/:pullUid"}
+          schema={AppRoutesSchemas[AppRoute.REPOSITORY_PULL_REQUEST_DETAILS]}
+          preHandler={loggedOrLoginRedirect}
+          handler={
+            RepositoryPullRequestsController.getRepositoryPullRequestDetailsView
+          }
+        />
+        <Router.Route
+          name={AppRoute.REPOSITORY_PULL_REQUEST_MERGE_ACTION}
+          method={"POST"}
+          path={"/:orgSlug/:repoSlug/pulls/:pullUid/merge"}
+          schema={
+            AppRoutesSchemas[AppRoute.REPOSITORY_PULL_REQUEST_MERGE_ACTION]
+          }
+          preHandler={loggedOrLoginRedirect}
+          handler={
+            RepositoryPullRequestsController.getRepositoryPullRequestMergeAction
+          }
+        />
+        <Router.Route
+          name={AppRoute.REPOSITORY_PULL_REQUEST_UPDATE_ACTION}
+          method={"POST"}
+          path={"/:orgSlug/:repoSlug/pulls/:pullUid/edit"}
+          schema={
+            AppRoutesSchemas[AppRoute.REPOSITORY_PULL_REQUEST_UPDATE_ACTION]
+          }
+          preHandler={loggedOrLoginRedirect}
+          handler={
+            RepositoryPullRequestsController.getRepositoryPullRequestUpdateAction
+          }
         />
         <Router.Route
           name={AppRoute.REPOSITORY_PULL_REQUESTS}
           method={"GET"}
           path={"/:orgSlug/:repoSlug/pulls"}
           schema={AppRoutesSchemas[AppRoute.REPOSITORY_PULL_REQUESTS]}
-          handler={RepositoryController.getRepositoryPullRequestsView}
+          handler={
+            RepositoryPullRequestsController.getRepositoryPullRequestsView
+          }
         />
         <Router.Route
           name={AppRoute.REPOSITORY_SHOW_OBJECT}