Files
anonymous_github/src/server/routes/user.ts
T
2026-05-05 10:32:31 +03:00

252 lines
6.3 KiB
TypeScript

import * as express from "express";
import config from "../../config";
import { ensureAuthenticated } from "./connection";
import { handleError, getUser, isOwnerOrAdmin } from "./route-utils";
import UserModel from "../../core/model/users/users.model";
import User from "../../core/User";
import FileModel from "../../core/model/files/files.model";
import { isConnected } from "../database";
import { octokit } from "../../core/GitHubUtils";
const router = express.Router();
// user needs to be connected for all user API
router.use(ensureAuthenticated);
router.get("/logout", async (req: express.Request, res: express.Response) => {
try {
req.logout((error) => {
if (error) {
console.error(`[ERROR] Logout error: ${error}`);
}
});
res.redirect("/");
} catch (error) {
handleError(error, res, req);
}
});
router.get("/", async (req: express.Request, res: express.Response) => {
try {
const user = await getUser(req);
res.json({
username: user.username,
photo: user.photo,
isAdmin: user.isAdmin,
});
} catch (error) {
handleError(error, res, req);
}
});
router.get("/quota", async (req: express.Request, res: express.Response) => {
try {
const user = await getUser(req);
const repositories = (await user.getRepositories()).filter(
(r) => r.owner.id === user.model.id
);
const ready = repositories.filter((r) => r.status == "ready");
let totalStorage = 0;
let totalFiles = 0;
const uncachedIds: string[] = [];
for (const r of ready) {
const cached = r.model.size;
if (cached && cached.file) {
totalStorage += cached.storage;
totalFiles += cached.file;
} else {
uncachedIds.push(r.repoId);
}
}
if (uncachedIds.length) {
const uncachedSet = new Set(uncachedIds);
const agg = await FileModel.aggregate([
{ $match: { repoId: { $in: uncachedIds } } },
{
$group: {
_id: "$repoId",
storage: { $sum: "$size" },
file: { $sum: 1 },
},
},
]);
const byId = new Map<string, { storage: number; file: number }>();
for (const row of agg) {
byId.set(row._id, { storage: row.storage || 0, file: row.file || 0 });
}
for (const r of ready) {
if (!uncachedSet.has(r.repoId)) continue;
const size = byId.get(r.repoId) || { storage: 0, file: 0 };
totalStorage += size.storage;
totalFiles += size.file;
r.model.size = size;
}
if (isConnected) {
await Promise.all(
ready
.filter((r) => uncachedSet.has(r.repoId))
.map((r) => r.model.save())
);
}
}
res.json({
storage: {
used: totalStorage,
total: config.DEFAULT_QUOTA,
},
file: {
used: totalFiles,
total: 0,
},
repository: {
used: ready.length,
total: 20,
},
});
} catch (error) {
handleError(error, res, req);
}
});
router.get("/default", async (req: express.Request, res: express.Response) => {
try {
const user = await getUser(req);
res.json(user.default);
} catch (error) {
handleError(error, res, req);
}
});
router.post("/default", async (req: express.Request, res: express.Response) => {
try {
const user = await getUser(req);
const d = req.body;
user.model.default = d;
await user.model.save();
res.send("ok");
} catch (error) {
handleError(error, res, req);
}
});
router.get(
"/anonymized_repositories",
async (req: express.Request, res: express.Response) => {
try {
const user = await getUser(req);
res.json(
(await user.getRepositories()).map((x) => {
const json = x.toJSON() as Record<string, unknown>;
json.role = x.owner.id === user.model.id ? "owner" : "coauthor";
return json;
})
);
} catch (error) {
handleError(error, res, req);
}
}
);
router.get(
"/anonymized_gists",
async (req: express.Request, res: express.Response) => {
try {
const user = await getUser(req);
res.json(
(await user.getGists()).map((x) => {
return x.toJSON();
})
);
} catch (error) {
handleError(error, res, req);
}
}
);
router.get(
"/anonymized_pull_requests",
async (req: express.Request, res: express.Response) => {
try {
const user = await getUser(req);
res.json(
(await user.getPullRequests()).map((x) => {
return x.toJSON();
})
);
} catch (error) {
handleError(error, res, req);
}
}
);
// search GitHub users (used by the coauthor picker)
router.get(
"/search/github-users",
async (req: express.Request, res: express.Response) => {
try {
const user = await getUser(req);
const q = (req.query.q as string) || "";
if (!q || q.length < 2) {
return res.json([]);
}
const oct = octokit(user.accessToken);
const r = await oct.search.users({ q, per_page: 10 });
res.json(
r.data.items.map((u) => ({
username: u.login,
githubId: String(u.id),
photo: u.avatar_url,
}))
);
} catch (error) {
handleError(error, res, req);
}
}
);
async function getAllRepositories(user: User, force: boolean) {
const repos = await user.getGitHubRepositories({
force,
});
return repos.map((x) => {
return {
fullName: x.fullName,
id: x.id,
};
});
}
router.get(
"/all_repositories",
async (req: express.Request, res: express.Response) => {
try {
const user = await getUser(req);
res.json(await getAllRepositories(user, req.query.force == "1"));
} catch (error) {
handleError(error, res, req);
}
}
);
router.get(
"/:username/all_repositories",
async (req: express.Request, res: express.Response) => {
try {
const loggedUser = await getUser(req);
isOwnerOrAdmin([req.params.username], loggedUser);
const model = await UserModel.findOne({ username: req.params.username });
if (!model) {
throw new Error("User not found");
}
const user = new User(model);
res.json(await getAllRepositories(user, req.query.force == "1"));
} catch (error) {
handleError(error, res, req);
}
}
);
export default router;