chore: refetch subscription when prefs menu opens (#2360)

This commit is contained in:
Mo
2023-07-17 09:04:22 -05:00
committed by GitHub
parent a56e1f5398
commit 7fb33c400c
31 changed files with 113 additions and 66 deletions

View File

@@ -39,7 +39,6 @@
"@standardnotes/domain-core": "^1.22.0",
"@standardnotes/models": "workspace:*",
"@standardnotes/responses": "workspace:*",
"@standardnotes/security": "^1.7.6",
"@standardnotes/utils": "workspace:*",
"reflect-metadata": "^0.1.13"
}

View File

@@ -65,13 +65,26 @@ export class FetchRequestHandler implements RequestHandlerInterface {
}
private async runRequest<T>(request: Request, body?: string | Uint8Array | undefined): Promise<HttpResponse<T>> {
const fetchResponse = await fetch(request, {
body,
})
try {
const fetchResponse = await fetch(request, {
body,
})
const response = await this.handleFetchResponse<T>(fetchResponse)
const response = await this.handleFetchResponse<T>(fetchResponse)
return response
return response
} catch (error) {
return {
status: HttpStatusCode.InternalServerError,
headers: new Map<string, string | null>(),
data: {
error: {
message:
'message' in (error as { message: string }) ? (error as { message: string }).message : 'Unknown error',
},
},
}
}
}
private async handleFetchResponse<T>(fetchResponse: Response): Promise<HttpResponse<T>> {

View File

@@ -1,5 +1,4 @@
import { ValetTokenOperation } from '@standardnotes/responses'
import { SharedVaultMoveType } from './SharedVaultMoveType'
import { SharedVaultMoveType, ValetTokenOperation } from '@standardnotes/responses'
export type CreateSharedVaultValetTokenParams = {
sharedVaultUuid: string

View File

@@ -18,4 +18,3 @@ export * from './User/UserRegistrationRequestParams'
export * from './User/UserUpdateRequestParams'
export * from './UserRequest/UserRequestRequestParams'
export * from './WebSocket/WebSocketConnectionTokenRequestParams'
export * from './SharedVault/SharedVaultMoveType'

View File

@@ -27,7 +27,6 @@
"dependencies": {
"@standardnotes/common": "^1.50.0",
"@standardnotes/domain-core": "^1.22.0",
"@standardnotes/security": "^1.7.6",
"reflect-metadata": "^0.1.13"
},
"devDependencies": {

View File

@@ -35,7 +35,6 @@
"dependencies": {
"@standardnotes/common": "^1.50.0",
"@standardnotes/features": "workspace:*",
"@standardnotes/security": "^1.7.6",
"reflect-metadata": "^0.1.13"
}
}

View File

@@ -1,4 +1,4 @@
import { ValetTokenOperation } from './ValetTokenOperation'
import { ValetTokenOperation } from '../Temp/ValetTokenOperation'
export type CreateValetTokenPayload = {
operation: ValetTokenOperation

View File

@@ -1 +0,0 @@
export type ValetTokenOperation = 'read' | 'write' | 'delete' | 'move'

View File

@@ -1,4 +1,4 @@
import { Role } from '@standardnotes/security'
import { Role } from '../Temp/Role'
export type DeprecatedResponseMeta = {
auth: {

View File

@@ -1,4 +1,4 @@
import { Role } from '@standardnotes/security'
import { Role } from '../Temp/Role'
export type HttpResponseMeta = {
auth: {

View File

@@ -0,0 +1,4 @@
export type Role = {
uuid: string
name: string
}

View File

@@ -0,0 +1,7 @@
export type Subscription = {
planName: string
endsAt: number
createdAt: number
updatedAt: number
cancelled: boolean
}

View File

@@ -0,0 +1,6 @@
export enum ValetTokenOperation {
Read = 'read',
Write = 'write',
Delete = 'delete',
Move = 'move',
}

View File

@@ -1,4 +1,4 @@
import { Subscription } from '@standardnotes/security'
import { Subscription } from '../Temp/Subscription'
export type GetSubscriptionResponse = {
subscription?: Subscription

View File

@@ -14,6 +14,12 @@ export * from './Auth/SignInResponse'
export * from './Auth/SignOutResponse'
export * from './Auth/User'
/** Temps are awaiting final publish state on server repo */
export * from './Temp/SharedVaultMoveType'
export * from './Temp/Subscription'
export * from './Temp/ValetTokenOperation'
export * from './Temp/Role'
export * from './Error/ClientDisplayableError'
export * from './Files/CloseUploadSessionResponse'
@@ -24,7 +30,6 @@ export * from './Files/DownloadFileChunkResponse'
export * from './Files/StartUploadSessionResponse'
export * from './Files/UploadFileChunkResponse'
export * from './Files/MoveFileResponse'
export * from './Files/ValetTokenOperation'
export * from './Http'

View File

@@ -24,7 +24,6 @@
"@standardnotes/files": "workspace:^",
"@standardnotes/models": "workspace:^",
"@standardnotes/responses": "workspace:*",
"@standardnotes/security": "^1.7.5",
"@standardnotes/sncrypto-common": "workspace:^",
"@standardnotes/utils": "workspace:*",
"reflect-metadata": "^0.1.13"

View File

@@ -1,4 +1,4 @@
import { Role } from '@standardnotes/security'
import { Role } from '@standardnotes/responses'
export type MetaReceivedData = {
userUuid: string

View File

@@ -10,7 +10,7 @@ import {
isNote,
NoteContent,
} from '@standardnotes/models'
import { ClientDisplayableError } from '@standardnotes/responses'
import { ClientDisplayableError, ValetTokenOperation } from '@standardnotes/responses'
import {
FilesApiInterface,
FileBackupMetadataFile,
@@ -520,7 +520,7 @@ export class FilesBackupService extends AbstractService implements BackupService
},
})
const token = await this.api.createUserFileValetToken(file.remoteIdentifier, 'read')
const token = await this.api.createUserFileValetToken(file.remoteIdentifier, ValetTokenOperation.Read)
if (token instanceof ClientDisplayableError) {
this.status.removeMessage(messageId)

View File

@@ -1,9 +1,10 @@
import { MutatorClientInterface } from './../Mutator/MutatorClientInterface'
import {
ClientDisplayableError,
ValetTokenOperation,
isClientDisplayableError,
isErrorResponse,
SharedVaultMoveType,
ValetTokenOperation,
} from '@standardnotes/responses'
import {
FileItem,
@@ -47,12 +48,7 @@ import { AbstractService } from '../Service/AbstractService'
import { SyncServiceInterface } from '../Sync/SyncServiceInterface'
import { DecryptItemsKeyWithUserFallback } from '../Encryption/Functions'
import { log, LoggingDomain } from '../Logging'
import {
SharedVaultMoveType,
SharedVaultServer,
SharedVaultServerInterface,
HttpServiceInterface,
} from '@standardnotes/api'
import { SharedVaultServer, SharedVaultServerInterface, HttpServiceInterface } from '@standardnotes/api'
import { ContentType } from '@standardnotes/domain-core'
const OneHundredMb = 100 * 1_000_000
@@ -111,7 +107,7 @@ export class FileService extends AbstractService implements FilesClientInterface
moveOperationType?: SharedVaultMoveType
sharedVaultToSharedVaultMoveTargetUuid?: string
}): Promise<string | ClientDisplayableError> {
if (params.operation !== 'write' && !params.fileUuidRequiredForExistingFiles) {
if (params.operation !== ValetTokenOperation.Write && !params.fileUuidRequiredForExistingFiles) {
throw new Error('File UUID is required for for non-write operations')
}
@@ -139,7 +135,7 @@ export class FileService extends AbstractService implements FilesClientInterface
const valetTokenResult = await this.createSharedVaultValetToken({
sharedVaultUuid: file.shared_vault_uuid ? file.shared_vault_uuid : sharedVault.sharing.sharedVaultUuid,
remoteIdentifier: file.remoteIdentifier,
operation: 'move',
operation: ValetTokenOperation.Move,
fileUuidRequiredForExistingFiles: file.uuid,
moveOperationType: file.shared_vault_uuid ? 'shared-vault-to-shared-vault' : 'user-to-shared-vault',
sharedVaultToSharedVaultMoveTargetUuid: file.shared_vault_uuid ? sharedVault.sharing.sharedVaultUuid : undefined,
@@ -164,7 +160,7 @@ export class FileService extends AbstractService implements FilesClientInterface
const valetTokenResult = await this.createSharedVaultValetToken({
sharedVaultUuid: file.shared_vault_uuid,
remoteIdentifier: file.remoteIdentifier,
operation: 'move',
operation: ValetTokenOperation.Move,
fileUuidRequiredForExistingFiles: file.uuid,
moveOperationType: 'shared-vault-to-user',
})
@@ -190,10 +186,10 @@ export class FileService extends AbstractService implements FilesClientInterface
? await this.createSharedVaultValetToken({
sharedVaultUuid: vault.sharing.sharedVaultUuid,
remoteIdentifier,
operation: 'write',
operation: ValetTokenOperation.Write,
unencryptedFileSizeForUpload: sizeInBytes,
})
: await this.createUserValetToken(remoteIdentifier, 'write', sizeInBytes)
: await this.createUserValetToken(remoteIdentifier, ValetTokenOperation.Write, sizeInBytes)
if (valetTokenResult instanceof ClientDisplayableError) {
return valetTokenResult
@@ -342,10 +338,10 @@ export class FileService extends AbstractService implements FilesClientInterface
? await this.createSharedVaultValetToken({
sharedVaultUuid: file.shared_vault_uuid,
remoteIdentifier: file.remoteIdentifier,
operation: 'read',
operation: ValetTokenOperation.Read,
fileUuidRequiredForExistingFiles: file.uuid,
})
: await this.createUserValetToken(file.remoteIdentifier, 'read')
: await this.createUserValetToken(file.remoteIdentifier, ValetTokenOperation.Read)
if (tokenResult instanceof ClientDisplayableError) {
return tokenResult
@@ -375,10 +371,10 @@ export class FileService extends AbstractService implements FilesClientInterface
? await this.createSharedVaultValetToken({
sharedVaultUuid: file.shared_vault_uuid,
remoteIdentifier: file.remoteIdentifier,
operation: 'delete',
operation: ValetTokenOperation.Delete,
fileUuidRequiredForExistingFiles: file.uuid,
})
: await this.createUserValetToken(file.remoteIdentifier, 'delete')
: await this.createUserValetToken(file.remoteIdentifier, ValetTokenOperation.Delete)
if (tokenResult instanceof ClientDisplayableError) {
return tokenResult

View File

@@ -13,8 +13,12 @@ import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface
import { AbstractService } from '../Service/AbstractService'
import { SubscriptionManagerInterface } from './SubscriptionManagerInterface'
import { AppleIAPReceipt } from './AppleIAPReceipt'
import { AvailableSubscriptions, getErrorFromErrorResponse, isErrorResponse } from '@standardnotes/responses'
import { Subscription } from '@standardnotes/security'
import {
AvailableSubscriptions,
getErrorFromErrorResponse,
isErrorResponse,
Subscription,
} from '@standardnotes/responses'
import { SubscriptionManagerEvent } from './SubscriptionManagerEvent'
export class SubscriptionManager
@@ -170,7 +174,7 @@ export class SubscriptionManager
}
}
private async fetchOnlineSubscription(): Promise<void> {
public async fetchOnlineSubscription(): Promise<void> {
if (!this.sessions.isSignedIn()) {
return
}

View File

@@ -1,8 +1,7 @@
import { ApplicationServiceInterface } from './../Service/ApplicationServiceInterface'
import { Invitation } from '@standardnotes/models'
import { AppleIAPReceipt } from './AppleIAPReceipt'
import { AvailableSubscriptions } from '@standardnotes/responses'
import { Subscription } from '@standardnotes/security'
import { AvailableSubscriptions, Subscription } from '@standardnotes/responses'
import { SubscriptionManagerEvent } from './SubscriptionManagerEvent'
export interface SubscriptionManagerInterface extends ApplicationServiceInterface<SubscriptionManagerEvent, unknown> {
@@ -15,6 +14,7 @@ export interface SubscriptionManagerInterface extends ApplicationServiceInterfac
get isUserSubscriptionExpired(): boolean
get isUserSubscriptionCanceled(): boolean
fetchOnlineSubscription(): Promise<void>
listSubscriptionInvitations(): Promise<Invitation[]>
inviteToSubscription(inviteeEmail: string): Promise<boolean>
cancelInvitation(inviteUuid: string): Promise<boolean>

View File

@@ -66,15 +66,13 @@ import {
HttpErrorResponse,
HttpSuccessResponse,
isErrorResponse,
ValetTokenOperation,
MoveFileResponse,
ValetTokenOperation,
} from '@standardnotes/responses'
import { LegacySession, MapperInterface, Session, SessionToken } from '@standardnotes/domain-core'
import { HttpServiceInterface } from '@standardnotes/api'
import { SNRootKeyParams } from '@standardnotes/encryption'
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
import { isUrlFirstParty, TRUSTED_FEATURE_HOSTS } from '@Lib/Hosts'
import { Paths } from './Paths'
import { DiskStorageService } from '../Storage/DiskStorageService'

View File

@@ -11,7 +11,7 @@ jest.mock('@standardnotes/features', () => ({
}))
import { FindNativeFeature } from '@standardnotes/features'
import { Subscription } from '@standardnotes/security'
import { Subscription } from '@standardnotes/responses'
describe('GetFeatureStatusUseCase', () => {
let items: jest.Mocked<ItemManagerInterface>

View File

@@ -1,6 +1,6 @@
import { AnyFeatureDescription, FeatureIdentifier, FindNativeFeature } from '@standardnotes/features'
import { DecryptedItemInterface } from '@standardnotes/models'
import { Subscription } from '@standardnotes/security'
import { Subscription } from '@standardnotes/responses'
import { FeatureStatus, ItemManagerInterface } from '@standardnotes/services'
import { convertTimestampToMilliseconds } from '@standardnotes/utils'

View File

@@ -51,7 +51,7 @@ describe('files', function () {
await setup({ fakeCrypto: true, subscription: true })
const remoteIdentifier = Utils.generateUuid()
const token = await application.apiService.createUserFileValetToken(remoteIdentifier, 'write')
const token = await application.apiService.createUserFileValetToken(remoteIdentifier, ValetTokenOperation.Write)
expect(token.length).to.be.above(0)
})
@@ -60,7 +60,10 @@ describe('files', function () {
await setup({ fakeCrypto: true, subscription: false })
const remoteIdentifier = Utils.generateUuid()
const tokenOrError = await application.apiService.createUserFileValetToken(remoteIdentifier, 'write')
const tokenOrError = await application.apiService.createUserFileValetToken(
remoteIdentifier,
ValetTokenOperation.Write,
)
expect(isClientDisplayableError(tokenOrError)).to.equal(true)
})
@@ -76,7 +79,10 @@ describe('files', function () {
})
const remoteIdentifier = Utils.generateUuid()
const tokenOrError = await application.apiService.createUserFileValetToken(remoteIdentifier, 'write')
const tokenOrError = await application.apiService.createUserFileValetToken(
remoteIdentifier,
ValetTokenOperation.Write,
)
expect(isClientDisplayableError(tokenOrError)).to.equal(true)
})
@@ -84,12 +90,18 @@ describe('files', function () {
it('creating two upload sessions successively should succeed', async function () {
await setup({ fakeCrypto: true, subscription: true })
const firstToken = await application.apiService.createUserFileValetToken(Utils.generateUuid(), 'write')
const firstToken = await application.apiService.createUserFileValetToken(
Utils.generateUuid(),
ValetTokenOperation.Write,
)
const firstSession = await application.apiService.startUploadSession(firstToken, 'user')
expect(firstSession.uploadId).to.be.ok
const secondToken = await application.apiService.createUserFileValetToken(Utils.generateUuid(), 'write')
const secondToken = await application.apiService.createUserFileValetToken(
Utils.generateUuid(),
ValetTokenOperation.Write,
)
const secondSession = await application.apiService.startUploadSession(secondToken, 'user')
expect(secondSession.uploadId).to.be.ok

View File

@@ -44,7 +44,6 @@
"@standardnotes/files": "workspace:*",
"@standardnotes/models": "workspace:*",
"@standardnotes/responses": "workspace:*",
"@standardnotes/security": "^1.7.6",
"@standardnotes/services": "workspace:*",
"@standardnotes/settings": "^1.20.0",
"@standardnotes/sncrypto-common": "workspace:*",

View File

@@ -1,6 +1,6 @@
const path = require('path');
const webpack = require('webpack');
const CircularDependencyPlugin = require('circular-dependency-plugin');
const path = require('path')
const webpack = require('webpack')
const CircularDependencyPlugin = require('circular-dependency-plugin')
module.exports = {
entry: {
@@ -57,4 +57,4 @@ module.exports = {
cwd: process.cwd(),
}),
],
};
}

View File

@@ -2,15 +2,30 @@ import { Title } from '@/Components/Preferences/PreferencesComponents/Content'
import SubscriptionInformation from './SubscriptionInformation'
import NoSubscription from './NoSubscription'
import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'react'
import { FunctionComponent, useEffect, useState } from 'react'
import PreferencesGroup from '@/Components/Preferences/PreferencesComponents/PreferencesGroup'
import PreferencesSegment from '@/Components/Preferences/PreferencesComponents/PreferencesSegment'
import { useApplication } from '@/Components/ApplicationProvider'
import { SubscriptionManagerEvent, Subscription } from '@standardnotes/snjs'
const Subscription: FunctionComponent = () => {
const application = useApplication()
const onlineSubscription = application.controllers.subscriptionController.onlineSubscription
const [onlineSubscription, setOnlineSubscription] = useState<Subscription | undefined>(
application.controllers.subscriptionController.onlineSubscription,
)
useEffect(() => {
return application.subscriptions.addEventObserver((event) => {
if (event === SubscriptionManagerEvent.DidFetchSubscription) {
setOnlineSubscription(application.controllers.subscriptionController.onlineSubscription)
}
})
}, [application.subscriptions, application.controllers.subscriptionController])
useEffect(() => {
void application.subscriptions.fetchOnlineSubscription()
}, [application.subscriptions])
return (
<PreferencesGroup>

View File

@@ -1,4 +1,4 @@
import { Subscription } from '@standardnotes/security'
import { Subscription } from '@standardnotes/responses'
import { destroyAllObjectProperties } from '@/Utils'
import {
ApplicationEvent,

View File

@@ -4221,7 +4221,6 @@ __metadata:
"@standardnotes/domain-core": ^1.22.0
"@standardnotes/models": "workspace:*"
"@standardnotes/responses": "workspace:*"
"@standardnotes/security": ^1.7.6
"@standardnotes/utils": "workspace:*"
"@types/jest": ^29.2.3
"@typescript-eslint/eslint-plugin": "*"
@@ -4518,7 +4517,6 @@ __metadata:
dependencies:
"@standardnotes/common": ^1.50.0
"@standardnotes/domain-core": ^1.22.0
"@standardnotes/security": ^1.7.6
"@types/jest": ^29.2.3
"@typescript-eslint/eslint-plugin": "*"
eslint: "*"
@@ -4774,7 +4772,6 @@ __metadata:
dependencies:
"@standardnotes/common": ^1.50.0
"@standardnotes/features": "workspace:*"
"@standardnotes/security": ^1.7.6
"@types/jest": ^29.2.3
"@typescript-eslint/eslint-plugin": "*"
eslint: "*"
@@ -4795,7 +4792,7 @@ __metadata:
languageName: node
linkType: hard
"@standardnotes/security@npm:1.7.6, @standardnotes/security@npm:^1.2.0, @standardnotes/security@npm:^1.7.5, @standardnotes/security@npm:^1.7.6":
"@standardnotes/security@npm:1.7.6, @standardnotes/security@npm:^1.2.0":
version: 1.7.6
resolution: "@standardnotes/security@npm:1.7.6"
dependencies:
@@ -4817,7 +4814,6 @@ __metadata:
"@standardnotes/files": "workspace:^"
"@standardnotes/models": "workspace:^"
"@standardnotes/responses": "workspace:*"
"@standardnotes/security": ^1.7.5
"@standardnotes/sncrypto-common": "workspace:^"
"@standardnotes/utils": "workspace:*"
"@types/jest": ^29.2.3
@@ -4918,7 +4914,6 @@ __metadata:
"@standardnotes/files": "workspace:*"
"@standardnotes/models": "workspace:*"
"@standardnotes/responses": "workspace:*"
"@standardnotes/security": ^1.7.6
"@standardnotes/services": "workspace:*"
"@standardnotes/settings": ^1.20.0
"@standardnotes/sncrypto-common": "workspace:*"