@tellescope/schema 0.0.7 → 0.0.11
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/lib/cjs/schema.d.ts +163 -1
- package/lib/cjs/schema.d.ts.map +1 -1
- package/lib/cjs/schema.js +284 -168
- package/lib/cjs/schema.js.map +1 -1
- package/lib/esm/schema.d.ts +163 -1
- package/lib/esm/schema.d.ts.map +1 -1
- package/lib/esm/schema.js +286 -170
- package/lib/esm/schema.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -6
- package/src/schema.ts +487 -200
- package/tsconfig.json +1 -1
package/src/schema.ts
CHANGED
|
@@ -1,7 +1,33 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
ServerModelForName,
|
|
3
|
+
DatabaseModel,
|
|
4
|
+
DatabaseRecord,
|
|
5
|
+
Enduser,
|
|
6
|
+
ObjectId,
|
|
7
|
+
ModelName,
|
|
8
|
+
} from "@tellescope/types-server"
|
|
9
|
+
import {
|
|
10
|
+
ErrorInfo,
|
|
11
|
+
Indexable,
|
|
12
|
+
Operation,
|
|
13
|
+
JSONType,
|
|
14
|
+
CRUD,
|
|
15
|
+
HTTPMethod,
|
|
16
|
+
SessionType,
|
|
17
|
+
UserIdentity,
|
|
18
|
+
} from "@tellescope/types-utilities"
|
|
19
|
+
import {
|
|
20
|
+
EnduserSession,
|
|
21
|
+
ConfiguredSession,
|
|
22
|
+
JourneyState,
|
|
23
|
+
UserSession,
|
|
24
|
+
AttendeeInfo,
|
|
25
|
+
MeetingStatus,
|
|
26
|
+
} from "@tellescope/types-models"
|
|
3
27
|
|
|
4
28
|
import {
|
|
29
|
+
EscapeBuilder,
|
|
30
|
+
|
|
5
31
|
booleanValidator,
|
|
6
32
|
dateValidator,
|
|
7
33
|
emailValidator,
|
|
@@ -33,130 +59,143 @@ import {
|
|
|
33
59
|
stringValidator250,
|
|
34
60
|
stringValidator5000,
|
|
35
61
|
listOfDisplayNameInfo,
|
|
62
|
+
fileTypeValidator,
|
|
63
|
+
fileSizeValidator,
|
|
64
|
+
meetingStatusValidator,
|
|
65
|
+
listOfAttendeesValidator,
|
|
66
|
+
meetingInfoValidator,
|
|
67
|
+
listOfUserIndentitiesValidator,
|
|
68
|
+
attendeeInfoValidator,
|
|
69
|
+
listOfObjectAnyFieldsValidator,
|
|
70
|
+
meetingsListValidator,
|
|
36
71
|
} from "@tellescope/validation"
|
|
37
72
|
|
|
38
73
|
import {
|
|
39
74
|
CREATOR_ONLY_ACCESS,
|
|
40
75
|
DEFAULT_OPERATIONS,
|
|
41
76
|
PLACEHOLDER_ID,
|
|
77
|
+
ENDUSER_SESSION_TYPE,
|
|
42
78
|
} from "@tellescope/constants"
|
|
79
|
+
export type RelationshipConstraint<T> = {
|
|
80
|
+
explanation: string; // human readable, for documentation purposes
|
|
81
|
+
evaluate: (v: T, dependencies: Indexable<Partial<DatabaseModel>>, session: UserSession | EnduserSession) => string | void;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type DependencyAccessConstraint <T> = { type: 'dependency', foreignModel: ModelName, foreignField: string, accessField: keyof T }
|
|
85
|
+
|
|
86
|
+
export type AccessConstraint <T> = { type: 'creatorOnly' }
|
|
87
|
+
| { type: 'filter', field: string }
|
|
88
|
+
| DependencyAccessConstraint<T>
|
|
89
|
+
|
|
90
|
+
export type UniqueArrayConstraint <T> = { array: keyof T, itemKey?: string }
|
|
91
|
+
|
|
92
|
+
export type Constraint <T> = {
|
|
93
|
+
unique: (keyof T & string | UniqueArrayConstraint<T>)[];
|
|
94
|
+
globalUnique?: (keyof T)[];
|
|
95
|
+
relationship: RelationshipConstraint<Partial<T>>[];
|
|
96
|
+
access?: AccessConstraint<T>[];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export type Initializer <T, R> = (a: T, s: UserSession | EnduserSession) => R
|
|
100
|
+
|
|
101
|
+
export type EndpointOptions = {
|
|
102
|
+
// parameters used for endpoint that aren't stored in the model
|
|
103
|
+
parameters?: { [index: string]: EscapeBuilder<any> },
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export type DependencyDeletionAction = 'delete' | 'unset' | 'setNull' | 'nop'
|
|
107
|
+
export type DependecyRelationship = 'foreignKey' | 'value'
|
|
108
|
+
|
|
109
|
+
export type Dependency <T=DatabaseRecord> = {
|
|
110
|
+
dependsOn: ModelName[], // list of => OR, multiple dependency records => AND
|
|
111
|
+
dependencyField: string,
|
|
112
|
+
relationship: DependecyRelationship,
|
|
113
|
+
onDependencyDelete: DependencyDeletionAction,
|
|
114
|
+
getDependentValues?: (t: T) => JSONType[], // for accessing the values of a Dependency
|
|
115
|
+
filterByDependency?: (foreignValue: JSONType, foreignModel?: DatabaseModel) => { // for filtering against a Dependency
|
|
116
|
+
field: string,
|
|
117
|
+
value: JSONType | 'any',
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export type ModelFieldInfo <T, R> = {
|
|
122
|
+
validator: EscapeBuilder<R>,
|
|
123
|
+
readonly?: boolean,
|
|
124
|
+
required?: boolean,
|
|
125
|
+
updatesDisabled?: boolean,
|
|
126
|
+
examples?: JSONType[],
|
|
127
|
+
initializer?: Initializer<Partial<T>, R>, // should include the required fields of T, not just partial
|
|
128
|
+
dependencies?: Dependency<Partial<T>>[],
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export type ModelFields<T> = {
|
|
132
|
+
[K in keyof T]: ModelFieldInfo<T, T[K]>
|
|
133
|
+
}
|
|
134
|
+
export type extractFields<Type> = Type extends ModelFields<infer X> ? X : never
|
|
43
135
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
// description?: string,
|
|
108
|
-
// notes?: string[],
|
|
109
|
-
// warnings?: string[],
|
|
110
|
-
// }
|
|
111
|
-
|
|
112
|
-
// type CustomAction <P=any, R=any> = {
|
|
113
|
-
// op: Operation | 'custom',
|
|
114
|
-
// access: CRUD,
|
|
115
|
-
// // parameters: InputValidation<P>,
|
|
116
|
-
// parameters: ModelFields<P>,
|
|
117
|
-
// returns: ModelFields<R>,
|
|
118
|
-
// path?: string,
|
|
119
|
-
// method?: HTTPMethod,
|
|
120
|
-
// } & ActionInfo
|
|
121
|
-
|
|
122
|
-
// type CustomActionsForModel = {
|
|
123
|
-
// [K in ModelName]: { [index: string]: CustomAction }
|
|
124
|
-
// }
|
|
125
|
-
|
|
126
|
-
// type ReadFilter <T> = { [K in keyof T]?: { required: boolean } }
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// // m is the original model (or undefined, if create)
|
|
130
|
-
// // allows for easier event handling based on specific updates (by comparing args to pre-update model)
|
|
131
|
-
// type SideEffectHandler <T, O=any> = (args: Partial<T>[], m: (Partial<T> | undefined)[] | undefined, n: (Partial<T> & { _id: ObjectId })[], s: ConfiguredSession, o: O) => Promise<ErrorInfo[]>;
|
|
132
|
-
|
|
133
|
-
// type SideEffect = {
|
|
134
|
-
// name: string;
|
|
135
|
-
// description: string;
|
|
136
|
-
// }
|
|
137
|
-
|
|
138
|
-
// export type Model<T, N extends ModelName> = {
|
|
139
|
-
// info: {
|
|
140
|
-
// name?: string,
|
|
141
|
-
// description?: string,
|
|
142
|
-
// sideEffects?: { [K in Operation]?: SideEffect[] }
|
|
143
|
-
// },
|
|
144
|
-
// fields: ModelFields<T>,
|
|
145
|
-
// constraints: Constraint<T>,
|
|
146
|
-
// defaultActions: { [K in Operation]?: ActionInfo },
|
|
147
|
-
// customActions: CustomActionsForModel[N],
|
|
148
|
-
// readFilter?: ReadFilter<T>,
|
|
149
|
-
// options?: {
|
|
150
|
-
// create?: EndpointOptions,
|
|
151
|
-
// }
|
|
152
|
-
// }
|
|
153
|
-
// type extractModelType<Type> = Type extends Model<infer T, infer N> ? T : never
|
|
154
|
-
|
|
155
|
-
// type DatabaseModelForName = ToServerModels<ModelForName>
|
|
156
|
-
|
|
157
|
-
// type Schema = {
|
|
158
|
-
// [N in keyof DatabaseModelForName]: Model<DatabaseModelForName[N], ModelName>
|
|
159
|
-
// }
|
|
136
|
+
type ArgumentInfo = {
|
|
137
|
+
description?: string;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
type ActionInfo = {
|
|
141
|
+
name?: string,
|
|
142
|
+
description?: string,
|
|
143
|
+
notes?: string[],
|
|
144
|
+
warnings?: string[],
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
type CustomAction <P=any, R=any> = {
|
|
148
|
+
op: Operation | 'custom',
|
|
149
|
+
access: CRUD,
|
|
150
|
+
// parameters: InputValidation<P>,
|
|
151
|
+
parameters: ModelFields<P>,
|
|
152
|
+
returns: R extends Array<any> ? ModelFieldInfo<any, R> : ModelFields<R>,
|
|
153
|
+
path?: string,
|
|
154
|
+
method?: HTTPMethod,
|
|
155
|
+
enduserOnly?: boolean,
|
|
156
|
+
} & ActionInfo
|
|
157
|
+
|
|
158
|
+
export type EnduserAction = {
|
|
159
|
+
field?: string,
|
|
160
|
+
} & ActionInfo
|
|
161
|
+
|
|
162
|
+
type CustomActionsForModel = {
|
|
163
|
+
[K in ModelName]: { [index: string]: CustomAction }
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
type ReadFilter <T> = { [K in keyof T]?: { required: boolean } }
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
// m is the original model (or undefined, if create)
|
|
170
|
+
// allows for easier event handling based on specific updates (by comparing args to pre-update model)
|
|
171
|
+
export type SideEffectHandler <T, O=any> = (args: Partial<T>[], m: (Partial<T> | undefined)[] | undefined, n: (Partial<T> & { _id: ObjectId })[], s: UserSession | EnduserSession, o: O) => Promise<ErrorInfo[]>;
|
|
172
|
+
|
|
173
|
+
type SideEffect = {
|
|
174
|
+
name: string;
|
|
175
|
+
description: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export type Model<T, N extends ModelName> = {
|
|
179
|
+
info: {
|
|
180
|
+
name?: string,
|
|
181
|
+
description?: string,
|
|
182
|
+
sideEffects?: { [K in Operation]?: SideEffect[] }
|
|
183
|
+
},
|
|
184
|
+
fields: ModelFields<T>,
|
|
185
|
+
constraints: Constraint<T>,
|
|
186
|
+
defaultActions: { [k in Operation]?: ActionInfo },
|
|
187
|
+
enduserActions?: { [index: string]: EnduserAction },
|
|
188
|
+
customActions: CustomActionsForModel[N],
|
|
189
|
+
readFilter?: ReadFilter<T>,
|
|
190
|
+
options?: {
|
|
191
|
+
create?: EndpointOptions,
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
export type extractModelType<Type> = Type extends Model<infer T, infer N> ? T : never
|
|
195
|
+
|
|
196
|
+
export type Schema = {
|
|
197
|
+
[N in keyof ServerModelForName]: Model<ServerModelForName[N], ModelName>
|
|
198
|
+
}
|
|
160
199
|
|
|
161
200
|
const sideEffects = {
|
|
162
201
|
trackJourneyEngagement: {
|
|
@@ -203,7 +242,11 @@ export type BuiltInFields_T = typeof BuiltInFields
|
|
|
203
242
|
export type CustomActions = {
|
|
204
243
|
api_keys: {
|
|
205
244
|
create: CustomAction<{}, { id: string, key: string}>,
|
|
206
|
-
}
|
|
245
|
+
},
|
|
246
|
+
files: {
|
|
247
|
+
prepare_file_upload: CustomAction<{ name: string, size: number, type: string }, { presignedUpload: object, file: File }>,
|
|
248
|
+
file_download_URL: CustomAction<{ secureName: string }, { downloadURL: string }>,
|
|
249
|
+
},
|
|
207
250
|
journeys: {
|
|
208
251
|
update_state: CustomAction<{ updates: JourneyState, id: string, name: string }, {}>,
|
|
209
252
|
},
|
|
@@ -219,7 +262,14 @@ export type CustomActions = {
|
|
|
219
262
|
users: {
|
|
220
263
|
display_names: CustomAction<{ }, { fname: string, lname: string, id: string }[]>,
|
|
221
264
|
refresh_session: CustomAction<{}, { user: UserSession, authToken: string }>,
|
|
222
|
-
}
|
|
265
|
+
},
|
|
266
|
+
meetings: {
|
|
267
|
+
start_meeting: CustomAction<{ }, { id: string, meeting: object, host: AttendeeInfo }>,
|
|
268
|
+
end_meeting: CustomAction<{ id: string }, { }>,
|
|
269
|
+
add_attendees_to_meeting: CustomAction<{ id: string, attendees: UserIdentity[] }, { }>,
|
|
270
|
+
my_meetings: CustomAction<{}, { id: string, updatedAt: string, status: MeetingStatus }[]>
|
|
271
|
+
attendee_info: CustomAction<{ id: string }, { attendee: AttendeeInfo, others: UserIdentity[] }>,
|
|
272
|
+
},
|
|
223
273
|
}
|
|
224
274
|
|
|
225
275
|
export type PublicActions = {
|
|
@@ -246,72 +296,26 @@ export const schema: SchemaV1 = {
|
|
|
246
296
|
update: [sideEffects.trackJourneyEngagement],
|
|
247
297
|
}
|
|
248
298
|
},
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
},
|
|
261
|
-
is_authenticated: {
|
|
262
|
-
op: "custom", access: 'read', method: "get",
|
|
263
|
-
name: 'Check enduser authentication',
|
|
264
|
-
path: '/enduser-is-authenticated',
|
|
265
|
-
description: "Checks the validity of an enduser's authToken",
|
|
266
|
-
parameters: {
|
|
267
|
-
id: { validator: mongoIdStringValidator, required: true },
|
|
268
|
-
authToken: { validator: stringValidator5000, required: true },
|
|
269
|
-
},
|
|
270
|
-
returns: {
|
|
271
|
-
isAuthenticated: { validator: booleanValidator, required: true },
|
|
272
|
-
enduser: { validator: 'enduser' },
|
|
273
|
-
} as any // add enduser eventually, when validator defined
|
|
274
|
-
},
|
|
275
|
-
refresh_session: {
|
|
276
|
-
op: "custom", access: 'update', method: "post",
|
|
277
|
-
name: 'Refresh enduser authentication',
|
|
278
|
-
path: '/refresh-enduser-session',
|
|
279
|
-
description: "When called by an authenticated enduser, generates a new session",
|
|
280
|
-
parameters: { },
|
|
281
|
-
enduserOnly: true,
|
|
282
|
-
returns: {
|
|
283
|
-
authToken: { validator: stringValidator, required: true },
|
|
284
|
-
enduser: { validator: 'enduser' },
|
|
285
|
-
} as any // add enduser eventually, when validator defined
|
|
286
|
-
},
|
|
287
|
-
logout: {
|
|
288
|
-
op: "custom", access: 'update', method: "post",
|
|
289
|
-
name: 'Logout enduser',
|
|
290
|
-
path: '/logout-enduser',
|
|
291
|
-
description: "Logs out an enduser",
|
|
292
|
-
parameters: {},
|
|
293
|
-
returns: {},
|
|
294
|
-
},
|
|
299
|
+
constraints: {
|
|
300
|
+
unique: ['email', 'phone', 'externalId'],
|
|
301
|
+
relationship: [
|
|
302
|
+
{
|
|
303
|
+
explanation: 'One of email or phone is required',
|
|
304
|
+
evaluate: ({ email, phone }) => {
|
|
305
|
+
if (!(email || phone))
|
|
306
|
+
return 'One of email or phone is required'
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
],
|
|
295
310
|
},
|
|
311
|
+
defaultActions: DEFAULT_OPERATIONS,
|
|
296
312
|
enduserActions: { logout: {}, refresh_session: {} },
|
|
297
|
-
publicActions: {
|
|
298
|
-
login: {
|
|
299
|
-
op: "custom", access: 'read', method: "post",
|
|
300
|
-
name: 'Login enduser',
|
|
301
|
-
path: '/login-enduser',
|
|
302
|
-
description: "Generates an authentication token for access to enduser-facing endpoints",
|
|
303
|
-
enduserOnly: true, // implemented as authenticate in enduser sdk only
|
|
304
|
-
parameters: {
|
|
305
|
-
id: { validator: mongoIdStringValidator },
|
|
306
|
-
password: { validator: stringValidator100, required: true }, // required until optional challenge token available
|
|
307
|
-
phone: { validator: phoneValidator },
|
|
308
|
-
email: { validator: emailValidator },
|
|
309
|
-
},
|
|
310
|
-
returns: { authToken: { validator: stringValidator5000 } },
|
|
311
|
-
},
|
|
312
|
-
},
|
|
313
313
|
fields: {
|
|
314
314
|
...BuiltInFields,
|
|
315
|
+
externalId: {
|
|
316
|
+
validator: stringValidator250,
|
|
317
|
+
examples: ['addfed3e-ddea-415b-b52b-df820c944dbb'],
|
|
318
|
+
},
|
|
315
319
|
email: {
|
|
316
320
|
validator: emailValidator,
|
|
317
321
|
examples: ['test@tellescope.com'],
|
|
@@ -374,23 +378,84 @@ export const schema: SchemaV1 = {
|
|
|
374
378
|
lastCommunication: {
|
|
375
379
|
validator: dateValidator,
|
|
376
380
|
},
|
|
381
|
+
avatar: {
|
|
382
|
+
validator: stringValidator100,
|
|
383
|
+
dependencies: [
|
|
384
|
+
{
|
|
385
|
+
dependsOn: ['files'],
|
|
386
|
+
dependencyField: 'secureName',
|
|
387
|
+
relationship: 'foreignKey',
|
|
388
|
+
onDependencyDelete: 'unset',
|
|
389
|
+
},
|
|
390
|
+
]
|
|
391
|
+
},
|
|
377
392
|
// recentMessagePreview: {
|
|
378
393
|
// validator: stringValidator,
|
|
379
394
|
// },
|
|
380
395
|
},
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
396
|
+
customActions: {
|
|
397
|
+
set_password: {
|
|
398
|
+
op: "custom", access: 'update', method: "post",
|
|
399
|
+
name: 'Set enduser password',
|
|
400
|
+
path: '/set-enduser-password',
|
|
401
|
+
description: "Sets (or resets) an enduser's password. Minimum length 8 characters.",
|
|
402
|
+
parameters: {
|
|
403
|
+
id: { validator: mongoIdStringValidator, required: true },
|
|
404
|
+
password: { validator: stringValidator100, required: true },
|
|
405
|
+
},
|
|
406
|
+
returns: { } //authToken: { validator: stringValidator5000 } },
|
|
407
|
+
},
|
|
408
|
+
is_authenticated: {
|
|
409
|
+
op: "custom", access: 'read', method: "get",
|
|
410
|
+
name: 'Check enduser authentication',
|
|
411
|
+
path: '/enduser-is-authenticated',
|
|
412
|
+
description: "Checks the validity of an enduser's authToken",
|
|
413
|
+
parameters: {
|
|
414
|
+
id: { validator: mongoIdStringValidator, required: true },
|
|
415
|
+
authToken: { validator: stringValidator5000, required: true },
|
|
416
|
+
},
|
|
417
|
+
returns: {
|
|
418
|
+
isAuthenticated: { validator: booleanValidator, required: true },
|
|
419
|
+
enduser: { validator: 'enduser' },
|
|
420
|
+
} as any // todo: add enduser eventually, when validator defined
|
|
421
|
+
},
|
|
422
|
+
refresh_session: {
|
|
423
|
+
op: "custom", access: 'update', method: "post",
|
|
424
|
+
name: 'Refresh enduser authentication',
|
|
425
|
+
path: '/refresh-enduser-session',
|
|
426
|
+
description: "When called by an authenticated enduser, generates a new session",
|
|
427
|
+
parameters: { },
|
|
428
|
+
enduserOnly: true,
|
|
429
|
+
returns: {
|
|
430
|
+
authToken: { validator: stringValidator, required: true },
|
|
431
|
+
enduser: { validator: 'enduser' },
|
|
432
|
+
} as any // todo: add enduser eventually, when validator defined
|
|
433
|
+
},
|
|
434
|
+
logout: {
|
|
435
|
+
op: "custom", access: 'update', method: "post",
|
|
436
|
+
name: 'Logout enduser',
|
|
437
|
+
path: '/logout-enduser',
|
|
438
|
+
description: "Logs out an enduser",
|
|
439
|
+
parameters: {},
|
|
440
|
+
returns: {},
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
publicActions: {
|
|
444
|
+
login: {
|
|
445
|
+
op: "custom", access: 'read', method: "post",
|
|
446
|
+
name: 'Login enduser',
|
|
447
|
+
path: '/login-enduser',
|
|
448
|
+
description: "Generates an authentication token for access to enduser-facing endpoints",
|
|
449
|
+
enduserOnly: true, // implemented as authenticate in enduser sdk only
|
|
450
|
+
parameters: {
|
|
451
|
+
id: { validator: mongoIdStringValidator },
|
|
452
|
+
password: { validator: stringValidator100, required: true }, // required until optional challenge token available
|
|
453
|
+
phone: { validator: phoneValidator },
|
|
454
|
+
email: { validator: emailValidator },
|
|
455
|
+
},
|
|
456
|
+
returns: { authToken: { validator: stringValidator5000 } },
|
|
457
|
+
},
|
|
392
458
|
},
|
|
393
|
-
defaultActions: DEFAULT_OPERATIONS,
|
|
394
459
|
},
|
|
395
460
|
api_keys: {
|
|
396
461
|
info: {},
|
|
@@ -608,7 +673,7 @@ export const schema: SchemaV1 = {
|
|
|
608
673
|
validator: mongoIdStringValidator,
|
|
609
674
|
examples: [PLACEHOLDER_ID],
|
|
610
675
|
readonly: true,
|
|
611
|
-
initializer: (a, s) => (s as UserSession).
|
|
676
|
+
initializer: (a, s) => (s as UserSession).id,
|
|
612
677
|
},
|
|
613
678
|
subject: {
|
|
614
679
|
validator: stringValidator,
|
|
@@ -728,7 +793,7 @@ export const schema: SchemaV1 = {
|
|
|
728
793
|
businessUserId: {
|
|
729
794
|
validator: mongoIdStringValidator,
|
|
730
795
|
readonly: true, // default to only self-sending, for now
|
|
731
|
-
initializer: (a, s) => (s as UserSession).
|
|
796
|
+
initializer: (a, s) => (s as UserSession).id,
|
|
732
797
|
dependencies: [{
|
|
733
798
|
dependsOn: ['users'],
|
|
734
799
|
dependencyField: '_id',
|
|
@@ -764,7 +829,7 @@ export const schema: SchemaV1 = {
|
|
|
764
829
|
chat_rooms: {
|
|
765
830
|
info: {},
|
|
766
831
|
constraints: {
|
|
767
|
-
unique: [{ array: 'userIds' }],
|
|
832
|
+
unique: [{ array: 'userIds' }, { array: 'enduserIds' }],
|
|
768
833
|
relationship: [],
|
|
769
834
|
access: [
|
|
770
835
|
{ type: 'filter', field: 'userIds' },
|
|
@@ -805,7 +870,13 @@ export const schema: SchemaV1 = {
|
|
|
805
870
|
validator: mongoIdStringValidator,
|
|
806
871
|
initializer: () => '',
|
|
807
872
|
readonly: true,
|
|
808
|
-
}
|
|
873
|
+
},
|
|
874
|
+
ticketId: {
|
|
875
|
+
validator: mongoIdStringValidator,
|
|
876
|
+
},
|
|
877
|
+
endedAt: {
|
|
878
|
+
validator: dateValidator,
|
|
879
|
+
},
|
|
809
880
|
},
|
|
810
881
|
defaultActions: DEFAULT_OPERATIONS,
|
|
811
882
|
enduserActions: { create: {}, read: {}, readMany: {} },
|
|
@@ -845,7 +916,7 @@ export const schema: SchemaV1 = {
|
|
|
845
916
|
senderId: {
|
|
846
917
|
validator: mongoIdStringValidator,
|
|
847
918
|
readonly: true, // create a separate endpoint for storing enduser chats
|
|
848
|
-
initializer: (a, s) => (s as UserSession).
|
|
919
|
+
initializer: (a, s) => (s as UserSession).id ?? (s as EnduserSession).id,
|
|
849
920
|
examples: [PLACEHOLDER_ID],
|
|
850
921
|
dependencies: [{ // can be userId or enduserId
|
|
851
922
|
dependsOn: ['users', 'endusers'],
|
|
@@ -939,6 +1010,20 @@ export const schema: SchemaV1 = {
|
|
|
939
1010
|
roles: {
|
|
940
1011
|
validator: listOfStringsValidator,
|
|
941
1012
|
},
|
|
1013
|
+
skills: {
|
|
1014
|
+
validator: listOfStringsValidator,
|
|
1015
|
+
},
|
|
1016
|
+
avatar: {
|
|
1017
|
+
validator: stringValidator100,
|
|
1018
|
+
dependencies: [
|
|
1019
|
+
{
|
|
1020
|
+
dependsOn: ['files'],
|
|
1021
|
+
dependencyField: 'secureName',
|
|
1022
|
+
relationship: 'foreignKey',
|
|
1023
|
+
onDependencyDelete: 'unset',
|
|
1024
|
+
},
|
|
1025
|
+
]
|
|
1026
|
+
},
|
|
942
1027
|
}
|
|
943
1028
|
},
|
|
944
1029
|
templates: {
|
|
@@ -971,5 +1056,207 @@ export const schema: SchemaV1 = {
|
|
|
971
1056
|
initializer: () => 'enduser'
|
|
972
1057
|
},
|
|
973
1058
|
}
|
|
974
|
-
}
|
|
1059
|
+
},
|
|
1060
|
+
files: {
|
|
1061
|
+
info: {},
|
|
1062
|
+
constraints: { unique: [], relationship: [] },
|
|
1063
|
+
defaultActions: { read: {}, readMany: {}, update: {} },
|
|
1064
|
+
fields: {
|
|
1065
|
+
...BuiltInFields,
|
|
1066
|
+
name: {
|
|
1067
|
+
validator: stringValidator250,
|
|
1068
|
+
required: true,
|
|
1069
|
+
},
|
|
1070
|
+
size: {
|
|
1071
|
+
validator: fileSizeValidator,
|
|
1072
|
+
required: true,
|
|
1073
|
+
},
|
|
1074
|
+
type: {
|
|
1075
|
+
validator: fileTypeValidator,
|
|
1076
|
+
required: true
|
|
1077
|
+
},
|
|
1078
|
+
secureName: {
|
|
1079
|
+
validator: stringValidator250,
|
|
1080
|
+
readonly: true,
|
|
1081
|
+
},
|
|
1082
|
+
},
|
|
1083
|
+
enduserActions: { prepare_file_upload: {} },
|
|
1084
|
+
customActions: {
|
|
1085
|
+
prepare_file_upload: {
|
|
1086
|
+
op: "custom", access: 'create', method: "post",
|
|
1087
|
+
name: 'Prepare File Upload',
|
|
1088
|
+
path: '/prepare-file-upload',
|
|
1089
|
+
description: "Generates an upload link for a file, storing metadata as a File record.",
|
|
1090
|
+
parameters: {
|
|
1091
|
+
name: {
|
|
1092
|
+
validator: stringValidator250,
|
|
1093
|
+
required: true,
|
|
1094
|
+
},
|
|
1095
|
+
size: {
|
|
1096
|
+
validator: fileSizeValidator,
|
|
1097
|
+
required: true,
|
|
1098
|
+
},
|
|
1099
|
+
type: {
|
|
1100
|
+
validator: fileTypeValidator,
|
|
1101
|
+
required: true
|
|
1102
|
+
},
|
|
1103
|
+
},
|
|
1104
|
+
returns: {
|
|
1105
|
+
presignedUpload: {
|
|
1106
|
+
validator: objectAnyFieldsValidator,
|
|
1107
|
+
},
|
|
1108
|
+
file: {
|
|
1109
|
+
validator: 'file' as any, // todo: add file validator
|
|
1110
|
+
},
|
|
1111
|
+
},
|
|
1112
|
+
},
|
|
1113
|
+
file_download_URL: {
|
|
1114
|
+
op: "custom", access: 'read', method: "get",
|
|
1115
|
+
name: 'Generate File Download',
|
|
1116
|
+
path: '/file-download-link',
|
|
1117
|
+
description: "Generates a temporary download link for a file.",
|
|
1118
|
+
parameters: {
|
|
1119
|
+
secureName: { validator: stringValidator250 },
|
|
1120
|
+
},
|
|
1121
|
+
returns: {
|
|
1122
|
+
downloadURL: { validator: stringValidator250 },
|
|
1123
|
+
},
|
|
1124
|
+
},
|
|
1125
|
+
},
|
|
1126
|
+
},
|
|
1127
|
+
tickets: {
|
|
1128
|
+
info: {},
|
|
1129
|
+
constraints: {
|
|
1130
|
+
unique: [],
|
|
1131
|
+
relationship: [
|
|
1132
|
+
{
|
|
1133
|
+
explanation: 'When created by an enduser, enduserId must match their id',
|
|
1134
|
+
evaluate: ({ enduserId },_,session) => {
|
|
1135
|
+
if (session.type === ENDUSER_SESSION_TYPE && session.id !== enduserId)
|
|
1136
|
+
return "enduserId does not match creator id for enduser session"
|
|
1137
|
+
}
|
|
1138
|
+
},
|
|
1139
|
+
],
|
|
1140
|
+
},
|
|
1141
|
+
defaultActions: DEFAULT_OPERATIONS,
|
|
1142
|
+
customActions: {},
|
|
1143
|
+
enduserActions: { create: {}, read: {}, readMany: {} },
|
|
1144
|
+
fields: {
|
|
1145
|
+
...BuiltInFields,
|
|
1146
|
+
title: {
|
|
1147
|
+
validator: stringValidator100,
|
|
1148
|
+
required: true,
|
|
1149
|
+
examples: ["Ticket Name"],
|
|
1150
|
+
},
|
|
1151
|
+
enduserId: {
|
|
1152
|
+
validator: mongoIdStringValidator,
|
|
1153
|
+
required: true,
|
|
1154
|
+
examples: [PLACEHOLDER_ID],
|
|
1155
|
+
},
|
|
1156
|
+
closedAt: {
|
|
1157
|
+
validator: dateValidator,
|
|
1158
|
+
},
|
|
1159
|
+
owner: {
|
|
1160
|
+
validator: mongoIdStringValidator,
|
|
1161
|
+
},
|
|
1162
|
+
message: {
|
|
1163
|
+
validator: stringValidator5000,
|
|
1164
|
+
examples: ["Message"],
|
|
1165
|
+
},
|
|
1166
|
+
type: {
|
|
1167
|
+
validator: stringValidator100,
|
|
1168
|
+
},
|
|
1169
|
+
skillsRequired: {
|
|
1170
|
+
validator: listOfStringsValidator,
|
|
1171
|
+
},
|
|
1172
|
+
}
|
|
1173
|
+
},
|
|
1174
|
+
meetings: {
|
|
1175
|
+
info: {},
|
|
1176
|
+
constraints: {
|
|
1177
|
+
unique: [],
|
|
1178
|
+
relationship: [],
|
|
1179
|
+
},
|
|
1180
|
+
defaultActions: { },
|
|
1181
|
+
customActions: {
|
|
1182
|
+
start_meeting: {
|
|
1183
|
+
op: "custom", access: 'create', method: "post",
|
|
1184
|
+
name: 'Start Meeting',
|
|
1185
|
+
path: '/start-meeting',
|
|
1186
|
+
description: "Generates an video meeting room",
|
|
1187
|
+
parameters: { },
|
|
1188
|
+
returns: {
|
|
1189
|
+
id: {
|
|
1190
|
+
validator: mongoIdStringValidator,
|
|
1191
|
+
},
|
|
1192
|
+
meeting: {
|
|
1193
|
+
validator: objectAnyFieldsValidator,
|
|
1194
|
+
},
|
|
1195
|
+
host: {
|
|
1196
|
+
validator: attendeeInfoValidator,
|
|
1197
|
+
},
|
|
1198
|
+
},
|
|
1199
|
+
},
|
|
1200
|
+
end_meeting: {
|
|
1201
|
+
op: "custom", access: 'update', method: "post",
|
|
1202
|
+
name: "End Meeting",
|
|
1203
|
+
path: '/end-meeting',
|
|
1204
|
+
description: "Ends a video meeting",
|
|
1205
|
+
parameters: { id: { validator: mongoIdStringValidator } },
|
|
1206
|
+
returns: { },
|
|
1207
|
+
},
|
|
1208
|
+
add_attendees_to_meeting: {
|
|
1209
|
+
op: "custom", access: 'update', method: "post",
|
|
1210
|
+
name: 'Add Attendees to Meeting',
|
|
1211
|
+
path: '/add-attendees-to-meeting',
|
|
1212
|
+
description: "Adds other attendees to a meeting",
|
|
1213
|
+
parameters: {
|
|
1214
|
+
id: { validator: mongoIdStringValidator },
|
|
1215
|
+
attendees: { validator: listOfUserIndentitiesValidator },
|
|
1216
|
+
},
|
|
1217
|
+
returns: { },
|
|
1218
|
+
},
|
|
1219
|
+
attendee_info: {
|
|
1220
|
+
op: "custom", access: 'read', method: "get",
|
|
1221
|
+
name: 'Get attendee info for meeting',
|
|
1222
|
+
path: '/attendee-info',
|
|
1223
|
+
description: "Gets meeting info for the current user, and details about other attendees",
|
|
1224
|
+
parameters: {
|
|
1225
|
+
id: { validator: mongoIdStringValidator },
|
|
1226
|
+
},
|
|
1227
|
+
returns: {
|
|
1228
|
+
attendee: { validator: attendeeInfoValidator },
|
|
1229
|
+
others: { validator: listOfUserIndentitiesValidator },
|
|
1230
|
+
},
|
|
1231
|
+
},
|
|
1232
|
+
my_meetings: {
|
|
1233
|
+
op: "custom", access: 'read', method: "get",
|
|
1234
|
+
name: 'Get list of meetings',
|
|
1235
|
+
path: '/my-meetings',
|
|
1236
|
+
description: "Gets meetings for the current user.",
|
|
1237
|
+
parameters: {
|
|
1238
|
+
id: { validator: mongoIdStringValidator },
|
|
1239
|
+
},
|
|
1240
|
+
returns: { validator: meetingsListValidator },
|
|
1241
|
+
}
|
|
1242
|
+
},
|
|
1243
|
+
enduserActions: { my_meetings: {} },
|
|
1244
|
+
fields: {
|
|
1245
|
+
...BuiltInFields,
|
|
1246
|
+
// all fields are updatable by custom endpoints only
|
|
1247
|
+
status: {
|
|
1248
|
+
validator: meetingStatusValidator,
|
|
1249
|
+
readonly: true,
|
|
1250
|
+
initializer: () => 'scheduled',
|
|
1251
|
+
},
|
|
1252
|
+
attendees: {
|
|
1253
|
+
validator: listOfAttendeesValidator,
|
|
1254
|
+
readonly: true,
|
|
1255
|
+
},
|
|
1256
|
+
meetingInfo: {
|
|
1257
|
+
validator: meetingInfoValidator,
|
|
1258
|
+
readonly: true
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
},
|
|
975
1262
|
}
|