feat(api): add listing workspaces
This commit is contained in:
@@ -2,4 +2,5 @@ export enum WorkspaceApiOperations {
|
|||||||
Creating,
|
Creating,
|
||||||
Inviting,
|
Inviting,
|
||||||
Accepting,
|
Accepting,
|
||||||
|
ListingWorkspaces,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { WorkspaceType } from '@standardnotes/common'
|
import { WorkspaceType } from '@standardnotes/common'
|
||||||
|
import { HttpStatusCode } from '../../Http'
|
||||||
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
|
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
|
||||||
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
|
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
|
||||||
import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceInvitationResponse'
|
import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceInvitationResponse'
|
||||||
|
import { WorkspaceListResponse } from '../../Response/Workspace/WorkspaceListResponse'
|
||||||
import { WorkspaceServerInterface } from '../../Server/Workspace/WorkspaceServerInterface'
|
import { WorkspaceServerInterface } from '../../Server/Workspace/WorkspaceServerInterface'
|
||||||
|
|
||||||
import { WorkspaceApiOperations } from './WorkspaceApiOperations'
|
import { WorkspaceApiOperations } from './WorkspaceApiOperations'
|
||||||
@@ -23,6 +25,10 @@ describe('WorkspaceApiService', () => {
|
|||||||
workspaceServer.acceptInvite = jest.fn().mockReturnValue({
|
workspaceServer.acceptInvite = jest.fn().mockReturnValue({
|
||||||
data: { success: true },
|
data: { success: true },
|
||||||
} as jest.Mocked<WorkspaceInvitationAcceptingResponse>)
|
} as jest.Mocked<WorkspaceInvitationAcceptingResponse>)
|
||||||
|
workspaceServer.listWorkspaces = jest.fn().mockReturnValue({
|
||||||
|
status: HttpStatusCode.Success,
|
||||||
|
data: { ownedWorkspaces: [], joinedWorkspaces: [] },
|
||||||
|
} as jest.Mocked<WorkspaceListResponse>)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should create a workspace', async () => {
|
it('should create a workspace', async () => {
|
||||||
@@ -202,4 +208,48 @@ describe('WorkspaceApiService', () => {
|
|||||||
|
|
||||||
expect(error).not.toBeNull()
|
expect(error).not.toBeNull()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should list workspaces', async () => {
|
||||||
|
const response = await createService().listWorkspaces()
|
||||||
|
|
||||||
|
expect(response).toEqual({
|
||||||
|
status: 200,
|
||||||
|
data: {
|
||||||
|
ownedWorkspaces: [],
|
||||||
|
joinedWorkspaces: [],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(workspaceServer.listWorkspaces).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not list workspaces if it is already listing them', async () => {
|
||||||
|
const service = createService()
|
||||||
|
Object.defineProperty(service, 'operationsInProgress', {
|
||||||
|
get: () => new Map([[WorkspaceApiOperations.ListingWorkspaces, true]]),
|
||||||
|
})
|
||||||
|
|
||||||
|
let error = null
|
||||||
|
try {
|
||||||
|
await service.listWorkspaces()
|
||||||
|
} catch (caughtError) {
|
||||||
|
error = caughtError
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).not.toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not list workspaces if the server fails', async () => {
|
||||||
|
workspaceServer.listWorkspaces = jest.fn().mockImplementation(() => {
|
||||||
|
throw new Error('Oops')
|
||||||
|
})
|
||||||
|
|
||||||
|
let error = null
|
||||||
|
try {
|
||||||
|
await createService().listWorkspaces()
|
||||||
|
} catch (caughtError) {
|
||||||
|
error = caughtError
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).not.toBeNull()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCre
|
|||||||
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
|
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
|
||||||
import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceInvitationResponse'
|
import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceInvitationResponse'
|
||||||
import { WorkspaceServerInterface } from '../../Server/Workspace/WorkspaceServerInterface'
|
import { WorkspaceServerInterface } from '../../Server/Workspace/WorkspaceServerInterface'
|
||||||
|
import { WorkspaceListResponse } from '../../Response/Workspace/WorkspaceListResponse'
|
||||||
|
|
||||||
import { WorkspaceApiServiceInterface } from './WorkspaceApiServiceInterface'
|
import { WorkspaceApiServiceInterface } from './WorkspaceApiServiceInterface'
|
||||||
import { WorkspaceApiOperations } from './WorkspaceApiOperations'
|
import { WorkspaceApiOperations } from './WorkspaceApiOperations'
|
||||||
@@ -17,6 +18,20 @@ export class WorkspaceApiService implements WorkspaceApiServiceInterface {
|
|||||||
this.operationsInProgress = new Map()
|
this.operationsInProgress = new Map()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async listWorkspaces(): Promise<WorkspaceListResponse> {
|
||||||
|
this.lockOperation(WorkspaceApiOperations.ListingWorkspaces)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.workspaceServer.listWorkspaces({})
|
||||||
|
|
||||||
|
this.unlockOperation(WorkspaceApiOperations.ListingWorkspaces)
|
||||||
|
|
||||||
|
return response
|
||||||
|
} catch (error) {
|
||||||
|
throw new ApiCallError(ErrorMessage.GenericFail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async acceptInvite(dto: {
|
async acceptInvite(dto: {
|
||||||
inviteUuid: string
|
inviteUuid: string
|
||||||
userUuid: string
|
userUuid: string
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Uuid, WorkspaceType } from '@standardnotes/common'
|
|||||||
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
|
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
|
||||||
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
|
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
|
||||||
import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceInvitationResponse'
|
import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceInvitationResponse'
|
||||||
|
import { WorkspaceListResponse } from '../../Response/Workspace/WorkspaceListResponse'
|
||||||
|
|
||||||
export interface WorkspaceApiServiceInterface {
|
export interface WorkspaceApiServiceInterface {
|
||||||
createWorkspace(dto: {
|
createWorkspace(dto: {
|
||||||
@@ -19,4 +20,5 @@ export interface WorkspaceApiServiceInterface {
|
|||||||
publicKey: string
|
publicKey: string
|
||||||
encryptedPrivateKey: string
|
encryptedPrivateKey: string
|
||||||
}): Promise<WorkspaceInvitationAcceptingResponse>
|
}): Promise<WorkspaceInvitationAcceptingResponse>
|
||||||
|
listWorkspaces(): Promise<WorkspaceListResponse>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export type WorkspaceListRequestParams = {
|
||||||
|
[additionalParam: string]: unknown
|
||||||
|
}
|
||||||
@@ -9,3 +9,4 @@ export * from './WebSocket/WebSocketConnectionTokenRequestParams'
|
|||||||
export * from './Workspace/WorkspaceCreationRequestParams'
|
export * from './Workspace/WorkspaceCreationRequestParams'
|
||||||
export * from './Workspace/WorkspaceInvitationAcceptingRequestParams'
|
export * from './Workspace/WorkspaceInvitationAcceptingRequestParams'
|
||||||
export * from './Workspace/WorkspaceInvitationRequestParams'
|
export * from './Workspace/WorkspaceInvitationRequestParams'
|
||||||
|
export * from './Workspace/WorkspaceListRequestParams'
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { Either } from '@standardnotes/common'
|
||||||
|
|
||||||
|
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
|
||||||
|
import { HttpResponse } from '../../Http/HttpResponse'
|
||||||
|
import { WorkspaceListResponseBody } from './WorkspaceListResponseBody'
|
||||||
|
|
||||||
|
export interface WorkspaceListResponse extends HttpResponse {
|
||||||
|
data: Either<WorkspaceListResponseBody, HttpErrorResponseBody>
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { Workspace } from '@standardnotes/models'
|
||||||
|
|
||||||
|
export type WorkspaceListResponseBody = {
|
||||||
|
ownedWorkspaces: Array<Workspace>
|
||||||
|
joinedWorkspaces: Array<Workspace>
|
||||||
|
}
|
||||||
@@ -18,3 +18,5 @@ export * from './Workspace/WorkspaceInvitationAcceptingResponse'
|
|||||||
export * from './Workspace/WorkspaceInvitationAcceptingResponseBody'
|
export * from './Workspace/WorkspaceInvitationAcceptingResponseBody'
|
||||||
export * from './Workspace/WorkspaceInvitationResponse'
|
export * from './Workspace/WorkspaceInvitationResponse'
|
||||||
export * from './Workspace/WorkspaceInvitationResponseBody'
|
export * from './Workspace/WorkspaceInvitationResponseBody'
|
||||||
|
export * from './Workspace/WorkspaceListResponse'
|
||||||
|
export * from './Workspace/WorkspaceListResponseBody'
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Uuid } from '@standardnotes/common'
|
|||||||
|
|
||||||
const WorkspacePaths = {
|
const WorkspacePaths = {
|
||||||
createWorkspace: '/v1/workspaces',
|
createWorkspace: '/v1/workspaces',
|
||||||
|
listWorkspaces: '/v1/workspaces',
|
||||||
inviteToWorkspace: (uuid: Uuid) => `/v1/workspaces/${uuid}/invites`,
|
inviteToWorkspace: (uuid: Uuid) => `/v1/workspaces/${uuid}/invites`,
|
||||||
acceptInvite: (uuid: Uuid) => `/v1/invites/${uuid}/accept`,
|
acceptInvite: (uuid: Uuid) => `/v1/invites/${uuid}/accept`,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { WorkspaceType } from '@standardnotes/common'
|
import { WorkspaceType } from '@standardnotes/common'
|
||||||
import { HttpServiceInterface } from '../../Http'
|
import { HttpServiceInterface, HttpStatusCode } from '../../Http'
|
||||||
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
|
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
|
||||||
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
|
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
|
||||||
import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceInvitationResponse'
|
import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceInvitationResponse'
|
||||||
|
import { WorkspaceListResponse } from '../../Response/Workspace/WorkspaceListResponse'
|
||||||
|
|
||||||
import { WorkspaceServer } from './WorkspaceServer'
|
import { WorkspaceServer } from './WorkspaceServer'
|
||||||
|
|
||||||
@@ -68,4 +69,18 @@ describe('WorkspaceServer', () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should list workspaces', async () => {
|
||||||
|
httpService.get = jest.fn().mockReturnValue({
|
||||||
|
status: HttpStatusCode.Success,
|
||||||
|
data: { ownedWorkspaces: [], joinedWorkspaces: [] },
|
||||||
|
} as jest.Mocked<WorkspaceListResponse>)
|
||||||
|
|
||||||
|
const response = await createServer().listWorkspaces({})
|
||||||
|
|
||||||
|
expect(response).toEqual({
|
||||||
|
status: 200,
|
||||||
|
data: { ownedWorkspaces: [], joinedWorkspaces: [] },
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceI
|
|||||||
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
|
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
|
||||||
import { WorkspaceInvitationAcceptingRequestParams } from '../../Request/Workspace/WorkspaceInvitationAcceptingRequestParams'
|
import { WorkspaceInvitationAcceptingRequestParams } from '../../Request/Workspace/WorkspaceInvitationAcceptingRequestParams'
|
||||||
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
|
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
|
||||||
|
import { WorkspaceListRequestParams } from '../../Request/Workspace/WorkspaceListRequestParams'
|
||||||
|
import { WorkspaceListResponse } from '../../Response/Workspace/WorkspaceListResponse'
|
||||||
|
|
||||||
import { Paths } from './Paths'
|
import { Paths } from './Paths'
|
||||||
import { WorkspaceServerInterface } from './WorkspaceServerInterface'
|
import { WorkspaceServerInterface } from './WorkspaceServerInterface'
|
||||||
@@ -12,6 +14,12 @@ import { WorkspaceServerInterface } from './WorkspaceServerInterface'
|
|||||||
export class WorkspaceServer implements WorkspaceServerInterface {
|
export class WorkspaceServer implements WorkspaceServerInterface {
|
||||||
constructor(private httpService: HttpServiceInterface) {}
|
constructor(private httpService: HttpServiceInterface) {}
|
||||||
|
|
||||||
|
async listWorkspaces(params: WorkspaceListRequestParams): Promise<WorkspaceListResponse> {
|
||||||
|
const response = await this.httpService.get(Paths.v1.listWorkspaces, params)
|
||||||
|
|
||||||
|
return response as WorkspaceListResponse
|
||||||
|
}
|
||||||
|
|
||||||
async acceptInvite(params: WorkspaceInvitationAcceptingRequestParams): Promise<WorkspaceInvitationAcceptingResponse> {
|
async acceptInvite(params: WorkspaceInvitationAcceptingRequestParams): Promise<WorkspaceInvitationAcceptingResponse> {
|
||||||
const response = await this.httpService.post(Paths.v1.acceptInvite(params.inviteUuid), params)
|
const response = await this.httpService.post(Paths.v1.acceptInvite(params.inviteUuid), params)
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,12 @@ import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceI
|
|||||||
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
|
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
|
||||||
import { WorkspaceInvitationAcceptingRequestParams } from '../../Request/Workspace/WorkspaceInvitationAcceptingRequestParams'
|
import { WorkspaceInvitationAcceptingRequestParams } from '../../Request/Workspace/WorkspaceInvitationAcceptingRequestParams'
|
||||||
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
|
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
|
||||||
|
import { WorkspaceListRequestParams } from '../../Request/Workspace/WorkspaceListRequestParams'
|
||||||
|
import { WorkspaceListResponse } from '../../Response/Workspace/WorkspaceListResponse'
|
||||||
|
|
||||||
export interface WorkspaceServerInterface {
|
export interface WorkspaceServerInterface {
|
||||||
createWorkspace(params: WorkspaceCreationRequestParams): Promise<WorkspaceCreationResponse>
|
createWorkspace(params: WorkspaceCreationRequestParams): Promise<WorkspaceCreationResponse>
|
||||||
|
listWorkspaces(params: WorkspaceListRequestParams): Promise<WorkspaceListResponse>
|
||||||
inviteToWorkspace(params: WorkspaceInvitationRequestParams): Promise<WorkspaceInvitationResponse>
|
inviteToWorkspace(params: WorkspaceInvitationRequestParams): Promise<WorkspaceInvitationResponse>
|
||||||
acceptInvite(params: WorkspaceInvitationAcceptingRequestParams): Promise<WorkspaceInvitationAcceptingResponse>
|
acceptInvite(params: WorkspaceInvitationAcceptingRequestParams): Promise<WorkspaceInvitationAcceptingResponse>
|
||||||
}
|
}
|
||||||
|
|||||||
10
packages/models/src/Domain/Api/Workspace/Workspace.ts
Normal file
10
packages/models/src/Domain/Api/Workspace/Workspace.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { WorkspaceType } from '@standardnotes/common'
|
||||||
|
|
||||||
|
export type Workspace = {
|
||||||
|
uuid: string
|
||||||
|
type: WorkspaceType
|
||||||
|
name: string | null
|
||||||
|
keyRotationIndex: number
|
||||||
|
createdAt: number
|
||||||
|
updatedAt: number
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ export * from './Api/Subscription/Invitation'
|
|||||||
export * from './Api/Subscription/InvitationStatus'
|
export * from './Api/Subscription/InvitationStatus'
|
||||||
export * from './Api/Subscription/InviteeIdentifierType'
|
export * from './Api/Subscription/InviteeIdentifierType'
|
||||||
export * from './Api/Subscription/InviterIdentifierType'
|
export * from './Api/Subscription/InviterIdentifierType'
|
||||||
|
export * from './Api/Workspace/Workspace'
|
||||||
export * from './Device/Environment'
|
export * from './Device/Environment'
|
||||||
export * from './Device/Platform'
|
export * from './Device/Platform'
|
||||||
export * from './Local/KeyParams/RootKeyParamsInterface'
|
export * from './Local/KeyParams/RootKeyParamsInterface'
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Uuid, WorkspaceType } from '@standardnotes/common'
|
import { Uuid, WorkspaceType } from '@standardnotes/common'
|
||||||
|
import { Workspace } from '@standardnotes/models'
|
||||||
|
|
||||||
export interface WorkspaceClientInterface {
|
export interface WorkspaceClientInterface {
|
||||||
createWorkspace(dto: {
|
createWorkspace(dto: {
|
||||||
@@ -15,4 +16,5 @@ export interface WorkspaceClientInterface {
|
|||||||
publicKey: string
|
publicKey: string
|
||||||
encryptedPrivateKey: string
|
encryptedPrivateKey: string
|
||||||
}): Promise<{ success: boolean }>
|
}): Promise<{ success: boolean }>
|
||||||
|
listWorkspaces(): Promise<{ ownedWorkspaces: Array<Workspace>; joinedWorkspaces: Array<Workspace> }>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { WorkspaceApiServiceInterface } from '@standardnotes/api'
|
import { WorkspaceApiServiceInterface } from '@standardnotes/api'
|
||||||
import { Uuid, WorkspaceType } from '@standardnotes/common'
|
import { Uuid, WorkspaceType } from '@standardnotes/common'
|
||||||
|
import { Workspace } from '@standardnotes/models'
|
||||||
|
|
||||||
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
|
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
|
||||||
import { AbstractService } from '../Service/AbstractService'
|
import { AbstractService } from '../Service/AbstractService'
|
||||||
@@ -13,6 +14,20 @@ export class WorkspaceManager extends AbstractService implements WorkspaceClient
|
|||||||
super(internalEventBus)
|
super(internalEventBus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async listWorkspaces(): Promise<{ ownedWorkspaces: Workspace[]; joinedWorkspaces: Workspace[] }> {
|
||||||
|
try {
|
||||||
|
const result = await this.workspaceApiService.listWorkspaces()
|
||||||
|
|
||||||
|
if (result.data.error !== undefined) {
|
||||||
|
return { ownedWorkspaces: [], joinedWorkspaces: [] }
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.data
|
||||||
|
} catch (error) {
|
||||||
|
return { ownedWorkspaces: [], joinedWorkspaces: [] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async acceptInvite(dto: {
|
async acceptInvite(dto: {
|
||||||
inviteUuid: string
|
inviteUuid: string
|
||||||
userUuid: string
|
userUuid: string
|
||||||
|
|||||||
Reference in New Issue
Block a user