refactor: native feature management (#2350)

This commit is contained in:
Mo
2023-07-12 12:56:08 -05:00
committed by GitHub
parent 49f7581cd8
commit 078ef3772c
223 changed files with 3996 additions and 3438 deletions

View File

@@ -1,17 +1,117 @@
import { StorageKey } from './../Storage/StorageKeys'
import { ApplicationStage } from './../Application/ApplicationStage'
import { StorageServiceInterface } from './../Storage/StorageServiceInterface'
import { InternalEventInterface } from './../Internal/InternalEventInterface'
import { SessionsClientInterface } from './../Session/SessionsClientInterface'
import { SubscriptionName } from '@standardnotes/common'
import { convertTimestampToMilliseconds } from '@standardnotes/utils'
import { ApplicationEvent } from './../Event/ApplicationEvent'
import { InternalEventHandlerInterface } from './../Internal/InternalEventHandlerInterface'
import { Invitation } from '@standardnotes/models'
import { SubscriptionApiServiceInterface } from '@standardnotes/api'
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
import { AbstractService } from '../Service/AbstractService'
import { SubscriptionClientInterface } from './SubscriptionClientInterface'
import { SubscriptionManagerInterface } from './SubscriptionManagerInterface'
import { AppleIAPReceipt } from './AppleIAPReceipt'
import { getErrorFromErrorResponse, isErrorResponse } from '@standardnotes/responses'
import { AvailableSubscriptions, getErrorFromErrorResponse, isErrorResponse } from '@standardnotes/responses'
import { Subscription } from '@standardnotes/security'
import { SubscriptionManagerEvent } from './SubscriptionManagerEvent'
export class SubscriptionManager
extends AbstractService<SubscriptionManagerEvent>
implements SubscriptionManagerInterface, InternalEventHandlerInterface
{
private onlineSubscription?: Subscription
private availableSubscriptions?: AvailableSubscriptions | undefined
export class SubscriptionManager extends AbstractService implements SubscriptionClientInterface {
constructor(
private subscriptionApiService: SubscriptionApiServiceInterface,
private sessions: SessionsClientInterface,
private storage: StorageServiceInterface,
protected override internalEventBus: InternalEventBusInterface,
) {
super(internalEventBus)
internalEventBus.addEventHandler(this, ApplicationEvent.UserRolesChanged)
internalEventBus.addEventHandler(this, ApplicationEvent.Launched)
internalEventBus.addEventHandler(this, ApplicationEvent.SignedIn)
}
async handleEvent(event: InternalEventInterface): Promise<void> {
switch (event.type) {
case ApplicationEvent.Launched: {
void this.fetchOnlineSubscription()
void this.fetchAvailableSubscriptions()
break
}
case ApplicationEvent.UserRolesChanged:
case ApplicationEvent.SignedIn:
void this.fetchOnlineSubscription()
break
}
}
public override async handleApplicationStage(stage: ApplicationStage): Promise<void> {
if (stage === ApplicationStage.StorageDecrypted_09) {
this.onlineSubscription = this.storage.getValue(StorageKey.Subscription)
void this.notifyEvent(SubscriptionManagerEvent.DidFetchSubscription)
}
}
hasOnlineSubscription(): boolean {
return this.onlineSubscription != undefined
}
getOnlineSubscription(): Subscription | undefined {
return this.onlineSubscription
}
getAvailableSubscriptions(): AvailableSubscriptions | undefined {
return this.availableSubscriptions
}
get userSubscriptionName(): string {
if (!this.onlineSubscription) {
throw new Error('Attempting to get subscription name without a subscription.')
}
if (
this.availableSubscriptions &&
this.availableSubscriptions[this.onlineSubscription.planName as SubscriptionName]
) {
return this.availableSubscriptions[this.onlineSubscription.planName as SubscriptionName].name
}
return ''
}
get userSubscriptionExpirationDate(): Date | undefined {
if (!this.onlineSubscription) {
return undefined
}
return new Date(convertTimestampToMilliseconds(this.onlineSubscription.endsAt))
}
get isUserSubscriptionExpired(): boolean {
if (!this.onlineSubscription) {
throw new Error('Attempting to check subscription expiration without a subscription.')
}
if (!this.userSubscriptionExpirationDate) {
return false
}
return this.userSubscriptionExpirationDate.getTime() < new Date().getTime()
}
get isUserSubscriptionCanceled(): boolean {
if (!this.onlineSubscription) {
throw new Error('Attempting to check subscription expiration without a subscription.')
}
return this.onlineSubscription.cancelled
}
async acceptInvitation(inviteUuid: string): Promise<{ success: true } | { success: false; message: string }> {
@@ -70,6 +170,48 @@ export class SubscriptionManager extends AbstractService implements Subscription
}
}
private async fetchOnlineSubscription(): Promise<void> {
if (!this.sessions.isSignedIn()) {
return
}
try {
const result = await this.subscriptionApiService.getUserSubscription({ userUuid: this.sessions.userUuid })
if (isErrorResponse(result)) {
return
}
const subscription = result.data.subscription
this.handleReceivedOnlineSubscriptionFromServer(subscription)
} catch (error) {
void error
}
}
private handleReceivedOnlineSubscriptionFromServer(subscription: Subscription | undefined): void {
this.onlineSubscription = subscription
this.storage.setValue(StorageKey.Subscription, subscription)
void this.notifyEvent(SubscriptionManagerEvent.DidFetchSubscription)
}
private async fetchAvailableSubscriptions(): Promise<void> {
try {
const response = await this.subscriptionApiService.getAvailableSubscriptions()
if (isErrorResponse(response)) {
return
}
this.availableSubscriptions = response.data
} catch (error) {
void error
}
}
async confirmAppleIAP(
params: AppleIAPReceipt,
subscriptionToken: string,