mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-05-21 16:56:51 +02:00
chore: improve error messages
This commit is contained in:
+96
-20
@@ -67,26 +67,79 @@ router.get("/", async (req: express.Request, res: express.Response) => {
|
||||
});
|
||||
|
||||
function validateConferenceForm(conf) {
|
||||
if (!conf.name) throw new AnonymousError("conf_name_missing");
|
||||
if (!conf.conferenceID) throw new AnonymousError("conf_id_missing");
|
||||
if (!conf.startDate) throw new AnonymousError("conf_start_date_missing");
|
||||
if (!conf.endDate) throw new AnonymousError("conf_end_date_missing");
|
||||
if (!conf.name)
|
||||
throw new AnonymousError("conf_name_missing", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
if (!conf.conferenceID)
|
||||
throw new AnonymousError("conf_id_missing", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
if (!conf.startDate)
|
||||
throw new AnonymousError("conf_start_date_missing", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
if (!conf.endDate)
|
||||
throw new AnonymousError("conf_end_date_missing", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
if (new Date(conf.startDate) > new Date(conf.endDate))
|
||||
throw new AnonymousError("conf_start_date_invalid");
|
||||
throw new AnonymousError("conf_start_date_invalid", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
if (new Date() > new Date(conf.endDate))
|
||||
throw new AnonymousError("conf_end_date_invalid");
|
||||
throw new AnonymousError("conf_end_date_invalid", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
if (plans.filter((p) => p.id == conf.plan.planID).length != 1)
|
||||
throw new AnonymousError("invalid_plan");
|
||||
throw new AnonymousError("invalid_plan", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
const plan = plans.filter((p) => p.id == conf.plan.planID)[0];
|
||||
if (plan.pricePerRepo > 0) {
|
||||
const billing = conf.billing;
|
||||
if (!billing) throw new AnonymousError("billing_missing");
|
||||
if (!billing.name) throw new AnonymousError("billing_name_missing");
|
||||
if (!billing.email) throw new AnonymousError("billing_email_missing");
|
||||
if (!billing.address) throw new AnonymousError("billing_address_missing");
|
||||
if (!billing.city) throw new AnonymousError("billing_city_missing");
|
||||
if (!billing.zip) throw new AnonymousError("billing_zip_missing");
|
||||
if (!billing.country) throw new AnonymousError("billing_country_missing");
|
||||
if (!billing)
|
||||
throw new AnonymousError("billing_missing", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
if (!billing.name)
|
||||
throw new AnonymousError("billing_name_missing", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
if (!billing.email)
|
||||
throw new AnonymousError("billing_email_missing", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
if (!billing.address)
|
||||
throw new AnonymousError("billing_address_missing", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
if (!billing.city)
|
||||
throw new AnonymousError("billing_city_missing", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
if (!billing.zip)
|
||||
throw new AnonymousError("billing_zip_missing", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
if (!billing.country)
|
||||
throw new AnonymousError("billing_country_missing", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +154,10 @@ router.post(
|
||||
conferenceID: req.params.conferenceID,
|
||||
});
|
||||
if (model.owners.indexOf(user.model.id) == -1)
|
||||
throw new AnonymousError("not_authorized");
|
||||
throw new AnonymousError("not_authorized", {
|
||||
object: req.params.conferenceID,
|
||||
httpStatus: 401,
|
||||
});
|
||||
}
|
||||
validateConferenceForm(req.body);
|
||||
model.name = req.body.name;
|
||||
@@ -146,7 +202,13 @@ router.post(
|
||||
res.send("ok");
|
||||
} catch (error) {
|
||||
if (error.message?.indexOf(" duplicate key") > -1) {
|
||||
return handleError(new AnonymousError("conf_id_used"), res);
|
||||
return handleError(
|
||||
new AnonymousError("conf_id_used", {
|
||||
object: req.params.conferenceID,
|
||||
httpStatus: 400,
|
||||
}),
|
||||
res
|
||||
);
|
||||
}
|
||||
handleError(error, res);
|
||||
}
|
||||
@@ -161,10 +223,17 @@ router.get(
|
||||
const data = await ConferenceModel.findOne({
|
||||
conferenceID: req.params.conferenceID,
|
||||
});
|
||||
if (!data) throw new AnonymousError("conf_not_found");
|
||||
if (!data)
|
||||
throw new AnonymousError("conf_not_found", {
|
||||
object: req.params.conferenceID,
|
||||
httpStatus: 404,
|
||||
});
|
||||
const conference = new Conference(data);
|
||||
if (conference.ownerIDs.indexOf(user.model.id) == -1)
|
||||
throw new AnonymousError("not_authorized");
|
||||
throw new AnonymousError("not_authorized", {
|
||||
object: req.params.conferenceID,
|
||||
httpStatus: 401,
|
||||
});
|
||||
const o: any = conference.toJSON();
|
||||
o.repositories = (await conference.repositories()).map((r) => r.toJSON());
|
||||
res.json(o);
|
||||
@@ -182,10 +251,17 @@ router.delete(
|
||||
const data = await ConferenceModel.findOne({
|
||||
conferenceID: req.params.conferenceID,
|
||||
});
|
||||
if (!data) throw new AnonymousError("conf_not_found");
|
||||
if (!data)
|
||||
throw new AnonymousError("conf_not_found", {
|
||||
object: req.params.conferenceID,
|
||||
httpStatus: 400,
|
||||
});
|
||||
const conference = new Conference(data);
|
||||
if (conference.ownerIDs.indexOf(user.model.id) == -1)
|
||||
throw new AnonymousError("not_authorized");
|
||||
throw new AnonymousError("not_authorized", {
|
||||
object: req.params.conferenceID,
|
||||
httpStatus: 401,
|
||||
});
|
||||
await conference.remove();
|
||||
res.send("ok");
|
||||
} catch (error) {
|
||||
|
||||
+5
-1
@@ -1,5 +1,6 @@
|
||||
import * as express from "express";
|
||||
import AnonymizedFile from "../AnonymizedFile";
|
||||
import AnonymousError from "../AnonymousError";
|
||||
import { getRepo, handleError } from "./route-utils";
|
||||
|
||||
export const router = express.Router();
|
||||
@@ -24,7 +25,10 @@ router.get(
|
||||
anonymizedPath,
|
||||
});
|
||||
if (!(await f.isFileSupported())) {
|
||||
return res.status(500).send({ error: "file_not_supported" });
|
||||
throw new AnonymousError("file_not_supported", {
|
||||
httpStatus: 403,
|
||||
object: f,
|
||||
});
|
||||
}
|
||||
res.attachment(
|
||||
anonymizedPath.substring(anonymizedPath.lastIndexOf("/") + 1)
|
||||
|
||||
@@ -24,15 +24,24 @@ router.post("/claim", async (req: express.Request, res: express.Response) => {
|
||||
const user = await getUser(req);
|
||||
try {
|
||||
if (!req.body.repoId) {
|
||||
return res.status(500).json({ error: "repoId_not_defined" });
|
||||
throw new AnonymousError("repoId_not_defined", {
|
||||
object: req.body,
|
||||
httpStatus: 400,
|
||||
});
|
||||
}
|
||||
if (!req.body.repoUrl) {
|
||||
return res.status(500).json({ error: "repoUrl_not_defined" });
|
||||
throw new AnonymousError("repoUrl_not_defined", {
|
||||
object: req.body,
|
||||
httpStatus: 400,
|
||||
});
|
||||
}
|
||||
|
||||
const repoConfig = await db.getRepository(req.body.repoId);
|
||||
if (repoConfig == null) {
|
||||
return res.status(500).json({ error: "repo_not_found" });
|
||||
throw new AnonymousError("repo_not_found", {
|
||||
object: req.body,
|
||||
httpStatus: 404,
|
||||
});
|
||||
}
|
||||
|
||||
const r = gh(req.body.repoUrl);
|
||||
@@ -42,7 +51,10 @@ router.post("/claim", async (req: express.Request, res: express.Response) => {
|
||||
accessToken: user.accessToken,
|
||||
});
|
||||
if ((repoConfig.source as GitHubBase).githubRepository.id != repo.id) {
|
||||
return res.status(500).json({ error: "repo_not_found" });
|
||||
throw new AnonymousError("repo_not_found", {
|
||||
object: req.body,
|
||||
httpStatus: 404,
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`${user.username} claims ${r.repository}.`);
|
||||
@@ -70,7 +82,10 @@ router.post(
|
||||
|
||||
const user = await getUser(req);
|
||||
if (repo.owner.id != user.id) {
|
||||
return res.status(401).json({ error: "not_authorized" });
|
||||
throw new AnonymousError("not_authorized", {
|
||||
object: req.params.repoId,
|
||||
httpStatus: 401,
|
||||
});
|
||||
}
|
||||
await repo.updateIfNeeded({ force: true });
|
||||
res.json({ status: repo.status });
|
||||
@@ -88,10 +103,17 @@ router.delete(
|
||||
if (!repo) return;
|
||||
// if (repo.status == "removing") return res.json({ status: repo.status });
|
||||
try {
|
||||
if (repo.status == "removed") throw new AnonymousError("is_removed");
|
||||
if (repo.status == "removed")
|
||||
throw new AnonymousError("is_removed", {
|
||||
object: req.params.repoId,
|
||||
httpStatus: 410,
|
||||
});
|
||||
const user = await getUser(req);
|
||||
if (repo.owner.id != user.id) {
|
||||
return res.status(401).json({ error: "not_authorized" });
|
||||
throw new AnonymousError("not_authorized", {
|
||||
object: req.params.repoId,
|
||||
httpStatus: 401,
|
||||
});
|
||||
}
|
||||
await repo.updateStatus("removing");
|
||||
await removeQueue.add(repo, { jobId: repo.repoId });
|
||||
@@ -152,7 +174,12 @@ router.get(
|
||||
repo: req.params.repo,
|
||||
accessToken: user.accessToken,
|
||||
});
|
||||
if (!repo) return res.status(404).send({ error: "repo_not_found" });
|
||||
if (!repo) {
|
||||
throw new AnonymousError("repo_not_found", {
|
||||
object: req.params.repoId,
|
||||
httpStatus: 404,
|
||||
});
|
||||
}
|
||||
return res.send(
|
||||
await repo.readme({
|
||||
accessToken: user.accessToken,
|
||||
@@ -174,7 +201,10 @@ router.get("/:repoId/", async (req: express.Request, res: express.Response) => {
|
||||
|
||||
const user = await getUser(req);
|
||||
if (repo.owner.id != user.id) {
|
||||
return res.status(401).send({ error: "not_authorized" });
|
||||
throw new AnonymousError("not_authorized", {
|
||||
object: req.params.repoId,
|
||||
httpStatus: 401,
|
||||
});
|
||||
}
|
||||
res.json((await db.getRepository(req.params.repoId)).toJSON());
|
||||
} catch (error) {
|
||||
@@ -188,22 +218,40 @@ function validateNewRepo(repoUpdate) {
|
||||
!repoUpdate.repoId.match(validCharacters) ||
|
||||
repoUpdate.repoId.length < 3
|
||||
) {
|
||||
throw new AnonymousError("invalid_repoId", repoUpdate.repoId);
|
||||
throw new AnonymousError("invalid_repoId", {
|
||||
object: repoUpdate,
|
||||
httpStatus: 400,
|
||||
});
|
||||
}
|
||||
if (!repoUpdate.source.branch) {
|
||||
throw new AnonymousError("branch_not_specified");
|
||||
throw new AnonymousError("branch_not_specified", {
|
||||
object: repoUpdate,
|
||||
httpStatus: 400,
|
||||
});
|
||||
}
|
||||
if (!repoUpdate.source.commit) {
|
||||
throw new AnonymousError("commit_not_specified");
|
||||
throw new AnonymousError("commit_not_specified", {
|
||||
object: repoUpdate,
|
||||
httpStatus: 400,
|
||||
});
|
||||
}
|
||||
if (!repoUpdate.options) {
|
||||
throw new AnonymousError("options_not_provided");
|
||||
throw new AnonymousError("options_not_provided", {
|
||||
object: repoUpdate,
|
||||
httpStatus: 400,
|
||||
});
|
||||
}
|
||||
if (!Array.isArray(repoUpdate.terms)) {
|
||||
throw new AnonymousError("invalid_terms_format", repoUpdate.terms);
|
||||
throw new AnonymousError("invalid_terms_format", {
|
||||
object: repoUpdate,
|
||||
httpStatus: 400,
|
||||
});
|
||||
}
|
||||
if (!/^[a-fA-F0-9]+$/.test(repoUpdate.source.commit)) {
|
||||
throw new AnonymousError("invalid_commit_format", repoUpdate.source.commit);
|
||||
throw new AnonymousError("invalid_commit_format", {
|
||||
object: repoUpdate,
|
||||
httpStatus: 400,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +296,10 @@ router.post(
|
||||
const user = await getUser(req);
|
||||
|
||||
if (repo.owner.id != user.id) {
|
||||
return res.status(401).json({ error: "not_authorized" });
|
||||
throw new AnonymousError("not_authorized", {
|
||||
object: req.params.repoId,
|
||||
httpStatus: 401,
|
||||
});
|
||||
}
|
||||
|
||||
const repoUpdate = req.body;
|
||||
@@ -289,7 +340,10 @@ router.post(
|
||||
new Date() > conf.endDate ||
|
||||
conf.status !== "ready"
|
||||
) {
|
||||
throw new AnonymousError("conf_not_activated");
|
||||
throw new AnonymousError("conf_not_activated", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
}
|
||||
const f = conf.repositories.filter((r) => r.id == repo.model.id);
|
||||
if (f.length) {
|
||||
@@ -346,7 +400,10 @@ router.post("/", async (req: express.Request, res: express.Response) => {
|
||||
if (repo.source.type == "GitHubDownload") {
|
||||
// details.size is in kilobytes
|
||||
if (repository.size > config.MAX_REPO_SIZE) {
|
||||
return res.status(500).send({ error: "invalid_mode" });
|
||||
throw new AnonymousError("invalid_mode", {
|
||||
object: repository,
|
||||
httpStatus: 400,
|
||||
});
|
||||
}
|
||||
}
|
||||
repo.conference = repoUpdate.conference;
|
||||
@@ -364,7 +421,10 @@ router.post("/", async (req: express.Request, res: express.Response) => {
|
||||
conf.status !== "ready"
|
||||
) {
|
||||
await repo.remove();
|
||||
throw new AnonymousError("conf_not_activated");
|
||||
throw new AnonymousError("conf_not_activated", {
|
||||
object: conf,
|
||||
httpStatus: 400,
|
||||
});
|
||||
}
|
||||
conf.repositories.push({
|
||||
id: repo.id,
|
||||
@@ -379,7 +439,11 @@ router.post("/", async (req: express.Request, res: express.Response) => {
|
||||
} catch (error) {
|
||||
if (error.message?.indexOf(" duplicate key") > -1) {
|
||||
return handleError(
|
||||
new AnonymousError("repoId_already_used", repoUpdate.repoId),
|
||||
new AnonymousError("repoId_already_used", {
|
||||
httpStatus: 400,
|
||||
cause: error,
|
||||
object: repoUpdate,
|
||||
}),
|
||||
res
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,14 +12,25 @@ const router = express.Router();
|
||||
router.get(
|
||||
"/:repoId/zip",
|
||||
async (req: express.Request, res: express.Response) => {
|
||||
if (!config.ENABLE_DOWNLOAD)
|
||||
return res.status(403).send({ error: "download_not_enabled" });
|
||||
const repo = await getRepo(req, res);
|
||||
if (!repo) return;
|
||||
|
||||
const pipeline = promisify(stream.pipeline);
|
||||
|
||||
try {
|
||||
if (!config.ENABLE_DOWNLOAD) {
|
||||
throw new AnonymousError("download_not_enabled", {
|
||||
httpStatus: 403,
|
||||
object: req.params.repoId,
|
||||
});
|
||||
}
|
||||
const repo = await getRepo(req, res);
|
||||
if (!repo) return;
|
||||
|
||||
if (repo.source.type != "GitHubDownload") {
|
||||
throw new AnonymousError("download_not_enabled", {
|
||||
httpStatus: 403,
|
||||
object: req.params.repoId,
|
||||
});
|
||||
}
|
||||
|
||||
res.attachment(`${repo.repoId}.zip`);
|
||||
|
||||
// cache the file for 6 hours
|
||||
@@ -67,7 +78,10 @@ router.get(
|
||||
repo.status == "removing" ||
|
||||
repo.status == "removed"
|
||||
) {
|
||||
throw new AnonymousError("repository_expired", repo);
|
||||
throw new AnonymousError("repository_expired", {
|
||||
object: repo,
|
||||
httpStatus: 410,
|
||||
});
|
||||
}
|
||||
|
||||
const fiveMinuteAgo = new Date();
|
||||
@@ -85,10 +99,16 @@ router.get(
|
||||
repo.model.statusMessage
|
||||
? repo.model.statusMessage
|
||||
: "repository_not_available",
|
||||
repo
|
||||
{
|
||||
object: repo,
|
||||
httpStatus: 500,
|
||||
}
|
||||
);
|
||||
}
|
||||
throw new AnonymousError("repository_not_ready", repo);
|
||||
throw new AnonymousError("repository_not_ready", {
|
||||
httpStatus: 404,
|
||||
object: repo,
|
||||
});
|
||||
}
|
||||
|
||||
await repo.updateIfNeeded();
|
||||
|
||||
+11
-18
@@ -38,24 +38,11 @@ export async function getRepo(
|
||||
}
|
||||
|
||||
function printError(error: any) {
|
||||
io.notifyError(error, error.value);
|
||||
if (error instanceof AnonymousError) {
|
||||
io.notifyError(error, error.value);
|
||||
let detail = error.value ? JSON.stringify(error.value) : null;
|
||||
if (error.value instanceof Repository) {
|
||||
detail = error.value.repoId;
|
||||
} else if (error.value instanceof AnonymizedFile) {
|
||||
detail = `/r/${error.value.repository.repoId}/${error.value.anonymizedPath}`;
|
||||
} else if (error.value instanceof GitHubRepository) {
|
||||
detail = `${error.value.fullName}`;
|
||||
} else if (error.value instanceof User) {
|
||||
detail = `${error.value.username}`;
|
||||
} else if (error.value instanceof GitHubBase) {
|
||||
detail = `${error.value.repository.repoId}`;
|
||||
}
|
||||
console.error(
|
||||
"[ERROR]",
|
||||
error.message,
|
||||
detail ? `'${detail}'` : null,
|
||||
error.toString(),
|
||||
error.stack.split("\n")[1].trim()
|
||||
);
|
||||
} else if (error instanceof Error) {
|
||||
@@ -72,7 +59,9 @@ export function handleError(error: any, res: express.Response) {
|
||||
message = error.message;
|
||||
}
|
||||
let status = 500;
|
||||
if (message && message.indexOf("not_found") > -1) {
|
||||
if (error.httpStatus) {
|
||||
status = error.httpStatus;
|
||||
} else if (message && message.indexOf("not_found") > -1) {
|
||||
status = 400;
|
||||
} else if (message && message.indexOf("not_connected") > -1) {
|
||||
status = 401;
|
||||
@@ -86,12 +75,16 @@ export async function getUser(req: express.Request) {
|
||||
const user = (req.user as any).user;
|
||||
if (!user) {
|
||||
req.logout();
|
||||
throw new AnonymousError("not_connected");
|
||||
throw new AnonymousError("not_connected", {
|
||||
httpStatus: 401,
|
||||
});
|
||||
}
|
||||
const model = await UserModel.findById(user._id);
|
||||
if (!model) {
|
||||
req.logout();
|
||||
throw new AnonymousError("not_connected");
|
||||
throw new AnonymousError("not_connected", {
|
||||
httpStatus: 401,
|
||||
});
|
||||
}
|
||||
return new User(model);
|
||||
}
|
||||
|
||||
+12
-3
@@ -12,14 +12,20 @@ async function webView(req: express.Request, res: express.Response) {
|
||||
if (!repo) return;
|
||||
try {
|
||||
if (!repo.options.page || !repo.options.pageSource) {
|
||||
throw new AnonymousError("page_not_activated");
|
||||
throw new AnonymousError("page_not_activated", {
|
||||
httpStatus: 400,
|
||||
object: repo,
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
repo.options.pageSource?.branch !=
|
||||
(repo.source as GitHubDownload).branch.name
|
||||
) {
|
||||
throw new AnonymousError("page_not_supported_on_different_branch");
|
||||
throw new AnonymousError("page_not_supported_on_different_branch", {
|
||||
httpStatus: 400,
|
||||
object: repo,
|
||||
});
|
||||
}
|
||||
|
||||
let requestPath = path.join(
|
||||
@@ -37,7 +43,10 @@ async function webView(req: express.Request, res: express.Response) {
|
||||
anonymizedPath: requestPath,
|
||||
});
|
||||
if (!(await f.isFileSupported())) {
|
||||
return res.status(500).send({ error: "file_not_supported" });
|
||||
throw new AnonymousError("file_not_supported", {
|
||||
httpStatus: 400,
|
||||
object: f,
|
||||
});
|
||||
}
|
||||
f.send(res);
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user