Files
anonymous_github/src/server/routes/pullRequest-private.ts
T

299 lines
9.0 KiB
TypeScript

import * as express from "express";
import { ensureAuthenticated } from "./connection";
import {
getPullRequest,
getUser,
handleError,
isOwnerOrAdmin,
extendExpirationDate,
} from "./route-utils";
import AnonymousError from "../../core/AnonymousError";
import { IAnonymizedPullRequestDocument } from "../../core/model/anonymizedPullRequests/anonymizedPullRequests.types";
import PullRequest from "../../core/PullRequest";
import AnonymizedPullRequestModel from "../../core/model/anonymizedPullRequests/anonymizedPullRequests.model";
import { RepositoryStatus } from "../../core/types";
const router = express.Router();
// user needs to be connected for all user API
router.use(ensureAuthenticated);
// refresh pullRequest
router.post(
"/:pullRequestId/refresh",
async (req: express.Request, res: express.Response) => {
try {
const pullRequest = await getPullRequest(req, res, { nocheck: true });
if (!pullRequest) return;
const user = await getUser(req);
isOwnerOrAdmin([pullRequest.owner.id], user);
await pullRequest.updateIfNeeded({ force: true });
res.json({ status: pullRequest.status });
} catch (error) {
handleError(error, res, req);
}
}
);
// extend the expiration of a pullRequest (default +6 months) and bring it back
// online if it had expired
router.post(
"/:pullRequestId/extend",
async (req: express.Request, res: express.Response) => {
try {
const pullRequest = await getPullRequest(req, res, { nocheck: true });
if (!pullRequest) return;
if (
pullRequest.status == RepositoryStatus.PREPARING ||
pullRequest.status == RepositoryStatus.REMOVING ||
pullRequest.status == RepositoryStatus.EXPIRING ||
pullRequest.status == RepositoryStatus.REMOVED
) {
throw new AnonymousError("invalid_status", {
object: pullRequest,
httpStatus: 409,
});
}
const user = await getUser(req);
isOwnerOrAdmin([pullRequest.owner.id], user);
const newExpiration = extendExpirationDate(
pullRequest.model.options.expirationDate
);
pullRequest.model.options.expirationDate = newExpiration;
await AnonymizedPullRequestModel.updateOne(
{ _id: pullRequest.model._id },
{ $set: { "options.expirationDate": newExpiration } }
).exec();
await pullRequest.updateIfNeeded({ force: true });
res.json({ status: pullRequest.status, expirationDate: newExpiration });
} catch (error) {
handleError(error, res, req);
}
}
);
// delete a pullRequest
router.delete(
"/:pullRequestId/",
async (req: express.Request, res: express.Response) => {
const pullRequest = await getPullRequest(req, res, { nocheck: true });
if (!pullRequest) return;
try {
if (pullRequest.status == "removed")
throw new AnonymousError("is_removed", {
object: req.params.pullRequestId,
httpStatus: 410,
});
const user = await getUser(req);
isOwnerOrAdmin([pullRequest.owner.id], user);
await pullRequest.remove();
return res.json({ status: pullRequest.status });
} catch (error) {
handleError(error, res, req);
}
}
);
router.get(
"/:owner/:repository/:pullRequestId",
async (req: express.Request, res: express.Response) => {
try {
const user = await getUser(req);
const pullRequest = new PullRequest(
new AnonymizedPullRequestModel({
owner: user.id,
source: {
pullRequestId: parseInt(req.params.pullRequestId),
repositoryFullName: `${req.params.owner}/${req.params.repository}`,
},
})
);
pullRequest.owner = user;
await pullRequest.download();
res.json(pullRequest.toJSON());
} catch (error) {
handleError(error, res, req);
}
}
);
// get pullRequest information
router.get(
"/:pullRequestId/",
async (req: express.Request, res: express.Response) => {
try {
const pullRequest = await getPullRequest(req, res, { nocheck: true });
if (!pullRequest) return;
const user = await getUser(req);
isOwnerOrAdmin([pullRequest.owner.id], user);
res.json(pullRequest.toJSON());
} catch (error) {
handleError(error, res, req);
}
}
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function validateNewPullRequest(pullRequestUpdate: any): void {
const validCharacters = /^[0-9a-zA-Z\-_]+$/;
if (
!pullRequestUpdate.pullRequestId.match(validCharacters) ||
pullRequestUpdate.pullRequestId.length < 3
) {
throw new AnonymousError("invalid_pullRequestId", {
object: pullRequestUpdate,
httpStatus: 400,
});
}
if (!pullRequestUpdate.source.repositoryFullName) {
throw new AnonymousError("repository_not_specified", {
object: pullRequestUpdate,
httpStatus: 400,
});
}
if (!pullRequestUpdate.source.pullRequestId) {
throw new AnonymousError("pullRequestId_not_specified", {
object: pullRequestUpdate,
httpStatus: 400,
});
}
if (
parseInt(pullRequestUpdate.source.pullRequestId) !=
pullRequestUpdate.source.pullRequestId
) {
throw new AnonymousError("pullRequestId_is_not_a_number", {
object: pullRequestUpdate,
httpStatus: 400,
});
}
if (!pullRequestUpdate.options) {
throw new AnonymousError("options_not_provided", {
object: pullRequestUpdate,
httpStatus: 400,
});
}
if (!Array.isArray(pullRequestUpdate.terms)) {
throw new AnonymousError("invalid_terms_format", {
object: pullRequestUpdate,
httpStatus: 400,
});
}
}
function updatePullRequestModel(
model: IAnonymizedPullRequestDocument,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
pullRequestUpdate: any
) {
model.options = {
terms: pullRequestUpdate.terms,
expirationMode: pullRequestUpdate.options.expirationMode,
expirationDate: pullRequestUpdate.options.expirationDate
? new Date(pullRequestUpdate.options.expirationDate)
: undefined,
update: pullRequestUpdate.options.update,
image: pullRequestUpdate.options.image,
link: pullRequestUpdate.options.link,
body: pullRequestUpdate.options.body,
title: pullRequestUpdate.options.title,
username: pullRequestUpdate.options.username,
origin: pullRequestUpdate.options.origin,
diff: pullRequestUpdate.options.diff,
comments: pullRequestUpdate.options.comments,
date: pullRequestUpdate.options.date,
};
}
// update a pullRequest
router.post(
"/:pullRequestId/",
async (req: express.Request, res: express.Response) => {
try {
const pullRequest = await getPullRequest(req, res, { nocheck: true });
if (!pullRequest) return;
const user = await getUser(req);
isOwnerOrAdmin([pullRequest.owner.id], user);
const pullRequestUpdate = req.body;
validateNewPullRequest(pullRequestUpdate);
pullRequest.model.anonymizeDate = new Date();
updatePullRequestModel(pullRequest.model, pullRequestUpdate);
// TODO handle conference
pullRequest.model.conference = pullRequestUpdate.conference;
await AnonymizedPullRequestModel.updateOne(
{ _id: pullRequest.model._id },
{
$set: {
options: pullRequest.model.options,
conference: pullRequest.model.conference,
anonymizeDate: pullRequest.model.anonymizeDate,
},
}
).exec();
await pullRequest.updateStatus(RepositoryStatus.PREPARING);
await pullRequest.updateIfNeeded({ force: true });
res.json(pullRequest.toJSON());
} catch (error) {
return handleError(error, res, req);
}
}
);
// add pullRequest
router.post("/", async (req: express.Request, res: express.Response) => {
const pullRequestUpdate = req.body;
try {
const user = await getUser(req);
validateNewPullRequest(pullRequestUpdate);
const pullRequest = new PullRequest(
new AnonymizedPullRequestModel({
owner: user.id,
options: pullRequestUpdate.options,
})
);
pullRequest.model.pullRequestId = pullRequestUpdate.pullRequestId;
pullRequest.model.anonymizeDate = new Date();
pullRequest.model.owner = user.id;
updatePullRequestModel(pullRequest.model, pullRequestUpdate);
pullRequest.source.accessToken = user.accessToken;
pullRequest.source.pullRequestId = pullRequestUpdate.source.pullRequestId;
pullRequest.source.repositoryFullName =
pullRequestUpdate.source.repositoryFullName;
pullRequest.conference = pullRequestUpdate.conference;
await pullRequest.model.save();
await pullRequest.anonymize();
res.send(pullRequest.toJSON());
} catch (error) {
if (
error instanceof Error &&
error.message.indexOf(" duplicate key") > -1
) {
return handleError(
new AnonymousError("pullRequestId_already_used", {
httpStatus: 400,
cause: error,
object: pullRequestUpdate,
}),
res,
req
);
}
return handleError(error, res, req);
}
});
export default router;