@smartive/graphql-magic 1.0.1
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/.eslintrc +21 -0
- package/.github/workflows/release.yml +24 -0
- package/.github/workflows/testing.yml +37 -0
- package/.nvmrc +1 -0
- package/.prettierignore +34 -0
- package/.prettierrc.json +1 -0
- package/.releaserc +27 -0
- package/CHANGELOG.md +6 -0
- package/README.md +15 -0
- package/dist/cjs/index.cjs +2646 -0
- package/dist/esm/client/gql.d.ts +1 -0
- package/dist/esm/client/gql.js +5 -0
- package/dist/esm/client/gql.js.map +1 -0
- package/dist/esm/client/index.d.ts +2 -0
- package/dist/esm/client/index.js +4 -0
- package/dist/esm/client/index.js.map +1 -0
- package/dist/esm/client/queries.d.ts +24 -0
- package/dist/esm/client/queries.js +152 -0
- package/dist/esm/client/queries.js.map +1 -0
- package/dist/esm/context.d.ts +30 -0
- package/dist/esm/context.js +2 -0
- package/dist/esm/context.js.map +1 -0
- package/dist/esm/errors.d.ts +17 -0
- package/dist/esm/errors.js +27 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/generate/generate.d.ts +7 -0
- package/dist/esm/generate/generate.js +211 -0
- package/dist/esm/generate/generate.js.map +1 -0
- package/dist/esm/generate/index.d.ts +3 -0
- package/dist/esm/generate/index.js +5 -0
- package/dist/esm/generate/index.js.map +1 -0
- package/dist/esm/generate/mutations.d.ts +2 -0
- package/dist/esm/generate/mutations.js +18 -0
- package/dist/esm/generate/mutations.js.map +1 -0
- package/dist/esm/generate/utils.d.ts +22 -0
- package/dist/esm/generate/utils.js +150 -0
- package/dist/esm/generate/utils.js.map +1 -0
- package/dist/esm/index.d.ts +10 -0
- package/dist/esm/index.js +12 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/migrations/generate.d.ts +28 -0
- package/dist/esm/migrations/generate.js +516 -0
- package/dist/esm/migrations/generate.js.map +1 -0
- package/dist/esm/migrations/index.d.ts +1 -0
- package/dist/esm/migrations/index.js +3 -0
- package/dist/esm/migrations/index.js.map +1 -0
- package/dist/esm/models.d.ts +170 -0
- package/dist/esm/models.js +27 -0
- package/dist/esm/models.js.map +1 -0
- package/dist/esm/permissions/check.d.ts +15 -0
- package/dist/esm/permissions/check.js +162 -0
- package/dist/esm/permissions/check.js.map +1 -0
- package/dist/esm/permissions/generate.d.ts +45 -0
- package/dist/esm/permissions/generate.js +77 -0
- package/dist/esm/permissions/generate.js.map +1 -0
- package/dist/esm/permissions/index.d.ts +2 -0
- package/dist/esm/permissions/index.js +4 -0
- package/dist/esm/permissions/index.js.map +1 -0
- package/dist/esm/resolvers/arguments.d.ts +26 -0
- package/dist/esm/resolvers/arguments.js +88 -0
- package/dist/esm/resolvers/arguments.js.map +1 -0
- package/dist/esm/resolvers/filters.d.ts +5 -0
- package/dist/esm/resolvers/filters.js +126 -0
- package/dist/esm/resolvers/filters.js.map +1 -0
- package/dist/esm/resolvers/index.d.ts +7 -0
- package/dist/esm/resolvers/index.js +9 -0
- package/dist/esm/resolvers/index.js.map +1 -0
- package/dist/esm/resolvers/mutations.d.ts +3 -0
- package/dist/esm/resolvers/mutations.js +255 -0
- package/dist/esm/resolvers/mutations.js.map +1 -0
- package/dist/esm/resolvers/node.d.ts +44 -0
- package/dist/esm/resolvers/node.js +102 -0
- package/dist/esm/resolvers/node.js.map +1 -0
- package/dist/esm/resolvers/resolver.d.ts +5 -0
- package/dist/esm/resolvers/resolver.js +143 -0
- package/dist/esm/resolvers/resolver.js.map +1 -0
- package/dist/esm/resolvers/resolvers.d.ts +9 -0
- package/dist/esm/resolvers/resolvers.js +39 -0
- package/dist/esm/resolvers/resolvers.js.map +1 -0
- package/dist/esm/resolvers/utils.d.ts +43 -0
- package/dist/esm/resolvers/utils.js +125 -0
- package/dist/esm/resolvers/utils.js.map +1 -0
- package/dist/esm/utils.d.ts +25 -0
- package/dist/esm/utils.js +159 -0
- package/dist/esm/utils.js.map +1 -0
- package/dist/esm/values.d.ts +15 -0
- package/dist/esm/values.js +7 -0
- package/dist/esm/values.js.map +1 -0
- package/jest.config.ts +12 -0
- package/package.json +66 -0
- package/renovate.json +32 -0
- package/src/client/gql.ts +7 -0
- package/src/client/index.ts +4 -0
- package/src/client/queries.ts +251 -0
- package/src/context.ts +27 -0
- package/src/errors.ts +32 -0
- package/src/generate/generate.ts +273 -0
- package/src/generate/index.ts +5 -0
- package/src/generate/mutations.ts +35 -0
- package/src/generate/utils.ts +223 -0
- package/src/index.ts +12 -0
- package/src/migrations/generate.ts +633 -0
- package/src/migrations/index.ts +3 -0
- package/src/models.ts +228 -0
- package/src/permissions/check.ts +239 -0
- package/src/permissions/generate.ts +143 -0
- package/src/permissions/index.ts +4 -0
- package/src/resolvers/arguments.ts +129 -0
- package/src/resolvers/filters.ts +163 -0
- package/src/resolvers/index.ts +9 -0
- package/src/resolvers/mutations.ts +313 -0
- package/src/resolvers/node.ts +193 -0
- package/src/resolvers/resolver.ts +223 -0
- package/src/resolvers/resolvers.ts +40 -0
- package/src/resolvers/utils.ts +188 -0
- package/src/utils.ts +186 -0
- package/src/values.ts +19 -0
- package/tests/unit/__snapshots__/generate.spec.ts.snap +105 -0
- package/tests/unit/__snapshots__/resolve.spec.ts.snap +60 -0
- package/tests/unit/generate.spec.ts +8 -0
- package/tests/unit/resolve.spec.ts +128 -0
- package/tests/unit/utils.ts +82 -0
- package/tsconfig.jest.json +13 -0
- package/tsconfig.json +13 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import type { Context } from './context';
|
|
2
|
+
import type { OrderBy } from './resolvers/arguments';
|
|
3
|
+
import type { Directive, Value } from './values';
|
|
4
|
+
export type RawModels = RawModel[];
|
|
5
|
+
export type RawModel = ScalarModel | EnumModel | RawEnumModel | InterfaceModel | ObjectModel | RawObjectModel | JsonObjectModel;
|
|
6
|
+
type BaseModel = {
|
|
7
|
+
name: string;
|
|
8
|
+
plural?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
};
|
|
11
|
+
export type ScalarModel = BaseModel & {
|
|
12
|
+
type: 'scalar';
|
|
13
|
+
};
|
|
14
|
+
export type EnumModel = BaseModel & {
|
|
15
|
+
type: 'enum';
|
|
16
|
+
values: string[];
|
|
17
|
+
deleted?: true;
|
|
18
|
+
};
|
|
19
|
+
export type RawEnumModel = BaseModel & {
|
|
20
|
+
type: 'raw-enum';
|
|
21
|
+
values: string[];
|
|
22
|
+
};
|
|
23
|
+
export type InterfaceModel = BaseModel & {
|
|
24
|
+
type: 'interface';
|
|
25
|
+
fields: ModelField[];
|
|
26
|
+
};
|
|
27
|
+
export type RawObjectModel = BaseModel & {
|
|
28
|
+
type: 'raw-object';
|
|
29
|
+
fields: ModelField[];
|
|
30
|
+
rawFilters?: {
|
|
31
|
+
name: string;
|
|
32
|
+
type: string;
|
|
33
|
+
list?: boolean;
|
|
34
|
+
nonNull?: boolean;
|
|
35
|
+
}[];
|
|
36
|
+
};
|
|
37
|
+
export type JsonObjectModel = BaseModel & {
|
|
38
|
+
type: 'json-object';
|
|
39
|
+
json: true;
|
|
40
|
+
fields: Pick<ModelField, 'type' | 'name' | 'nonNull'>[];
|
|
41
|
+
};
|
|
42
|
+
export type Entity = Record<string, any>;
|
|
43
|
+
export type Action = 'create' | 'update' | 'delete' | 'restore';
|
|
44
|
+
export type MutationHook = (model: Model, action: Action, when: 'before' | 'after', data: {
|
|
45
|
+
prev: Entity;
|
|
46
|
+
input: Entity;
|
|
47
|
+
normalizedInput: Entity;
|
|
48
|
+
next: Entity;
|
|
49
|
+
}, ctx: Context) => Promise<void>;
|
|
50
|
+
export type ObjectModel = BaseModel & {
|
|
51
|
+
type: 'object';
|
|
52
|
+
interfaces?: string[];
|
|
53
|
+
nonStrict?: boolean;
|
|
54
|
+
queriable?: boolean;
|
|
55
|
+
listQueriable?: boolean;
|
|
56
|
+
creatable?: boolean;
|
|
57
|
+
updatable?: boolean;
|
|
58
|
+
deletable?: boolean;
|
|
59
|
+
displayField?: string;
|
|
60
|
+
defaultOrderBy?: OrderBy;
|
|
61
|
+
fields: ModelField[];
|
|
62
|
+
deleted?: true;
|
|
63
|
+
oldName?: string;
|
|
64
|
+
};
|
|
65
|
+
export type InputObject = {
|
|
66
|
+
name: string;
|
|
67
|
+
type: string;
|
|
68
|
+
nonNull?: boolean;
|
|
69
|
+
};
|
|
70
|
+
export declare const isObjectModel: (model: RawModel) => model is ObjectModel;
|
|
71
|
+
export declare const isEnumModel: (model: RawModel) => model is EnumModel;
|
|
72
|
+
export declare const isRawEnumModel: (model: RawModel) => model is RawEnumModel;
|
|
73
|
+
export declare const isScalarModel: (model: RawModel) => model is ScalarModel;
|
|
74
|
+
export declare const isRawObjectModel: (model: RawModel) => model is RawObjectModel;
|
|
75
|
+
export declare const isJsonObjectModel: (model: RawModel) => model is RawObjectModel;
|
|
76
|
+
export declare const isEnumList: (models: RawModels, field: ModelField) => boolean;
|
|
77
|
+
export declare const and: (...predicates: ((field: ModelField) => boolean)[]) => (field: ModelField) => boolean;
|
|
78
|
+
export declare const not: (predicate: (field: ModelField) => boolean) => (field: ModelField) => boolean;
|
|
79
|
+
export declare const isRelation: ({ relation }: ModelField) => boolean;
|
|
80
|
+
export type VisibleRelationsByRole = Record<string, Record<string, string[]>>;
|
|
81
|
+
export declare const isVisibleRelation: (visibleRelationsByRole: VisibleRelationsByRole, modelName: string, role: string) => ({ name }: Field) => boolean;
|
|
82
|
+
export declare const isToOneRelation: ({ toOne }: ModelField) => boolean;
|
|
83
|
+
export declare const isQueriableField: ({ queriable }: ModelField) => boolean;
|
|
84
|
+
export declare const isRaw: ({ raw }: ModelField) => boolean;
|
|
85
|
+
export declare const isVisible: ({ hidden }: ModelField) => boolean;
|
|
86
|
+
export declare const isSimpleField: (field: ModelField) => boolean;
|
|
87
|
+
export declare const isUpdatable: ({ updatable }: ModelField) => boolean;
|
|
88
|
+
export declare const isCreatable: ({ creatable }: ModelField) => boolean;
|
|
89
|
+
export declare const isQueriableBy: (role: string) => (field: ModelField) => boolean;
|
|
90
|
+
export declare const isUpdatableBy: (role: string) => (field: ModelField) => boolean;
|
|
91
|
+
export declare const isCreatableBy: (role: string) => (field: ModelField) => boolean;
|
|
92
|
+
export declare const actionableRelations: (model: Model, action: 'create' | 'update' | 'filter') => ModelField[];
|
|
93
|
+
export type Field = {
|
|
94
|
+
name: string;
|
|
95
|
+
type: string;
|
|
96
|
+
default?: Value;
|
|
97
|
+
list?: boolean;
|
|
98
|
+
nonNull?: boolean;
|
|
99
|
+
args?: Field[];
|
|
100
|
+
directives?: Directive[];
|
|
101
|
+
};
|
|
102
|
+
export type ModelField = Field & {
|
|
103
|
+
primary?: boolean;
|
|
104
|
+
unique?: boolean;
|
|
105
|
+
filterable?: boolean;
|
|
106
|
+
defaultFilter?: Value;
|
|
107
|
+
searchable?: boolean;
|
|
108
|
+
possibleValues?: Value[];
|
|
109
|
+
orderable?: boolean;
|
|
110
|
+
comparable?: boolean;
|
|
111
|
+
relation?: boolean;
|
|
112
|
+
onDelete?: 'cascade' | 'set-null';
|
|
113
|
+
reverse?: string;
|
|
114
|
+
toOne?: boolean;
|
|
115
|
+
foreignKey?: string;
|
|
116
|
+
queriable?: false;
|
|
117
|
+
queriableBy?: string[];
|
|
118
|
+
creatable?: boolean;
|
|
119
|
+
creatableBy?: string[];
|
|
120
|
+
updatable?: boolean;
|
|
121
|
+
updatableBy?: string[];
|
|
122
|
+
generated?: boolean;
|
|
123
|
+
raw?: boolean;
|
|
124
|
+
json?: boolean;
|
|
125
|
+
dateTimeType?: 'year' | 'date' | 'datetime' | 'year_and_month';
|
|
126
|
+
stringType?: 'email' | 'url' | 'phone';
|
|
127
|
+
floatType?: 'currency' | 'percentage';
|
|
128
|
+
unit?: 'million';
|
|
129
|
+
intType?: 'currency';
|
|
130
|
+
min?: number;
|
|
131
|
+
max?: number;
|
|
132
|
+
tooltip?: string;
|
|
133
|
+
description?: string;
|
|
134
|
+
large?: true;
|
|
135
|
+
maxLength?: number;
|
|
136
|
+
double?: boolean;
|
|
137
|
+
precision?: number;
|
|
138
|
+
scale?: number;
|
|
139
|
+
defaultValue?: string | number | ReadonlyArray<string> | undefined;
|
|
140
|
+
endOfDay?: boolean;
|
|
141
|
+
obfuscate?: true;
|
|
142
|
+
required?: boolean;
|
|
143
|
+
indent?: boolean;
|
|
144
|
+
hidden?: boolean;
|
|
145
|
+
deleted?: true;
|
|
146
|
+
oldName?: string;
|
|
147
|
+
};
|
|
148
|
+
export type Models = Model[];
|
|
149
|
+
export type Model = ObjectModel & {
|
|
150
|
+
fieldsByName: Record<string, ModelField>;
|
|
151
|
+
relations: Relation[];
|
|
152
|
+
relationsByName: Record<string, Relation>;
|
|
153
|
+
reverseRelations: ReverseRelation[];
|
|
154
|
+
reverseRelationsByName: Record<string, ReverseRelation>;
|
|
155
|
+
};
|
|
156
|
+
export type Relation = {
|
|
157
|
+
field: ModelField;
|
|
158
|
+
model: Model;
|
|
159
|
+
reverseRelation: ReverseRelation;
|
|
160
|
+
};
|
|
161
|
+
export type ReverseRelation = {
|
|
162
|
+
name: string;
|
|
163
|
+
type: string;
|
|
164
|
+
foreignKey: string;
|
|
165
|
+
toOne: boolean;
|
|
166
|
+
model: Model;
|
|
167
|
+
field: ModelField;
|
|
168
|
+
fieldModel: Model;
|
|
169
|
+
};
|
|
170
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const isObjectModel = (model) => model.type === 'object';
|
|
2
|
+
export const isEnumModel = (model) => model.type === 'enum';
|
|
3
|
+
export const isRawEnumModel = (model) => model.type === 'raw-enum';
|
|
4
|
+
export const isScalarModel = (model) => model.type === 'scalar';
|
|
5
|
+
export const isRawObjectModel = (model) => model.type === 'raw-object';
|
|
6
|
+
export const isJsonObjectModel = (model) => model.type === 'json-object';
|
|
7
|
+
export const isEnumList = (models, field) => field?.list === true && models.find(({ name }) => name === field.type)?.type === 'enum';
|
|
8
|
+
export const and = (...predicates) => (field) => predicates.every((predicate) => predicate(field));
|
|
9
|
+
export const not = (predicate) => (field) => !predicate(field);
|
|
10
|
+
export const isRelation = ({ relation }) => !!relation;
|
|
11
|
+
export const isVisibleRelation = (visibleRelationsByRole, modelName, role) => {
|
|
12
|
+
const whitelist = visibleRelationsByRole[role]?.[modelName];
|
|
13
|
+
return ({ name }) => (whitelist ? whitelist.includes(name) : true);
|
|
14
|
+
};
|
|
15
|
+
export const isToOneRelation = ({ toOne }) => !!toOne;
|
|
16
|
+
export const isQueriableField = ({ queriable }) => queriable !== false;
|
|
17
|
+
export const isRaw = ({ raw }) => !!raw;
|
|
18
|
+
export const isVisible = ({ hidden }) => hidden !== true;
|
|
19
|
+
export const isSimpleField = and(not(isRelation), not(isRaw));
|
|
20
|
+
export const isUpdatable = ({ updatable }) => !!updatable;
|
|
21
|
+
export const isCreatable = ({ creatable }) => !!creatable;
|
|
22
|
+
export const isQueriableBy = (role) => (field) => isQueriableField(field) && (!field.queriableBy || field.queriableBy.includes(role));
|
|
23
|
+
export const isUpdatableBy = (role) => (field) => isUpdatable(field) && (!field.updatableBy || field.updatableBy.includes(role));
|
|
24
|
+
export const isCreatableBy = (role) => (field) => isCreatable(field) && (!field.creatableBy || field.creatableBy.includes(role));
|
|
25
|
+
export const actionableRelations = (model, action) => model.fields.filter(({ relation, ...field }) => relation &&
|
|
26
|
+
field[`${action === 'filter' ? action : action.slice(0, -1)}able`]);
|
|
27
|
+
//# sourceMappingURL=models.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/models.ts"],"names":[],"mappings":"AA+EA,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAe,EAAwB,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;AAEhG,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAe,EAAsB,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC;AAE1F,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAe,EAAyB,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC;AAEpG,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAe,EAAwB,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;AAEhG,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAe,EAA2B,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC;AAE1G,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAe,EAA2B,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC;AAE5G,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAAiB,EAAE,KAAiB,EAAE,EAAE,CACjE,KAAK,EAAE,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,KAAK,MAAM,CAAC;AAE1F,MAAM,CAAC,MAAM,GAAG,GACd,CAAC,GAAG,UAA8C,EAAE,EAAE,CACtD,CAAC,KAAiB,EAAE,EAAE,CACpB,UAAU,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;AAEtD,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,SAAyC,EAAE,EAAE,CAAC,CAAC,KAAiB,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAE3G,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EAAE,QAAQ,EAAc,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;AAInE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,sBAA8C,EAAE,SAAiB,EAAE,IAAY,EAAE,EAAE;IACnH,MAAM,SAAS,GAAG,sBAAsB,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;IAC5D,OAAO,CAAC,EAAE,IAAI,EAAS,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAC5E,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,EAAE,KAAK,EAAc,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AAElE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,EAAE,SAAS,EAAc,EAAE,EAAE,CAAC,SAAS,KAAK,KAAK,CAAC;AAEnF,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAE,GAAG,EAAc,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;AAEpD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,EAAE,MAAM,EAAc,EAAE,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC;AAErE,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AAE9D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EAAE,SAAS,EAAc,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAEtE,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EAAE,SAAS,EAAc,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAEtE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,KAAiB,EAAE,EAAE,CACnE,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAEtF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,KAAiB,EAAE,EAAE,CACnE,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAEjF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,KAAiB,EAAE,EAAE,CACnE,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAEjF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,KAAY,EAAE,MAAsC,EAAE,EAAE,CAC1F,KAAK,CAAC,MAAM,CAAC,MAAM,CACjB,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,CACzB,QAAQ;IACR,KAAK,CAAC,GAAG,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAkD,CAAC,CACjH,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Knex } from 'knex';
|
|
2
|
+
import { FullContext } from '../context';
|
|
3
|
+
import { Model } from '../models';
|
|
4
|
+
import { BasicValue } from '../values';
|
|
5
|
+
import { PermissionAction, PermissionStack } from './generate';
|
|
6
|
+
export declare const getPermissionStack: (ctx: Pick<FullContext, 'permissions' | 'user'>, type: string, action: PermissionAction) => boolean | PermissionStack;
|
|
7
|
+
export declare const applyPermissions: (ctx: Pick<FullContext, 'models' | 'permissions' | 'user' | 'knex'>, type: string, tableAlias: string, query: Knex.QueryBuilder, action: PermissionAction, verifiedPermissionStack?: PermissionStack) => boolean | PermissionStack;
|
|
8
|
+
/**
|
|
9
|
+
* Check whether entity as currently in db can be mutated (update or delete)
|
|
10
|
+
*/
|
|
11
|
+
export declare const getEntityToMutate: (ctx: Pick<FullContext, 'models' | 'permissions' | 'user' | 'knex'>, model: Model, where: Record<string, BasicValue>, action: 'UPDATE' | 'DELETE' | 'RESTORE') => Promise<any>;
|
|
12
|
+
/**
|
|
13
|
+
* Check whether given data can be written to db (insert or update)
|
|
14
|
+
*/
|
|
15
|
+
export declare const checkCanWrite: (ctx: Pick<FullContext, 'models' | 'permissions' | 'user' | 'knex'>, model: Model, data: Record<string, BasicValue>, action: 'CREATE' | 'UPDATE') => Promise<void>;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { NotFoundError, PermissionError } from '../errors';
|
|
2
|
+
import { AliasGenerator, hash, ors } from '../resolvers/utils';
|
|
3
|
+
import { get, getModelPlural, summonByName } from '../utils';
|
|
4
|
+
export const getPermissionStack = (ctx, type, action) => {
|
|
5
|
+
const rolePermissions = ctx.permissions[ctx.user.role];
|
|
6
|
+
if (typeof rolePermissions === 'boolean' || rolePermissions === undefined) {
|
|
7
|
+
return !!rolePermissions;
|
|
8
|
+
}
|
|
9
|
+
const typePermissions = rolePermissions[type];
|
|
10
|
+
if (typeof typePermissions === 'boolean' || typePermissions === undefined) {
|
|
11
|
+
return !!typePermissions;
|
|
12
|
+
}
|
|
13
|
+
const actionPermission = typePermissions[action];
|
|
14
|
+
if (typeof actionPermission === 'boolean' || actionPermission === undefined) {
|
|
15
|
+
return !!actionPermission;
|
|
16
|
+
}
|
|
17
|
+
return actionPermission;
|
|
18
|
+
};
|
|
19
|
+
export const applyPermissions = (ctx, type, tableAlias, query, action, verifiedPermissionStack) => {
|
|
20
|
+
const permissionStack = getPermissionStack(ctx, type, action);
|
|
21
|
+
if (permissionStack === true) {
|
|
22
|
+
return permissionStack;
|
|
23
|
+
}
|
|
24
|
+
if (permissionStack === false) {
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
|
|
26
|
+
query.where(false);
|
|
27
|
+
return permissionStack;
|
|
28
|
+
}
|
|
29
|
+
if (verifiedPermissionStack?.every((prefixChain) => permissionStack.some((chain) => hash(prefixChain) === hash(chain.slice(0, -1)) &&
|
|
30
|
+
// TODO: this is stricter than it could be if we add these checks to the query
|
|
31
|
+
!('where' in get(chain, chain.length - 1)) &&
|
|
32
|
+
!('me' in get(chain, chain.length - 1))))) {
|
|
33
|
+
// The user has access to a parent entity with one or more from a set of rules, all of which are inherited by this entity
|
|
34
|
+
// No need for additional checks
|
|
35
|
+
return permissionStack;
|
|
36
|
+
}
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
|
|
38
|
+
ors(query, permissionStack.map((links) => (query) => query
|
|
39
|
+
.whereNull(`${tableAlias}.id`)
|
|
40
|
+
.orWhereExists((subQuery) => permissionLinkQuery(ctx, subQuery, links, ctx.knex.raw(`"${tableAlias}".id`)))));
|
|
41
|
+
return permissionStack;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Check whether entity as currently in db can be mutated (update or delete)
|
|
45
|
+
*/
|
|
46
|
+
export const getEntityToMutate = async (ctx, model, where, action) => {
|
|
47
|
+
const query = ctx.knex(model.name).where(where).first();
|
|
48
|
+
let entity = await query.clone();
|
|
49
|
+
if (!entity) {
|
|
50
|
+
throw new NotFoundError('Entity to mutate');
|
|
51
|
+
}
|
|
52
|
+
applyPermissions(ctx, model.name, model.name, query, action);
|
|
53
|
+
entity = await query;
|
|
54
|
+
if (!entity) {
|
|
55
|
+
throw new PermissionError(action, `this ${model.name}`);
|
|
56
|
+
}
|
|
57
|
+
return entity;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Check whether given data can be written to db (insert or update)
|
|
61
|
+
*/
|
|
62
|
+
export const checkCanWrite = async (ctx, model, data, action) => {
|
|
63
|
+
const permissionStack = getPermissionStack(ctx, model.name, action);
|
|
64
|
+
if (permissionStack === true) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (permissionStack === false) {
|
|
68
|
+
throw new PermissionError(action, getModelPlural(model));
|
|
69
|
+
}
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- using `select(1 as any)` to instantiate an "empty" query builder
|
|
71
|
+
const query = ctx.knex.select(1).first();
|
|
72
|
+
let linked = false;
|
|
73
|
+
for (const field of model.fields
|
|
74
|
+
.filter(({ relation }) => relation)
|
|
75
|
+
.filter((field) => field.generated || (action === 'CREATE' ? field.creatable : field.updatable))) {
|
|
76
|
+
const foreignKey = field.foreignKey || `${field.name}Id`;
|
|
77
|
+
const foreignId = data[foreignKey];
|
|
78
|
+
if (!foreignId) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const fieldPermissions = field[action === 'CREATE' ? 'creatableBy' : 'updatableBy'];
|
|
82
|
+
if (fieldPermissions && !fieldPermissions.includes(ctx.user.role)) {
|
|
83
|
+
throw new PermissionError(action, `this ${model.name}'s ${field.name}`);
|
|
84
|
+
}
|
|
85
|
+
linked = true;
|
|
86
|
+
const fieldPermissionStack = getPermissionStack(ctx, field.type, 'LINK');
|
|
87
|
+
if (fieldPermissionStack === true) {
|
|
88
|
+
// User can link any entity from this type, just check whether it exists
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
|
|
90
|
+
query.whereExists((subQuery) => subQuery.from(`${field.type} as a`).whereRaw(`a.id = ?`, foreignId));
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (fieldPermissionStack === false || !fieldPermissionStack.length) {
|
|
94
|
+
throw new PermissionError(action, `this ${model.name}'s ${field.name}`);
|
|
95
|
+
}
|
|
96
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
|
|
97
|
+
ors(query, fieldPermissionStack.map((links) => (query) => query.whereExists((subQuery) => permissionLinkQuery(ctx, subQuery, links, foreignId))));
|
|
98
|
+
}
|
|
99
|
+
if (linked) {
|
|
100
|
+
const canMutate = await query;
|
|
101
|
+
if (!canMutate) {
|
|
102
|
+
throw new PermissionError(action, `this ${model.name} because there are no entities you can link it to`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else if (action === 'CREATE') {
|
|
106
|
+
throw new PermissionError(action, `this ${model.name} because there are no entity types you can link it to`);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const permissionLinkQuery = (ctx, subQuery, links, id) => {
|
|
110
|
+
const aliases = new AliasGenerator();
|
|
111
|
+
let alias = aliases.getShort();
|
|
112
|
+
const { type, me, where } = links[0];
|
|
113
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
|
|
114
|
+
subQuery.from(`${type} as ${alias}`);
|
|
115
|
+
if (me) {
|
|
116
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
|
|
117
|
+
subQuery.where({ [`${alias}.id`]: ctx.user.id });
|
|
118
|
+
}
|
|
119
|
+
if (where) {
|
|
120
|
+
applyWhere(summonByName(ctx.models, type), subQuery, alias, where, aliases);
|
|
121
|
+
}
|
|
122
|
+
for (const { type, foreignKey, reverse, where } of links) {
|
|
123
|
+
const model = summonByName(ctx.models, type);
|
|
124
|
+
const subAlias = aliases.getShort();
|
|
125
|
+
if (reverse) {
|
|
126
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
|
|
127
|
+
subQuery.leftJoin(`${type} as ${subAlias}`, `${alias}.${foreignKey || 'id'}`, `${subAlias}.id`);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
|
|
131
|
+
subQuery.rightJoin(`${type} as ${subAlias}`, `${alias}.id`, `${subAlias}.${foreignKey || 'id'}`);
|
|
132
|
+
}
|
|
133
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
|
|
134
|
+
subQuery.where({ [`${subAlias}.deleted`]: false });
|
|
135
|
+
if (where) {
|
|
136
|
+
applyWhere(model, subQuery, subAlias, where, aliases);
|
|
137
|
+
}
|
|
138
|
+
alias = subAlias;
|
|
139
|
+
}
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
|
|
141
|
+
subQuery.whereRaw(`"${alias}".id = ?`, id);
|
|
142
|
+
};
|
|
143
|
+
const applyWhere = (model, query, alias, where, aliases) => {
|
|
144
|
+
for (const [key, value] of Object.entries(where)) {
|
|
145
|
+
const relation = model.relationsByName[key];
|
|
146
|
+
if (relation) {
|
|
147
|
+
const subAlias = aliases.getShort();
|
|
148
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
|
|
149
|
+
query.leftJoin(`${relation.model.name} as ${subAlias}`, `${alias}.${relation.field.foreignKey || `${relation.field.name}Id`}`, `${subAlias}.id`);
|
|
150
|
+
applyWhere(relation.model, query, subAlias, value, aliases);
|
|
151
|
+
}
|
|
152
|
+
else if (Array.isArray(value)) {
|
|
153
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
|
|
154
|
+
query.whereIn(`${alias}.${key}`, value);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
|
|
158
|
+
query.where({ [`${alias}.${key}`]: value });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/permissions/check.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE3D,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAI7D,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,GAA8C,EAC9C,IAAY,EACZ,MAAwB,EACG,EAAE;IAC7B,MAAM,eAAe,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvD,IAAI,OAAO,eAAe,KAAK,SAAS,IAAI,eAAe,KAAK,SAAS,EAAE;QACzE,OAAO,CAAC,CAAC,eAAe,CAAC;KAC1B;IAED,MAAM,eAAe,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,OAAO,eAAe,KAAK,SAAS,IAAI,eAAe,KAAK,SAAS,EAAE;QACzE,OAAO,CAAC,CAAC,eAAe,CAAC;KAC1B;IAED,MAAM,gBAAgB,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IACjD,IAAI,OAAO,gBAAgB,KAAK,SAAS,IAAI,gBAAgB,KAAK,SAAS,EAAE;QAC3E,OAAO,CAAC,CAAC,gBAAgB,CAAC;KAC3B;IAED,OAAO,gBAAgB,CAAC;AAC1B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,GAAkE,EAClE,IAAY,EACZ,UAAkB,EAClB,KAAwB,EACxB,MAAwB,EACxB,uBAAyC,EACd,EAAE;IAC7B,MAAM,eAAe,GAAG,kBAAkB,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAE9D,IAAI,eAAe,KAAK,IAAI,EAAE;QAC5B,OAAO,eAAe,CAAC;KACxB;IAED,IAAI,eAAe,KAAK,KAAK,EAAE;QAC7B,wGAAwG;QACxG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACnB,OAAO,eAAe,CAAC;KACxB;IAED,IACE,uBAAuB,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,EAAE,CAC7C,eAAe,CAAC,IAAI,CAClB,CAAC,KAAK,EAAE,EAAE,CACR,IAAI,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9C,8EAA8E;QAC9E,CAAC,CAAC,OAAO,IAAI,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC1C,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAC1C,CACF,EACD;QACA,yHAAyH;QACzH,gCAAgC;QAChC,OAAO,eAAe,CAAC;KACxB;IAED,wGAAwG;IACxG,GAAG,CACD,KAAK,EACL,eAAe,CAAC,GAAG,CACjB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,CACnB,KAAK;SACF,SAAS,CAAC,GAAG,UAAU,KAAK,CAAC;SAC7B,aAAa,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,mBAAmB,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,UAAU,MAAM,CAAC,CAAC,CAAC,CAChH,CACF,CAAC;IAEF,OAAO,eAAe,CAAC;AACzB,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EACpC,GAAkE,EAClE,KAAY,EACZ,KAAiC,EACjC,MAAuC,EACvC,EAAE;IACF,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;IACxD,IAAI,MAAM,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;IAEjC,IAAI,CAAC,MAAM,EAAE;QACX,MAAM,IAAI,aAAa,CAAC,kBAAkB,CAAC,CAAC;KAC7C;IAED,gBAAgB,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC7D,MAAM,GAAG,MAAM,KAAK,CAAC;IACrB,IAAI,CAAC,MAAM,EAAE;QACX,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;KACzD;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAChC,GAAkE,EAClE,KAAY,EACZ,IAAgC,EAChC,MAA2B,EAC3B,EAAE;IACF,MAAM,eAAe,GAAG,kBAAkB,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAEpE,IAAI,eAAe,KAAK,IAAI,EAAE;QAC5B,OAAO;KACR;IACD,IAAI,eAAe,KAAK,KAAK,EAAE;QAC7B,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;KAC1D;IAED,kIAAkI;IAClI,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAQ,CAAC,CAAC,KAAK,EAAE,CAAC;IAChD,IAAI,MAAM,GAAG,KAAK,CAAC;IAEnB,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM;SAC7B,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC;SAClC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE;QAClG,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC;QACzD,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAW,CAAC;QAC7C,IAAI,CAAC,SAAS,EAAE;YACd,SAAS;SACV;QAED,MAAM,gBAAgB,GAAG,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QACpF,IAAI,gBAAgB,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YACjE,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,QAAQ,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;SACzE;QAED,MAAM,GAAG,IAAI,CAAC;QAEd,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAEzE,IAAI,oBAAoB,KAAK,IAAI,EAAE;YACjC,wEAAwE;YACxE,wGAAwG;YACxG,KAAK,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,OAAO,CAAC,CAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;YACrG,SAAS;SACV;QAED,IAAI,oBAAoB,KAAK,KAAK,IAAI,CAAC,oBAAoB,CAAC,MAAM,EAAE;YAClE,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,QAAQ,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;SACzE;QAED,wGAAwG;QACxG,GAAG,CACD,KAAK,EACL,oBAAoB,CAAC,GAAG,CACtB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,mBAAmB,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAC5G,CACF,CAAC;KACH;IAED,IAAI,MAAM,EAAE;QACV,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC;QAC9B,IAAI,CAAC,SAAS,EAAE;YACd,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,QAAQ,KAAK,CAAC,IAAI,mDAAmD,CAAC,CAAC;SAC1G;KACF;SAAM,IAAI,MAAM,KAAK,QAAQ,EAAE;QAC9B,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,QAAQ,KAAK,CAAC,IAAI,uDAAuD,CAAC,CAAC;KAC9G;AACH,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAC1B,GAAyC,EACzC,QAA2B,EAC3B,KAAuB,EACvB,EAAoC,EACpC,EAAE;IACF,MAAM,OAAO,GAAG,IAAI,cAAc,EAAE,CAAC;IACrC,IAAI,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC/B,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;IACtC,wGAAwG;IACxG,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,KAAK,EAAE,CAAC,CAAC;IACrC,IAAI,EAAE,EAAE;QACN,wGAAwG;QACxG,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,KAAK,KAAK,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;KAClD;IACD,IAAI,KAAK,EAAE;QACT,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;KAC7E;IAED,KAAK,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,KAAK,EAAE;QACxD,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;QACpC,IAAI,OAAO,EAAE;YACX,wGAAwG;YACxG,QAAQ,CAAC,QAAQ,CAAC,GAAG,IAAI,OAAO,QAAQ,EAAE,EAAE,GAAG,KAAK,IAAI,UAAU,IAAI,IAAI,EAAE,EAAE,GAAG,QAAQ,KAAK,CAAC,CAAC;SACjG;aAAM;YACL,wGAAwG;YACxG,QAAQ,CAAC,SAAS,CAAC,GAAG,IAAI,OAAO,QAAQ,EAAE,EAAE,GAAG,KAAK,KAAK,EAAE,GAAG,QAAQ,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC,CAAC;SAClG;QACD,wGAAwG;QACxG,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,QAAQ,UAAU,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACnD,IAAI,KAAK,EAAE;YACT,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;SACvD;QACD,KAAK,GAAG,QAAQ,CAAC;KAClB;IACD,wGAAwG;IACxG,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,UAAU,EAAE,EAAE,CAAC,CAAC;AAC7C,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,KAAY,EAAE,KAAwB,EAAE,KAAa,EAAE,KAAU,EAAE,OAAuB,EAAE,EAAE;IAChH,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QAChD,MAAM,QAAQ,GAAG,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QAE5C,IAAI,QAAQ,EAAE;YACZ,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;YACpC,wGAAwG;YACxG,KAAK,CAAC,QAAQ,CACZ,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,QAAQ,EAAE,EACvC,GAAG,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC,UAAU,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,EACrE,GAAG,QAAQ,KAAK,CACjB,CAAC;YACF,UAAU,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;SAC7D;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YAC/B,wGAAwG;YACxG,KAAK,CAAC,OAAO,CAAC,GAAG,KAAK,IAAI,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;SACzC;aAAM;YACL,wGAAwG;YACxG,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,KAAK,IAAI,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;SAC7C;KACF;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Models } from '../models';
|
|
2
|
+
export type PermissionAction = 'READ' | 'CREATE' | 'UPDATE' | 'DELETE' | 'RESTORE' | 'LINK';
|
|
3
|
+
/**
|
|
4
|
+
* Initial representation (tree structure, as defined by user).
|
|
5
|
+
*/
|
|
6
|
+
export type PermissionsConfig = {
|
|
7
|
+
[role: string]: true | {
|
|
8
|
+
[type: string]: PermissionsBlock;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
export type PermissionsBlock = {
|
|
12
|
+
[action in PermissionAction]?: true;
|
|
13
|
+
} & {
|
|
14
|
+
WHERE?: Record<string, any>;
|
|
15
|
+
RELATIONS?: {
|
|
16
|
+
[relation: string]: PermissionsBlock;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Final representation (lookup table (role, model, action) -> permission stack).
|
|
21
|
+
*/
|
|
22
|
+
export type Permissions = {
|
|
23
|
+
[role: string]: true | RolePermissions;
|
|
24
|
+
};
|
|
25
|
+
type RolePermissions = {
|
|
26
|
+
[type: string]: {
|
|
27
|
+
[action in PermissionAction]?: true | PermissionStack;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* For a given role, model and action,
|
|
32
|
+
* this represents the list of potential (join) paths
|
|
33
|
+
* that would grant permission to perform that action.
|
|
34
|
+
*/
|
|
35
|
+
export type PermissionStack = PermissionChain[];
|
|
36
|
+
export type PermissionChain = PermissionLink[];
|
|
37
|
+
export type PermissionLink = {
|
|
38
|
+
type: string;
|
|
39
|
+
foreignKey?: string;
|
|
40
|
+
reverse?: boolean;
|
|
41
|
+
me?: boolean;
|
|
42
|
+
where?: any;
|
|
43
|
+
};
|
|
44
|
+
export declare const generatePermissions: (models: Models, config: PermissionsConfig) => Permissions;
|
|
45
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { summonByName } from '../utils';
|
|
2
|
+
const ACTIONS = ['READ', 'CREATE', 'UPDATE', 'DELETE', 'RESTORE', 'LINK'];
|
|
3
|
+
export const generatePermissions = (models, config) => {
|
|
4
|
+
const permissions = {};
|
|
5
|
+
for (const [role, roleConfig] of Object.entries(config)) {
|
|
6
|
+
if (roleConfig === true) {
|
|
7
|
+
permissions[role] = true;
|
|
8
|
+
continue;
|
|
9
|
+
}
|
|
10
|
+
const rolePermissions = {};
|
|
11
|
+
for (const [key, block] of Object.entries(roleConfig)) {
|
|
12
|
+
const type = key === 'me' ? 'User' : key;
|
|
13
|
+
if (key !== 'me' && !('WHERE' in block)) {
|
|
14
|
+
rolePermissions[type] = {};
|
|
15
|
+
for (const action of ACTIONS) {
|
|
16
|
+
if (action === 'READ' || action in block) {
|
|
17
|
+
rolePermissions[type][action] = true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
addPermissions(models, rolePermissions, [
|
|
22
|
+
{
|
|
23
|
+
type,
|
|
24
|
+
...(key === 'me' && { me: true }),
|
|
25
|
+
...('WHERE' in block && { where: block.WHERE }),
|
|
26
|
+
},
|
|
27
|
+
], block);
|
|
28
|
+
}
|
|
29
|
+
permissions[role] = rolePermissions;
|
|
30
|
+
}
|
|
31
|
+
return permissions;
|
|
32
|
+
};
|
|
33
|
+
const addPermissions = (models, permissions, links, block) => {
|
|
34
|
+
const { type } = links[links.length - 1];
|
|
35
|
+
const model = summonByName(models, type);
|
|
36
|
+
for (const action of ACTIONS) {
|
|
37
|
+
if (action === 'READ' || action in block) {
|
|
38
|
+
if (!permissions[type]) {
|
|
39
|
+
permissions[type] = {};
|
|
40
|
+
}
|
|
41
|
+
if (!permissions[type][action]) {
|
|
42
|
+
permissions[type][action] = [];
|
|
43
|
+
}
|
|
44
|
+
if (permissions[type][action] !== true) {
|
|
45
|
+
permissions[type][action].push(links);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (block.RELATIONS) {
|
|
50
|
+
for (const [relation, subBlock] of Object.entries(block.RELATIONS)) {
|
|
51
|
+
const field = model.fields.find((field) => field.relation && field.name === relation);
|
|
52
|
+
let link;
|
|
53
|
+
if (field) {
|
|
54
|
+
link = {
|
|
55
|
+
type: field.type,
|
|
56
|
+
foreignKey: field.foreignKey || `${field.name}Id`,
|
|
57
|
+
reverse: true,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const field = model.reverseRelationsByName[relation];
|
|
62
|
+
if (!field) {
|
|
63
|
+
throw new Error(`Relation ${relation} in model ${model.name} does not exist.`);
|
|
64
|
+
}
|
|
65
|
+
link = {
|
|
66
|
+
type: field.model.name,
|
|
67
|
+
foreignKey: field.foreignKey,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (subBlock.WHERE) {
|
|
71
|
+
link.where = subBlock.WHERE;
|
|
72
|
+
}
|
|
73
|
+
addPermissions(models, permissions, [...links, link], subBlock);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/permissions/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/permissions/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AAEjC,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { GraphQLSchema, TypeDefinitionNode, TypeNode } from 'graphql';
|
|
2
|
+
import { Value } from '../values';
|
|
3
|
+
import { FieldResolverNode } from './node';
|
|
4
|
+
import { Maybe } from './utils';
|
|
5
|
+
export type Where = Record<string, Value>;
|
|
6
|
+
export type OrderBy = Record<string, 'ASC' | 'DESC'>[];
|
|
7
|
+
export type Args = {
|
|
8
|
+
where?: Where | null;
|
|
9
|
+
};
|
|
10
|
+
export type ListArgs = {
|
|
11
|
+
limit?: number | null | undefined;
|
|
12
|
+
offset?: number | null | undefined;
|
|
13
|
+
orderBy?: string[];
|
|
14
|
+
};
|
|
15
|
+
export type NormalizedArguments = {
|
|
16
|
+
limit?: number;
|
|
17
|
+
offset?: number;
|
|
18
|
+
orderBy?: OrderBy;
|
|
19
|
+
where?: Where;
|
|
20
|
+
search?: string;
|
|
21
|
+
mine?: boolean;
|
|
22
|
+
language?: string;
|
|
23
|
+
};
|
|
24
|
+
export declare const normalizeArguments: (node: FieldResolverNode) => NormalizedArguments;
|
|
25
|
+
export declare function normalizeValue(value: Value, type: TypeNode, schema: GraphQLSchema): Value;
|
|
26
|
+
export declare const normalizeValueByTypeDefinition: (value: Value, type: Maybe<TypeDefinitionNode>, schema: GraphQLSchema) => any;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Kind } from 'graphql';
|
|
2
|
+
import { summonByKey } from '../utils';
|
|
3
|
+
function getRawValue(value, values) {
|
|
4
|
+
switch (value.kind) {
|
|
5
|
+
case Kind.LIST:
|
|
6
|
+
if (!values) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
return value.values.map((value) => getRawValue(value, values));
|
|
10
|
+
case Kind.VARIABLE:
|
|
11
|
+
return values?.[value.name.value];
|
|
12
|
+
case Kind.INT:
|
|
13
|
+
return parseInt(value.value, 10);
|
|
14
|
+
case Kind.NULL:
|
|
15
|
+
return null;
|
|
16
|
+
case Kind.FLOAT:
|
|
17
|
+
return parseFloat(value.value);
|
|
18
|
+
case Kind.STRING:
|
|
19
|
+
case Kind.BOOLEAN:
|
|
20
|
+
case Kind.ENUM:
|
|
21
|
+
return value.value;
|
|
22
|
+
case Kind.OBJECT: {
|
|
23
|
+
if (!value.fields.length) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const res = {};
|
|
27
|
+
for (const field of value.fields) {
|
|
28
|
+
res[field.name.value] = getRawValue(field.value, values);
|
|
29
|
+
}
|
|
30
|
+
return res;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export const normalizeArguments = (node) => {
|
|
35
|
+
const normalizedArguments = {};
|
|
36
|
+
if (node.field.arguments) {
|
|
37
|
+
for (const argument of node.field.arguments) {
|
|
38
|
+
const rawValue = getRawValue(argument.value, node.ctx.info.variableValues);
|
|
39
|
+
const normalizedValue = normalizeValue(rawValue, summonByKey(node.fieldDefinition.arguments || [], 'name.value', argument.name.value).type, node.ctx.info.schema);
|
|
40
|
+
if (normalizedValue === undefined) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
normalizedArguments[argument.name.value] = normalizedValue;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return normalizedArguments;
|
|
47
|
+
};
|
|
48
|
+
export function normalizeValue(value, type, schema) {
|
|
49
|
+
switch (type.kind) {
|
|
50
|
+
case Kind.LIST_TYPE: {
|
|
51
|
+
if (Array.isArray(value)) {
|
|
52
|
+
const res = [];
|
|
53
|
+
for (const v of value) {
|
|
54
|
+
res.push(normalizeValue(v, type.type, schema));
|
|
55
|
+
}
|
|
56
|
+
return res;
|
|
57
|
+
}
|
|
58
|
+
const normalizedValue = normalizeValue(value, type.type, schema);
|
|
59
|
+
if (normalizedValue === undefined) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
return [normalizedValue];
|
|
63
|
+
}
|
|
64
|
+
case Kind.NON_NULL_TYPE:
|
|
65
|
+
return normalizeValue(value, type.type, schema);
|
|
66
|
+
case Kind.NAMED_TYPE:
|
|
67
|
+
return normalizeValueByTypeDefinition(value, schema.getType(type.name.value)?.astNode, schema);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export const normalizeValueByTypeDefinition = (value, type, schema) => {
|
|
71
|
+
if (!type || type.kind !== Kind.INPUT_OBJECT_TYPE_DEFINITION) {
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
if (!value) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const res = {};
|
|
78
|
+
for (const key of Object.keys(value)) {
|
|
79
|
+
const field = summonByKey(type.fields, 'name.value', key);
|
|
80
|
+
const normalizedValue = normalizeValue(value[key], field.type, schema);
|
|
81
|
+
if (normalizedValue === undefined) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
res[key] = normalizedValue;
|
|
85
|
+
}
|
|
86
|
+
return res;
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=arguments.js.map
|