Integrating recent internal changes
- Changes JSON paging APIs to be zero-based indexes - Additional optional security app configuration - Fixes a minor configuration issue - Adds a more robust "RepositoryEntity" that is not used in the site, but by jobs or data systems - Updated deps - Graph provider adds a "get direct reports" method
This commit is contained in:
Родитель
d0c834edac
Коммит
7f3c6f7b43
|
@ -328,6 +328,20 @@
|
|||
"DEBUG": "startup,appinsights"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Job: Repositories Table (13)",
|
||||
"program": "${workspaceRoot}/dist/jobs/repositories.js",
|
||||
"cwd": "${workspaceRoot}/dist",
|
||||
"preLaunchTask": "tsbuild",
|
||||
"sourceMaps": true,
|
||||
"console": "integratedTerminal",
|
||||
"env": {
|
||||
"NODE_ENV": "development",
|
||||
"DEBUG": "startup,appinsights"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
|
|
|
@ -35,7 +35,7 @@ export default class JsonPager<T> {
|
|||
const requestedPageSize = query.pageSize ? Number(query.pageSize) : defaultPageSize;
|
||||
const requestedPage = query.page ? Number(query.page) : 0;
|
||||
this.pageSize = Math.min(requestedPageSize, maxPageSize);
|
||||
const page = requestedPage || 1;
|
||||
const page = requestedPage || 0;
|
||||
if (page < 0 || isNaN(page)) {
|
||||
throw jsonError('Invalid page', 400);
|
||||
}
|
||||
|
@ -43,10 +43,11 @@ export default class JsonPager<T> {
|
|||
}
|
||||
|
||||
slice(array: T[]) {
|
||||
// now this is zero-based indexing
|
||||
this.total = array.length;
|
||||
this.lastPage = Math.ceil(this.total / this.pageSize);
|
||||
// TODO: this can go past the end, i.e. search while on page 7, it will not return page 1 results
|
||||
this.begin = ((this.page - 1) * this.pageSize);
|
||||
this.begin = this.page * this.pageSize;
|
||||
this.end = this.begin + this.pageSize;
|
||||
const subset = array.slice(this.begin, this.end);
|
||||
this.subsetReturnSize = subset.length;
|
||||
|
@ -57,11 +58,12 @@ export default class JsonPager<T> {
|
|||
if (mappedValues && mappedValues.length !== this.subsetReturnSize) {
|
||||
console.warn(`The mapped values length ${mappedValues.length} !== ${this.subsetReturnSize} that was computed`);
|
||||
}
|
||||
const pageCount = this.lastPage;
|
||||
return this.res.json({
|
||||
values: mappedValues,
|
||||
total: this.total,
|
||||
lastPage: this.lastPage,
|
||||
nextPage: this.page + 1, // TODO: should not return if it's the end of the road
|
||||
lastPage: pageCount - 1,
|
||||
nextPage: this.page + 1 >= pageCount ? this.page : this.page + 1,
|
||||
page: this.page,
|
||||
pageSize: this.pageSize,
|
||||
});
|
||||
|
@ -71,4 +73,16 @@ export default class JsonPager<T> {
|
|||
const subset = this.slice(array);
|
||||
return this.sendJson(subset);
|
||||
}
|
||||
|
||||
static FromSqlParameters(pageSize: number, page: number, total: number) {
|
||||
// let's keep this math in a single place
|
||||
const pageCount = Math.ceil(total / pageSize);
|
||||
return {
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
lastPage: pageCount - 1,
|
||||
nextPage: page + 1 >= pageCount ? page : page + 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,19 +5,28 @@
|
|||
|
||||
import asyncHandler from 'express-async-handler';
|
||||
import { ReposAppRequest, AccountJsonFormat } from '../../interfaces';
|
||||
import { IGraphEntry } from '../../lib/graphProvider';
|
||||
|
||||
import { jsonError } from '../../middleware';
|
||||
import { getProviders } from '../../transitional';
|
||||
|
||||
export default asyncHandler(async (req: ReposAppRequest, res, next) => {
|
||||
const providers = getProviders(req);
|
||||
const { operations, queryCache } = providers;
|
||||
const { operations, queryCache, graphProvider } = providers;
|
||||
const login = req.params.login as string;
|
||||
let corporateEntry: IGraphEntry = null;
|
||||
try {
|
||||
const account = await operations.getAccountByUsername(login);
|
||||
const idAsString = String(account.id);
|
||||
await account.tryGetLink();
|
||||
const json = account.asJson(AccountJsonFormat.UplevelWithLink);
|
||||
try {
|
||||
if (graphProvider && account.link?.corporateId) {
|
||||
corporateEntry = await graphProvider.getUserById(account.link.corporateId);
|
||||
}
|
||||
} catch (ignoreError) {
|
||||
//
|
||||
}
|
||||
const json = account.asJson(AccountJsonFormat.GitHubDetailedWithLink);
|
||||
const orgs = await queryCache.userOrganizations(idAsString);
|
||||
const teams = await queryCache.userTeams(idAsString);
|
||||
for (let team of teams) {
|
||||
|
@ -56,7 +65,7 @@ export default asyncHandler(async (req: ReposAppRequest, res, next) => {
|
|||
private: c.repository.private,
|
||||
};
|
||||
}),
|
||||
}, json);
|
||||
}, json, { corporateEntry });
|
||||
return res.json(combined);
|
||||
} catch (error) {
|
||||
return next(jsonError(`login ${login} error: ${error}`, 500));
|
||||
|
|
|
@ -56,6 +56,17 @@ export class Account {
|
|||
case AccountJsonFormat.GitHub: {
|
||||
return basic;
|
||||
}
|
||||
case AccountJsonFormat.GitHubDetailedWithLink: {
|
||||
const cloneEntity = Object.assign({}, this._originalEntity || {});
|
||||
delete cloneEntity.cost;
|
||||
delete cloneEntity.headers;
|
||||
const link = this._link ? corporateLinkToJson(this._link) : undefined;
|
||||
return {
|
||||
account: cloneEntity,
|
||||
isLinked: !!link,
|
||||
link,
|
||||
};
|
||||
}
|
||||
case AccountJsonFormat.UplevelWithLink: {
|
||||
const link = this._link ? corporateLinkToJson(this._link) : undefined;
|
||||
return {
|
||||
|
|
|
@ -125,6 +125,7 @@ export class Operations
|
|||
dataApp: hasModernGitHubApps ? config.github.app.data : null,
|
||||
backgroundJobs: hasModernGitHubApps ? config.github.app.jobs : null,
|
||||
updatesApp: hasModernGitHubApps ? config.github.app.updates : null,
|
||||
securityApp: hasModernGitHubApps ? config.github.app.security : null,
|
||||
app: this.providers.app,
|
||||
});
|
||||
this._dynamicOrganizationIds = new Set();
|
||||
|
@ -163,6 +164,16 @@ export class Operations
|
|||
return this;
|
||||
}
|
||||
|
||||
get previewMediaTypes() {
|
||||
return {
|
||||
repository: {
|
||||
// this will allow GitHub Enterprise Cloud "visibility" fields to appear
|
||||
getDetails: 'nebula-preview',
|
||||
list: 'nebula-preview',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
get organizationNames(): string[] {
|
||||
if (!this._organizationNames) {
|
||||
const names = [];
|
||||
|
|
|
@ -266,10 +266,13 @@ export class Organization {
|
|||
options = options || {};
|
||||
const operations = throwIfNotGitHubCapable(this._operations);
|
||||
const github = operations.github;
|
||||
const previewMediaTypes = operations['previewMediaTypes'] || {}; // TEMPORARY MEDIA TYPE HACK
|
||||
const mediaType = previewMediaTypes?.repository?.getDetails ? { previews: [previewMediaTypes.repository.list]} : undefined;
|
||||
const parameters = {
|
||||
org: this.name,
|
||||
type: 'all',
|
||||
per_page: getPageSize(operations),
|
||||
mediaType,
|
||||
};
|
||||
const caching = {
|
||||
maxAgeSeconds: getMaxAgeSeconds(operations, CacheDefault.orgReposStaleSeconds, options),
|
||||
|
|
|
@ -13,6 +13,7 @@ import { IPurposefulGetAuthorizationHeader, IOperationsInstance, ICacheOptions,
|
|||
import { IListPullsParameters, GitHubPullRequestState } from '../lib/github/collections';
|
||||
|
||||
import { wrapError } from '../utils';
|
||||
import { RepositoryActions } from './repositoryActions';
|
||||
|
||||
interface IRepositoryMoments {
|
||||
created?: moment.Moment;
|
||||
|
@ -250,6 +251,10 @@ export class Repository {
|
|||
return false;
|
||||
}
|
||||
|
||||
get actions() {
|
||||
return new RepositoryActions(this, this._getAuthorizationHeader, this._getSpecificAuthorizationHeader, this._operations);
|
||||
}
|
||||
|
||||
async getDetails(options?: ICacheOptions): Promise<any> {
|
||||
options = options || {};
|
||||
const operations = throwIfNotGitHubCapable(this._operations);
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
//
|
||||
// Copyright (c) Microsoft.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
import { Repository } from './repository';
|
||||
import { getPageSize, getMaxAgeSeconds, CacheDefault } from '.';
|
||||
import { AppPurpose } from '../github';
|
||||
import { IPurposefulGetAuthorizationHeader, IOperationsInstance, IGetBranchesOptions, IGitHubBranch, throwIfNotGitHubCapable, IGetPullsOptions, ICacheOptions, IGetAuthorizationHeader } from '../interfaces';
|
||||
|
||||
export class RepositoryActions {
|
||||
private _getAuthorizationHeader: IPurposefulGetAuthorizationHeader;
|
||||
private _getSpecificAuthorizationHeader: IPurposefulGetAuthorizationHeader;
|
||||
private _operations: IOperationsInstance;
|
||||
|
||||
private _repository: Repository;
|
||||
|
||||
constructor(repository: Repository, getAuthorizationHeader: IPurposefulGetAuthorizationHeader, getSpecificAuthorizationHeader: IPurposefulGetAuthorizationHeader, operations: IOperationsInstance) {
|
||||
this._repository = repository;
|
||||
this._getAuthorizationHeader = getAuthorizationHeader;
|
||||
this._getSpecificAuthorizationHeader = getSpecificAuthorizationHeader;
|
||||
this._operations = operations;
|
||||
}
|
||||
|
||||
async getWorkflow(workflowId: number, cacheOptions?: ICacheOptions): Promise<any> {
|
||||
cacheOptions = cacheOptions || {};
|
||||
const operations = throwIfNotGitHubCapable(this._operations);
|
||||
const github = operations.github;
|
||||
const parameters = {
|
||||
owner: this._repository.organization.name,
|
||||
repo: this._repository.name,
|
||||
workflow_id: workflowId,
|
||||
};
|
||||
if (!cacheOptions.maxAgeSeconds) {
|
||||
cacheOptions.maxAgeSeconds = getMaxAgeSeconds(operations, CacheDefault.repoBranchesStaleSeconds /* not specific */);
|
||||
}
|
||||
if (cacheOptions.backgroundRefresh === undefined) {
|
||||
cacheOptions.backgroundRefresh = true;
|
||||
}
|
||||
const entity = await github.call(this.authorize(AppPurpose.Security), 'actions.getWorkflow', parameters, cacheOptions);
|
||||
return entity;
|
||||
}
|
||||
|
||||
async getRepositorySecrets(): Promise<any> {
|
||||
const operations = throwIfNotGitHubCapable(this._operations);
|
||||
const github = operations.github;
|
||||
const parameters = {
|
||||
owner: this._repository.organization.name,
|
||||
repo: this._repository.name,
|
||||
};
|
||||
const entity = await github.post(this.authorize(AppPurpose.Security), 'actions.listRepoSecrets', parameters);
|
||||
return entity;
|
||||
}
|
||||
|
||||
async getWorkflows(cacheOptions?: ICacheOptions): Promise<any> {
|
||||
cacheOptions = cacheOptions || {};
|
||||
const operations = throwIfNotGitHubCapable(this._operations);
|
||||
const github = operations.github;
|
||||
const parameters = {
|
||||
owner: this._repository.organization.name,
|
||||
repo: this._repository.name,
|
||||
per_page: getPageSize(operations),
|
||||
};
|
||||
if (!cacheOptions.maxAgeSeconds) {
|
||||
cacheOptions.maxAgeSeconds = getMaxAgeSeconds(operations, CacheDefault.repoBranchesStaleSeconds /* not specific */);
|
||||
}
|
||||
if (cacheOptions.backgroundRefresh === undefined) {
|
||||
cacheOptions.backgroundRefresh = true;
|
||||
}
|
||||
const entity = await github.call(this.authorize(AppPurpose.Security), 'actions.listRepoWorkflows', parameters, cacheOptions);
|
||||
return entity;
|
||||
}
|
||||
|
||||
private authorize(purpose: AppPurpose): IGetAuthorizationHeader | string {
|
||||
const getAuthorizationHeader = this._getSpecificAuthorizationHeader.bind(this, purpose) as IGetAuthorizationHeader;
|
||||
return getAuthorizationHeader;
|
||||
}
|
||||
}
|
|
@ -2,20 +2,21 @@
|
|||
"auditlogrecord": "env://ENTITY_PROVIDER_AUDITLOG?default=firstconfigured",
|
||||
"eventrecord": "env://ENTITY_PROVIDER_EVENT?default=firstconfigured",
|
||||
|
||||
"teamjoin": "env://ENTITY_PROVIDER_TEAMJOIN?default=firstconfigured",
|
||||
"repositorymetadata": "env://ENTITY_PROVIDER_TEAMJOIN?default=firstconfigured",
|
||||
"teamjoin": "env://ENTITY_PROVIDER_TEAM_JOIN?default=firstconfigured",
|
||||
"repositorymetadata": "env://ENTITY_PROVIDER_REPOSITORY_METADATA?default=firstconfigured",
|
||||
|
||||
"organizationsettings": "env://ENTITY_PROVIDER_TEAMJOIN?default=firstconfigured",
|
||||
"organizationsettings": "env://ENTITY_PROVIDER_ORGANIZATION_SETTINGS?default=firstconfigured",
|
||||
|
||||
"organizationmembercache": "env://ENTITY_PROVIDER_TEAMJOIN?default=firstconfigured",
|
||||
"repositorycache": "env://ENTITY_PROVIDER_TEAMJOIN?default=firstconfigured",
|
||||
"repositorycollaboratorcache": "env://ENTITY_PROVIDER_TEAMJOIN?default=firstconfigured",
|
||||
"repositoryteamcache": "env://ENTITY_PROVIDER_TEAMJOIN?default=firstconfigured",
|
||||
"teamcache": "env://ENTITY_PROVIDER_TEAMJOIN?default=firstconfigured",
|
||||
"teammembercache": "env://ENTITY_PROVIDER_TEAMJOIN?default=firstconfigured",
|
||||
"organizationmembercache": "env://ENTITY_PROVIDER_ORGANIZATION_MEMBER_CACHE?default=firstconfigured",
|
||||
"repository": "env://ENTITY_PROVIDER_REPOSITORY?default=firstconfigured",
|
||||
"repositorycache": "env://ENTITY_PROVIDER_REPOSITORY_CACE?default=firstconfigured",
|
||||
"repositorycollaboratorcache": "env://ENTITY_PROVIDER_REPOSITORY_COLLABORATOR_CACHE?default=firstconfigured",
|
||||
"repositoryteamcache": "env://ENTITY_PROVIDER_REPOSITORY_TEAM_CACHE?default=firstconfigured",
|
||||
"teamcache": "env://ENTITY_PROVIDER_TEAM_CACHE?default=firstconfigured",
|
||||
"teammembercache": "env://ENTITY_PROVIDER_TEAM_MEMBER_CACHE?default=firstconfigured",
|
||||
|
||||
"usersettings": "env://ENTITY_PROVIDER_USERSETTINGS?default=firstconfigured",
|
||||
|
||||
"tokens": "env://ENTITY_PROVIDER_TEAMJOIN?default=table",
|
||||
"localextensionkey": "env://ENTITY_PROVIDER_TEAMJOIN?default=table"
|
||||
"tokens": "env://ENTITY_PROVIDER_TOKENS?default=table",
|
||||
"localextensionkey": "env://ENTITY_PROVIDER_LOCALEXTENSIONKEY?default=table"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"appId": "env://GITHUB_APP_SECURITY_APP_ID",
|
||||
"appKey": "env://GITHUB_APP_SECURITY_KEY",
|
||||
"appKeyFile": "env://GITHUB_APP_SECURITY_KEY_FILE",
|
||||
"webhookSecret": "",
|
||||
"slug": "env://GITHUB_APP_SECURITY_SLUG",
|
||||
"description": "Security Response"
|
||||
}
|
|
@ -0,0 +1,295 @@
|
|||
//
|
||||
// Copyright (c) Microsoft.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
import { IDictionary } from '../interfaces';
|
||||
import { EntityMetadataBase, EntityMetadataMappings, EntityMetadataType, IEntityMetadata, IEntityMetadataBaseOptions, IEntityMetadataFixedQuery, keyValueMetadataField, MetadataMappingDefinition, QueryBase } from '../lib/entityMetadataProvider';
|
||||
import { PostgresConfiguration, PostgresSettings } from '../lib/entityMetadataProvider/postgres';
|
||||
import { GitHubRepositoryVisibility } from './repositoryMetadata/repositoryMetadata';
|
||||
|
||||
const type = new EntityMetadataType('RepositoryDetails');
|
||||
const typeColumnValue = 'repositorydetails';
|
||||
const defaultTableName = 'repositories';
|
||||
const thisProviderType = type;
|
||||
type InterfaceProviderType = IRepositoryProvider;
|
||||
type ClassType = RepositoryEntity;
|
||||
EntityMetadataMappings.Register(type, MetadataMappingDefinition.EntityInstantiate, () => { return new RepositoryEntity(); });
|
||||
|
||||
class ThisQueryBase extends QueryBase<ClassType> {
|
||||
constructor(public query: Query) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
class ThisQuery<T> extends ThisQueryBase {
|
||||
constructor(query: Query, public parameters: T) {
|
||||
super(query);
|
||||
if (!this.parameters) {
|
||||
this.parameters = {} as T;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const repositoryId = 'repositoryId';
|
||||
const primaryFieldId = repositoryId;
|
||||
|
||||
interface IProperties {
|
||||
repositoryId: any;
|
||||
organizationId: any;
|
||||
cached: any;
|
||||
name: any;
|
||||
organizationLogin: any;
|
||||
fullName: any;
|
||||
private: any;
|
||||
visibility: any;
|
||||
fork: any;
|
||||
archived: any;
|
||||
disabled: any;
|
||||
pushedAt: any;
|
||||
createdAt: any;
|
||||
updatedAt: any;
|
||||
description: any;
|
||||
homepage: any;
|
||||
language: any;
|
||||
forksCount: any;
|
||||
stargazersCount: any;
|
||||
watchersCount: any;
|
||||
size: any;
|
||||
defaultBranch: any;
|
||||
openIssuesCount: any;
|
||||
topics: any; // array of strings
|
||||
hasIssues: any;
|
||||
hasProjects: any;
|
||||
hasWiki: any;
|
||||
hasPages: any;
|
||||
hasDownloads: any;
|
||||
subscribersCount: any;
|
||||
networkCount: any;
|
||||
license: any; // ?
|
||||
parentId: any;
|
||||
parentName: any;
|
||||
parentOrganizationName: any;
|
||||
parentOrganizationId: any;
|
||||
additionalData: any;
|
||||
}
|
||||
|
||||
const Field: IProperties = {
|
||||
[keyValueMetadataField]: keyValueMetadataField,
|
||||
repositoryId: 'repositoryId',
|
||||
organizationId: 'organizationId',
|
||||
cached: 'cached',
|
||||
name: 'name',
|
||||
organizationLogin: 'organizationLogin',
|
||||
fullName: 'fullName',
|
||||
private: 'private',
|
||||
visibility: 'visibility',
|
||||
fork: 'fork',
|
||||
archived: 'archived',
|
||||
disabled: 'disabled',
|
||||
pushedAt: 'pushedAt',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt',
|
||||
description: 'description',
|
||||
homepage: 'homepage',
|
||||
language: 'language',
|
||||
forksCount: 'forksCount',
|
||||
stargazersCount: 'stargazersCount',
|
||||
watchersCount: 'watchersCount',
|
||||
size: 'size',
|
||||
defaultBranch: 'defaultBranch',
|
||||
openIssuesCount: 'openIssuesCount',
|
||||
topics: 'topics',
|
||||
hasIssues: 'hasIssues',
|
||||
hasProjects: 'hasProjects',
|
||||
hasWiki: 'hasWiki',
|
||||
hasPages: 'hasPages',
|
||||
hasDownloads: 'hasDownloads',
|
||||
subscribersCount: 'subscribersCount',
|
||||
networkCount: 'networkCount',
|
||||
license: 'license',
|
||||
parentId: 'parentId',
|
||||
parentName: 'parentName',
|
||||
parentOrganizationName: 'parentOrganizationName',
|
||||
parentOrganizationId: 'parentOrganizationId',
|
||||
}
|
||||
|
||||
const dateColumns = [
|
||||
Field.cached,
|
||||
Field.pushedAt,
|
||||
Field.createdAt,
|
||||
Field.updatedAt,
|
||||
];
|
||||
|
||||
enum Query {
|
||||
}
|
||||
|
||||
export class RepositoryEntity implements IProperties {
|
||||
repositoryId: number;
|
||||
organizationId: number;
|
||||
[keyValueMetadataField]: IDictionary<any>;
|
||||
|
||||
name: string;
|
||||
organizationLogin: string;
|
||||
fullName: string;
|
||||
|
||||
cached: Date;
|
||||
private: boolean;
|
||||
visibility: GitHubRepositoryVisibility;
|
||||
fork: boolean;
|
||||
archived: boolean;
|
||||
disabled: boolean; // ?
|
||||
pushedAt: Date;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string;
|
||||
homepage: string;
|
||||
language: string; // ?
|
||||
forksCount: number;
|
||||
stargazersCount: number;
|
||||
watchersCount: number;
|
||||
size: number;
|
||||
defaultBranch: string;
|
||||
openIssuesCount: number;
|
||||
topics: string[]; // ?
|
||||
hasIssues: boolean;
|
||||
hasProjects: boolean;
|
||||
hasWiki: boolean;
|
||||
hasPages: boolean;
|
||||
hasDownloads: boolean;
|
||||
subscribersCount: number;
|
||||
networkCount: number;
|
||||
license: string; // ??
|
||||
parentId: number;
|
||||
parentName: string;
|
||||
parentOrganizationName: string;
|
||||
parentOrganizationId: number;
|
||||
|
||||
asJson() {
|
||||
// Based on the hard-coded names, nothing intelligent.
|
||||
return {
|
||||
id: this.repositoryId,
|
||||
name: this.name,
|
||||
organization: this.organizationLogin && this.organizationId ? {
|
||||
id: this.organizationId,
|
||||
login: this.organizationLogin,
|
||||
} : null,
|
||||
full_name: this.fullName || `${this.organizationLogin}/${this.name}`,
|
||||
private: this.private,
|
||||
visibility: this.visibility,
|
||||
fork: this.fork,
|
||||
archived: this.archived,
|
||||
disabled: this.disabled,
|
||||
pushed_at: this.pushedAt ? (new Date(this.pushedAt)).toISOString() : undefined,
|
||||
created_at: this.createdAt ? (new Date(this.createdAt)).toISOString() : undefined,
|
||||
updated_at: this.updatedAt ? (new Date(this.updatedAt)).toISOString() : undefined,
|
||||
description: this.description,
|
||||
homepage: this.homepage,
|
||||
language: this.language,
|
||||
forks_count: this.forksCount,
|
||||
stargazers_count: this.stargazersCount,
|
||||
watchers_count: this.watchersCount,
|
||||
size: this.size,
|
||||
default_branch: this.defaultBranch,
|
||||
open_issues_count: this.openIssuesCount,
|
||||
topics: this.topics,
|
||||
has_issues: this.hasIssues,
|
||||
has_projects: this.hasProjects,
|
||||
has_wiki: this.hasWiki,
|
||||
has_downloads: this.hasDownloads,
|
||||
subscribers_count: this.subscribersCount,
|
||||
network_count: this.networkCount,
|
||||
license: this.license ? { spdx_id: this.license } : null,
|
||||
parent: this.parentId && this.parentName && this.parentOrganizationId && this.parentOrganizationName ? {
|
||||
id: this.parentId,
|
||||
name: this.parentName,
|
||||
organization: {
|
||||
id: this.parentOrganizationId,
|
||||
login: this.parentOrganizationName,
|
||||
},
|
||||
} : null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
EntityMetadataMappings.Register(type, PostgresSettings.PostgresQueries, (query: IEntityMetadataFixedQuery, mapMetadataPropertiesToFields: string[], metadataColumnName: string, tableName: string, getEntityTypeColumnValue) => {
|
||||
const base = query as ThisQueryBase;
|
||||
switch (base.query) {
|
||||
default:
|
||||
throw new Error(`The query ${base.query} is not implemented by this provider for the type ${type}`);
|
||||
}
|
||||
});
|
||||
|
||||
export interface IRepositoryProvider {
|
||||
initialize(): Promise<void>;
|
||||
get(repositoryId: number): Promise<ClassType>;
|
||||
insert(entity: ClassType): Promise<string>;
|
||||
replace(entity: ClassType): Promise<void>;
|
||||
delete(entity: ClassType): Promise<void>;
|
||||
}
|
||||
|
||||
export class RepositoryProvider extends EntityMetadataBase implements IRepositoryProvider {
|
||||
constructor(options: IEntityMetadataBaseOptions) {
|
||||
super(thisProviderType, options);
|
||||
EntityImplementation.EnsureDefinitions();
|
||||
}
|
||||
|
||||
async replace(metadata: ClassType): Promise<void> {
|
||||
const entity = this.serialize(thisProviderType, metadata);
|
||||
await this._entities.updateMetadata(entity);
|
||||
}
|
||||
|
||||
async delete(metadata: ClassType): Promise<void> {
|
||||
const entity = this.serialize(thisProviderType, metadata);
|
||||
await this._entities.deleteMetadata(entity);
|
||||
}
|
||||
|
||||
async get(repositoryId: number): Promise<ClassType> {
|
||||
this.ensureHelpers(thisProviderType);
|
||||
let metadata: IEntityMetadata = null;
|
||||
metadata = await this._entities.getMetadata(thisProviderType, String(repositoryId));
|
||||
return this.deserialize<ClassType>(thisProviderType, metadata);
|
||||
}
|
||||
|
||||
async insert(metadata: ClassType): Promise<string> {
|
||||
const entity = this.serialize(thisProviderType, metadata);
|
||||
await this._entities.setMetadata(entity);
|
||||
return entity.entityId;
|
||||
}
|
||||
|
||||
rowToEntity(row: unknown) {
|
||||
const metadata = PostgresConfiguration.RowToMetadataObject(type, row);
|
||||
return this.deserialize<RepositoryEntity>(thisProviderType, metadata);
|
||||
}
|
||||
}
|
||||
|
||||
export default async function initializeRepositoryProvider(options?: IEntityMetadataBaseOptions): Promise<InterfaceProviderType> {
|
||||
const provider = new RepositoryProvider(options);
|
||||
await provider.initialize();
|
||||
return provider;
|
||||
}
|
||||
|
||||
const fieldNames = Object.getOwnPropertyNames(Field);
|
||||
const nativeFieldNames = fieldNames.filter(x => x !== Field[keyValueMetadataField]);
|
||||
|
||||
EntityMetadataMappings.Register(type, MetadataMappingDefinition.EntityIdColumnName, primaryFieldId);
|
||||
EntityMetadataMappings.Register(type, PostgresSettings.PostgresDefaultTypeColumnName, typeColumnValue);
|
||||
EntityMetadataMappings.Register(type, PostgresSettings.PostgresDateColumns, dateColumns);
|
||||
|
||||
PostgresConfiguration.SetDefaultTableName(type, defaultTableName);
|
||||
PostgresConfiguration.MapFieldsToColumnNamesFromListLowercased(type, fieldNames);
|
||||
PostgresConfiguration.IdentifyNativeFields(type, nativeFieldNames);
|
||||
PostgresConfiguration.ValidateMappings(type, fieldNames, [primaryFieldId]);
|
||||
|
||||
// Runtime validation of FieldNames
|
||||
for (let i = 0; i < fieldNames.length; i++) {
|
||||
const fn = fieldNames[i];
|
||||
if (Field[fn] !== fn) {
|
||||
throw new Error(`Field name ${fn} and value do not match in ${__filename}`);
|
||||
}
|
||||
}
|
||||
|
||||
export const EntityImplementation = {
|
||||
Type: type,
|
||||
EnsureDefinitions: () => {},
|
||||
};
|
|
@ -11,6 +11,7 @@ export enum AppPurpose {
|
|||
Operations = 'Operations',
|
||||
BackgroundJobs = 'BackgroundJobs', // "secondary" / "default" fallback
|
||||
Updates = 'Updates',
|
||||
Security = 'Security',
|
||||
}
|
||||
|
||||
export enum GitHubAppAuthenticationType {
|
||||
|
@ -36,5 +37,6 @@ export interface IGitHubAppsOptions {
|
|||
customerFacingApp?: IGitHubAppConfiguration;
|
||||
operationsApp?: IGitHubAppConfiguration;
|
||||
updatesApp?: IGitHubAppConfiguration;
|
||||
securityApp?: IGitHubAppConfiguration;
|
||||
app: IReposApplication;
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ export class GitHubTokenManager {
|
|||
await this.initializeApp(AppPurpose.Data, this.#options.dataApp);
|
||||
await this.initializeApp(AppPurpose.BackgroundJobs, this.#options.backgroundJobs);
|
||||
await this.initializeApp(AppPurpose.Updates, this.#options.updatesApp);
|
||||
await this.initializeApp(AppPurpose.Security, this.#options.securityApp);
|
||||
}
|
||||
|
||||
organizationSupportsAnyPurpose(organizationName: string, organizationSettings?: OrganizationSetting) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
export enum AccountJsonFormat {
|
||||
GitHub = 'github',
|
||||
UplevelWithLink = 'github+link',
|
||||
GitHubDetailedWithLink = 'detailed+link',
|
||||
}
|
||||
|
||||
export interface IAccountBasics {
|
||||
|
|
|
@ -36,6 +36,7 @@ import { IMailProvider } from '../lib/mailProvider';
|
|||
import { IQueueProcessor } from '../lib/queues';
|
||||
import { ICustomizedNewRepositoryLogic, ICustomizedTeamPermissionsWebhookLogic } from '../transitional';
|
||||
import { IEntityMetadataProvider } from '../lib/entityMetadataProvider';
|
||||
import { IRepositoryProvider } from '../entities/repository';
|
||||
|
||||
export interface IProviders {
|
||||
app: IReposApplication;
|
||||
|
@ -71,6 +72,7 @@ export interface IProviders {
|
|||
webhookQueueProcessor?: IQueueProcessor;
|
||||
sessionRedisClient?: redis.RedisClient;
|
||||
cacheProvider?: ICacheHelper;
|
||||
repositoryProvider?: IRepositoryProvider;
|
||||
repositoryCacheProvider?: IRepositoryCacheProvider;
|
||||
repositoryCollaboratorCacheProvider?: IRepositoryCollaboratorCacheProvider;
|
||||
// repositoryMetadataProvider?: IRepositoryMetadataProvider;
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
//
|
||||
// Copyright (c) Microsoft.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
// JOB: refresh repository data
|
||||
// This is very similar to the query cache, but using proper Postgres type entities, and
|
||||
// not being used by the app today.
|
||||
|
||||
// Implementation is initial and not as robust (will refresh everything, even things not touched
|
||||
// since the last update; limited telemetry.)
|
||||
|
||||
import throat from 'throat';
|
||||
|
||||
import app from '../app';
|
||||
import { Organization, Repository } from '../business';
|
||||
import { IRepositoryProvider, RepositoryEntity } from '../entities/repository';
|
||||
import { IProviders, IReposJob, IReposJobResult } from '../interfaces';
|
||||
import { ErrorHelper } from '../transitional';
|
||||
import { sleep } from '../utils';
|
||||
|
||||
const sleepBetweenReposMs = 125;
|
||||
const maxParallel = 6;
|
||||
|
||||
const shouldUpdateCached = true;
|
||||
|
||||
async function refreshRepositories({ providers }: IReposJob): Promise<IReposJobResult> {
|
||||
const { operations } = providers;
|
||||
const started = new Date();
|
||||
console.log(`Starting at ${started}`);
|
||||
|
||||
const orgs = operations.getOrganizations();
|
||||
const throttle = throat(maxParallel);
|
||||
await Promise.allSettled(orgs.map((organization, index) => throttle(async () => {
|
||||
return processOrganization(providers, organization, index, orgs.length);
|
||||
})));
|
||||
|
||||
// TODO: query all, remove any not processed [recently]
|
||||
console.log(`Finished at ${new Date()}, started at ${started}`);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
async function processOrganization(providers: IProviders, organization: Organization, orgIndex: number, orgsLength: number): Promise<unknown> {
|
||||
const { repositoryProvider } = providers;
|
||||
try {
|
||||
let repos = await organization.getRepositories();
|
||||
repos = repos.sort(sortDates);
|
||||
for (let i = 0; i < repos.length; i++) {
|
||||
const repo = repos[i];
|
||||
const prefix = `org ${orgIndex}/${orgsLength}: repo ${i}/${repos.length}: `;
|
||||
try {
|
||||
let repositoryEntity = await tryGetRepositoryEntity(repositoryProvider, repo.id);
|
||||
if (await repo.isDeleted()) {
|
||||
if (repositoryEntity) {
|
||||
await repositoryProvider.delete(repositoryEntity);
|
||||
console.log(`${prefix}Deleted repository ${organization.name}/${repo.name}`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const entity = repo.getEntity();
|
||||
let update = false;
|
||||
if (!repositoryEntity) {
|
||||
repositoryEntity = new RepositoryEntity();
|
||||
setFields(repositoryProvider, repositoryEntity, entity);
|
||||
await repositoryProvider.insert(repositoryEntity);
|
||||
console.log(`${prefix}inserted ${organization.name}/${repositoryEntity.name}`);
|
||||
continue;
|
||||
} else {
|
||||
setFields(repositoryProvider, repositoryEntity, entity);
|
||||
// not detecting changes now
|
||||
update = true;
|
||||
}
|
||||
if (!update && shouldUpdateCached) {
|
||||
update = true;
|
||||
repositoryEntity.cached = new Date();
|
||||
}
|
||||
if (update) {
|
||||
await repositoryProvider.replace(repositoryEntity);
|
||||
console.log(`${prefix}Updated all fields for ${organization.name}/${repo.name}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`${prefix}repo error: ${repo.name} in organization ${organization.name}`);
|
||||
}
|
||||
|
||||
await sleep(sleepBetweenReposMs);
|
||||
}
|
||||
} catch (organizationError) {
|
||||
console.warn(`error processing ${organization.name}: ${organizationError}`);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
function setFields(repositoryProvider: IRepositoryProvider, repositoryEntity: RepositoryEntity, entity: any) {
|
||||
repositoryEntity.repositoryId = entity.id;
|
||||
repositoryEntity.archived = entity.archived;
|
||||
repositoryEntity.cached = new Date();
|
||||
if (entity.created_at) {
|
||||
repositoryEntity.createdAt = new Date(entity.created_at);
|
||||
}
|
||||
repositoryEntity.defaultBranch = entity.default_branch;
|
||||
repositoryEntity.description = entity.description;
|
||||
repositoryEntity.disabled = entity.disabled;
|
||||
repositoryEntity.fork = entity.fork;
|
||||
repositoryEntity.forksCount = entity.forks_count;
|
||||
repositoryEntity.hasDownloads = entity.has_downloads;
|
||||
repositoryEntity.hasIssues = entity.has_issues;
|
||||
repositoryEntity.hasPages = entity.has_pages;
|
||||
repositoryEntity.hasProjects = entity.has_projects;
|
||||
repositoryEntity.hasWiki = entity.has_wiki;
|
||||
repositoryEntity.homepage = entity.homepage;
|
||||
repositoryEntity.language = entity.language;
|
||||
repositoryEntity.license = entity.license?.spdx_id;
|
||||
repositoryEntity.fullName = entity.full_name;
|
||||
repositoryEntity.organizationLogin = entity.organization?.login;
|
||||
repositoryEntity.name = entity.name;
|
||||
repositoryEntity.networkCount = entity.network_count;
|
||||
repositoryEntity.openIssuesCount = entity.open_issues_count;
|
||||
repositoryEntity.organizationId = entity.organization?.id;
|
||||
repositoryEntity.parentId = entity.parent?.id;
|
||||
repositoryEntity.parentName = entity.parent?.login;
|
||||
repositoryEntity.parentOrganizationId = entity.parent?.organization?.id;
|
||||
repositoryEntity.parentOrganizationName = entity.parent?.organization?.login;
|
||||
repositoryEntity.private = entity.private;
|
||||
if (entity.pushed_at) {
|
||||
repositoryEntity.pushedAt = new Date(entity.pushed_at);
|
||||
}
|
||||
repositoryEntity.size = entity.size;
|
||||
repositoryEntity.stargazersCount = entity.stargazers_count;
|
||||
repositoryEntity.subscribersCount = entity.subscribers_count;
|
||||
repositoryEntity.topics = entity.topics;
|
||||
if (entity.updated_at) {
|
||||
repositoryEntity.updatedAt = new Date(entity.updated_at);
|
||||
}
|
||||
repositoryEntity.visibility = entity.visibility;
|
||||
repositoryEntity.watchersCount = entity.watchers_count;
|
||||
return repositoryEntity;
|
||||
}
|
||||
|
||||
async function tryGetRepositoryEntity(repositoryProvider: IRepositoryProvider, repositoryId: number): Promise<RepositoryEntity> {
|
||||
try {
|
||||
const repositoryEntity = await repositoryProvider.get(repositoryId);
|
||||
return repositoryEntity;
|
||||
} catch (error) {
|
||||
if (ErrorHelper.IsNotFound(error)) {
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function sortDates(a: Repository, b: Repository): number { // Inverted sort (newest first)
|
||||
const aa = getRecentDate(a);
|
||||
const bb = getRecentDate(b);
|
||||
return aa == bb ? 0 : (aa < bb) ? 1 : -1;
|
||||
}
|
||||
|
||||
function getRecentDate(repo: Repository) {
|
||||
const dates: Date[] = [
|
||||
getAsDate(repo, 'created_at'),
|
||||
getAsDate(repo, 'pushed_at'),
|
||||
getAsDate(repo, 'updated_at'),
|
||||
].sort();
|
||||
return dates[dates.length - 1];
|
||||
}
|
||||
|
||||
function getAsDate(repo: Repository, fieldName: string) {
|
||||
if (repo[fieldName]) {
|
||||
const val = repo[fieldName];
|
||||
if (typeof(val) === 'string') {
|
||||
return new Date(val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
return new Date(0);
|
||||
}
|
||||
|
||||
|
||||
app.runJob(
|
||||
refreshRepositories, { timeoutMinutes: 320, defaultDebugOutput: 'restapi', insightsPrefix: 'JobRefreshRepositories' });
|
|
@ -184,6 +184,14 @@ export class PostgresConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
static StripRowInternals(type: EntityMetadataType, rowWithEntityValues: unknown) {
|
||||
return stripEntityIdentities(type, rowWithEntityValues);
|
||||
}
|
||||
|
||||
static RowToMetadataObject(type: EntityMetadataType, row: unknown) {
|
||||
return rowToMetadataObject(type, row);
|
||||
}
|
||||
|
||||
static MapFieldsToColumnNamesFromListLowercased(type: EntityMetadataType, fieldNames: string[]) {
|
||||
PostgresConfiguration.MapFieldsToColumnNames(type, new Map(fieldNames.map(fieldName => {
|
||||
return [fieldName, fieldName];
|
||||
|
@ -207,6 +215,41 @@ export interface IPostgresQuery {
|
|||
values: any;
|
||||
}
|
||||
|
||||
function stripEntityIdentities(type: EntityMetadataType, entity: any) {
|
||||
let entityTypeString = null;
|
||||
let entityCreated = null;
|
||||
let entityId = null;
|
||||
if (MapMetadataPropertiesToFields.entityType) {
|
||||
entityTypeString = entity[MapMetadataPropertiesToFields.entityType];
|
||||
delete entity[MapMetadataPropertiesToFields.entityType];
|
||||
}
|
||||
if (MapMetadataPropertiesToFields.entityId) {
|
||||
entityId = entity[MapMetadataPropertiesToFields.entityId];
|
||||
delete entity[MapMetadataPropertiesToFields.entityId];
|
||||
}
|
||||
if (MapMetadataPropertiesToFields.entityCreated) {
|
||||
entityCreated = entity[MapMetadataPropertiesToFields.entityCreated];
|
||||
delete entity[MapMetadataPropertiesToFields.entityCreated];
|
||||
}
|
||||
const internals = PostgresInternals.instance(type);
|
||||
const { metadata, native, leftovers } = internals.extractRowToFieldObjects(entity, MetadataColumnName, false);
|
||||
const combined = {...metadata, ...native};
|
||||
const entityFieldNames = Object.getOwnPropertyNames(combined);
|
||||
return { entity: combined, entityTypeString, entityId, entityCreated, entityFieldNames, leftovers };
|
||||
}
|
||||
|
||||
function rowToMetadataObject(type: EntityMetadataType, row: any): IEntityMetadata {
|
||||
const { entity, entityId, entityCreated, entityFieldNames } = stripEntityIdentities(type, row);
|
||||
const entityIdentity: IEntityMetadata = {
|
||||
entityType: type,
|
||||
entityId,
|
||||
entityFieldNames,
|
||||
entityCreated,
|
||||
};
|
||||
const newMetadataObject: IEntityMetadata = Object.assign(entity, entityIdentity);
|
||||
return newMetadataObject;
|
||||
}
|
||||
|
||||
export function PostgresGetAllEntities(tableName: string, entityTypeColumn: string, entityTypeValue: string): IPostgresQuery {
|
||||
const sql = `
|
||||
SELECT * FROM ${tableName} WHERE
|
||||
|
@ -507,38 +550,11 @@ export class PostgresEntityMetadataProvider implements IEntityMetadataProvider {
|
|||
}
|
||||
|
||||
private stripEntityIdentities(type: EntityMetadataType, entity: any) {
|
||||
let entityTypeString = null;
|
||||
let entityCreated = null;
|
||||
let entityId = null;
|
||||
if (MapMetadataPropertiesToFields.entityType) {
|
||||
entityTypeString = entity[MapMetadataPropertiesToFields.entityType];
|
||||
delete entity[MapMetadataPropertiesToFields.entityType];
|
||||
}
|
||||
if (MapMetadataPropertiesToFields.entityId) {
|
||||
entityId = entity[MapMetadataPropertiesToFields.entityId];
|
||||
delete entity[MapMetadataPropertiesToFields.entityId];
|
||||
}
|
||||
if (MapMetadataPropertiesToFields.entityCreated) {
|
||||
entityCreated = entity[MapMetadataPropertiesToFields.entityCreated];
|
||||
delete entity[MapMetadataPropertiesToFields.entityCreated];
|
||||
}
|
||||
const internals = PostgresInternals.instance(type);
|
||||
const { metadata, native, leftovers } = internals.extractRowToFieldObjects(entity, MetadataColumnName, false);
|
||||
const combined = {...metadata, ...native};
|
||||
const entityFieldNames = Object.getOwnPropertyNames(combined);
|
||||
return { entity: combined, entityTypeString, entityId, entityCreated, entityFieldNames, leftovers };
|
||||
return stripEntityIdentities(type, entity);
|
||||
}
|
||||
|
||||
private rowToMetadataObject(type: EntityMetadataType, row: any): IEntityMetadata {
|
||||
const { entity, entityId, entityCreated, entityFieldNames } = this.stripEntityIdentities(type, row);
|
||||
const entityIdentity: IEntityMetadata = {
|
||||
entityType: type,
|
||||
entityId,
|
||||
entityFieldNames,
|
||||
entityCreated,
|
||||
};
|
||||
const newMetadataObject: IEntityMetadata = Object.assign(entity, entityIdentity);
|
||||
return newMetadataObject;
|
||||
return rowToMetadataObject(type, row);
|
||||
}
|
||||
|
||||
private async sqlQueryToMetadataArray(type, sql, values, skipEntityMapping): Promise<IEntityMetadata[]> {
|
||||
|
|
|
@ -52,6 +52,8 @@ export interface IGraphProvider {
|
|||
getManagerById(corporateId: string): Promise<IGraphEntry>;
|
||||
getManagementChain(corporateId: string): Promise<IGraphEntry[]>;
|
||||
|
||||
getDirectReports(corporateIdOrUpn: string): Promise<IGraphEntry[]>;
|
||||
|
||||
getMailAddressByUsername(corporateUsername: string): Promise<string>;
|
||||
getUserIdByUsername(corporateUsername: string): Promise<string>;
|
||||
|
||||
|
|
|
@ -216,6 +216,31 @@ export class MicrosoftGraphProvider implements IGraphProvider {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
async getDirectReports(corporateIdOrUpn: string): Promise<IGraphEntry[]> {
|
||||
let response = await this.lookupInGraph([
|
||||
'users',
|
||||
corporateIdOrUpn,
|
||||
'directReports',
|
||||
], {
|
||||
selectValues: 'id,displayName,mailNickname,mail,userPrincipalName,userType,jobTitle',
|
||||
}) as any[];
|
||||
if (!response.filter && (response as any).value?.filter) {
|
||||
response = (response as any).value;
|
||||
}
|
||||
return response.filter(e => e.userType !== GraphUserType.Guest).map(entry => {
|
||||
return {
|
||||
id: entry.id,
|
||||
mailNickname: entry.mailNickname,
|
||||
displayName: entry.displayName,
|
||||
mail: entry.mail,
|
||||
givenName: entry.givenName,
|
||||
userPrincipalName: entry.userPrincipalName,
|
||||
jobTitle: entry.jobTitle,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async getUsersByMailNicknames(mailNicknames: string[]): Promise<IGraphEntry[]> {
|
||||
let response = await this.lookupInGraph([
|
||||
'users',
|
||||
|
@ -328,7 +353,7 @@ export class MicrosoftGraphProvider implements IGraphProvider {
|
|||
|
||||
private async getUserByIdLookup(aadId: string, token: string, subResource: string): Promise<any> {
|
||||
const extraPath = subResource ? `/${subResource}` : '';
|
||||
const url = `https://graph.microsoft.com/v1.0/users/${aadId}${extraPath}?$select=id,mailNickname,userType,displayName,givenName,mail,userPrincipalName`;
|
||||
const url = `https://graph.microsoft.com/v1.0/users/${aadId}${extraPath}?$select=id,mailNickname,userType,displayName,givenName,mail,userPrincipalName,jobTitle`;
|
||||
if (this.#_cache) {
|
||||
try {
|
||||
const cached = await this.#_cache.getObject(url);
|
||||
|
|
|
@ -74,6 +74,7 @@ import RouteSslify from './sslify';
|
|||
import MiddlewareIndex from '.';
|
||||
import { ICacheHelper } from '../lib/caching';
|
||||
import { IApplicationProfile, IProviders, IReposApplication, InnerError } from '../interfaces';
|
||||
import initializeRepositoryProvider from '../entities/repository';
|
||||
|
||||
const DefaultApplicationProfile: IApplicationProfile = {
|
||||
applicationName: 'GitHub Management Portal',
|
||||
|
@ -176,6 +177,7 @@ async function initializeAsync(app: IReposApplication, express, rootdir: string,
|
|||
providers.teamMemberCacheProvider = await CreateTeamMemberCacheProviderInstance({ entityMetadataProvider: providerNameToInstance(config.entityProviders.teammembercache) });
|
||||
providers.auditLogRecordProvider = await createAndInitializeAuditLogRecordProviderInstance({ entityMetadataProvider: providerNameToInstance(config.entityProviders.auditlogrecord) });
|
||||
providers.userSettingsProvider = new UserSettingsProvider({ entityMetadataProvider: providerNameToInstance(config.entityProviders.usersettings) });
|
||||
providers.repositoryProvider = await initializeRepositoryProvider({ entityMetadataProvider: providerNameToInstance(config.entityProviders.repository) });
|
||||
await providers.userSettingsProvider.initialize();
|
||||
providers.queryCache = new QueryCache(providers);
|
||||
if (config.campaigns && config.campaigns.provider === 'cosmosdb') {
|
||||
|
|
|
@ -5,15 +5,16 @@
|
|||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "opensource-portal",
|
||||
"version": "7.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@azure/cosmos": "3.10.5",
|
||||
"@azure/cosmos": "3.11.0",
|
||||
"@azure/data-tables": "12.0.0-beta.2",
|
||||
"@azure/storage-blob": "12.5.0",
|
||||
"@azure/storage-queue": "12.4.0",
|
||||
"@octokit/auth-app": "3.3.0",
|
||||
"@octokit/rest": "18.5.2",
|
||||
"@octokit/auth-app": "3.4.0",
|
||||
"@octokit/rest": "18.5.3",
|
||||
"adal-node": "0.2.2",
|
||||
"applicationinsights": "1.8.10",
|
||||
"async-prompt": "1.0.1",
|
||||
|
@ -28,7 +29,7 @@
|
|||
"child-process-promise": "2.2.1",
|
||||
"color-contrast-checker": "1.5.0",
|
||||
"compression": "1.7.4",
|
||||
"connect-redis": "5.1.0",
|
||||
"connect-redis": "5.2.0",
|
||||
"cors": "2.8.5",
|
||||
"csv-parser": "3.0.0",
|
||||
"debug": "4.3.1",
|
||||
|
@ -41,7 +42,7 @@
|
|||
"github-username-regex": "^1.0.0",
|
||||
"hsts": "2.2.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"jwks-rsa": "2.0.2",
|
||||
"jwks-rsa": "2.0.3",
|
||||
"language-map": "1.4.0",
|
||||
"lodash": "4.17.21",
|
||||
"luxon": "1.26.0",
|
||||
|
@ -51,7 +52,7 @@
|
|||
"morgan": "1.10.0",
|
||||
"mz": "2.7.0",
|
||||
"node-jose": "2.0.0",
|
||||
"nodemailer": "6.5.0",
|
||||
"nodemailer": "6.6.0",
|
||||
"oauth": "0.9.x",
|
||||
"object-path": "0.11.5",
|
||||
"octicons": "5.0.1",
|
||||
|
@ -62,11 +63,11 @@
|
|||
"passport-azure-ad": "4.3.0",
|
||||
"passport-github": "1.1.0",
|
||||
"passport-strategy": "1.x.x",
|
||||
"pg": "8.5.1",
|
||||
"pg": "8.6.0",
|
||||
"pg-escape": "0.2.0",
|
||||
"pug": "3.0.2",
|
||||
"recursive-readdir": "2.2.2",
|
||||
"redis": "3.1.1",
|
||||
"redis": "3.1.2",
|
||||
"redis-mock": "0.56.3",
|
||||
"secure-compare": "3.0.1",
|
||||
"semver": "7.3.5",
|
||||
|
@ -77,7 +78,7 @@
|
|||
"tmp-promise": "3.0.2",
|
||||
"unzipper": "^0.10.11",
|
||||
"uuid": "8.3.2",
|
||||
"validator": "13.5.2"
|
||||
"validator": "13.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/azure-sb": "0.0.38",
|
||||
|
@ -87,12 +88,12 @@
|
|||
"@types/debug": "4.1.5",
|
||||
"@types/express": "4.17.11",
|
||||
"@types/express-session": "1.17.3",
|
||||
"@types/jest": "26.0.22",
|
||||
"@types/jest": "26.0.23",
|
||||
"@types/lodash": "4.14.168",
|
||||
"@types/luxon": "1.26.3",
|
||||
"@types/luxon": "1.26.5",
|
||||
"@types/memory-cache": "0.2.1",
|
||||
"@types/morgan": "1.9.2",
|
||||
"@types/node": "14.14.37",
|
||||
"@types/node": "15.0.2",
|
||||
"@types/node-jose": "1.1.5",
|
||||
"@types/passport": "1.0.6",
|
||||
"@types/passport-azure-ad": "4.0.8",
|
||||
|
@ -102,14 +103,14 @@
|
|||
"@types/recursive-readdir": "2.2.0",
|
||||
"@types/redis": "2.8.28",
|
||||
"@types/request": "2.48.5",
|
||||
"@types/semver": "7.3.4",
|
||||
"@types/semver": "7.3.5",
|
||||
"@types/simple-oauth2": "4.1.0",
|
||||
"@types/unzipper": "^0.10.3",
|
||||
"@types/uuid": "8.3.0",
|
||||
"@types/validator": "13.1.3",
|
||||
"jest": "26.6.3",
|
||||
"jest-junit": "12.0.0",
|
||||
"ts-jest": "26.5.4",
|
||||
"ts-jest": "26.5.6",
|
||||
"ts-node": "9.1.1",
|
||||
"typescript": "4.2.4"
|
||||
}
|
||||
|
@ -308,16 +309,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@azure/cosmos": {
|
||||
"version": "3.10.5",
|
||||
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.10.5.tgz",
|
||||
"integrity": "sha512-if1uApYNjNXzB+reNFvzEBHvinxdQOzU8fni9e9Fs9jcPv9m76t2pzmYJNrxxCiFLP0vbNr/QCfQzIPQVw6v/A==",
|
||||
"version": "3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.11.0.tgz",
|
||||
"integrity": "sha512-E4I1P7qV9PBr6D1Ea5UW/QQ6VS6bbBCmf2y0cWVmR6/0B8IVTsHQEjTzMqTKvu3Cuxgl6/FUsBRw9m684RLBzA==",
|
||||
"dependencies": {
|
||||
"@azure/core-auth": "^1.2.0",
|
||||
"@azure/core-auth": "^1.3.0",
|
||||
"@azure/core-rest-pipeline": "^1.0.0",
|
||||
"debug": "^4.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"jsbi": "^3.1.3",
|
||||
"node-abort-controller": "^1.2.0",
|
||||
"node-fetch": "^2.6.0",
|
||||
"priorityqueuejs": "^1.0.0",
|
||||
"semaphore": "^1.0.5",
|
||||
"tslib": "^2.0.0",
|
||||
|
@ -1346,9 +1347,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@octokit/auth-app": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-3.3.0.tgz",
|
||||
"integrity": "sha512-89jfgpEc0P+7V3SjMiNfTMrAOYQcmZ5g0HbBql0Vd7U47QWxUdrORv003Dtcjpc96GMo7pGaGbVlEEkG+pPwEA==",
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-3.4.0.tgz",
|
||||
"integrity": "sha512-zBVgTnLJb0uoNMGCpcDkkAbPeavHX7oAjJkaDv2nqMmsXSsCw4AbUhjl99EtJQG/JqFY/kLFHM9330Wn0k70+g==",
|
||||
"dependencies": {
|
||||
"@octokit/auth-oauth-app": "^4.1.0",
|
||||
"@octokit/auth-oauth-user": "^1.2.3",
|
||||
|
@ -1462,9 +1463,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-6.0.0.tgz",
|
||||
"integrity": "sha512-CnDdK7ivHkBtJYzWzZm7gEkanA7gKH6a09Eguz7flHw//GacPJLmkHA3f3N++MJmlxD1Fl+mB7B32EEpSCwztQ=="
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-6.1.1.tgz",
|
||||
"integrity": "sha512-ICBhnEb+ahi/TTdNuYb/kTyKVBgAM0VD4k6JPzlhJyzt3Z+Tq/bynwCD+gpkJP7AEcNnzC8YO5R39trmzEo2UA=="
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest": {
|
||||
"version": "2.13.2",
|
||||
|
@ -1486,11 +1487,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.0.0.tgz",
|
||||
"integrity": "sha512-Jc7CLNUueIshXT+HWt6T+M0sySPjF32mSFQAK7UfAg8qGeRI6OM1GSBxDLwbXjkqy2NVdnqCedJcP1nC785JYg==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.0.1.tgz",
|
||||
"integrity": "sha512-vvWbPtPqLyIzJ7A4IPdTl+8IeuKAwMJ4LjvmqWOOdfSuqWQYZXq2CEd0hsnkidff2YfKlguzujHs/reBdAx8Sg==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.13.0",
|
||||
"@octokit/types": "^6.13.1",
|
||||
"deprecation": "^2.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@ -1523,22 +1524,22 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@octokit/rest": {
|
||||
"version": "18.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.5.2.tgz",
|
||||
"integrity": "sha512-Kz03XYfKS0yYdi61BkL9/aJ0pP2A/WK5vF/syhu9/kY30J8He3P68hv9GRpn8bULFx2K0A9MEErn4v3QEdbZcw==",
|
||||
"version": "18.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.5.3.tgz",
|
||||
"integrity": "sha512-KPAsUCr1DOdLVbZJgGNuE/QVLWEaVBpFQwDAz/2Cnya6uW2wJ/P5RVGk0itx7yyN1aGa8uXm2pri4umEqG1JBA==",
|
||||
"dependencies": {
|
||||
"@octokit/core": "^3.2.3",
|
||||
"@octokit/plugin-paginate-rest": "^2.6.2",
|
||||
"@octokit/plugin-request-log": "^1.0.2",
|
||||
"@octokit/plugin-rest-endpoint-methods": "5.0.0"
|
||||
"@octokit/plugin-rest-endpoint-methods": "5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/types": {
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.13.0.tgz",
|
||||
"integrity": "sha512-W2J9qlVIU11jMwKHUp5/rbVUeErqelCsO5vW5PKNb7wAXQVUz87Rc+imjlEvpvbH8yUb+KHmv8NEjVZdsdpyxA==",
|
||||
"version": "6.13.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.13.2.tgz",
|
||||
"integrity": "sha512-jN5LImYHvv7W6SZargq1UMJ3EiaqIz5qkpfsv4GAb4b16SGqctxtOU2TQAZxvsKHkOw2A4zxdsi5wR9en1/ezQ==",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^6.0.0"
|
||||
"@octokit/openapi-types": "^6.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@opencensus/web-types": {
|
||||
|
@ -1821,9 +1822,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/jest": {
|
||||
"version": "26.0.22",
|
||||
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.22.tgz",
|
||||
"integrity": "sha512-eeWwWjlqxvBxc4oQdkueW5OF/gtfSceKk4OnOAGlUSwS/liBRtZppbJuz1YkgbrbfGOoeBHun9fOvXnjNwrSOw==",
|
||||
"version": "26.0.23",
|
||||
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.23.tgz",
|
||||
"integrity": "sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"jest-diff": "^26.0.0",
|
||||
|
@ -1850,9 +1851,9 @@
|
|||
"integrity": "sha512-RaE0B+14ToE4l6UqdarKPnXwVDuigfFv+5j9Dze/Nqr23yyuqdNvzcZi3xB+3Agvi5R4EOgAksfv3lXX4vBt9w=="
|
||||
},
|
||||
"node_modules/@types/luxon": {
|
||||
"version": "1.26.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-1.26.3.tgz",
|
||||
"integrity": "sha512-2TELN+Pd3Ocde87sKJMSQ9Wdj0zc/okHK3/+fOQHr3CaWv4jtVtcMzmt1Foww1+5YvPd9B5vL3XR6u5KF0daEA==",
|
||||
"version": "1.26.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-1.26.5.tgz",
|
||||
"integrity": "sha512-XeQxxRMyJi1znfzHw4CGDLyup/raj84SnjjkI2fDootZPGlB0yqtvlvEIAmzHDa5wiEI5JJevZOWxpcofsaV+A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/memory-cache": {
|
||||
|
@ -1876,9 +1877,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "14.14.37",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz",
|
||||
"integrity": "sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw=="
|
||||
"version": "15.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.2.tgz",
|
||||
"integrity": "sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA=="
|
||||
},
|
||||
"node_modules/@types/node-fetch": {
|
||||
"version": "2.5.8",
|
||||
|
@ -2036,9 +2037,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.4.tgz",
|
||||
"integrity": "sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ==",
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.5.tgz",
|
||||
"integrity": "sha512-iotVxtCCsPLRAvxMFFgxL8HD2l4mAZ2Oin7/VJ2ooWO0VOK4EGOGmZWZn1uCq7RofR3I/1IOSjCHlFT71eVK0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/serve-static": {
|
||||
|
@ -3505,9 +3506,9 @@
|
|||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||
},
|
||||
"node_modules/connect-redis": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-5.1.0.tgz",
|
||||
"integrity": "sha512-Cosy8gGUdkBPEYG84svgkzIGzspKBb98NUX4Nfc5eTJOF0A++41ZV15rPwWW0n5nU/FusNgNzuMeXhLVEQF80Q==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-5.2.0.tgz",
|
||||
"integrity": "sha512-wcv1lZWa2K7RbsdSlrvwApBQFLQx+cia+oirLIeim0axR3D/9ZJbHdeTM/j8tJYYKk34dVs2QPAuAqcIklWD+Q==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
|
@ -6634,9 +6635,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/jose": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-2.0.4.tgz",
|
||||
"integrity": "sha512-EArN9f6aq1LT/fIGGsfghOnNXn4noD+3dG5lL/ljY3LcRjw1u9w+4ahu/4ahsN6N0kRLyyW6zqdoYk7LNx3+YQ==",
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz",
|
||||
"integrity": "sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA==",
|
||||
"dependencies": {
|
||||
"@panva/asn1.js": "^1.0.0"
|
||||
},
|
||||
|
@ -6867,13 +6868,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/jwks-rsa": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-2.0.2.tgz",
|
||||
"integrity": "sha512-oRnlZvmP21LxqEgEFiPycLn3jyw/QuynyaERe7GMxR4TlTg7BRGBgEyEN+rRN4xGHMekXur1RY/MSt8UJBiSgA==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-2.0.3.tgz",
|
||||
"integrity": "sha512-/rkjXRWAp0cS00tunsHResw68P5iTQru8+jHufLNv3JHc4nObFEndfEUSuPugh09N+V9XYxKUqi7QrkmCHSSSg==",
|
||||
"dependencies": {
|
||||
"@types/express-jwt": "0.0.42",
|
||||
"debug": "^4.1.0",
|
||||
"jose": "^2.0.2",
|
||||
"jose": "^2.0.5",
|
||||
"limiter": "^1.1.5",
|
||||
"lru-memoizer": "^2.1.2"
|
||||
},
|
||||
|
@ -7621,9 +7622,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.5.0.tgz",
|
||||
"integrity": "sha512-Tm4RPrrIZbnqDKAvX+/4M+zovEReiKlEXWDzG4iwtpL9X34MJY+D5LnQPH/+eghe8DLlAVshHAJZAZWBGhkguw==",
|
||||
"version": "6.6.0",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.6.0.tgz",
|
||||
"integrity": "sha512-ikSMDU1nZqpo2WUPE0wTTw/NGGImTkwpJKDIFPZT+YvvR9Sj+ze5wzu95JHkBMglQLoG2ITxU21WukCC/XsFkg==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
|
@ -8230,15 +8231,15 @@
|
|||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
||||
},
|
||||
"node_modules/pg": {
|
||||
"version": "8.5.1",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.5.1.tgz",
|
||||
"integrity": "sha512-9wm3yX9lCfjvA98ybCyw2pADUivyNWT/yIP4ZcDVpMN0og70BUWYEGXPCTAQdGTAqnytfRADb7NERrY1qxhIqw==",
|
||||
"version": "8.6.0",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.6.0.tgz",
|
||||
"integrity": "sha512-qNS9u61lqljTDFvmk/N66EeGq3n6Ujzj0FFyNMGQr6XuEv4tgNTXvJQTfJdcvGit5p5/DWPu+wj920hAJFI+QQ==",
|
||||
"dependencies": {
|
||||
"buffer-writer": "2.0.0",
|
||||
"packet-reader": "1.0.0",
|
||||
"pg-connection-string": "^2.4.0",
|
||||
"pg-pool": "^3.2.2",
|
||||
"pg-protocol": "^1.4.0",
|
||||
"pg-connection-string": "^2.5.0",
|
||||
"pg-pool": "^3.3.0",
|
||||
"pg-protocol": "^1.5.0",
|
||||
"pg-types": "^2.1.0",
|
||||
"pgpass": "1.x"
|
||||
},
|
||||
|
@ -8255,9 +8256,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/pg-connection-string": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.4.0.tgz",
|
||||
"integrity": "sha512-3iBXuv7XKvxeMrIgym7njT+HlZkwZqqGX4Bu9cci8xHZNT+Um1gWKqCsAzcC0d95rcKMU5WBg6YRUcHyV0HZKQ=="
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz",
|
||||
"integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ=="
|
||||
},
|
||||
"node_modules/pg-escape": {
|
||||
"version": "0.2.0",
|
||||
|
@ -8273,17 +8274,17 @@
|
|||
}
|
||||
},
|
||||
"node_modules/pg-pool": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.2.2.tgz",
|
||||
"integrity": "sha512-ORJoFxAlmmros8igi608iVEbQNNZlp89diFVx6yV5v+ehmpMY9sK6QgpmgoXbmkNaBAx8cOOZh9g80kJv1ooyA==",
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.3.0.tgz",
|
||||
"integrity": "sha512-0O5huCql8/D6PIRFAlmccjphLYWC+JIzvUhSzXSpGaf+tjTZc4nn+Lr7mLXBbFJfvwbP0ywDv73EiaBsxn7zdg==",
|
||||
"peerDependencies": {
|
||||
"pg": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pg-protocol": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.4.0.tgz",
|
||||
"integrity": "sha512-El+aXWcwG/8wuFICMQjM5ZSAm6OWiJicFdNYo+VY3QP+8vI4SvLIWVe51PppTzMhikUJR+PsyIFKqfdXPz/yxA=="
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz",
|
||||
"integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ=="
|
||||
},
|
||||
"node_modules/pg-types": {
|
||||
"version": "2.2.0",
|
||||
|
@ -8848,9 +8849,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/redis": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/redis/-/redis-3.1.1.tgz",
|
||||
"integrity": "sha512-QhkKhOuzhogR1NDJfBD34TQJz2ZJwDhhIC6ZmvpftlmfYShHHQXjjNspAJ+Z2HH5NwSBVYBVganbiZ8bgFMHjg==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz",
|
||||
"integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==",
|
||||
"dependencies": {
|
||||
"denque": "^1.5.0",
|
||||
"redis-commands": "^1.7.0",
|
||||
|
@ -10510,9 +10511,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/ts-jest": {
|
||||
"version": "26.5.4",
|
||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.4.tgz",
|
||||
"integrity": "sha512-I5Qsddo+VTm94SukBJ4cPimOoFZsYTeElR2xy6H2TOVs+NsvgYglW8KuQgKoApOKuaU/Ix/vrF9ebFZlb5D2Pg==",
|
||||
"version": "26.5.6",
|
||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz",
|
||||
"integrity": "sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"bs-logger": "0.x",
|
||||
|
@ -10927,9 +10928,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/validator": {
|
||||
"version": "13.5.2",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-13.5.2.tgz",
|
||||
"integrity": "sha512-mD45p0rvHVBlY2Zuy3F3ESIe1h5X58GPfAtslBjY7EtTqGquZTj+VX/J4RnHWN8FKq0C9WRVt1oWAcytWRuYLQ==",
|
||||
"version": "13.6.0",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz",
|
||||
"integrity": "sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg==",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
|
@ -11378,16 +11379,16 @@
|
|||
}
|
||||
},
|
||||
"@azure/cosmos": {
|
||||
"version": "3.10.5",
|
||||
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.10.5.tgz",
|
||||
"integrity": "sha512-if1uApYNjNXzB+reNFvzEBHvinxdQOzU8fni9e9Fs9jcPv9m76t2pzmYJNrxxCiFLP0vbNr/QCfQzIPQVw6v/A==",
|
||||
"version": "3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.11.0.tgz",
|
||||
"integrity": "sha512-E4I1P7qV9PBr6D1Ea5UW/QQ6VS6bbBCmf2y0cWVmR6/0B8IVTsHQEjTzMqTKvu3Cuxgl6/FUsBRw9m684RLBzA==",
|
||||
"requires": {
|
||||
"@azure/core-auth": "^1.2.0",
|
||||
"@azure/core-auth": "^1.3.0",
|
||||
"@azure/core-rest-pipeline": "^1.0.0",
|
||||
"debug": "^4.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"jsbi": "^3.1.3",
|
||||
"node-abort-controller": "^1.2.0",
|
||||
"node-fetch": "^2.6.0",
|
||||
"priorityqueuejs": "^1.0.0",
|
||||
"semaphore": "^1.0.5",
|
||||
"tslib": "^2.0.0",
|
||||
|
@ -12250,9 +12251,9 @@
|
|||
}
|
||||
},
|
||||
"@octokit/auth-app": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-3.3.0.tgz",
|
||||
"integrity": "sha512-89jfgpEc0P+7V3SjMiNfTMrAOYQcmZ5g0HbBql0Vd7U47QWxUdrORv003Dtcjpc96GMo7pGaGbVlEEkG+pPwEA==",
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-3.4.0.tgz",
|
||||
"integrity": "sha512-zBVgTnLJb0uoNMGCpcDkkAbPeavHX7oAjJkaDv2nqMmsXSsCw4AbUhjl99EtJQG/JqFY/kLFHM9330Wn0k70+g==",
|
||||
"requires": {
|
||||
"@octokit/auth-oauth-app": "^4.1.0",
|
||||
"@octokit/auth-oauth-user": "^1.2.3",
|
||||
|
@ -12366,9 +12367,9 @@
|
|||
}
|
||||
},
|
||||
"@octokit/openapi-types": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-6.0.0.tgz",
|
||||
"integrity": "sha512-CnDdK7ivHkBtJYzWzZm7gEkanA7gKH6a09Eguz7flHw//GacPJLmkHA3f3N++MJmlxD1Fl+mB7B32EEpSCwztQ=="
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-6.1.1.tgz",
|
||||
"integrity": "sha512-ICBhnEb+ahi/TTdNuYb/kTyKVBgAM0VD4k6JPzlhJyzt3Z+Tq/bynwCD+gpkJP7AEcNnzC8YO5R39trmzEo2UA=="
|
||||
},
|
||||
"@octokit/plugin-paginate-rest": {
|
||||
"version": "2.13.2",
|
||||
|
@ -12385,11 +12386,11 @@
|
|||
"requires": {}
|
||||
},
|
||||
"@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.0.0.tgz",
|
||||
"integrity": "sha512-Jc7CLNUueIshXT+HWt6T+M0sySPjF32mSFQAK7UfAg8qGeRI6OM1GSBxDLwbXjkqy2NVdnqCedJcP1nC785JYg==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.0.1.tgz",
|
||||
"integrity": "sha512-vvWbPtPqLyIzJ7A4IPdTl+8IeuKAwMJ4LjvmqWOOdfSuqWQYZXq2CEd0hsnkidff2YfKlguzujHs/reBdAx8Sg==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.13.0",
|
||||
"@octokit/types": "^6.13.1",
|
||||
"deprecation": "^2.3.1"
|
||||
}
|
||||
},
|
||||
|
@ -12419,22 +12420,22 @@
|
|||
}
|
||||
},
|
||||
"@octokit/rest": {
|
||||
"version": "18.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.5.2.tgz",
|
||||
"integrity": "sha512-Kz03XYfKS0yYdi61BkL9/aJ0pP2A/WK5vF/syhu9/kY30J8He3P68hv9GRpn8bULFx2K0A9MEErn4v3QEdbZcw==",
|
||||
"version": "18.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.5.3.tgz",
|
||||
"integrity": "sha512-KPAsUCr1DOdLVbZJgGNuE/QVLWEaVBpFQwDAz/2Cnya6uW2wJ/P5RVGk0itx7yyN1aGa8uXm2pri4umEqG1JBA==",
|
||||
"requires": {
|
||||
"@octokit/core": "^3.2.3",
|
||||
"@octokit/plugin-paginate-rest": "^2.6.2",
|
||||
"@octokit/plugin-request-log": "^1.0.2",
|
||||
"@octokit/plugin-rest-endpoint-methods": "5.0.0"
|
||||
"@octokit/plugin-rest-endpoint-methods": "5.0.1"
|
||||
}
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.13.0.tgz",
|
||||
"integrity": "sha512-W2J9qlVIU11jMwKHUp5/rbVUeErqelCsO5vW5PKNb7wAXQVUz87Rc+imjlEvpvbH8yUb+KHmv8NEjVZdsdpyxA==",
|
||||
"version": "6.13.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.13.2.tgz",
|
||||
"integrity": "sha512-jN5LImYHvv7W6SZargq1UMJ3EiaqIz5qkpfsv4GAb4b16SGqctxtOU2TQAZxvsKHkOw2A4zxdsi5wR9en1/ezQ==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^6.0.0"
|
||||
"@octokit/openapi-types": "^6.1.1"
|
||||
}
|
||||
},
|
||||
"@opencensus/web-types": {
|
||||
|
@ -12702,9 +12703,9 @@
|
|||
}
|
||||
},
|
||||
"@types/jest": {
|
||||
"version": "26.0.22",
|
||||
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.22.tgz",
|
||||
"integrity": "sha512-eeWwWjlqxvBxc4oQdkueW5OF/gtfSceKk4OnOAGlUSwS/liBRtZppbJuz1YkgbrbfGOoeBHun9fOvXnjNwrSOw==",
|
||||
"version": "26.0.23",
|
||||
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.23.tgz",
|
||||
"integrity": "sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"jest-diff": "^26.0.0",
|
||||
|
@ -12731,9 +12732,9 @@
|
|||
"integrity": "sha512-RaE0B+14ToE4l6UqdarKPnXwVDuigfFv+5j9Dze/Nqr23yyuqdNvzcZi3xB+3Agvi5R4EOgAksfv3lXX4vBt9w=="
|
||||
},
|
||||
"@types/luxon": {
|
||||
"version": "1.26.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-1.26.3.tgz",
|
||||
"integrity": "sha512-2TELN+Pd3Ocde87sKJMSQ9Wdj0zc/okHK3/+fOQHr3CaWv4jtVtcMzmt1Foww1+5YvPd9B5vL3XR6u5KF0daEA==",
|
||||
"version": "1.26.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-1.26.5.tgz",
|
||||
"integrity": "sha512-XeQxxRMyJi1znfzHw4CGDLyup/raj84SnjjkI2fDootZPGlB0yqtvlvEIAmzHDa5wiEI5JJevZOWxpcofsaV+A==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/memory-cache": {
|
||||
|
@ -12757,9 +12758,9 @@
|
|||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "14.14.37",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz",
|
||||
"integrity": "sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw=="
|
||||
"version": "15.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.2.tgz",
|
||||
"integrity": "sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA=="
|
||||
},
|
||||
"@types/node-fetch": {
|
||||
"version": "2.5.8",
|
||||
|
@ -12916,9 +12917,9 @@
|
|||
}
|
||||
},
|
||||
"@types/semver": {
|
||||
"version": "7.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.4.tgz",
|
||||
"integrity": "sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ==",
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.5.tgz",
|
||||
"integrity": "sha512-iotVxtCCsPLRAvxMFFgxL8HD2l4mAZ2Oin7/VJ2ooWO0VOK4EGOGmZWZn1uCq7RofR3I/1IOSjCHlFT71eVK0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/serve-static": {
|
||||
|
@ -14106,9 +14107,9 @@
|
|||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||
},
|
||||
"connect-redis": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-5.1.0.tgz",
|
||||
"integrity": "sha512-Cosy8gGUdkBPEYG84svgkzIGzspKBb98NUX4Nfc5eTJOF0A++41ZV15rPwWW0n5nU/FusNgNzuMeXhLVEQF80Q=="
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-5.2.0.tgz",
|
||||
"integrity": "sha512-wcv1lZWa2K7RbsdSlrvwApBQFLQx+cia+oirLIeim0axR3D/9ZJbHdeTM/j8tJYYKk34dVs2QPAuAqcIklWD+Q=="
|
||||
},
|
||||
"constantinople": {
|
||||
"version": "4.0.1",
|
||||
|
@ -16566,9 +16567,9 @@
|
|||
}
|
||||
},
|
||||
"jose": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-2.0.4.tgz",
|
||||
"integrity": "sha512-EArN9f6aq1LT/fIGGsfghOnNXn4noD+3dG5lL/ljY3LcRjw1u9w+4ahu/4ahsN6N0kRLyyW6zqdoYk7LNx3+YQ==",
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz",
|
||||
"integrity": "sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA==",
|
||||
"requires": {
|
||||
"@panva/asn1.js": "^1.0.0"
|
||||
}
|
||||
|
@ -16755,13 +16756,13 @@
|
|||
}
|
||||
},
|
||||
"jwks-rsa": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-2.0.2.tgz",
|
||||
"integrity": "sha512-oRnlZvmP21LxqEgEFiPycLn3jyw/QuynyaERe7GMxR4TlTg7BRGBgEyEN+rRN4xGHMekXur1RY/MSt8UJBiSgA==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-2.0.3.tgz",
|
||||
"integrity": "sha512-/rkjXRWAp0cS00tunsHResw68P5iTQru8+jHufLNv3JHc4nObFEndfEUSuPugh09N+V9XYxKUqi7QrkmCHSSSg==",
|
||||
"requires": {
|
||||
"@types/express-jwt": "0.0.42",
|
||||
"debug": "^4.1.0",
|
||||
"jose": "^2.0.2",
|
||||
"jose": "^2.0.5",
|
||||
"limiter": "^1.1.5",
|
||||
"lru-memoizer": "^2.1.2"
|
||||
}
|
||||
|
@ -17391,9 +17392,9 @@
|
|||
"integrity": "sha512-ma6oU4Sk0qOoKEAymVoTvk8EdXEobdS7m/mAGhDJ8Rouugho48crHBORAmy5BoOcv8wraPM6xumapQp5hl4iIQ=="
|
||||
},
|
||||
"nodemailer": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.5.0.tgz",
|
||||
"integrity": "sha512-Tm4RPrrIZbnqDKAvX+/4M+zovEReiKlEXWDzG4iwtpL9X34MJY+D5LnQPH/+eghe8DLlAVshHAJZAZWBGhkguw=="
|
||||
"version": "6.6.0",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.6.0.tgz",
|
||||
"integrity": "sha512-ikSMDU1nZqpo2WUPE0wTTw/NGGImTkwpJKDIFPZT+YvvR9Sj+ze5wzu95JHkBMglQLoG2ITxU21WukCC/XsFkg=="
|
||||
},
|
||||
"normalize-package-data": {
|
||||
"version": "2.5.0",
|
||||
|
@ -17877,23 +17878,23 @@
|
|||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
||||
},
|
||||
"pg": {
|
||||
"version": "8.5.1",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.5.1.tgz",
|
||||
"integrity": "sha512-9wm3yX9lCfjvA98ybCyw2pADUivyNWT/yIP4ZcDVpMN0og70BUWYEGXPCTAQdGTAqnytfRADb7NERrY1qxhIqw==",
|
||||
"version": "8.6.0",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.6.0.tgz",
|
||||
"integrity": "sha512-qNS9u61lqljTDFvmk/N66EeGq3n6Ujzj0FFyNMGQr6XuEv4tgNTXvJQTfJdcvGit5p5/DWPu+wj920hAJFI+QQ==",
|
||||
"requires": {
|
||||
"buffer-writer": "2.0.0",
|
||||
"packet-reader": "1.0.0",
|
||||
"pg-connection-string": "^2.4.0",
|
||||
"pg-pool": "^3.2.2",
|
||||
"pg-protocol": "^1.4.0",
|
||||
"pg-connection-string": "^2.5.0",
|
||||
"pg-pool": "^3.3.0",
|
||||
"pg-protocol": "^1.5.0",
|
||||
"pg-types": "^2.1.0",
|
||||
"pgpass": "1.x"
|
||||
}
|
||||
},
|
||||
"pg-connection-string": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.4.0.tgz",
|
||||
"integrity": "sha512-3iBXuv7XKvxeMrIgym7njT+HlZkwZqqGX4Bu9cci8xHZNT+Um1gWKqCsAzcC0d95rcKMU5WBg6YRUcHyV0HZKQ=="
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz",
|
||||
"integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ=="
|
||||
},
|
||||
"pg-escape": {
|
||||
"version": "0.2.0",
|
||||
|
@ -17906,15 +17907,15 @@
|
|||
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="
|
||||
},
|
||||
"pg-pool": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.2.2.tgz",
|
||||
"integrity": "sha512-ORJoFxAlmmros8igi608iVEbQNNZlp89diFVx6yV5v+ehmpMY9sK6QgpmgoXbmkNaBAx8cOOZh9g80kJv1ooyA==",
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.3.0.tgz",
|
||||
"integrity": "sha512-0O5huCql8/D6PIRFAlmccjphLYWC+JIzvUhSzXSpGaf+tjTZc4nn+Lr7mLXBbFJfvwbP0ywDv73EiaBsxn7zdg==",
|
||||
"requires": {}
|
||||
},
|
||||
"pg-protocol": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.4.0.tgz",
|
||||
"integrity": "sha512-El+aXWcwG/8wuFICMQjM5ZSAm6OWiJicFdNYo+VY3QP+8vI4SvLIWVe51PppTzMhikUJR+PsyIFKqfdXPz/yxA=="
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz",
|
||||
"integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ=="
|
||||
},
|
||||
"pg-types": {
|
||||
"version": "2.2.0",
|
||||
|
@ -18373,9 +18374,9 @@
|
|||
}
|
||||
},
|
||||
"redis": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/redis/-/redis-3.1.1.tgz",
|
||||
"integrity": "sha512-QhkKhOuzhogR1NDJfBD34TQJz2ZJwDhhIC6ZmvpftlmfYShHHQXjjNspAJ+Z2HH5NwSBVYBVganbiZ8bgFMHjg==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz",
|
||||
"integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==",
|
||||
"requires": {
|
||||
"denque": "^1.5.0",
|
||||
"redis-commands": "^1.7.0",
|
||||
|
@ -19714,9 +19715,9 @@
|
|||
"integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk="
|
||||
},
|
||||
"ts-jest": {
|
||||
"version": "26.5.4",
|
||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.4.tgz",
|
||||
"integrity": "sha512-I5Qsddo+VTm94SukBJ4cPimOoFZsYTeElR2xy6H2TOVs+NsvgYglW8KuQgKoApOKuaU/Ix/vrF9ebFZlb5D2Pg==",
|
||||
"version": "26.5.6",
|
||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz",
|
||||
"integrity": "sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bs-logger": "0.x",
|
||||
|
@ -20044,9 +20045,9 @@
|
|||
}
|
||||
},
|
||||
"validator": {
|
||||
"version": "13.5.2",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-13.5.2.tgz",
|
||||
"integrity": "sha512-mD45p0rvHVBlY2Zuy3F3ESIe1h5X58GPfAtslBjY7EtTqGquZTj+VX/J4RnHWN8FKq0C9WRVt1oWAcytWRuYLQ=="
|
||||
"version": "13.6.0",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz",
|
||||
"integrity": "sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg=="
|
||||
},
|
||||
"vary": {
|
||||
"version": "1.1.2",
|
||||
|
|
28
package.json
28
package.json
|
@ -47,12 +47,12 @@
|
|||
"_end_microsoft_internal_": 0,
|
||||
"//...": "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ",
|
||||
"dependencies": {
|
||||
"@azure/cosmos": "3.10.5",
|
||||
"@azure/cosmos": "3.11.0",
|
||||
"@azure/data-tables": "12.0.0-beta.2",
|
||||
"@azure/storage-blob": "12.5.0",
|
||||
"@azure/storage-queue": "12.4.0",
|
||||
"@octokit/auth-app": "3.3.0",
|
||||
"@octokit/rest": "18.5.2",
|
||||
"@octokit/auth-app": "3.4.0",
|
||||
"@octokit/rest": "18.5.3",
|
||||
"adal-node": "0.2.2",
|
||||
"applicationinsights": "1.8.10",
|
||||
"async-prompt": "1.0.1",
|
||||
|
@ -67,7 +67,7 @@
|
|||
"child-process-promise": "2.2.1",
|
||||
"color-contrast-checker": "1.5.0",
|
||||
"compression": "1.7.4",
|
||||
"connect-redis": "5.1.0",
|
||||
"connect-redis": "5.2.0",
|
||||
"cors": "2.8.5",
|
||||
"csv-parser": "3.0.0",
|
||||
"debug": "4.3.1",
|
||||
|
@ -80,7 +80,7 @@
|
|||
"github-username-regex": "^1.0.0",
|
||||
"hsts": "2.2.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"jwks-rsa": "2.0.2",
|
||||
"jwks-rsa": "2.0.3",
|
||||
"language-map": "1.4.0",
|
||||
"lodash": "4.17.21",
|
||||
"luxon": "1.26.0",
|
||||
|
@ -90,7 +90,7 @@
|
|||
"morgan": "1.10.0",
|
||||
"mz": "2.7.0",
|
||||
"node-jose": "2.0.0",
|
||||
"nodemailer": "6.5.0",
|
||||
"nodemailer": "6.6.0",
|
||||
"oauth": "0.9.x",
|
||||
"object-path": "0.11.5",
|
||||
"octicons": "5.0.1",
|
||||
|
@ -101,11 +101,11 @@
|
|||
"passport-azure-ad": "4.3.0",
|
||||
"passport-github": "1.1.0",
|
||||
"passport-strategy": "1.x.x",
|
||||
"pg": "8.5.1",
|
||||
"pg": "8.6.0",
|
||||
"pg-escape": "0.2.0",
|
||||
"pug": "3.0.2",
|
||||
"recursive-readdir": "2.2.2",
|
||||
"redis": "3.1.1",
|
||||
"redis": "3.1.2",
|
||||
"redis-mock": "0.56.3",
|
||||
"secure-compare": "3.0.1",
|
||||
"semver": "7.3.5",
|
||||
|
@ -116,7 +116,7 @@
|
|||
"tmp-promise": "3.0.2",
|
||||
"unzipper": "^0.10.11",
|
||||
"uuid": "8.3.2",
|
||||
"validator": "13.5.2"
|
||||
"validator": "13.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/azure-sb": "0.0.38",
|
||||
|
@ -126,12 +126,12 @@
|
|||
"@types/debug": "4.1.5",
|
||||
"@types/express": "4.17.11",
|
||||
"@types/express-session": "1.17.3",
|
||||
"@types/jest": "26.0.22",
|
||||
"@types/jest": "26.0.23",
|
||||
"@types/lodash": "4.14.168",
|
||||
"@types/luxon": "1.26.3",
|
||||
"@types/luxon": "1.26.5",
|
||||
"@types/memory-cache": "0.2.1",
|
||||
"@types/morgan": "1.9.2",
|
||||
"@types/node": "14.14.37",
|
||||
"@types/node": "15.0.2",
|
||||
"@types/node-jose": "1.1.5",
|
||||
"@types/passport": "1.0.6",
|
||||
"@types/passport-azure-ad": "4.0.8",
|
||||
|
@ -141,14 +141,14 @@
|
|||
"@types/recursive-readdir": "2.2.0",
|
||||
"@types/redis": "2.8.28",
|
||||
"@types/request": "2.48.5",
|
||||
"@types/semver": "7.3.4",
|
||||
"@types/semver": "7.3.5",
|
||||
"@types/simple-oauth2": "4.1.0",
|
||||
"@types/unzipper": "^0.10.3",
|
||||
"@types/uuid": "8.3.0",
|
||||
"@types/validator": "13.1.3",
|
||||
"jest": "26.6.3",
|
||||
"jest-junit": "12.0.0",
|
||||
"ts-jest": "26.5.4",
|
||||
"ts-jest": "26.5.6",
|
||||
"ts-node": "9.1.1",
|
||||
"typescript": "4.2.4"
|
||||
}
|
||||
|
|
53
pg.sql
53
pg.sql
|
@ -188,4 +188,57 @@ CREATE INDEX IF NOT EXISTS voting_electionid ON voting ((metadata->>'electionid'
|
|||
CREATE INDEX IF NOT EXISTS voting_results ON voting ((metadata->>'electionid'), (metadata->>'nominationid'));
|
||||
CREATE INDEX IF NOT EXISTS voting_gin ON voting USING gin (metadata jsonb_path_ops);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS repositories (
|
||||
entitytype text,
|
||||
entityid text,
|
||||
metadata jsonb,
|
||||
|
||||
repositoryid bigint,
|
||||
organizationid bigint,
|
||||
cached timestamptz,
|
||||
name text,
|
||||
organizationlogin text,
|
||||
fullname text,
|
||||
private boolean,
|
||||
visibility text,
|
||||
fork boolean,
|
||||
archived boolean,
|
||||
disabled boolean,
|
||||
pushedat timestamptz,
|
||||
createdat timestamptz,
|
||||
updatedat timestamptz,
|
||||
description text,
|
||||
homepage text,
|
||||
language text,
|
||||
forkscount integer,
|
||||
stargazerscount integer,
|
||||
watcherscount integer,
|
||||
size bigint,
|
||||
defaultbranch text,
|
||||
openissuescount integer,
|
||||
topics text[],
|
||||
hasissues boolean,
|
||||
hasprojects boolean,
|
||||
haswiki boolean,
|
||||
haspages boolean,
|
||||
hasdownloads boolean,
|
||||
subscriberscount integer,
|
||||
networkcount integer,
|
||||
license text,
|
||||
parentid bigint,
|
||||
parentname text,
|
||||
parentorganizationname text,
|
||||
parentorganizationid bigint,
|
||||
|
||||
PRIMARY KEY(entitytype, entityid)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS repositories_byid ON repositories (repositoryid);
|
||||
CREATE INDEX IF NOT EXISTS repositories_by_org ON repositories (organizationid);
|
||||
CREATE INDEX IF NOT EXISTS repositories_byidpriv ON repositories (repositoryid, private);
|
||||
CREATE INDEX IF NOT EXISTS repositories_byidvis ON repositories (repositoryid, visibility);
|
||||
CREATE INDEX IF NOT EXISTS repositories_by_created ON repositories (createdat);
|
||||
CREATE INDEX IF NOT EXISTS repositories_by_updated ON repositories (updatedat);
|
||||
CREATE INDEX IF NOT EXISTS repositories_by_pushed ON repositories (pushedat);
|
||||
|
||||
COMMIT;
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Response } from 'express';
|
|||
import crypto from 'crypto';
|
||||
import githubUsernameRegex from 'github-username-regex';
|
||||
import { AxiosError } from 'axios';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
import { GitHubRepositoryPermission } from './entities/repositoryMetadata/repositoryMetadata';
|
||||
|
||||
|
|
|
@ -296,3 +296,4 @@ block content
|
|||
p.
|
||||
This view is cached and eventually consistent within a few hours.
|
||||
The presence of people in this list does not imply that they are an employee.
|
||||
|
Загрузка…
Ссылка в новой задаче