2021-10-07 06:09:38 +03:00
|
|
|
//
|
|
|
|
// Copyright (c) Microsoft.
|
|
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
//
|
|
|
|
|
|
|
|
import { Repository } from './repository';
|
|
|
|
import { wrapError } from '../utils';
|
|
|
|
import { AppPurpose } from '../github';
|
|
|
|
import { CacheDefault, getMaxAgeSeconds } from '.';
|
2022-10-07 09:59:30 +03:00
|
|
|
import {
|
|
|
|
IOperationsInstance,
|
|
|
|
IPurposefulGetAuthorizationHeader,
|
|
|
|
GitHubIssueState,
|
|
|
|
throwIfNotGitHubCapable,
|
|
|
|
ICacheOptions,
|
|
|
|
IGetAuthorizationHeader,
|
|
|
|
ICacheOptionsWithPurpose,
|
|
|
|
} from '../interfaces';
|
2021-10-07 06:09:38 +03:00
|
|
|
import { ErrorHelper } from '../transitional';
|
|
|
|
import { RepositoryProjectColumn } from './repositoryProjectColumn';
|
|
|
|
import * as common from './common';
|
|
|
|
|
|
|
|
export class RepositoryProject {
|
|
|
|
private _operations: IOperationsInstance;
|
|
|
|
private _getAuthorizationHeader: IPurposefulGetAuthorizationHeader;
|
|
|
|
private _getSpecificAuthorizationHeader: IPurposefulGetAuthorizationHeader;
|
|
|
|
|
|
|
|
private _id: number;
|
|
|
|
private _repository: Repository;
|
|
|
|
|
|
|
|
private _entity: any;
|
|
|
|
|
|
|
|
private _purpose: AppPurpose;
|
|
|
|
|
2022-10-07 09:59:30 +03:00
|
|
|
constructor(
|
|
|
|
repository: Repository,
|
|
|
|
projectId: number,
|
|
|
|
operations: IOperationsInstance,
|
|
|
|
getAuthorizationHeader: IPurposefulGetAuthorizationHeader,
|
|
|
|
getSpecificAuthorizationHeader: IPurposefulGetAuthorizationHeader,
|
|
|
|
entity?: any
|
|
|
|
) {
|
2021-10-07 06:09:38 +03:00
|
|
|
this._getAuthorizationHeader = getAuthorizationHeader;
|
|
|
|
this._getSpecificAuthorizationHeader = getSpecificAuthorizationHeader;
|
|
|
|
this._repository = repository;
|
|
|
|
this._id = projectId;
|
|
|
|
this._operations = operations;
|
|
|
|
if (entity) {
|
|
|
|
this._entity = entity;
|
|
|
|
}
|
|
|
|
this.overrideDefaultAppPurpose(AppPurpose.Onboarding);
|
|
|
|
}
|
|
|
|
|
|
|
|
overrideDefaultAppPurpose(purpose: AppPurpose) {
|
|
|
|
this._purpose = purpose;
|
|
|
|
}
|
|
|
|
|
2022-10-07 09:59:30 +03:00
|
|
|
get id(): number {
|
|
|
|
return this._entity?.id as number;
|
|
|
|
}
|
|
|
|
get name(): string {
|
|
|
|
return this._entity?.name as string;
|
|
|
|
}
|
|
|
|
get body(): string {
|
|
|
|
return this._entity?.body as string;
|
|
|
|
}
|
|
|
|
get private(): boolean {
|
|
|
|
return this._entity?.private as boolean;
|
|
|
|
}
|
|
|
|
get state(): GitHubIssueState {
|
|
|
|
return this._entity?.state as GitHubIssueState;
|
|
|
|
}
|
|
|
|
get htmlUrl(): string {
|
|
|
|
return this._entity?.html_url as string;
|
|
|
|
}
|
2021-10-07 06:09:38 +03:00
|
|
|
|
2022-10-07 09:59:30 +03:00
|
|
|
getEntity(): any {
|
|
|
|
return this._entity;
|
|
|
|
}
|
2021-10-07 06:09:38 +03:00
|
|
|
|
|
|
|
get repository(): Repository {
|
|
|
|
return this._repository;
|
|
|
|
}
|
|
|
|
|
|
|
|
async update(patch: any): Promise<any> {
|
|
|
|
const operations = throwIfNotGitHubCapable(this._operations);
|
|
|
|
const parameters = Object.assign(patch, {
|
|
|
|
project_id: this.id,
|
|
|
|
});
|
2022-10-07 09:59:30 +03:00
|
|
|
const details = await operations.github.post(
|
|
|
|
this.authorizeSpecificPurpose(this._purpose),
|
|
|
|
'projects.update',
|
|
|
|
parameters
|
|
|
|
);
|
2021-10-07 06:09:38 +03:00
|
|
|
return details;
|
|
|
|
}
|
|
|
|
|
2022-04-01 20:13:27 +03:00
|
|
|
async delete(): Promise<boolean> {
|
|
|
|
const operations = throwIfNotGitHubCapable(this._operations);
|
|
|
|
const parameters = {
|
|
|
|
project_id: this.id,
|
|
|
|
};
|
|
|
|
augmentInertiaPreview(parameters);
|
2022-10-07 09:59:30 +03:00
|
|
|
await operations.github.post(
|
|
|
|
this.authorizeSpecificPurpose(this._purpose),
|
|
|
|
'projects.delete',
|
|
|
|
parameters
|
|
|
|
);
|
2022-04-01 20:13:27 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-10-07 06:09:38 +03:00
|
|
|
async createColumn(name: string): Promise<RepositoryProjectColumn> {
|
|
|
|
const operations = throwIfNotGitHubCapable(this._operations);
|
|
|
|
const parameters = {
|
|
|
|
project_id: String(this.id),
|
|
|
|
name,
|
|
|
|
};
|
|
|
|
augmentInertiaPreview(parameters);
|
2022-10-07 09:59:30 +03:00
|
|
|
const details = await operations.github.post(
|
|
|
|
this.authorizeSpecificPurpose(AppPurpose.Onboarding),
|
|
|
|
'projects.createColumn',
|
|
|
|
parameters
|
|
|
|
);
|
|
|
|
const column = new RepositoryProjectColumn(
|
|
|
|
this,
|
|
|
|
details.number,
|
|
|
|
operations,
|
|
|
|
this._getAuthorizationHeader,
|
|
|
|
details
|
|
|
|
);
|
2021-10-07 06:09:38 +03:00
|
|
|
return column;
|
|
|
|
}
|
|
|
|
|
2022-10-07 09:59:30 +03:00
|
|
|
async getColumns(
|
|
|
|
options?: ICacheOptionsWithPurpose
|
|
|
|
): Promise<RepositoryProjectColumn[]> {
|
2021-10-07 06:09:38 +03:00
|
|
|
options = options || {};
|
|
|
|
const operations = throwIfNotGitHubCapable(this._operations);
|
|
|
|
const parameters = Object.assign({
|
|
|
|
project_id: this._id,
|
|
|
|
});
|
|
|
|
augmentInertiaPreview(parameters);
|
|
|
|
const purpose = options?.purpose || this._purpose;
|
|
|
|
const cacheOptions: ICacheOptions = {
|
2022-10-07 09:59:30 +03:00
|
|
|
maxAgeSeconds: getMaxAgeSeconds(
|
|
|
|
operations,
|
|
|
|
CacheDefault.orgRepoDetailsStaleSeconds,
|
|
|
|
options
|
|
|
|
),
|
2021-10-07 06:09:38 +03:00
|
|
|
};
|
|
|
|
if (options.backgroundRefresh !== undefined) {
|
|
|
|
cacheOptions.backgroundRefresh = options.backgroundRefresh;
|
|
|
|
}
|
|
|
|
// NOTE: this will not retrieve more than a few columns since we are not paging (by design); GH default is 30 anyway.
|
2022-10-07 09:59:30 +03:00
|
|
|
const raw = await operations.github.call(
|
|
|
|
this.authorizeSpecificPurpose(purpose),
|
|
|
|
'projects.listColumns',
|
|
|
|
parameters
|
|
|
|
);
|
|
|
|
const columns = common.createInstances<RepositoryProjectColumn>(
|
|
|
|
this,
|
|
|
|
projectColumnFromEntity,
|
|
|
|
raw
|
|
|
|
);
|
2021-10-07 06:09:38 +03:00
|
|
|
return columns;
|
|
|
|
}
|
|
|
|
|
|
|
|
// async getColumn(columnId: number): Promise<any> {
|
|
|
|
// }
|
|
|
|
|
2022-10-07 09:59:30 +03:00
|
|
|
async getDetails(
|
|
|
|
options?: ICacheOptionsWithPurpose,
|
|
|
|
okToUseLocalEntity: boolean = true
|
|
|
|
): Promise<any> {
|
2021-10-07 06:09:38 +03:00
|
|
|
if (okToUseLocalEntity && this._entity) {
|
|
|
|
return this._entity;
|
|
|
|
}
|
|
|
|
options = options || {};
|
|
|
|
const operations = throwIfNotGitHubCapable(this._operations);
|
|
|
|
if (!this._id) {
|
|
|
|
throw new Error('project.id required');
|
|
|
|
}
|
|
|
|
const parameters = {
|
|
|
|
project_id: this._id,
|
|
|
|
};
|
|
|
|
augmentInertiaPreview(parameters);
|
|
|
|
const purpose = options?.purpose || this._purpose;
|
|
|
|
const cacheOptions: ICacheOptions = {
|
|
|
|
// NOTE: just reusing repo details stale time
|
2022-10-07 09:59:30 +03:00
|
|
|
maxAgeSeconds: getMaxAgeSeconds(
|
|
|
|
operations,
|
|
|
|
CacheDefault.orgRepoDetailsStaleSeconds,
|
|
|
|
options
|
|
|
|
),
|
2021-10-07 06:09:38 +03:00
|
|
|
};
|
|
|
|
if (options.backgroundRefresh !== undefined) {
|
|
|
|
cacheOptions.backgroundRefresh = options.backgroundRefresh;
|
|
|
|
}
|
|
|
|
try {
|
2022-10-07 09:59:30 +03:00
|
|
|
const entity = await operations.github.call(
|
|
|
|
this.authorizeSpecificPurpose(purpose),
|
|
|
|
'projects.get',
|
|
|
|
parameters,
|
|
|
|
cacheOptions
|
|
|
|
);
|
2021-10-07 06:09:38 +03:00
|
|
|
this._entity = entity;
|
|
|
|
return entity;
|
|
|
|
} catch (error) {
|
|
|
|
const notFound = error.status && error.status == /* loose */ 404;
|
2022-10-07 09:59:30 +03:00
|
|
|
error = wrapError(
|
|
|
|
error,
|
|
|
|
notFound
|
|
|
|
? 'The project could not be found.'
|
|
|
|
: `Could not get details about the project. ${error.status}`,
|
|
|
|
notFound
|
|
|
|
);
|
2021-10-07 06:09:38 +03:00
|
|
|
if (notFound) {
|
|
|
|
error.status = 404;
|
|
|
|
}
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async isDeleted(options?: ICacheOptions): Promise<boolean> {
|
|
|
|
try {
|
2022-10-07 09:59:30 +03:00
|
|
|
await this.getDetails(
|
|
|
|
options,
|
|
|
|
false /* do not use local entity instance */
|
|
|
|
);
|
2021-10-07 06:09:38 +03:00
|
|
|
} catch (maybeDeletedError) {
|
|
|
|
if (ErrorHelper.IsNotFound(maybeDeletedError)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
throw maybeDeletedError;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-10-07 09:59:30 +03:00
|
|
|
private authorizeSpecificPurpose(
|
|
|
|
purpose: AppPurpose
|
|
|
|
): IGetAuthorizationHeader | string {
|
|
|
|
const getAuthorizationHeader = this._getSpecificAuthorizationHeader.bind(
|
|
|
|
this,
|
|
|
|
purpose
|
|
|
|
) as IGetAuthorizationHeader;
|
2021-10-07 06:09:38 +03:00
|
|
|
return getAuthorizationHeader;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function projectColumnFromEntity(entity) {
|
|
|
|
// 'this' is bound for this function to be a private method
|
|
|
|
const operations = this._operations;
|
2022-10-07 09:59:30 +03:00
|
|
|
const column = new RepositoryProjectColumn(
|
|
|
|
this,
|
|
|
|
entity.id,
|
|
|
|
operations,
|
|
|
|
this._getSpecificAuthorizationHeader,
|
|
|
|
entity
|
|
|
|
);
|
2021-10-07 06:09:38 +03:00
|
|
|
return column;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function augmentInertiaPreview(parameters: any) {
|
|
|
|
(parameters as any).mediaType = {
|
2022-10-07 09:59:30 +03:00
|
|
|
previews: ['inertia'],
|
2021-10-07 06:09:38 +03:00
|
|
|
};
|
|
|
|
}
|