.ts
TypeScript
(application/typescript)
// std
import { join, resolve } from "node:path";
// 1st-party
import type { ReqHandler } from "@ethicdevs/react-monolith";
// app
import { AppRoute, AppRouteParams } from "../../routes.defs";
import { Env } from "../../env";
// app services
import { makeOrganizationService } from "../../services/organization";
import { makeRepositoryService } from "../../services/repository";
import { makeUsersService } from "../../services/user";
// app views
import RepositoryForkView, {
  RepositoryForkViewProps,
} from "../../views/repository/RepositoryForkView";

const postRepositoryForkAction: ReqHandler<
  AppRouteParams,
  AppRoute.REPOSITORY_FORK_ACTION
> = async (request, reply) => {
  if (
    request.session.data.authenticated === false ||
    request.session.data.curr_user_uid == null
  ) {
    reply.redirect(302, request.namedViewsPathMap[AppRoute.AUTH_LOGIN]);
    return reply;
  }

  const reqHandler = reply.makeRequestHandler(request, reply);
  const organizationService = makeOrganizationService({ request });
  const repoService = makeRepositoryService({ request });
  const usersService = makeUsersService({ request });

  const { body, params, validationError } = request;
  const { orgSlug: sourceOrgSlug, repoSlug: sourceRepoSlug } = params;
  const {
    target_org_slug: targetOrgSlug,
    target_repo_slug: targetRepoSlug,
    target_repo_display_name: targetRepoDisplayName,
    target_repo_visibility: targetRepoVisibility,
  } = body;

  const sourceParentOrg = await organizationService.getOrganizationBySlug(
    sourceOrgSlug
  );

  if (sourceParentOrg == null) {
    return reply.status(404).callNotFound();
  }

  const sourceRepo = await repoService.getRepository(
    sourceOrgSlug,
    sourceRepoSlug
  );

  if (sourceRepo == null) {
    return reply.status(404).callNotFound();
  }

  const targetParentOrg = await organizationService.getOrganizationBySlug(
    targetOrgSlug
  );

  if (targetParentOrg == null) {
    return reply.status(404).callNotFound();
  }

  const availableParentOrgs = await usersService.getUserOrganizations(
    request.session.data.curr_user_uid
  );

  if (validationError != null) {
    const { message: errorMessage } = validationError;
    return reqHandler<RepositoryForkViewProps>(RepositoryForkView.name, {
      availableParentOrgs,
      sourceParentOrg,
      sourceRepo,
      errorMessage,
      initialValues: body,
    });
  }

  try {
    const newRepo = await repoService.forkRepository({
      source: {
        parentOrg: sourceParentOrg,
        parentOrgRepositoriesDir: resolve(
          join(Env.GIT_REPOSITORIES_ROOT, sourceParentOrg.slug)
        ),
        repository: sourceRepo,
      },
      target: {
        parentOrg: targetParentOrg,
        parentOrgRepositoriesDir: resolve(
          join(Env.GIT_REPOSITORIES_ROOT, targetParentOrg.slug)
        ),
        repoSlug: targetRepoSlug,
        repoData: {
          displayName: targetRepoDisplayName,
          visibility: targetRepoVisibility,
        },
      },
    });

    reply.redirect(302, `/${targetParentOrg.slug}/${newRepo.slug}`);
    return reply;
  } catch (err) {
    return reqHandler<RepositoryForkViewProps>(RepositoryForkView.name, {
      availableParentOrgs,
      sourceParentOrg,
      sourceRepo,
      errorMessage: (err as Error).message,
      initialValues: body,
    });
  }
};

export default postRepositoryForkAction;