Skip to the content

Capsid menu

app/routes/project.bulk.ts

40 lines and 2 functions in DrDustinEdwards/carrel, at commit d5d5e82 on 2026-10-24. This file on GitHub.

Functions

The functions of project.bulk.ts
FunctionLinesComplexityCoveredCRAPMutation
parse12 to 24760%WatchCRAP 10.1No data: mutation testing has not run on this repo yet
action26 to 44871%WatchCRAP 9.6No data: mutation testing has not run on this repo yet

Imports

It imports app/lib/bulk.server.ts, app/lib/context.ts, app/lib/projects.server.ts. No module of this repo imports it.

Source

// The posts list's bulk endpoint: one action on several posts, answered as JSON with an outcome for
// every post. Roles are checked in bulk.server.ts (a delete is the Owner's, a tag or a copy is an
// Editor's, and a live post's change is refused for an Editor on that post alone), before the site
// is asked anything. POST only.

import { bulkApply, type BulkRequest } from "~/lib/bulk.server";
import { getEnv, getViewer } from "~/lib/context";
import { requireSiteProject } from "~/lib/projects.server";

import type { Route } from "./+types/project.bulk";

function parse(form: FormData): BulkRequest | null {
  const op = String(form.get("op") ?? "");
  switch (op) {
    case "tag-add":
    case "tag-remove":
      return { op, tag: String(form.get("tag") ?? "") };
    case "duplicate":
    case "delete":
      return { op };
    default:
      return null;
  }
}

export async function action({ params, request, context }: Route.ActionArgs) {
  if (request.method !== "POST") return Response.json({ error: "Method not allowed." }, { status: 405 });
  const env = getEnv(context);
  const viewer = getViewer(context);
  const project = await requireSiteProject(env.DB, viewer, params.project, "read");
  const form = await request.formData();
  const bulk = parse(form);
  if (!bulk) return Response.json({ error: "That is not a bulk action." }, { status: 400 });
  try {
    const results = await bulkApply(env, project, viewer, bulk, form.getAll("id").map(String));
    return Response.json({ results });
  } catch (thrown) {
    if (!(thrown instanceof Response)) throw thrown;
    if (thrown.status === 403) {
      return Response.json({ error: bulk.op === "delete" ? "Deleting posts is the Owner's step." : "You may not change posts here." }, { status: 403 });
    }
    return Response.json({ error: (await thrown.text()) || "The request was not accepted." }, { status: thrown.status });
  }
}