@appsemble/utils 0.24.10 → 0.24.13
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/README.md +3 -3
- package/api/components/schemas/App.js +5 -3
- package/api/components/schemas/TeamInviteActionDefinition.js +1 -1
- package/api/components/schemas/TeamJoinActionDefinition.js +1 -1
- package/api/components/schemas/UserPropertyDefinition.js +2 -0
- package/api/paths/apps.js +23 -0
- package/api/paths/user.js +1 -1
- package/package.json +2 -2
- package/validation.js +13 -0
- package/validation.test.js +90 -0
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
#  Appsemble Utilities
|
|
2
2
|
|
|
3
3
|
> Internal utility functions used across multiple Appsemble projects.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@appsemble/utils)
|
|
6
|
-
[](https://gitlab.com/appsemble/appsemble/-/releases/0.24.13)
|
|
7
7
|
[](https://prettier.io)
|
|
8
8
|
|
|
9
9
|
## Table of Contents
|
|
@@ -26,5 +26,5 @@ not guaranteed.
|
|
|
26
26
|
|
|
27
27
|
## License
|
|
28
28
|
|
|
29
|
-
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.24.
|
|
29
|
+
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.24.13/LICENSE.md) ©
|
|
30
30
|
[Appsemble](https://appsemble.com)
|
|
@@ -56,10 +56,12 @@ This doesn’t affect whether or not the app can be accessed on its own domain.
|
|
|
56
56
|
description: 'Whether or not people who have access to the app may see the app definition.',
|
|
57
57
|
},
|
|
58
58
|
locked: {
|
|
59
|
-
|
|
59
|
+
enum: ['fullLock', 'studioLock', 'unlocked'],
|
|
60
|
+
default: 'unlocked',
|
|
60
61
|
description: `Determines whether this app should be locked from being updated.
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
If this is set to \`fullLock\`, no changes can be made to the app,
|
|
63
|
+
if this is set to \`studioLock\`, no changes can be made from the studio but updating from the CLI is possible,
|
|
64
|
+
and to make any changes from the studio, this should be set to \`unlocked\`.
|
|
63
65
|
`,
|
|
64
66
|
},
|
|
65
67
|
template: {
|
|
@@ -7,7 +7,7 @@ export const TeamInviteActionDefinition = extendJSONSchema(BaseActionDefinition,
|
|
|
7
7
|
properties: {
|
|
8
8
|
type: {
|
|
9
9
|
enum: ['team.invite'],
|
|
10
|
-
description: '
|
|
10
|
+
description: 'Invite a user to join a team.',
|
|
11
11
|
},
|
|
12
12
|
id: {
|
|
13
13
|
description: 'The ID of the team to invite the user to.',
|
|
@@ -33,6 +33,8 @@ export const UserPropertyDefinition = {
|
|
|
33
33
|
properties: {
|
|
34
34
|
schema: {
|
|
35
35
|
anyOf: [
|
|
36
|
+
{ $ref: '#/components/schemas/JSONSchemaInteger' },
|
|
37
|
+
{ $ref: '#/components/schemas/JSONSchemaArray' },
|
|
36
38
|
{ $ref: '#/components/schemas/JSONSchemaString' },
|
|
37
39
|
{ $ref: '#/components/schemas/JSONSchemaNumber' },
|
|
38
40
|
{ $ref: '#/components/schemas/JSONSchemaEnum' },
|
package/api/paths/apps.js
CHANGED
|
@@ -563,6 +563,29 @@ export const paths = {
|
|
|
563
563
|
security: [{ app: ['openid'] }, {}],
|
|
564
564
|
},
|
|
565
565
|
},
|
|
566
|
+
'/api/apps/{appId}/demoMembers': {
|
|
567
|
+
parameters: [{ $ref: '#/components/parameters/appId' }],
|
|
568
|
+
get: {
|
|
569
|
+
tags: ['app'],
|
|
570
|
+
description: 'Fetch all demo members of an app.',
|
|
571
|
+
operationId: 'getDemoAppMembers',
|
|
572
|
+
responses: {
|
|
573
|
+
200: {
|
|
574
|
+
description: 'The list of demo app members.',
|
|
575
|
+
content: {
|
|
576
|
+
'application/json': {
|
|
577
|
+
schema: {
|
|
578
|
+
type: 'array',
|
|
579
|
+
items: {
|
|
580
|
+
$ref: '#/components/schemas/OrganizationMember',
|
|
581
|
+
},
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
},
|
|
585
|
+
},
|
|
586
|
+
},
|
|
587
|
+
},
|
|
588
|
+
},
|
|
566
589
|
'/api/apps/{appId}/members': {
|
|
567
590
|
parameters: [{ $ref: '#/components/parameters/appId' }],
|
|
568
591
|
get: {
|
package/api/paths/user.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appsemble/utils",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.13",
|
|
4
4
|
"description": "Utility functions used in Appsemble internally",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"app",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"test": "vitest"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@appsemble/types": "0.24.
|
|
40
|
+
"@appsemble/types": "0.24.13",
|
|
41
41
|
"axios": "^1.0.0",
|
|
42
42
|
"cron-parser": "^4.0.0",
|
|
43
43
|
"date-fns": "^2.0.0",
|
package/validation.js
CHANGED
|
@@ -76,6 +76,19 @@ function validateResourceSchemas(definition, report) {
|
|
|
76
76
|
}
|
|
77
77
|
const { schema } = resource;
|
|
78
78
|
const prefix = ['resources', resourceName, 'schema'];
|
|
79
|
+
const reservedKeywords = new Set([
|
|
80
|
+
'created',
|
|
81
|
+
'updated',
|
|
82
|
+
'author',
|
|
83
|
+
'editor',
|
|
84
|
+
'seed',
|
|
85
|
+
'ephemeral',
|
|
86
|
+
'clonable',
|
|
87
|
+
'expires',
|
|
88
|
+
]);
|
|
89
|
+
if (reservedKeywords.has(resourceName)) {
|
|
90
|
+
report(schema, 'is a reserved keyword', ['resources', resourceName]);
|
|
91
|
+
}
|
|
79
92
|
validateJSONSchema(schema, prefix, report);
|
|
80
93
|
if (!('type' in schema)) {
|
|
81
94
|
report(schema, 'must define type object', prefix);
|
package/validation.test.js
CHANGED
|
@@ -866,6 +866,96 @@ describe('validateAppDefinition', () => {
|
|
|
866
866
|
new ValidationError('does not exist in this app’s roles', 'Unknown', undefined, ['roles', 0]),
|
|
867
867
|
]);
|
|
868
868
|
});
|
|
869
|
+
it('should validate resource types against reserved keywords', async () => {
|
|
870
|
+
const app = {
|
|
871
|
+
name: 'Test app',
|
|
872
|
+
defaultPage: 'Test Page',
|
|
873
|
+
pages: [
|
|
874
|
+
{
|
|
875
|
+
name: 'Test Page',
|
|
876
|
+
blocks: [],
|
|
877
|
+
},
|
|
878
|
+
],
|
|
879
|
+
resources: {
|
|
880
|
+
created: {
|
|
881
|
+
schema: {
|
|
882
|
+
type: 'object',
|
|
883
|
+
properties: {
|
|
884
|
+
name: { type: 'string' },
|
|
885
|
+
},
|
|
886
|
+
},
|
|
887
|
+
},
|
|
888
|
+
updated: {
|
|
889
|
+
schema: {
|
|
890
|
+
type: 'object',
|
|
891
|
+
properties: {
|
|
892
|
+
name: { type: 'string' },
|
|
893
|
+
},
|
|
894
|
+
},
|
|
895
|
+
},
|
|
896
|
+
author: {
|
|
897
|
+
schema: {
|
|
898
|
+
type: 'object',
|
|
899
|
+
properties: {
|
|
900
|
+
name: { type: 'string' },
|
|
901
|
+
},
|
|
902
|
+
},
|
|
903
|
+
},
|
|
904
|
+
editor: {
|
|
905
|
+
schema: {
|
|
906
|
+
type: 'object',
|
|
907
|
+
properties: {
|
|
908
|
+
name: { type: 'string' },
|
|
909
|
+
},
|
|
910
|
+
},
|
|
911
|
+
},
|
|
912
|
+
seed: {
|
|
913
|
+
schema: {
|
|
914
|
+
type: 'object',
|
|
915
|
+
properties: {
|
|
916
|
+
name: { type: 'string' },
|
|
917
|
+
},
|
|
918
|
+
},
|
|
919
|
+
},
|
|
920
|
+
ephemeral: {
|
|
921
|
+
schema: {
|
|
922
|
+
type: 'object',
|
|
923
|
+
properties: {
|
|
924
|
+
name: { type: 'string' },
|
|
925
|
+
},
|
|
926
|
+
},
|
|
927
|
+
},
|
|
928
|
+
clonable: {
|
|
929
|
+
schema: {
|
|
930
|
+
type: 'object',
|
|
931
|
+
properties: {
|
|
932
|
+
name: { type: 'string' },
|
|
933
|
+
},
|
|
934
|
+
},
|
|
935
|
+
},
|
|
936
|
+
expires: {
|
|
937
|
+
schema: {
|
|
938
|
+
type: 'object',
|
|
939
|
+
properties: {
|
|
940
|
+
name: { type: 'string' },
|
|
941
|
+
},
|
|
942
|
+
},
|
|
943
|
+
},
|
|
944
|
+
},
|
|
945
|
+
};
|
|
946
|
+
const result = await validateAppDefinition(app, () => []);
|
|
947
|
+
expect(result.valid).toBe(false);
|
|
948
|
+
expect(result.errors).toStrictEqual([
|
|
949
|
+
new ValidationError('is a reserved keyword', { type: 'object', properties: { name: { type: 'string' } } }, undefined, ['resources', 'created']),
|
|
950
|
+
new ValidationError('is a reserved keyword', { type: 'object', properties: { name: { type: 'string' } } }, undefined, ['resources', 'updated']),
|
|
951
|
+
new ValidationError('is a reserved keyword', { type: 'object', properties: { name: { type: 'string' } } }, undefined, ['resources', 'author']),
|
|
952
|
+
new ValidationError('is a reserved keyword', { type: 'object', properties: { name: { type: 'string' } } }, undefined, ['resources', 'editor']),
|
|
953
|
+
new ValidationError('is a reserved keyword', { type: 'object', properties: { name: { type: 'string' } } }, undefined, ['resources', 'seed']),
|
|
954
|
+
new ValidationError('is a reserved keyword', { type: 'object', properties: { name: { type: 'string' } } }, undefined, ['resources', 'ephemeral']),
|
|
955
|
+
new ValidationError('is a reserved keyword', { type: 'object', properties: { name: { type: 'string' } } }, undefined, ['resources', 'clonable']),
|
|
956
|
+
new ValidationError('is a reserved keyword', { type: 'object', properties: { name: { type: 'string' } } }, undefined, ['resources', 'expires']),
|
|
957
|
+
]);
|
|
958
|
+
});
|
|
869
959
|
it('should validate the resource roles exist', async () => {
|
|
870
960
|
const app = createTestApp();
|
|
871
961
|
app.resources.person.roles = ['Unknown'];
|