|
|
@ -16,20 +16,14 @@ import { ContextKeys, CoreGitConfiguration, GlyphChars, Schemes } from '../const |
|
|
|
import type { Container } from '../container'; |
|
|
|
import { setContext } from '../context'; |
|
|
|
import { AccessDeniedError, ProviderNotFoundError } from '../errors'; |
|
|
|
import type { FeatureAccess, Features } from '../features'; |
|
|
|
import { PlusFeatures } from '../features'; |
|
|
|
import type { FeatureAccess, Features, PlusFeatures } from '../features'; |
|
|
|
import type { RemoteProvider } from '../git/remotes/remoteProvider'; |
|
|
|
import { Logger } from '../logger'; |
|
|
|
import type { SubscriptionChangeEvent } from '../plus/subscription/subscriptionService'; |
|
|
|
import type { RepoComparisonKey } from '../repositories'; |
|
|
|
import { asRepoComparisonKey, Repositories } from '../repositories'; |
|
|
|
import type { FreeSubscriptionPlans, RequiredSubscriptionPlans, Subscription } from '../subscription'; |
|
|
|
import { |
|
|
|
getSubscriptionPlan, |
|
|
|
getSubscriptionPlanPriority, |
|
|
|
isSubscriptionPaidPlan, |
|
|
|
SubscriptionPlanId, |
|
|
|
} from '../subscription'; |
|
|
|
import type { RequiredSubscriptionPlans, Subscription } from '../subscription'; |
|
|
|
import { getSubscriptionPlanPriority, isSubscriptionPaidPlan, SubscriptionPlanId } from '../subscription'; |
|
|
|
import { groupByFilterMap, groupByMap } from '../system/array'; |
|
|
|
import { gate } from '../system/decorators/gate'; |
|
|
|
import { debug, getLogScope, log } from '../system/decorators/log'; |
|
|
@ -111,8 +105,6 @@ export const enum RepositoriesVisibility { |
|
|
|
} |
|
|
|
|
|
|
|
export class GitProviderService implements Disposable { |
|
|
|
static readonly previewFeatures: Map<PlusFeatures | undefined, boolean> | undefined; // = new Map();
|
|
|
|
|
|
|
|
private readonly _onDidChangeProviders = new EventEmitter<GitProvidersChangeEvent>(); |
|
|
|
get onDidChangeProviders(): Event<GitProvidersChangeEvent> { |
|
|
|
return this._onDidChangeProviders.event; |
|
|
@ -526,40 +518,10 @@ export class GitProviderService implements Disposable { |
|
|
|
cacheKey = path; |
|
|
|
} |
|
|
|
|
|
|
|
let accessPromise = this._accessCache.get(cacheKey); |
|
|
|
if (accessPromise == null) { |
|
|
|
accessPromise = this.accessCore(feature, repoPath); |
|
|
|
this._accessCache.set(cacheKey, accessPromise); |
|
|
|
} |
|
|
|
|
|
|
|
const access = await accessPromise; |
|
|
|
if (feature === PlusFeatures.Graph) { |
|
|
|
if (access.visibility == null && repoPath != null) { |
|
|
|
access.visibility = await this.visibility(repoPath); |
|
|
|
} |
|
|
|
|
|
|
|
if ( |
|
|
|
(access.visibility !== RepositoryVisibility.Private && |
|
|
|
access.subscription.current.plan.effective.id === SubscriptionPlanId.Free) || |
|
|
|
(access.visibility === RepositoryVisibility.Private && access.subscription.current.previewTrial == null) |
|
|
|
) { |
|
|
|
return { |
|
|
|
allowed: !( |
|
|
|
access.visibility === RepositoryVisibility.Private && |
|
|
|
access.subscription.current.previewTrial == null |
|
|
|
), |
|
|
|
subscription: { |
|
|
|
current: { |
|
|
|
...access.subscription.current, |
|
|
|
plan: { |
|
|
|
...access.subscription.current.plan, |
|
|
|
effective: getSubscriptionPlan(SubscriptionPlanId.Pro, undefined), |
|
|
|
}, |
|
|
|
}, |
|
|
|
}, |
|
|
|
visibility: access.visibility, |
|
|
|
}; |
|
|
|
} |
|
|
|
let access = this._accessCache.get(cacheKey); |
|
|
|
if (access == null) { |
|
|
|
access = this.accessCore(feature, repoPath); |
|
|
|
this._accessCache.set(cacheKey, access); |
|
|
|
} |
|
|
|
|
|
|
|
return access; |
|
|
@ -573,14 +535,13 @@ export class GitProviderService implements Disposable { |
|
|
|
} |
|
|
|
|
|
|
|
const plan = subscription.plan.effective.id; |
|
|
|
if (isSubscriptionPaidPlan(plan) || GitProviderService.previewFeatures?.get(feature)) { |
|
|
|
if (isSubscriptionPaidPlan(plan)) { |
|
|
|
return { allowed: true, subscription: { current: subscription } }; |
|
|
|
} |
|
|
|
|
|
|
|
function getRepoAccess( |
|
|
|
this: GitProviderService, |
|
|
|
repoPath: string | Uri, |
|
|
|
plan: FreeSubscriptionPlans, |
|
|
|
force: boolean = false, |
|
|
|
): Promise<FeatureAccess> { |
|
|
|
const { path: cacheKey } = this.getProvider(repoPath); |
|
|
@ -588,26 +549,17 @@ export class GitProviderService implements Disposable { |
|
|
|
let access = force ? undefined : this._accessCache.get(cacheKey); |
|
|
|
if (access == null) { |
|
|
|
access = this.visibility(repoPath).then(visibility => { |
|
|
|
if (visibility !== RepositoryVisibility.Private) { |
|
|
|
switch (plan) { |
|
|
|
case SubscriptionPlanId.Free: |
|
|
|
return { |
|
|
|
allowed: false, |
|
|
|
subscription: { current: subscription, required: SubscriptionPlanId.FreePlus }, |
|
|
|
visibility: visibility, |
|
|
|
}; |
|
|
|
case SubscriptionPlanId.FreePlus: |
|
|
|
return { |
|
|
|
allowed: true, |
|
|
|
subscription: { current: subscription }, |
|
|
|
visibility: visibility, |
|
|
|
}; |
|
|
|
} |
|
|
|
if (visibility === RepositoryVisibility.Private) { |
|
|
|
return { |
|
|
|
allowed: false, |
|
|
|
subscription: { current: subscription, required: SubscriptionPlanId.Pro }, |
|
|
|
visibility: visibility, |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
return { |
|
|
|
allowed: false, |
|
|
|
subscription: { current: subscription, required: SubscriptionPlanId.Pro }, |
|
|
|
allowed: true, |
|
|
|
subscription: { current: subscription }, |
|
|
|
visibility: visibility, |
|
|
|
}; |
|
|
|
}); |
|
|
@ -625,7 +577,7 @@ export class GitProviderService implements Disposable { |
|
|
|
} |
|
|
|
|
|
|
|
if (repositories.length === 1) { |
|
|
|
return getRepoAccess.call(this, repositories[0].path, plan); |
|
|
|
return getRepoAccess.call(this, repositories[0].path); |
|
|
|
} |
|
|
|
|
|
|
|
let allowed = true; |
|
|
@ -634,7 +586,7 @@ export class GitProviderService implements Disposable { |
|
|
|
|
|
|
|
const maxPriority = getSubscriptionPlanPriority(SubscriptionPlanId.Pro); |
|
|
|
|
|
|
|
for await (const result of fastestSettled(repositories.map(r => getRepoAccess.call(this, r.path, plan)))) { |
|
|
|
for await (const result of fastestSettled(repositories.map(r => getRepoAccess.call(this, r.path)))) { |
|
|
|
if (result.status !== 'fulfilled' || result.value.allowed) continue; |
|
|
|
|
|
|
|
allowed = false; |
|
|
@ -653,7 +605,7 @@ export class GitProviderService implements Disposable { |
|
|
|
} |
|
|
|
|
|
|
|
// Pass force = true to bypass the cache and avoid a promise loop (where we used the cached promise we just created to try to resolve itself 🤦)
|
|
|
|
return getRepoAccess.call(this, repoPath, plan, true); |
|
|
|
return getRepoAccess.call(this, repoPath, true); |
|
|
|
} |
|
|
|
|
|
|
|
async ensureAccess(feature: PlusFeatures, repoPath?: string): Promise<void> { |
|
|
|