diff --git a/public/partials/admin/user.htm b/public/partials/admin/user.htm
new file mode 100644
index 0000000..8a4d7e4
--- /dev/null
+++ b/public/partials/admin/user.htm
@@ -0,0 +1,257 @@
+
+
+
+
+ {{userInfo.username}}
+
+
+
+
ID
+
{{userInfo._id}}
+
+
Email
+
{{userInfo.emails[0].email}}
+
+
accessTokens
+
{{userInfo.accessTokens.github}}
+
+
Github
+
+
+
Github Repositories
+
{{userInfo.repositories.length}}
+
+
+
Repositories {{repositories.length}}
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @
+
+ anonymized {{repo.anonymizeDate | humanTime}}
+
+
+
+
+
+ {{::repo.options.terms.length | number}}
+
+
+ {{::repo.size.storage |
+ humanFileSize}}
+
+
+ {{::repo.pageView | number}}
+
+
+
+ Last view: {{::repo.lastView | humanTime}}
+
+
+ Expire: {{repo.options.expirationDate | humanTime}}
+
+
+
+ -
+ There is no repository to display.
+
+
+
+
diff --git a/public/partials/admin/users.htm b/public/partials/admin/users.htm
index 1edb6b5..40d6c6b 100644
--- a/public/partials/admin/users.htm
+++ b/public/partials/admin/users.htm
@@ -155,7 +155,7 @@
- {{user.username}}
+
{
+ if ($scope.user == null) {
+ $location.url("/");
+ }
+ });
+ if ($scope.user == null) {
+ $location.url("/");
+ }
+
+ $scope.userInfo;
+ $scope.repositories = [];
+ $scope.search = "";
+ $scope.filters = {
+ status: { ready: true, expired: false, removed: false },
+ };
+ $scope.orderBy = "-anonymizeDate";
+
+ $scope.repoFiler = (repo) => {
+ if ($scope.filters.status[repo.status] == false) return false;
+
+ if ($scope.search.trim().length == 0) return true;
+
+ if (repo.source.fullName.indexOf($scope.search) > -1) return true;
+ if (repo.repoId.indexOf($scope.search) > -1) return true;
+
+ return false;
+ };
+
+ function getUserRepositories(username) {
+ $http.get("/api/admin/users/" + username + "/repos", {}).then(
+ (res) => {
+ $scope.repositories = res.data;
+ },
+ (err) => {
+ console.error(err);
+ }
+ );
+ }
+ function getUser(username) {
+ $http.get("/api/admin/users/" + username, {}).then(
+ (res) => {
+ $scope.userInfo = res.data;
+ },
+ (err) => {
+ console.error(err);
+ }
+ );
+ }
+ getUser($routeParams.username);
+ getUserRepositories($routeParams.username);
+
+ let timeClear = null;
+ $scope.$watch(
+ "query",
+ () => {
+ clearTimeout(timeClear);
+ timeClear = setTimeout(() => {
+ getUserRepositories($routeParams.username);
+ }, 500);
+ },
+ true
+ );
+ },
+ ])
.controller("conferencesAdminController", [
"$scope",
"$http",
diff --git a/public/script/app.js b/public/script/app.js
index 904aff3..3693c08 100644
--- a/public/script/app.js
+++ b/public/script/app.js
@@ -101,6 +101,11 @@ angular
controller: "usersAdminController",
title: "Users Admin - Anonymous GitHub",
})
+ .when("/admin/users/:username", {
+ templateUrl: "/partials/admin/user.htm",
+ controller: "userAdminController",
+ title: "User Admin - Anonymous GitHub",
+ })
.when("/admin/conferences", {
templateUrl: "/partials/admin/conferences.htm",
controller: "conferencesAdminController",
diff --git a/src/routes/admin.ts b/src/routes/admin.ts
index 1b052ec..a31dbed 100644
--- a/src/routes/admin.ts
+++ b/src/routes/admin.ts
@@ -1,10 +1,12 @@
import { Queue } from "bullmq";
import * as express from "express";
+import AnonymousError from "../AnonymousError";
import AnonymizedRepositoryModel from "../database/anonymizedRepositories/anonymizedRepositories.model";
import ConferenceModel from "../database/conference/conferences.model";
import UserModel from "../database/users/users.model";
import { downloadQueue, removeQueue } from "../queue";
import Repository from "../Repository";
+import User from "../User";
import { ensureAuthenticated } from "./connection";
import { handleError, getUser, isOwnerOrAdmin } from "./route-utils";
@@ -165,7 +167,43 @@ router.get("/users", async (req, res) => {
.skip(skipIndex),
});
});
-
+router.get(
+ "/users/:username",
+ async (req: express.Request, res: express.Response) => {
+ try {
+ const model = await UserModel.findOne({ username: req.params.username });
+ if (!model) {
+ req.logout((error) => console.error(error));
+ throw new AnonymousError("user_not_found", {
+ httpStatus: 404,
+ });
+ }
+ const user = new User(model);
+ res.json(user);
+ } catch (error) {
+ handleError(error, res, req);
+ }
+ }
+);
+router.get(
+ "/users/:username/repos",
+ async (req: express.Request, res: express.Response) => {
+ try {
+ const model = await UserModel.findOne({ username: req.params.username });
+ if (!model) {
+ req.logout((error) => console.error(error));
+ throw new AnonymousError("user_not_found", {
+ httpStatus: 404,
+ });
+ }
+ const user = new User(model);
+ const repos = await user.getRepositories();
+ res.json(repos);
+ } catch (error) {
+ handleError(error, res, req);
+ }
+ }
+);
router.get("/conferences", async (req, res) => {
const page = parseInt(req.query.page as string) || 1;
const limit = parseInt(req.query.limit as string) || 10;