Kaynağa Gözat

Adds bundle & organization info

main
Eric Amodio 1 yıl önce
ebeveyn
işleme
7d3d0ff74f
3 değiştirilmiş dosya ile 135 ekleme ve 55 silme
  1. +83
    -45
      src/plus/subscription/subscriptionService.ts
  2. +13
    -1
      src/subscription.ts
  3. +39
    -9
      src/system/object.ts

+ 83
- 45
src/plus/subscription/subscriptionService.ts Dosyayı Görüntüle

@ -329,12 +329,16 @@ export class SubscriptionService implements Disposable {
plan: {
actual: getSubscriptionPlan(
SubscriptionPlanId.Free,
false,
undefined,
this._subscription.plan?.actual?.startedOn != null
? new Date(this._subscription.plan.actual.startedOn)
: undefined,
),
effective: getSubscriptionPlan(
SubscriptionPlanId.Free,
false,
undefined,
this._subscription.plan?.effective?.startedOn != null
? new Date(this._subscription.plan.actual.startedOn)
: undefined,
@ -485,7 +489,7 @@ export class SubscriptionService implements Disposable {
...this._subscription,
plan: {
...this._subscription.plan,
effective: getSubscriptionPlan(SubscriptionPlanId.Pro, startedOn, expiresOn),
effective: getSubscriptionPlan(SubscriptionPlanId.Pro, false, undefined, startedOn, expiresOn),
},
previewTrial: previewTrial,
});
@ -614,6 +618,8 @@ export class SubscriptionService implements Disposable {
name: data.user.name,
email: data.user.email,
verified: data.user.status === 'activated',
createdOn: data.user.createdDate,
organizationIds: data.orgIds ?? [],
};
const effectiveLicenses = Object.entries(data.licenses.effectiveLicenses) as [GKLicenseType, GKLicense][];
@ -634,6 +640,8 @@ export class SubscriptionService implements Disposable {
const [licenseType, license] = paidLicenses[0];
actual = getSubscriptionPlan(
convertLicenseTypeToPlanId(licenseType),
isBundleLicenseType(licenseType),
license.organizationId,
new Date(license.latestStartDate),
new Date(license.latestEndDate),
);
@ -642,6 +650,8 @@ export class SubscriptionService implements Disposable {
if (actual == null) {
actual = getSubscriptionPlan(
SubscriptionPlanId.FreePlus,
false,
undefined,
data.user.firstGitLensCheckIn != null ? new Date(data.user.firstGitLensCheckIn) : undefined,
);
}
@ -661,6 +671,8 @@ export class SubscriptionService implements Disposable {
const [licenseType, license] = effectiveLicenses[0];
effective = getSubscriptionPlan(
convertLicenseTypeToPlanId(licenseType),
isBundleLicenseType(licenseType),
license.organizationId,
new Date(license.latestStartDate),
new Date(license.latestEndDate),
);
@ -823,8 +835,8 @@ export class SubscriptionService implements Disposable {
if (subscription == null) {
subscription = {
plan: {
actual: getSubscriptionPlan(SubscriptionPlanId.Free),
effective: getSubscriptionPlan(SubscriptionPlanId.Free),
actual: getSubscriptionPlan(SubscriptionPlanId.Free, false, undefined),
effective: getSubscriptionPlan(SubscriptionPlanId.Free, false, undefined),
},
account: undefined,
state: SubscriptionState.Free,
@ -839,6 +851,8 @@ export class SubscriptionService implements Disposable {
...subscription.plan,
effective: getSubscriptionPlan(
SubscriptionPlanId.Pro,
false,
undefined,
new Date(subscription.previewTrial.startedOn),
new Date(subscription.previewTrial.expiresOn),
),
@ -868,45 +882,12 @@ export class SubscriptionService implements Disposable {
if (matches) return;
queueMicrotask(() => {
this.container.telemetry.setGlobalAttributes({
'account.id': subscription!.account?.id,
'account.verified': subscription!.account?.verified,
'subscription.actual.id': subscription!.plan.actual.id,
'subscription.actual.startedOn': subscription!.plan.actual.startedOn,
'subscription.actual.expiresOn': subscription!.plan.actual.expiresOn,
'subscription.effective.id': subscription!.plan.effective.id,
'subscription.effective.startedOn': subscription!.plan.effective.startedOn,
'subscription.effective.expiresOn': subscription!.plan.effective.expiresOn,
'subscription.state': subscription!.state,
});
let data = flattenSubscription(subscription);
this.container.telemetry.setGlobalAttributes(data);
const data = {
'account.id': subscription!.account?.id,
'account.verified': subscription!.account?.verified,
...flatten(subscription!.plan, { prefix: 'subscription', skipNulls: true, stringify: true }),
...flatten(subscription!.previewTrial, {
prefix: 'subscription.previewTrial',
skipNulls: true,
stringify: true,
}),
'subscription.state': subscription!.state,
...(!matches && previous != null
? {
'previous.account.id': previous.account?.id,
'previous.account.verified': previous.account?.verified,
...flatten(previous.plan, {
prefix: 'previous.subscription',
skipNulls: true,
stringify: true,
}),
...flatten(previous.previewTrial, {
prefix: 'previous.subscription.previewTrial',
skipNulls: true,
stringify: true,
}),
'previous.subscription.state': previous.state,
}
: {}),
data = {
...data,
...(!matches ? flattenSubscription(previous, 'previous') : {}),
};
this.container.telemetry.sendEvent(previous == null ? 'subscription' : 'subscription/changed', data);
@ -1063,14 +1044,49 @@ export class SubscriptionService implements Disposable {
}
}
function flattenSubscription(subscription: Optional<Subscription, 'state'> | undefined, prefix?: string) {
if (subscription == null) return {};
return {
...flatten(subscription.account, {
arrays: 'join',
prefix: `${prefix ? `${prefix}.` : ''}account`,
skipPaths: ['name', 'email'],
skipNulls: true,
stringify: true,
}),
...flatten(subscription.plan, {
prefix: `${prefix ? `${prefix}.` : ''}subscription`,
skipPaths: ['actual.name', 'effective.name'],
skipNulls: true,
stringify: true,
}),
...flatten(subscription.previewTrial, {
prefix: `${prefix ? `${prefix}.` : ''}subscription.previewTrial`,
skipPaths: ['actual.name', 'effective.name'],
skipNulls: true,
stringify: true,
}),
'subscription.state': subscription.state,
};
}
function assertSubscriptionState(subscription: Optional<Subscription, 'state'>): asserts subscription is Subscription {}
interface GKLicenseInfo {
user: GKUser;
licenses: {
paidLicenses: Record<GKLicenseType, GKLicense>;
effectiveLicenses: Record<GKLicenseType, GKLicense>;
readonly user: GKUser;
readonly licenses: {
readonly paidLicenses: Record<GKLicenseType, GKLicense>;
readonly effectiveLicenses: Record<GKLicenseType, GKLicense>;
};
readonly orgIds?: string[];
}
interface GKLicense {
readonly latestStatus: 'active' | 'canceled' | 'cancelled' | 'expired' | 'in_trial' | 'non_renewing' | 'trial';
readonly latestStartDate: string;
readonly latestEndDate: string;
readonly organizationId: string | undefined;
}
type GKLicenseType =
@ -1085,6 +1101,15 @@ type GKLicenseType =
| 'bundle-self-hosted-enterprise'
| 'bundle-standalone-enterprise';
interface GKUser {
readonly id: string;
readonly name: string;
readonly email: string;
readonly status: 'activated' | 'pending';
readonly createdDate: string;
readonly firstGitLensCheckIn?: string;
}
function convertLicenseTypeToPlanId(licenseType: GKLicenseType): SubscriptionPlanId {
switch (licenseType) {
case 'gitlens-pro':
@ -1105,6 +1130,19 @@ function convertLicenseTypeToPlanId(licenseType: GKLicenseType): SubscriptionPla
}
}
function isBundleLicenseType(licenseType: GKLicenseType): boolean {
switch (licenseType) {
case 'bundle-pro':
case 'bundle-teams':
case 'bundle-hosted-enterprise':
case 'bundle-self-hosted-enterprise':
case 'bundle-standalone-enterprise':
return true;
default:
return false;
}
}
function licenseStatusPriority(status: GKLicense['latestStatus']): number {
switch (status) {
case 'active':

+ 13
- 1
src/subscription.ts Dosyayı Görüntüle

@ -27,8 +27,10 @@ export interface Subscription {
export interface SubscriptionPlan {
readonly id: SubscriptionPlanId;
readonly name: string;
readonly bundle: boolean;
readonly startedOn: string;
readonly expiresOn?: string | undefined;
readonly organizationId: string | undefined;
}
export interface SubscriptionAccount {
@ -36,6 +38,8 @@ export interface SubscriptionAccount {
readonly name: string;
readonly email: string | undefined;
readonly verified: boolean;
readonly createdOn: string;
readonly organizationIds: string[];
}
export interface SubscriptionPreviewTrial {
@ -102,10 +106,18 @@ export function computeSubscriptionState(subscription: Optional
}
}
export function getSubscriptionPlan(id: SubscriptionPlanId, startedOn?: Date, expiresOn?: Date): SubscriptionPlan {
export function getSubscriptionPlan(
id: SubscriptionPlanId,
bundle: boolean,
organizationId: string | undefined,
startedOn?: Date,
expiresOn?: Date,
): SubscriptionPlan {
return {
id: id,
name: getSubscriptionPlanName(id),
bundle: bundle,
organizationId: organizationId,
startedOn: (startedOn ?? new Date()).toISOString(),
expiresOn: expiresOn != null ? expiresOn.toISOString() : undefined,
};

+ 39
- 9
src/system/object.ts Dosyayı Görüntüle

@ -8,31 +8,54 @@ export function areEqual(a: any, b: any): boolean {
return JSON.stringify(a) === JSON.stringify(b);
}
export function flatten(o: any, options: { prefix?: string; skipNulls: true; stringify: true }): Record<string, string>;
export function flatten(
o: any,
options: { prefix?: string; skipNulls: true; stringify?: false },
options: { arrays?: 'join' | 'spread'; prefix?: string; skipPaths?: string[]; skipNulls: true; stringify: true },
): Record<string, string>;
export function flatten(
o: any,
options: { arrays?: 'join' | 'spread'; prefix?: string; skipPaths?: string[]; skipNulls: true; stringify?: false },
): Record<string, NonNullable<any>>;
export function flatten(
o: any,
options: { prefix?: string; skipNulls?: false; stringify: true },
options: { arrays?: 'join' | 'spread'; prefix?: string; skipPaths?: string[]; skipNulls?: false; stringify: true },
): Record<string, string | null>;
export function flatten(
o: any,
options: { prefix?: string; skipNulls?: false; stringify: 'all' },
options: { arrays?: 'join' | 'spread'; prefix?: string; skipPaths?: string[]; skipNulls?: false; stringify: 'all' },
): Record<string, string>;
export function flatten(
o: any,
options?: { prefix?: string; skipNulls?: boolean; stringify?: boolean },
options?: {
arrays?: 'join' | 'spread';
prefix?: string;
skipPaths?: string[];
skipNulls?: boolean;
stringify?: boolean;
},
): Record<string, any>;
export function flatten(
o: any,
options?: { prefix?: string; skipNulls?: boolean; stringify?: boolean | 'all' },
options?: {
arrays?: 'join' | 'spread';
prefix?: string;
skipPaths?: string[];
skipNulls?: boolean;
stringify?: boolean | 'all';
},
): Record<string, any> {
const skipPaths =
options?.skipPaths != null && options.skipPaths.length
? options?.prefix
? options.skipPaths.map(p => `${options.prefix}.${p}`)
: options.skipPaths
: undefined;
const skipNulls = options?.skipNulls ?? false;
const stringify = options?.stringify ?? false;
function flattenCore(flattened: Record<string, any>, key: string, value: any) {
if (skipPaths?.includes(key)) return;
if (Object(value) !== value) {
if (value == null) {
if (skipNulls) return;
@ -40,15 +63,22 @@ export function flatten(
flattened[key] = stringify ? (stringify == 'all' ? JSON.stringify(value) : value ?? null) : value;
} else if (typeof value === 'string') {
flattened[key] = value;
} else if (stringify) {
flattened[key] =
typeof value === 'number' || typeof value === 'boolean' ? value : JSON.stringify(value);
} else {
flattened[key] = stringify ? JSON.stringify(value) : value;
flattened[key] = value;
}
} else if (Array.isArray(value)) {
const len = value.length;
if (len === 0) return;
for (let i = 0; i < len; i++) {
flattenCore(flattened, `${key}[${i}]`, value[i]);
if (options?.arrays === 'join') {
flattened[key] = value.join(',');
} else {
for (let i = 0; i < len; i++) {
flattenCore(flattened, `${key}[${i}]`, value[i]);
}
}
} else {
const entries = Object.entries(value);

Yükleniyor…
İptal
Kaydet