mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-07-07 14:17:51 +02:00
chore: improve error messages
This commit is contained in:
+27
-7
@@ -43,7 +43,10 @@ export default class AnonymizedFile {
|
|||||||
constructor(data: { repository: Repository; anonymizedPath: string }) {
|
constructor(data: { repository: Repository; anonymizedPath: string }) {
|
||||||
this.repository = data.repository;
|
this.repository = data.repository;
|
||||||
if (!this.repository.options.terms)
|
if (!this.repository.options.terms)
|
||||||
throw new AnonymousError("terms_not_specified");
|
throw new AnonymousError("terms_not_specified", {
|
||||||
|
object: this,
|
||||||
|
httpStatus: 400,
|
||||||
|
});
|
||||||
this.anonymizedPath = data.anonymizedPath;
|
this.anonymizedPath = data.anonymizedPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +57,11 @@ export default class AnonymizedFile {
|
|||||||
*/
|
*/
|
||||||
async originalPath(): Promise<string> {
|
async originalPath(): Promise<string> {
|
||||||
if (this._originalPath) return this._originalPath;
|
if (this._originalPath) return this._originalPath;
|
||||||
if (!this.anonymizedPath) throw new AnonymousError("path_not_specified");
|
if (!this.anonymizedPath)
|
||||||
|
throw new AnonymousError("path_not_specified", {
|
||||||
|
object: this,
|
||||||
|
httpStatus: 400,
|
||||||
|
});
|
||||||
|
|
||||||
const paths = this.anonymizedPath.trim().split("/");
|
const paths = this.anonymizedPath.trim().split("/");
|
||||||
|
|
||||||
@@ -70,7 +77,10 @@ export default class AnonymizedFile {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!currentAnonymized[fileName]) {
|
if (!currentAnonymized[fileName]) {
|
||||||
throw new AnonymousError("file_not_found", this);
|
throw new AnonymousError("file_not_found", {
|
||||||
|
object: this,
|
||||||
|
httpStatus: 404,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
currentAnonymized = currentAnonymized[fileName];
|
currentAnonymized = currentAnonymized[fileName];
|
||||||
|
|
||||||
@@ -103,7 +113,7 @@ export default class AnonymizedFile {
|
|||||||
currentAnonymized.sha === undefined ||
|
currentAnonymized.sha === undefined ||
|
||||||
currentAnonymized.size === undefined
|
currentAnonymized.size === undefined
|
||||||
) {
|
) {
|
||||||
throw new AnonymousError("folder_not_supported", this);
|
throw new AnonymousError("folder_not_supported", { object: this });
|
||||||
}
|
}
|
||||||
|
|
||||||
const file: TreeFile = currentAnonymized as TreeFile;
|
const file: TreeFile = currentAnonymized as TreeFile;
|
||||||
@@ -114,7 +124,10 @@ export default class AnonymizedFile {
|
|||||||
// it should never happen
|
// it should never happen
|
||||||
const shaTree = tree2sha(currentOriginal);
|
const shaTree = tree2sha(currentOriginal);
|
||||||
if (!currentAnonymized.sha || !shaTree[file.sha]) {
|
if (!currentAnonymized.sha || !shaTree[file.sha]) {
|
||||||
throw new AnonymousError("file_not_found", this);
|
throw new AnonymousError("file_not_found", {
|
||||||
|
object: this,
|
||||||
|
httpStatus: 404,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this._originalPath = path.join(currentOriginalPath, shaTree[file.sha]);
|
this._originalPath = path.join(currentOriginalPath, shaTree[file.sha]);
|
||||||
@@ -147,7 +160,10 @@ export default class AnonymizedFile {
|
|||||||
|
|
||||||
async content(): Promise<stream.Readable> {
|
async content(): Promise<stream.Readable> {
|
||||||
if (this.fileSize && this.fileSize > config.MAX_FILE_SIZE) {
|
if (this.fileSize && this.fileSize > config.MAX_FILE_SIZE) {
|
||||||
throw new AnonymousError("file_too_big", this);
|
throw new AnonymousError("file_too_big", {
|
||||||
|
object: this,
|
||||||
|
httpStatus: 403,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (await storage.exists(this.originalCachePath)) {
|
if (await storage.exists(this.originalCachePath)) {
|
||||||
return storage.read(this.originalCachePath);
|
return storage.read(this.originalCachePath);
|
||||||
@@ -163,7 +179,11 @@ export default class AnonymizedFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get originalCachePath() {
|
get originalCachePath() {
|
||||||
if (!this.originalPath) throw new AnonymousError("path_not_defined");
|
if (!this.originalPath)
|
||||||
|
throw new AnonymousError("path_not_defined", {
|
||||||
|
object: this,
|
||||||
|
httpStatus: 400,
|
||||||
|
});
|
||||||
return path.join(this.repository.originalCachePath, this._originalPath);
|
return path.join(this.repository.originalCachePath, this._originalPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-6
@@ -1,18 +1,53 @@
|
|||||||
import { CustomError } from 'ts-custom-error'
|
import { CustomError } from "ts-custom-error";
|
||||||
|
import AnonymizedFile from "./AnonymizedFile";
|
||||||
|
import Repository from "./Repository";
|
||||||
|
import GitHubBase from "./source/GitHubBase";
|
||||||
|
import { GitHubRepository } from "./source/GitHubRepository";
|
||||||
|
import User from "./User";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom error message
|
* Custom error message
|
||||||
*/
|
*/
|
||||||
export default class AnonymousError extends CustomError {
|
export default class AnonymousError extends CustomError {
|
||||||
|
value?: any;
|
||||||
|
httpStatus?: number;
|
||||||
|
cause?: Error;
|
||||||
|
|
||||||
value: any;
|
constructor(
|
||||||
|
message: string,
|
||||||
constructor(message: string, value?: any) {
|
opt?: {
|
||||||
|
httpStatus?: number;
|
||||||
|
cause?: Error;
|
||||||
|
object?: any;
|
||||||
|
}
|
||||||
|
) {
|
||||||
super(message);
|
super(message);
|
||||||
this.value = value;
|
this.value = opt?.object;
|
||||||
|
this.httpStatus = opt?.httpStatus;
|
||||||
|
this.cause = opt?.cause;
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
return this.message;
|
let out = "";
|
||||||
|
let detail = this.value ? JSON.stringify(this.value) : null;
|
||||||
|
if (this.value instanceof Repository) {
|
||||||
|
detail = this.value.repoId;
|
||||||
|
} else if (this.value instanceof AnonymizedFile) {
|
||||||
|
detail = `/r/${this.value.repository.repoId}/${this.value.anonymizedPath}`;
|
||||||
|
} else if (this.value instanceof GitHubRepository) {
|
||||||
|
detail = `${this.value.fullName}`;
|
||||||
|
} else if (this.value instanceof User) {
|
||||||
|
detail = `${this.value.username}`;
|
||||||
|
} else if (this.value instanceof GitHubBase) {
|
||||||
|
detail = `${this.value.repository.repoId}`;
|
||||||
|
}
|
||||||
|
out += this.message;
|
||||||
|
if (detail) {
|
||||||
|
out += `: ${detail}`;
|
||||||
|
}
|
||||||
|
if (this.cause) {
|
||||||
|
out += `\n\tCause by ${this.cause}\n${this.cause.stack}`;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-5
@@ -34,7 +34,10 @@ export default class Repository {
|
|||||||
this.source = new Zip(data.source, this);
|
this.source = new Zip(data.source, this);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new AnonymousError("unsupported_source", data.source.type);
|
throw new AnonymousError("unsupported_source", {
|
||||||
|
object: data.source.type,
|
||||||
|
httpStatus: 400,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
this.owner = new User(new UserModel({ _id: data.owner }));
|
this.owner = new User(new UserModel({ _id: data.owner }));
|
||||||
}
|
}
|
||||||
@@ -110,7 +113,10 @@ export default class Repository {
|
|||||||
this.status == "removing" ||
|
this.status == "removing" ||
|
||||||
this.status == "removed"
|
this.status == "removed"
|
||||||
) {
|
) {
|
||||||
throw new AnonymousError("repository_expired", this);
|
throw new AnonymousError("repository_expired", {
|
||||||
|
object: this,
|
||||||
|
httpStatus: 410,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
const fiveMinuteAgo = new Date();
|
const fiveMinuteAgo = new Date();
|
||||||
fiveMinuteAgo.setMinutes(fiveMinuteAgo.getMinutes() - 5);
|
fiveMinuteAgo.setMinutes(fiveMinuteAgo.getMinutes() - 5);
|
||||||
@@ -119,7 +125,9 @@ export default class Repository {
|
|||||||
this.status == "preparing" ||
|
this.status == "preparing" ||
|
||||||
(this.status == "download" && this._model.statusDate > fiveMinuteAgo)
|
(this.status == "download" && this._model.statusDate > fiveMinuteAgo)
|
||||||
) {
|
) {
|
||||||
throw new AnonymousError("repository_not_ready", this);
|
throw new AnonymousError("repository_not_ready", {
|
||||||
|
object: this,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +178,9 @@ export default class Repository {
|
|||||||
);
|
);
|
||||||
await this.updateStatus("error", "branch_not_found");
|
await this.updateStatus("error", "branch_not_found");
|
||||||
await this.resetSate();
|
await this.resetSate();
|
||||||
throw new AnonymousError("branch_not_found", this);
|
throw new AnonymousError("branch_not_found", {
|
||||||
|
object: this,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
this._model.anonymizeDate = new Date();
|
this._model.anonymizeDate = new Date();
|
||||||
console.log(`${this._model.repoId} will be updated to ${newCommit}`);
|
console.log(`${this._model.repoId} will be updated to ${newCommit}`);
|
||||||
@@ -234,8 +244,9 @@ export default class Repository {
|
|||||||
/**
|
/**
|
||||||
* Reset/delete the state of the repository
|
* Reset/delete the state of the repository
|
||||||
*/
|
*/
|
||||||
async resetSate(status?: RepositoryStatus) {
|
async resetSate(status?: RepositoryStatus, statusMessage?: string) {
|
||||||
if (status) this._model.status = status;
|
if (status) this._model.status = status;
|
||||||
|
if (statusMessage) this._model.statusMessage = statusMessage;
|
||||||
// remove attribute
|
// remove attribute
|
||||||
this._model.size = { storage: 0, file: 0 };
|
this._model.size = { storage: 0, file: 0 };
|
||||||
this._model.originalFiles = null;
|
this._model.originalFiles = null;
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ export async function connect() {
|
|||||||
|
|
||||||
export async function getRepository(repoId: string) {
|
export async function getRepository(repoId: string) {
|
||||||
const data = await AnonymizedRepositoryModel.findOne({ repoId });
|
const data = await AnonymizedRepositoryModel.findOne({ repoId });
|
||||||
if (!data) throw new AnonymousError("repo_not_found", repoId);
|
if (!data)
|
||||||
|
throw new AnonymousError("repo_not_found", {
|
||||||
|
object: repoId,
|
||||||
|
httpStatus: 400,
|
||||||
|
});
|
||||||
return new Repository(data);
|
return new Repository(data);
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-2
@@ -1,5 +1,6 @@
|
|||||||
import * as Queue from "bull";
|
import * as Queue from "bull";
|
||||||
import config from "../config";
|
import config from "../config";
|
||||||
|
import AnonymousError from "./AnonymousError";
|
||||||
import { getRepository } from "./database/database";
|
import { getRepository } from "./database/database";
|
||||||
import Repository from "./Repository";
|
import Repository from "./Repository";
|
||||||
|
|
||||||
@@ -28,7 +29,15 @@ removeQueue.process(5, async (job) => {
|
|||||||
const repo = await getRepository(job.data.repoId);
|
const repo = await getRepository(job.data.repoId);
|
||||||
await repo.remove();
|
await repo.remove();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("error", error);
|
if (error instanceof AnonymousError) {
|
||||||
|
console.error(
|
||||||
|
"[ERROR]",
|
||||||
|
error.toString(),
|
||||||
|
error.stack.split("\n")[1].trim()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
console.log(`${job.data.repoId} is removed`);
|
console.log(`${job.data.repoId} is removed`);
|
||||||
}
|
}
|
||||||
@@ -43,7 +52,15 @@ downloadQueue.process(2, async (job) => {
|
|||||||
job.progress("resetSate");
|
job.progress("resetSate");
|
||||||
await repo.anonymize();
|
await repo.anonymize();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("error", error);
|
if (error instanceof AnonymousError) {
|
||||||
|
console.error(
|
||||||
|
"[ERROR]",
|
||||||
|
error.toString(),
|
||||||
|
error.stack.split("\n")[1].trim()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
console.log(`${job.data.repoId} is downloaded`);
|
console.log(`${job.data.repoId} is downloaded`);
|
||||||
}
|
}
|
||||||
|
|||||||
+96
-20
@@ -67,26 +67,79 @@ router.get("/", async (req: express.Request, res: express.Response) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function validateConferenceForm(conf) {
|
function validateConferenceForm(conf) {
|
||||||
if (!conf.name) throw new AnonymousError("conf_name_missing");
|
if (!conf.name)
|
||||||
if (!conf.conferenceID) throw new AnonymousError("conf_id_missing");
|
throw new AnonymousError("conf_name_missing", {
|
||||||
if (!conf.startDate) throw new AnonymousError("conf_start_date_missing");
|
object: conf,
|
||||||
if (!conf.endDate) throw new AnonymousError("conf_end_date_missing");
|
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))
|
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))
|
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)
|
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];
|
const plan = plans.filter((p) => p.id == conf.plan.planID)[0];
|
||||||
if (plan.pricePerRepo > 0) {
|
if (plan.pricePerRepo > 0) {
|
||||||
const billing = conf.billing;
|
const billing = conf.billing;
|
||||||
if (!billing) throw new AnonymousError("billing_missing");
|
if (!billing)
|
||||||
if (!billing.name) throw new AnonymousError("billing_name_missing");
|
throw new AnonymousError("billing_missing", {
|
||||||
if (!billing.email) throw new AnonymousError("billing_email_missing");
|
object: conf,
|
||||||
if (!billing.address) throw new AnonymousError("billing_address_missing");
|
httpStatus: 400,
|
||||||
if (!billing.city) throw new AnonymousError("billing_city_missing");
|
});
|
||||||
if (!billing.zip) throw new AnonymousError("billing_zip_missing");
|
if (!billing.name)
|
||||||
if (!billing.country) throw new AnonymousError("billing_country_missing");
|
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,
|
conferenceID: req.params.conferenceID,
|
||||||
});
|
});
|
||||||
if (model.owners.indexOf(user.model.id) == -1)
|
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);
|
validateConferenceForm(req.body);
|
||||||
model.name = req.body.name;
|
model.name = req.body.name;
|
||||||
@@ -146,7 +202,13 @@ router.post(
|
|||||||
res.send("ok");
|
res.send("ok");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.message?.indexOf(" duplicate key") > -1) {
|
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);
|
handleError(error, res);
|
||||||
}
|
}
|
||||||
@@ -161,10 +223,17 @@ router.get(
|
|||||||
const data = await ConferenceModel.findOne({
|
const data = await ConferenceModel.findOne({
|
||||||
conferenceID: req.params.conferenceID,
|
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);
|
const conference = new Conference(data);
|
||||||
if (conference.ownerIDs.indexOf(user.model.id) == -1)
|
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();
|
const o: any = conference.toJSON();
|
||||||
o.repositories = (await conference.repositories()).map((r) => r.toJSON());
|
o.repositories = (await conference.repositories()).map((r) => r.toJSON());
|
||||||
res.json(o);
|
res.json(o);
|
||||||
@@ -182,10 +251,17 @@ router.delete(
|
|||||||
const data = await ConferenceModel.findOne({
|
const data = await ConferenceModel.findOne({
|
||||||
conferenceID: req.params.conferenceID,
|
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);
|
const conference = new Conference(data);
|
||||||
if (conference.ownerIDs.indexOf(user.model.id) == -1)
|
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();
|
await conference.remove();
|
||||||
res.send("ok");
|
res.send("ok");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
+5
-1
@@ -1,5 +1,6 @@
|
|||||||
import * as express from "express";
|
import * as express from "express";
|
||||||
import AnonymizedFile from "../AnonymizedFile";
|
import AnonymizedFile from "../AnonymizedFile";
|
||||||
|
import AnonymousError from "../AnonymousError";
|
||||||
import { getRepo, handleError } from "./route-utils";
|
import { getRepo, handleError } from "./route-utils";
|
||||||
|
|
||||||
export const router = express.Router();
|
export const router = express.Router();
|
||||||
@@ -24,7 +25,10 @@ router.get(
|
|||||||
anonymizedPath,
|
anonymizedPath,
|
||||||
});
|
});
|
||||||
if (!(await f.isFileSupported())) {
|
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(
|
res.attachment(
|
||||||
anonymizedPath.substring(anonymizedPath.lastIndexOf("/") + 1)
|
anonymizedPath.substring(anonymizedPath.lastIndexOf("/") + 1)
|
||||||
|
|||||||
@@ -24,15 +24,24 @@ router.post("/claim", async (req: express.Request, res: express.Response) => {
|
|||||||
const user = await getUser(req);
|
const user = await getUser(req);
|
||||||
try {
|
try {
|
||||||
if (!req.body.repoId) {
|
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) {
|
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);
|
const repoConfig = await db.getRepository(req.body.repoId);
|
||||||
if (repoConfig == null) {
|
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);
|
const r = gh(req.body.repoUrl);
|
||||||
@@ -42,7 +51,10 @@ router.post("/claim", async (req: express.Request, res: express.Response) => {
|
|||||||
accessToken: user.accessToken,
|
accessToken: user.accessToken,
|
||||||
});
|
});
|
||||||
if ((repoConfig.source as GitHubBase).githubRepository.id != repo.id) {
|
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}.`);
|
console.log(`${user.username} claims ${r.repository}.`);
|
||||||
@@ -70,7 +82,10 @@ router.post(
|
|||||||
|
|
||||||
const user = await getUser(req);
|
const user = await getUser(req);
|
||||||
if (repo.owner.id != user.id) {
|
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 });
|
await repo.updateIfNeeded({ force: true });
|
||||||
res.json({ status: repo.status });
|
res.json({ status: repo.status });
|
||||||
@@ -88,10 +103,17 @@ router.delete(
|
|||||||
if (!repo) return;
|
if (!repo) return;
|
||||||
// if (repo.status == "removing") return res.json({ status: repo.status });
|
// if (repo.status == "removing") return res.json({ status: repo.status });
|
||||||
try {
|
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);
|
const user = await getUser(req);
|
||||||
if (repo.owner.id != user.id) {
|
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 repo.updateStatus("removing");
|
||||||
await removeQueue.add(repo, { jobId: repo.repoId });
|
await removeQueue.add(repo, { jobId: repo.repoId });
|
||||||
@@ -152,7 +174,12 @@ router.get(
|
|||||||
repo: req.params.repo,
|
repo: req.params.repo,
|
||||||
accessToken: user.accessToken,
|
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(
|
return res.send(
|
||||||
await repo.readme({
|
await repo.readme({
|
||||||
accessToken: user.accessToken,
|
accessToken: user.accessToken,
|
||||||
@@ -174,7 +201,10 @@ router.get("/:repoId/", async (req: express.Request, res: express.Response) => {
|
|||||||
|
|
||||||
const user = await getUser(req);
|
const user = await getUser(req);
|
||||||
if (repo.owner.id != user.id) {
|
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());
|
res.json((await db.getRepository(req.params.repoId)).toJSON());
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -188,22 +218,40 @@ function validateNewRepo(repoUpdate) {
|
|||||||
!repoUpdate.repoId.match(validCharacters) ||
|
!repoUpdate.repoId.match(validCharacters) ||
|
||||||
repoUpdate.repoId.length < 3
|
repoUpdate.repoId.length < 3
|
||||||
) {
|
) {
|
||||||
throw new AnonymousError("invalid_repoId", repoUpdate.repoId);
|
throw new AnonymousError("invalid_repoId", {
|
||||||
|
object: repoUpdate,
|
||||||
|
httpStatus: 400,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (!repoUpdate.source.branch) {
|
if (!repoUpdate.source.branch) {
|
||||||
throw new AnonymousError("branch_not_specified");
|
throw new AnonymousError("branch_not_specified", {
|
||||||
|
object: repoUpdate,
|
||||||
|
httpStatus: 400,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (!repoUpdate.source.commit) {
|
if (!repoUpdate.source.commit) {
|
||||||
throw new AnonymousError("commit_not_specified");
|
throw new AnonymousError("commit_not_specified", {
|
||||||
|
object: repoUpdate,
|
||||||
|
httpStatus: 400,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (!repoUpdate.options) {
|
if (!repoUpdate.options) {
|
||||||
throw new AnonymousError("options_not_provided");
|
throw new AnonymousError("options_not_provided", {
|
||||||
|
object: repoUpdate,
|
||||||
|
httpStatus: 400,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (!Array.isArray(repoUpdate.terms)) {
|
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)) {
|
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);
|
const user = await getUser(req);
|
||||||
|
|
||||||
if (repo.owner.id != user.id) {
|
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;
|
const repoUpdate = req.body;
|
||||||
@@ -289,7 +340,10 @@ router.post(
|
|||||||
new Date() > conf.endDate ||
|
new Date() > conf.endDate ||
|
||||||
conf.status !== "ready"
|
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);
|
const f = conf.repositories.filter((r) => r.id == repo.model.id);
|
||||||
if (f.length) {
|
if (f.length) {
|
||||||
@@ -346,7 +400,10 @@ router.post("/", async (req: express.Request, res: express.Response) => {
|
|||||||
if (repo.source.type == "GitHubDownload") {
|
if (repo.source.type == "GitHubDownload") {
|
||||||
// details.size is in kilobytes
|
// details.size is in kilobytes
|
||||||
if (repository.size > config.MAX_REPO_SIZE) {
|
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;
|
repo.conference = repoUpdate.conference;
|
||||||
@@ -364,7 +421,10 @@ router.post("/", async (req: express.Request, res: express.Response) => {
|
|||||||
conf.status !== "ready"
|
conf.status !== "ready"
|
||||||
) {
|
) {
|
||||||
await repo.remove();
|
await repo.remove();
|
||||||
throw new AnonymousError("conf_not_activated");
|
throw new AnonymousError("conf_not_activated", {
|
||||||
|
object: conf,
|
||||||
|
httpStatus: 400,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
conf.repositories.push({
|
conf.repositories.push({
|
||||||
id: repo.id,
|
id: repo.id,
|
||||||
@@ -379,7 +439,11 @@ router.post("/", async (req: express.Request, res: express.Response) => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.message?.indexOf(" duplicate key") > -1) {
|
if (error.message?.indexOf(" duplicate key") > -1) {
|
||||||
return handleError(
|
return handleError(
|
||||||
new AnonymousError("repoId_already_used", repoUpdate.repoId),
|
new AnonymousError("repoId_already_used", {
|
||||||
|
httpStatus: 400,
|
||||||
|
cause: error,
|
||||||
|
object: repoUpdate,
|
||||||
|
}),
|
||||||
res
|
res
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,25 @@ const router = express.Router();
|
|||||||
router.get(
|
router.get(
|
||||||
"/:repoId/zip",
|
"/:repoId/zip",
|
||||||
async (req: express.Request, res: express.Response) => {
|
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);
|
const pipeline = promisify(stream.pipeline);
|
||||||
|
|
||||||
try {
|
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`);
|
res.attachment(`${repo.repoId}.zip`);
|
||||||
|
|
||||||
// cache the file for 6 hours
|
// cache the file for 6 hours
|
||||||
@@ -67,7 +78,10 @@ router.get(
|
|||||||
repo.status == "removing" ||
|
repo.status == "removing" ||
|
||||||
repo.status == "removed"
|
repo.status == "removed"
|
||||||
) {
|
) {
|
||||||
throw new AnonymousError("repository_expired", repo);
|
throw new AnonymousError("repository_expired", {
|
||||||
|
object: repo,
|
||||||
|
httpStatus: 410,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const fiveMinuteAgo = new Date();
|
const fiveMinuteAgo = new Date();
|
||||||
@@ -85,10 +99,16 @@ router.get(
|
|||||||
repo.model.statusMessage
|
repo.model.statusMessage
|
||||||
? repo.model.statusMessage
|
? repo.model.statusMessage
|
||||||
: "repository_not_available",
|
: "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();
|
await repo.updateIfNeeded();
|
||||||
|
|||||||
+11
-18
@@ -38,24 +38,11 @@ export async function getRepo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function printError(error: any) {
|
function printError(error: any) {
|
||||||
|
io.notifyError(error, error.value);
|
||||||
if (error instanceof AnonymousError) {
|
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(
|
console.error(
|
||||||
"[ERROR]",
|
"[ERROR]",
|
||||||
error.message,
|
error.toString(),
|
||||||
detail ? `'${detail}'` : null,
|
|
||||||
error.stack.split("\n")[1].trim()
|
error.stack.split("\n")[1].trim()
|
||||||
);
|
);
|
||||||
} else if (error instanceof Error) {
|
} else if (error instanceof Error) {
|
||||||
@@ -72,7 +59,9 @@ export function handleError(error: any, res: express.Response) {
|
|||||||
message = error.message;
|
message = error.message;
|
||||||
}
|
}
|
||||||
let status = 500;
|
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;
|
status = 400;
|
||||||
} else if (message && message.indexOf("not_connected") > -1) {
|
} else if (message && message.indexOf("not_connected") > -1) {
|
||||||
status = 401;
|
status = 401;
|
||||||
@@ -86,12 +75,16 @@ export async function getUser(req: express.Request) {
|
|||||||
const user = (req.user as any).user;
|
const user = (req.user as any).user;
|
||||||
if (!user) {
|
if (!user) {
|
||||||
req.logout();
|
req.logout();
|
||||||
throw new AnonymousError("not_connected");
|
throw new AnonymousError("not_connected", {
|
||||||
|
httpStatus: 401,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
const model = await UserModel.findById(user._id);
|
const model = await UserModel.findById(user._id);
|
||||||
if (!model) {
|
if (!model) {
|
||||||
req.logout();
|
req.logout();
|
||||||
throw new AnonymousError("not_connected");
|
throw new AnonymousError("not_connected", {
|
||||||
|
httpStatus: 401,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return new User(model);
|
return new User(model);
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-3
@@ -12,14 +12,20 @@ async function webView(req: express.Request, res: express.Response) {
|
|||||||
if (!repo) return;
|
if (!repo) return;
|
||||||
try {
|
try {
|
||||||
if (!repo.options.page || !repo.options.pageSource) {
|
if (!repo.options.page || !repo.options.pageSource) {
|
||||||
throw new AnonymousError("page_not_activated");
|
throw new AnonymousError("page_not_activated", {
|
||||||
|
httpStatus: 400,
|
||||||
|
object: repo,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
repo.options.pageSource?.branch !=
|
repo.options.pageSource?.branch !=
|
||||||
(repo.source as GitHubDownload).branch.name
|
(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(
|
let requestPath = path.join(
|
||||||
@@ -37,7 +43,10 @@ async function webView(req: express.Request, res: express.Response) {
|
|||||||
anonymizedPath: requestPath,
|
anonymizedPath: requestPath,
|
||||||
});
|
});
|
||||||
if (!(await f.isFileSupported())) {
|
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);
|
f.send(res);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -38,11 +38,17 @@ export default abstract class GitHubBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getFileContent(file: AnonymizedFile): Promise<stream.Readable> {
|
async getFileContent(file: AnonymizedFile): Promise<stream.Readable> {
|
||||||
throw new AnonymousError("Method not implemented.");
|
throw new AnonymousError("method_not_implemented", {
|
||||||
|
httpStatus: 501,
|
||||||
|
object: this,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getFiles(): Promise<Tree> {
|
getFiles(): Promise<Tree> {
|
||||||
throw new AnonymousError("Method not implemented.");
|
throw new AnonymousError("method_not_implemented", {
|
||||||
|
httpStatus: 501,
|
||||||
|
object: this,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getToken(owner?: string) {
|
async getToken(owner?: string) {
|
||||||
|
|||||||
@@ -45,7 +45,10 @@ export default class GitHubDownload extends GitHubBase implements SourceBase {
|
|||||||
this.repository.status == "download" &&
|
this.repository.status == "download" &&
|
||||||
this.repository.model.statusDate > fiveMinuteAgo
|
this.repository.model.statusDate > fiveMinuteAgo
|
||||||
)
|
)
|
||||||
throw new AnonymousError("repo_in_download", this.repository);
|
throw new AnonymousError("repo_in_download", {
|
||||||
|
httpStatus: 404,
|
||||||
|
object: this.repository,
|
||||||
|
});
|
||||||
let response: OctokitResponse<unknown, number>;
|
let response: OctokitResponse<unknown, number>;
|
||||||
try {
|
try {
|
||||||
response = await this._getZipUrl(await this.getToken());
|
response = await this._getZipUrl(await this.getToken());
|
||||||
@@ -55,11 +58,19 @@ export default class GitHubDownload extends GitHubBase implements SourceBase {
|
|||||||
response = await this._getZipUrl(config.GITHUB_TOKEN);
|
response = await this._getZipUrl(config.GITHUB_TOKEN);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await this.repository.resetSate("error");
|
await this.repository.resetSate("error");
|
||||||
throw new AnonymousError("repo_not_accessible", this.repository);
|
throw new AnonymousError("repo_not_accessible", {
|
||||||
|
httpStatus: 404,
|
||||||
|
cause: error,
|
||||||
|
object: this.repository,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await this.repository.resetSate("error");
|
await this.repository.resetSate("error");
|
||||||
throw new AnonymousError("repo_not_accessible", this.repository);
|
throw new AnonymousError("repo_not_accessible", {
|
||||||
|
httpStatus: 404,
|
||||||
|
object: this.repository,
|
||||||
|
cause: error,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await this.repository.updateStatus("download");
|
await this.repository.updateStatus("download");
|
||||||
@@ -89,7 +100,11 @@ export default class GitHubDownload extends GitHubBase implements SourceBase {
|
|||||||
await storage.extractTar(originalPath, downloadStream);
|
await storage.extractTar(originalPath, downloadStream);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await this.repository.updateStatus("error", "unable_to_download");
|
await this.repository.updateStatus("error", "unable_to_download");
|
||||||
throw new AnonymousError("unable_to_download", error);
|
throw new AnonymousError("unable_to_download", {
|
||||||
|
httpStatus: 500,
|
||||||
|
cause: error,
|
||||||
|
object: this.repository,
|
||||||
|
});
|
||||||
} finally {
|
} finally {
|
||||||
inDownload = false;
|
inDownload = false;
|
||||||
clearTimeout(progressTimeout);
|
clearTimeout(progressTimeout);
|
||||||
|
|||||||
@@ -117,7 +117,11 @@ export class GitHubRepository {
|
|||||||
selected.readme = readme;
|
selected.readme = readme;
|
||||||
await model.save();
|
await model.save();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new AnonymousError("readme_not_available", this);
|
throw new AnonymousError("readme_not_available", {
|
||||||
|
httpStatus: 404,
|
||||||
|
cause: error,
|
||||||
|
object: this,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +131,10 @@ export class GitHubRepository {
|
|||||||
public get owner(): string {
|
public get owner(): string {
|
||||||
const repo = gh(this.fullName);
|
const repo = gh(this.fullName);
|
||||||
if (!repo) {
|
if (!repo) {
|
||||||
throw new AnonymousError("invalid_repo", this);
|
throw new AnonymousError("invalid_repo", {
|
||||||
|
httpStatus: 400,
|
||||||
|
object: this,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return repo.owner || this.fullName;
|
return repo.owner || this.fullName;
|
||||||
}
|
}
|
||||||
@@ -135,7 +142,10 @@ export class GitHubRepository {
|
|||||||
public get repo(): string {
|
public get repo(): string {
|
||||||
const repo = gh(this.fullName);
|
const repo = gh(this.fullName);
|
||||||
if (!repo) {
|
if (!repo) {
|
||||||
throw new AnonymousError("invalid_repo", this);
|
throw new AnonymousError("invalid_repo", {
|
||||||
|
httpStatus: 400,
|
||||||
|
object: this,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return repo.name || this.fullName;
|
return repo.name || this.fullName;
|
||||||
}
|
}
|
||||||
@@ -159,18 +169,22 @@ export async function getRepositoryFromGitHub(opt: {
|
|||||||
})
|
})
|
||||||
).data;
|
).data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.status == 404) {
|
throw new AnonymousError("repo_not_found", {
|
||||||
throw new AnonymousError("repo_not_found", {
|
httpStatus: error.status,
|
||||||
|
object: {
|
||||||
owner: opt.owner,
|
owner: opt.owner,
|
||||||
repo: opt.repo,
|
repo: opt.repo,
|
||||||
});
|
},
|
||||||
}
|
cause: error,
|
||||||
throw error;
|
});
|
||||||
}
|
}
|
||||||
if (!r)
|
if (!r)
|
||||||
throw new AnonymousError("repo_not_found", {
|
throw new AnonymousError("repo_not_found", {
|
||||||
owner: opt.owner,
|
httpStatus: 404,
|
||||||
repo: opt.repo,
|
object: {
|
||||||
|
owner: opt.owner,
|
||||||
|
repo: opt.repo,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
let model = await RepositoryModel.findOne({ externalId: "gh_" + r.id });
|
let model = await RepositoryModel.findOne({ externalId: "gh_" + r.id });
|
||||||
if (!model) {
|
if (!model) {
|
||||||
|
|||||||
@@ -25,7 +25,11 @@ export default class GitHubStream extends GitHubBase implements SourceBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getFileContent(file: AnonymizedFile): Promise<stream.Readable> {
|
async getFileContent(file: AnonymizedFile): Promise<stream.Readable> {
|
||||||
if (!file.sha) throw new AnonymousError("file_sha_not_provided", file);
|
if (!file.sha)
|
||||||
|
throw new AnonymousError("file_sha_not_provided", {
|
||||||
|
httpStatus: 400,
|
||||||
|
object: file,
|
||||||
|
});
|
||||||
const octokit = new Octokit({
|
const octokit = new Octokit({
|
||||||
auth: await this.getToken(),
|
auth: await this.getToken(),
|
||||||
});
|
});
|
||||||
@@ -37,7 +41,10 @@ export default class GitHubStream extends GitHubBase implements SourceBase {
|
|||||||
file_sha: file.sha,
|
file_sha: file.sha,
|
||||||
});
|
});
|
||||||
if (!ghRes.data.content && ghRes.data.size != 0) {
|
if (!ghRes.data.content && ghRes.data.size != 0) {
|
||||||
throw new AnonymousError("file_not_accessible", file);
|
throw new AnonymousError("file_not_accessible", {
|
||||||
|
httpStatus: 404,
|
||||||
|
object: file,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// empty file
|
// empty file
|
||||||
let content: Buffer;
|
let content: Buffer;
|
||||||
@@ -54,12 +61,12 @@ export default class GitHubStream extends GitHubBase implements SourceBase {
|
|||||||
await storage.write(file.originalCachePath, content);
|
await storage.write(file.originalCachePath, content);
|
||||||
return stream.Readable.from(content);
|
return stream.Readable.from(content);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.status == 403) {
|
throw new AnonymousError("file_too_big", {
|
||||||
throw new AnonymousError("file_too_big", file);
|
httpStatus: error.status,
|
||||||
}
|
cause: error,
|
||||||
console.error(error);
|
object: file,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
throw new AnonymousError("file_not_accessible", file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFiles() {
|
async getFiles() {
|
||||||
@@ -85,8 +92,16 @@ export default class GitHubStream extends GitHubBase implements SourceBase {
|
|||||||
recursive: "1",
|
recursive: "1",
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await this.repository.resetSate("error");
|
await this.repository.resetSate("error", "repo_not_accessible");
|
||||||
throw new AnonymousError("repo_not_accessible", this.repository);
|
throw new AnonymousError("repo_not_accessible", {
|
||||||
|
httpStatus: error.status,
|
||||||
|
cause: error,
|
||||||
|
object: {
|
||||||
|
owner: this.githubRepository.owner,
|
||||||
|
repo: this.githubRepository.repo,
|
||||||
|
tree_sha: sha,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const tree = this.tree2Tree(ghRes.data.tree, truncatedTree, parentPath);
|
const tree = this.tree2Tree(ghRes.data.tree, truncatedTree, parentPath);
|
||||||
|
|||||||
+4
-1
@@ -20,7 +20,10 @@ export default class S3Storage implements StorageBase {
|
|||||||
client: S3;
|
client: S3;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
if (!config.S3_BUCKET) throw new AnonymousError("s3_config_not_provided");
|
if (!config.S3_BUCKET)
|
||||||
|
throw new AnonymousError("s3_config_not_provided", {
|
||||||
|
httpStatus: 500,
|
||||||
|
});
|
||||||
this.client = new S3({
|
this.client = new S3({
|
||||||
region: config.S3_REGION,
|
region: config.S3_REGION,
|
||||||
endpoint: config.S3_ENDPOINT,
|
endpoint: config.S3_ENDPOINT,
|
||||||
|
|||||||
Reference in New Issue
Block a user