@neuralinnovations/dataisland-sdk 0.0.1-dev1 → 0.0.1-dev2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/jest.config.ts +5 -5
- package/jest.setup.ts +2 -0
- package/package.json +2 -1
- package/src/appBuilder.ts +20 -1
- package/src/appSdk.ts +28 -9
- package/src/commands/startCommandHandler.ts +14 -0
- package/src/context.ts +31 -0
- package/src/credentials.ts +3 -3
- package/src/disposable.ts +1 -1
- package/src/dto/userInfoResponse.ts +37 -0
- package/src/events.ts +0 -4
- package/src/index.ts +9 -1
- package/src/internal/app.impl.ts +89 -21
- package/src/internal/appBuilder.impl.ts +28 -1
- package/src/middleware.ts +1 -1
- package/src/services/commandService.ts +44 -0
- package/src/services/middlewareService.ts +4 -2
- package/src/services/organizationImpl.ts +51 -0
- package/src/services/organizationService.ts +126 -0
- package/src/services/organizationsImpl.ts +55 -0
- package/src/services/requestBuilder.ts +102 -0
- package/src/services/rpcService.ts +111 -51
- package/src/services/service.ts +1 -1
- package/src/services/userProfileService.ts +86 -0
- package/src/storages/organizations.ts +76 -0
- package/src/storages/userProfile.ts +42 -0
- package/src/types.ts +6 -30
- package/src/unitTest.ts +42 -0
- package/test/commands.test.ts +24 -0
- package/test/index.test.ts +132 -52
- package/test/services.test.ts +56 -0
- package/test/setup.ts +2 -0
- package/test/unitTest.test.ts +21 -0
- package/src/internal/context.ts +0 -13
@@ -0,0 +1,126 @@
|
|
1
|
+
import { Service } from './service'
|
2
|
+
import {
|
3
|
+
OrganizationEvent,
|
4
|
+
OrganizationId,
|
5
|
+
Organizations
|
6
|
+
} from '../storages/organizations'
|
7
|
+
import { OrganizationDto, UserSettings } from '../dto/userInfoResponse'
|
8
|
+
import { RpcService } from './rpcService'
|
9
|
+
import { OrganizationImpl } from './organizationImpl'
|
10
|
+
import { OrganizationsImpl } from './organizationsImpl'
|
11
|
+
|
12
|
+
export class OrganizationService extends Service {
|
13
|
+
private impl: OrganizationsImpl = new OrganizationsImpl(this)
|
14
|
+
|
15
|
+
get organizations(): Organizations {
|
16
|
+
return this.impl
|
17
|
+
}
|
18
|
+
|
19
|
+
initFrom(
|
20
|
+
settings: UserSettings,
|
21
|
+
adminInOrganization: string[],
|
22
|
+
organizations: OrganizationDto[]
|
23
|
+
) {
|
24
|
+
this.impl.currentOrganizationId = settings.activeOrganizationId
|
25
|
+
for (const organization of organizations) {
|
26
|
+
const org = new OrganizationImpl(this, this.impl).initFrom(
|
27
|
+
organization,
|
28
|
+
adminInOrganization.includes(organization.id)
|
29
|
+
)
|
30
|
+
// add organization to collection
|
31
|
+
this.impl.organizations.push(org)
|
32
|
+
|
33
|
+
// dispatch event, organization added
|
34
|
+
this.impl.dispatch({
|
35
|
+
type: OrganizationEvent.ADDED,
|
36
|
+
data: org
|
37
|
+
})
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
async deleteOrganization(id: OrganizationId): Promise<void> {
|
42
|
+
if (id === undefined || id === null) {
|
43
|
+
throw new Error('Organization delete, id is undefined or null')
|
44
|
+
}
|
45
|
+
if (id.length === 0 || id.trim().length === 0) {
|
46
|
+
throw new Error('Organization delete, id is empty')
|
47
|
+
}
|
48
|
+
if (!this.impl.contains(id)) {
|
49
|
+
throw new Error(`Organization delete, id: ${id} is not found`)
|
50
|
+
}
|
51
|
+
const response = await this.resolve(RpcService)
|
52
|
+
?.requestBuilder('/api/v1/Organizations')
|
53
|
+
.searchParam('id', id)
|
54
|
+
.sendDelete()
|
55
|
+
if (!response?.ok) {
|
56
|
+
let text: string = ''
|
57
|
+
try {
|
58
|
+
text = (await response?.text()) ?? ''
|
59
|
+
} catch (e) {
|
60
|
+
console.error(e)
|
61
|
+
}
|
62
|
+
|
63
|
+
throw new Error(
|
64
|
+
`Organization delete, response is not ok, status: ${response?.status},${response?.statusText} ${text}`
|
65
|
+
)
|
66
|
+
}
|
67
|
+
const org = <OrganizationImpl>this.impl.get(id)
|
68
|
+
const index = this.impl.organizations.indexOf(org)
|
69
|
+
if (index < 0) {
|
70
|
+
throw new Error('Organization delete, index is not found')
|
71
|
+
}
|
72
|
+
|
73
|
+
// remove organization from collection
|
74
|
+
this.impl.organizations.splice(index, 1)
|
75
|
+
|
76
|
+
// dispatch event, organization removed
|
77
|
+
this.impl.dispatch({
|
78
|
+
type: OrganizationEvent.REMOVED,
|
79
|
+
data: org
|
80
|
+
})
|
81
|
+
|
82
|
+
// dispose organization
|
83
|
+
org.dispose()
|
84
|
+
}
|
85
|
+
|
86
|
+
async createOrganization(
|
87
|
+
name: string,
|
88
|
+
description: string
|
89
|
+
): Promise<OrganizationImpl> {
|
90
|
+
if (name === undefined || name === null) {
|
91
|
+
throw new Error('Organization create, name is undefined or null')
|
92
|
+
}
|
93
|
+
if (description === undefined || description === null) {
|
94
|
+
throw new Error('Organization create, description is undefined or null')
|
95
|
+
}
|
96
|
+
if (name.length === 0 || name.trim().length === 0) {
|
97
|
+
throw new Error('Organization create, name is empty')
|
98
|
+
}
|
99
|
+
const response = await this.resolve(RpcService)
|
100
|
+
?.requestBuilder('api/v1/Organizations')
|
101
|
+
.sendPost({
|
102
|
+
profile: {
|
103
|
+
name: name,
|
104
|
+
description: description
|
105
|
+
}
|
106
|
+
})
|
107
|
+
if (!response?.ok) {
|
108
|
+
throw new Error('Organization create, response is not ok')
|
109
|
+
}
|
110
|
+
const content = (await response.json())['organization'] as OrganizationDto
|
111
|
+
|
112
|
+
// create organization and init from content
|
113
|
+
const org = new OrganizationImpl(this, this.impl).initFrom(content, true)
|
114
|
+
|
115
|
+
// add organization to collection
|
116
|
+
this.impl.organizations.push(org)
|
117
|
+
|
118
|
+
// dispatch event, organization added
|
119
|
+
this.impl.dispatch({
|
120
|
+
type: OrganizationEvent.ADDED,
|
121
|
+
data: org
|
122
|
+
})
|
123
|
+
|
124
|
+
return org
|
125
|
+
}
|
126
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
import {
|
2
|
+
Organization,
|
3
|
+
OrganizationEvent,
|
4
|
+
OrganizationId,
|
5
|
+
Organizations
|
6
|
+
} from '../storages/organizations'
|
7
|
+
import { OrganizationImpl } from './organizationImpl'
|
8
|
+
import { OrganizationService } from './organizationService'
|
9
|
+
|
10
|
+
export class OrganizationsImpl extends Organizations {
|
11
|
+
constructor(public readonly service: OrganizationService) {
|
12
|
+
super()
|
13
|
+
}
|
14
|
+
|
15
|
+
public organizations: OrganizationImpl[] = []
|
16
|
+
public currentOrganizationId?: OrganizationId
|
17
|
+
|
18
|
+
get collection(): readonly Organization[] {
|
19
|
+
return this.organizations
|
20
|
+
}
|
21
|
+
|
22
|
+
get current(): OrganizationId {
|
23
|
+
return <OrganizationId>this.currentOrganizationId
|
24
|
+
}
|
25
|
+
|
26
|
+
set current(value: OrganizationId) {
|
27
|
+
if (this.currentOrganizationId !== value) {
|
28
|
+
this.currentOrganizationId = value
|
29
|
+
this.dispatch({
|
30
|
+
type: OrganizationEvent.CURRENT_CHANGED,
|
31
|
+
data: this
|
32
|
+
})
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
get(id: OrganizationId): Organization {
|
37
|
+
return <Organization>this.tryGet(id)
|
38
|
+
}
|
39
|
+
|
40
|
+
tryGet(id: OrganizationId): Organization | undefined {
|
41
|
+
return this.organizations.find(organization => organization.id === id)
|
42
|
+
}
|
43
|
+
|
44
|
+
contains(id: OrganizationId): boolean {
|
45
|
+
return this.organizations.some(organization => organization.id === id)
|
46
|
+
}
|
47
|
+
|
48
|
+
async create(name: string, description: string): Promise<Organization> {
|
49
|
+
return this.service.createOrganization(name, description)
|
50
|
+
}
|
51
|
+
|
52
|
+
delete(id: string): Promise<void> {
|
53
|
+
return this.service.deleteOrganization(id)
|
54
|
+
}
|
55
|
+
}
|
@@ -0,0 +1,102 @@
|
|
1
|
+
export class RequestBuilder {
|
2
|
+
private readonly _headers: Headers
|
3
|
+
private readonly _searchParams: URLSearchParams
|
4
|
+
|
5
|
+
constructor(
|
6
|
+
private readonly _url: URL,
|
7
|
+
private readonly _request: (req: Request) => Promise<Response>
|
8
|
+
) {
|
9
|
+
this._headers = new Headers()
|
10
|
+
this._searchParams = new URLSearchParams()
|
11
|
+
}
|
12
|
+
|
13
|
+
public header(name: string, value: string): RequestBuilder {
|
14
|
+
this._headers.set(name, value)
|
15
|
+
return this
|
16
|
+
}
|
17
|
+
|
18
|
+
public headers(
|
19
|
+
headers?: [string, string][] | Record<string, string> | Headers
|
20
|
+
): RequestBuilder {
|
21
|
+
if (headers === undefined) {
|
22
|
+
return this
|
23
|
+
}
|
24
|
+
if (headers instanceof Headers) {
|
25
|
+
headers.forEach((value, name) => {
|
26
|
+
this._headers.set(name, value)
|
27
|
+
})
|
28
|
+
} else {
|
29
|
+
Object.entries(headers).forEach(([name, value]) => {
|
30
|
+
this._headers.set(name, value)
|
31
|
+
})
|
32
|
+
}
|
33
|
+
return this
|
34
|
+
}
|
35
|
+
|
36
|
+
public searchParam(name: string, value: string): RequestBuilder {
|
37
|
+
this._searchParams.set(name, value)
|
38
|
+
return this
|
39
|
+
}
|
40
|
+
|
41
|
+
public searchParams(searchParams?: Map<string, string>): RequestBuilder {
|
42
|
+
if (searchParams === undefined) {
|
43
|
+
return this
|
44
|
+
}
|
45
|
+
searchParams.forEach((value, name) => {
|
46
|
+
this._searchParams.set(name, value)
|
47
|
+
})
|
48
|
+
return this
|
49
|
+
}
|
50
|
+
|
51
|
+
public async sendPost(body?: BodyInit | null | object): Promise<Response> {
|
52
|
+
const url = this._url
|
53
|
+
url.search = this._searchParams.toString()
|
54
|
+
if (body !== undefined && body !== null && typeof body === 'object') {
|
55
|
+
body = JSON.stringify(body)
|
56
|
+
}
|
57
|
+
return await this._request(
|
58
|
+
new Request(url, {
|
59
|
+
method: 'POST',
|
60
|
+
headers: this._headers,
|
61
|
+
body
|
62
|
+
})
|
63
|
+
)
|
64
|
+
}
|
65
|
+
|
66
|
+
public async sendGet(): Promise<Response> {
|
67
|
+
const url = this._url
|
68
|
+
url.search = this._searchParams.toString()
|
69
|
+
return await this._request(
|
70
|
+
new Request(url, {
|
71
|
+
method: 'GET',
|
72
|
+
headers: this._headers
|
73
|
+
})
|
74
|
+
)
|
75
|
+
}
|
76
|
+
|
77
|
+
public async sendDelete(): Promise<Response> {
|
78
|
+
const url = this._url
|
79
|
+
url.search = this._searchParams.toString()
|
80
|
+
return await this._request(
|
81
|
+
new Request(url, {
|
82
|
+
method: 'DELETE',
|
83
|
+
headers: this._headers
|
84
|
+
})
|
85
|
+
)
|
86
|
+
}
|
87
|
+
|
88
|
+
public async sendPut(body?: BodyInit | null | object): Promise<Response> {
|
89
|
+
const url = this._url
|
90
|
+
url.search = this._searchParams.toString()
|
91
|
+
if (body !== undefined && body !== null && typeof body === 'object') {
|
92
|
+
body = JSON.stringify(body)
|
93
|
+
}
|
94
|
+
return await this._request(
|
95
|
+
new Request(url, {
|
96
|
+
method: 'PUT',
|
97
|
+
headers: this._headers,
|
98
|
+
body
|
99
|
+
})
|
100
|
+
)
|
101
|
+
}
|
102
|
+
}
|
@@ -1,72 +1,132 @@
|
|
1
1
|
import { Service, type ServiceContext } from './service'
|
2
2
|
import { MiddlewareService } from './middlewareService'
|
3
|
+
import { RequestBuilder } from './requestBuilder'
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
/**
|
6
|
+
* Options for the RpcService.
|
7
|
+
*/
|
8
|
+
export interface RequestOptions {
|
9
|
+
searchParams?: Map<string, string>
|
10
|
+
headers?: [string, string][] | Record<string, string> | Headers
|
11
|
+
}
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
+
/**
|
14
|
+
* RPC service.
|
15
|
+
*/
|
16
|
+
export class RpcService extends Service {
|
17
|
+
constructor(
|
18
|
+
serviceContext: ServiceContext,
|
19
|
+
/**
|
20
|
+
* Host of the RPC service.
|
21
|
+
* It is not used if you use the `urlBuilder` option.
|
22
|
+
*/
|
23
|
+
public readonly host: string,
|
24
|
+
/**
|
25
|
+
* Options for the RpcService.
|
26
|
+
*/
|
27
|
+
private readonly options?: {
|
28
|
+
// make it possible to override the url builder
|
29
|
+
urlBuilder?: (path: string) => URL
|
30
|
+
// make it possible to override the fetch method
|
31
|
+
fetchMethod?: (uri: Request) => Promise<Response>
|
32
|
+
}
|
33
|
+
) {
|
34
|
+
super(serviceContext)
|
13
35
|
}
|
14
36
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
37
|
+
/**
|
38
|
+
* Request method.
|
39
|
+
*/
|
40
|
+
async request(req: Request): Promise<Response> {
|
41
|
+
const middlewareService = this.resolve(MiddlewareService)
|
42
|
+
if (middlewareService !== undefined) {
|
43
|
+
return await middlewareService.process(req, async req => {
|
44
|
+
return (await this.options?.fetchMethod?.(req)) ?? (await fetch(req))
|
19
45
|
})
|
20
|
-
|
46
|
+
}
|
47
|
+
return (await this.options?.fetchMethod?.(req)) ?? (await fetch(req))
|
21
48
|
}
|
22
49
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
50
|
+
/**
|
51
|
+
* Build URL.
|
52
|
+
* @param path
|
53
|
+
*/
|
54
|
+
buildUrl(path: string): URL {
|
55
|
+
if (this.options !== undefined && this.options.urlBuilder !== undefined) {
|
56
|
+
return this.options.urlBuilder(path)
|
57
|
+
}
|
58
|
+
if (this.host.endsWith('/') && path.startsWith('/')) {
|
59
|
+
return new URL(`${this.host}${path.slice(1)}`)
|
60
|
+
}
|
61
|
+
if (!this.host.endsWith('/') && !path.startsWith('/')) {
|
62
|
+
return new URL(`${this.host}/${path}`)
|
63
|
+
}
|
64
|
+
return new URL(`${this.host}${path}`)
|
30
65
|
}
|
31
66
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
)
|
67
|
+
/**
|
68
|
+
* Create a request builder.
|
69
|
+
* @param path
|
70
|
+
*/
|
71
|
+
requestBuilder(path: string): RequestBuilder {
|
72
|
+
return new RequestBuilder(this.buildUrl(path), this.request.bind(this))
|
39
73
|
}
|
40
74
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
75
|
+
/**
|
76
|
+
* Send a GET request.
|
77
|
+
* @param path
|
78
|
+
* @param options
|
79
|
+
*/
|
80
|
+
async get(path: string, options?: RequestOptions): Promise<Response> {
|
81
|
+
return this.requestBuilder(path)
|
82
|
+
.searchParams(options?.searchParams)
|
83
|
+
.headers(options?.headers)
|
84
|
+
.sendGet()
|
47
85
|
}
|
48
|
-
}
|
49
86
|
|
50
|
-
|
51
|
-
|
52
|
-
|
87
|
+
/**
|
88
|
+
* Send a POST request.
|
89
|
+
* @param path
|
90
|
+
* @param body
|
91
|
+
* @param options
|
92
|
+
*/
|
93
|
+
async post(
|
94
|
+
path: string,
|
95
|
+
body?: BodyInit | null,
|
96
|
+
options?: RequestOptions
|
97
|
+
): Promise<Response> {
|
98
|
+
return this.requestBuilder(path)
|
99
|
+
.searchParams(options?.searchParams)
|
100
|
+
.headers(options?.headers)
|
101
|
+
.sendPost(body)
|
53
102
|
}
|
54
103
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
104
|
+
/**
|
105
|
+
* Send a PUT request.
|
106
|
+
* @param path
|
107
|
+
* @param body
|
108
|
+
* @param options
|
109
|
+
*/
|
110
|
+
async put(
|
111
|
+
path: string,
|
112
|
+
body?: BodyInit | null,
|
113
|
+
options?: RequestOptions
|
114
|
+
): Promise<Response> {
|
115
|
+
return this.requestBuilder(path)
|
116
|
+
.searchParams(options?.searchParams)
|
117
|
+
.headers(options?.headers)
|
118
|
+
.sendPut(body)
|
64
119
|
}
|
65
120
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
121
|
+
/**
|
122
|
+
* Send a DELETE request.
|
123
|
+
* @param path
|
124
|
+
* @param options
|
125
|
+
*/
|
126
|
+
async delete(path: string, options?: RequestOptions): Promise<Response> {
|
127
|
+
return this.requestBuilder(path)
|
128
|
+
.searchParams(options?.searchParams)
|
129
|
+
.headers(options?.headers)
|
130
|
+
.sendDelete()
|
71
131
|
}
|
72
132
|
}
|
package/src/services/service.ts
CHANGED
@@ -0,0 +1,86 @@
|
|
1
|
+
import { Service } from './service'
|
2
|
+
import { RpcService } from './rpcService'
|
3
|
+
import { UserEvent, UserProfile } from '../storages/userProfile'
|
4
|
+
import { UserInfoResponse } from '../dto/userInfoResponse'
|
5
|
+
import { OrganizationService } from './organizationService'
|
6
|
+
|
7
|
+
class UserProfileImpl extends UserProfile {
|
8
|
+
private content?: UserInfoResponse
|
9
|
+
|
10
|
+
get id(): string {
|
11
|
+
if (this.content) {
|
12
|
+
return this.content.user.id
|
13
|
+
}
|
14
|
+
throw new Error('The profile is not loaded.')
|
15
|
+
}
|
16
|
+
|
17
|
+
get name(): string {
|
18
|
+
if (this.content) {
|
19
|
+
return this.content.user.profile.name
|
20
|
+
}
|
21
|
+
throw new Error('The profile is not loaded.')
|
22
|
+
}
|
23
|
+
|
24
|
+
get email(): string {
|
25
|
+
if (this.content) {
|
26
|
+
return this.content.user.profile.email
|
27
|
+
}
|
28
|
+
throw new Error('The profile is not loaded.')
|
29
|
+
}
|
30
|
+
|
31
|
+
get isDeleted(): boolean {
|
32
|
+
if (this.content) {
|
33
|
+
return this.content.user.isDeleted
|
34
|
+
}
|
35
|
+
throw new Error('The profile is not loaded.')
|
36
|
+
}
|
37
|
+
|
38
|
+
get createdAt(): Date {
|
39
|
+
if (this.content) {
|
40
|
+
return new Date(this.content.user.created_at)
|
41
|
+
}
|
42
|
+
throw new Error('The profile is not loaded.')
|
43
|
+
}
|
44
|
+
|
45
|
+
get modifiedAt(): Date {
|
46
|
+
if (this.content) {
|
47
|
+
return new Date(this.content.user.modified_at)
|
48
|
+
}
|
49
|
+
throw new Error('The profile is not loaded.')
|
50
|
+
}
|
51
|
+
|
52
|
+
initFrom(content: UserInfoResponse) {
|
53
|
+
this.content = content
|
54
|
+
this.dispatch({
|
55
|
+
type: UserEvent.CHANGED,
|
56
|
+
data: this
|
57
|
+
})
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
export class UserProfileService extends Service {
|
62
|
+
private readonly impl: UserProfileImpl = new UserProfileImpl()
|
63
|
+
|
64
|
+
get userProfile(): UserProfile {
|
65
|
+
return this.impl
|
66
|
+
}
|
67
|
+
|
68
|
+
async fetch(fireError: boolean = true) {
|
69
|
+
const rpc = this.resolve(RpcService) as RpcService
|
70
|
+
const response = await rpc.requestBuilder('api/v1/Users/self2').sendGet()
|
71
|
+
if (fireError && !response.ok) {
|
72
|
+
throw new Error('Failed to fetch user profile.')
|
73
|
+
}
|
74
|
+
const content = (await response.json()) as UserInfoResponse
|
75
|
+
this.impl.initFrom(content)
|
76
|
+
|
77
|
+
const organizationService = this.resolve(
|
78
|
+
OrganizationService
|
79
|
+
) as OrganizationService
|
80
|
+
organizationService.initFrom(
|
81
|
+
content.user.settings,
|
82
|
+
content.adminInOrganization,
|
83
|
+
content.organizations
|
84
|
+
)
|
85
|
+
}
|
86
|
+
}
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import { EventDispatcher } from '../events'
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Organization id.
|
5
|
+
*/
|
6
|
+
export type OrganizationId = string
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Organization.
|
10
|
+
*/
|
11
|
+
export abstract class Organization {
|
12
|
+
/**
|
13
|
+
* Organization id.
|
14
|
+
*/
|
15
|
+
abstract get id(): OrganizationId
|
16
|
+
|
17
|
+
/**
|
18
|
+
* Organization name.
|
19
|
+
*/
|
20
|
+
abstract get name(): string
|
21
|
+
|
22
|
+
/**
|
23
|
+
* Organization description.
|
24
|
+
*/
|
25
|
+
abstract get description(): string
|
26
|
+
}
|
27
|
+
|
28
|
+
/**
|
29
|
+
* Organization event.
|
30
|
+
*/
|
31
|
+
export enum OrganizationEvent {
|
32
|
+
ADDED = 'added',
|
33
|
+
REMOVED = 'removed',
|
34
|
+
CHANGED = 'changed',
|
35
|
+
CURRENT_CHANGED = 'currentChanged'
|
36
|
+
}
|
37
|
+
|
38
|
+
/**
|
39
|
+
* Organizations storage.
|
40
|
+
*/
|
41
|
+
export abstract class Organizations extends EventDispatcher<
|
42
|
+
OrganizationEvent,
|
43
|
+
Organization | Organizations
|
44
|
+
> {
|
45
|
+
/**
|
46
|
+
* User's organizations.
|
47
|
+
*/
|
48
|
+
abstract get collection(): ReadonlyArray<Organization>
|
49
|
+
|
50
|
+
/**
|
51
|
+
* Current organization.
|
52
|
+
*/
|
53
|
+
abstract get current(): OrganizationId
|
54
|
+
abstract set current(value: OrganizationId)
|
55
|
+
|
56
|
+
/**
|
57
|
+
* Get organization by id.
|
58
|
+
*/
|
59
|
+
abstract get(id: OrganizationId): Organization
|
60
|
+
|
61
|
+
/**
|
62
|
+
* Try to get organization by id.
|
63
|
+
* @param id
|
64
|
+
*/
|
65
|
+
abstract tryGet(id: OrganizationId): Organization | undefined
|
66
|
+
|
67
|
+
/**
|
68
|
+
* Create new organization.
|
69
|
+
*/
|
70
|
+
abstract create(name: string, description: string): Promise<Organization>
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Delete organization.
|
74
|
+
*/
|
75
|
+
abstract delete(id: OrganizationId): Promise<void>
|
76
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { EventDispatcher } from '../events'
|
2
|
+
|
3
|
+
export type UserId = string
|
4
|
+
|
5
|
+
export enum UserEvent {
|
6
|
+
CHANGED = 'changed'
|
7
|
+
}
|
8
|
+
|
9
|
+
export abstract class UserProfile extends EventDispatcher<
|
10
|
+
UserEvent,
|
11
|
+
UserProfile
|
12
|
+
> {
|
13
|
+
/**
|
14
|
+
* User id.
|
15
|
+
*/
|
16
|
+
abstract get id(): UserId
|
17
|
+
|
18
|
+
/**
|
19
|
+
* User name.
|
20
|
+
*/
|
21
|
+
abstract get name(): string
|
22
|
+
|
23
|
+
/**
|
24
|
+
* User email.
|
25
|
+
*/
|
26
|
+
abstract get email(): string
|
27
|
+
|
28
|
+
/**
|
29
|
+
* Is user deleted.
|
30
|
+
*/
|
31
|
+
abstract get isDeleted(): boolean
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Created at.
|
35
|
+
*/
|
36
|
+
abstract get createdAt(): Date
|
37
|
+
|
38
|
+
/**
|
39
|
+
* Modified at.
|
40
|
+
*/
|
41
|
+
abstract get modifiedAt(): Date
|
42
|
+
}
|