1 | import React, {ReactNode} from 'react';
|
2 |
|
3 | import Types from '../types';
|
4 | import { IComponent} from "../types/component";
|
5 | import { IInfrastructure } from "../types";
|
6 | import {ENTRY_INSTANCE_TYPE, createEntryProps, IEntryArgs} from "../datalayer/entry-component";
|
7 | import { IC_USER_ID} from "./auth-middleware";
|
8 | import createMiddleware from '../middleware/middleware-component';
|
9 |
|
10 | import ConnectSequence from 'connect-sequence';
|
11 |
|
12 | import {getEntryListQuery, setEntryMutation, setEntry, ddbListEntries, deleteEntry} from '../datalayer/datalayer-libs';
|
13 |
|
14 |
|
15 | import {
|
16 | graphql,
|
17 | GraphQLObjectType,
|
18 | GraphQLString,
|
19 | GraphQLNonNull,
|
20 | GraphQLList,
|
21 | GraphQLInputObjectType
|
22 | } from 'graphql';
|
23 |
|
24 |
|
25 | export interface ISecuredEntryProps {
|
26 |
|
27 | /**
|
28 | * Functions that the Authentication-Component looks for
|
29 | */
|
30 | setUserId: any,
|
31 | setMiddleware: any,
|
32 | externalMiddleware?: any,
|
33 |
|
34 | /**
|
35 | * the id of the authentication-provider
|
36 | */
|
37 | userId?: any,
|
38 |
|
39 |
|
40 | }
|
41 |
|
42 | /**
|
43 | * an entry specifies a kind of data that can be stored in a line of the table
|
44 | */
|
45 | export default (props: IEntryArgs | any) => {
|
46 |
|
47 | // the component must have the properties of IComponent
|
48 | const componentProps: IInfrastructure & IComponent = {
|
49 | infrastructureType: Types.INFRASTRUCTURE_TYPE_COMPONENT,
|
50 | instanceType: ENTRY_INSTANCE_TYPE,
|
51 | instanceId: props.id
|
52 | };
|
53 |
|
54 | const mwProps = {
|
55 | middleware: createMiddleware({callback: (req, res, next) => {
|
56 | console.log("this is the default mw of the SecuredEntry: ", props.id)
|
57 |
|
58 | if (securedEntryProps.externalMiddleware) {
|
59 | console.log("now using the provided middleware")
|
60 | return new ConnectSequence(req, res, next)
|
61 | .append(securedEntryProps.externalMiddleware.callback)
|
62 | .run();
|
63 | }
|
64 | return next();
|
65 |
|
66 | }})
|
67 | };
|
68 |
|
69 | const securedEntryProps: ISecuredEntryProps = {
|
70 | //origRangeKey: props.rangeKey,
|
71 |
|
72 | setUserId: (userId) => {
|
73 | console.log(props.id, " received userId: ", userId)
|
74 | securedEntryProps.userId = userId;
|
75 | //props.rangeKey = IC_USER_ID
|
76 | },
|
77 |
|
78 | /**
|
79 | * We MUST NOT OVERWRITE exisiting functions, only data. middleware is a function
|
80 | * because they get not called
|
81 | */
|
82 |
|
83 | // the authentication-component replaces the middleware!
|
84 | setMiddleware: (mw) => {
|
85 | console.log(props.id, " received middleware: ", mw)
|
86 | securedEntryProps.externalMiddleware = mw;
|
87 | }
|
88 | };
|
89 |
|
90 | const entryProps: any = createEntryProps(Object.assign({}, props, componentProps, securedEntryProps));
|
91 |
|
92 | const setUserIdFromContext = (context) => {
|
93 |
|
94 | //console.log("check userId? ", entryProps, props, securedEntryProps)
|
95 | // when called through ssr, we do not get the userId through the ICs. But the DataLayer-Integration puts
|
96 | // it into the context for us
|
97 |
|
98 | if (securedEntryProps && securedEntryProps.userId) {
|
99 | console.log("SecuredEntry already has userId, not taking from context: ", securedEntryProps.userId);
|
100 | return;
|
101 | }
|
102 |
|
103 | if (context && context.userId) {
|
104 | if (securedEntryProps) {
|
105 | securedEntryProps["userId"] = context["userId"];
|
106 |
|
107 | } else {
|
108 | console.error("no entryProps exist, cannot set userId")
|
109 | }
|
110 | return;
|
111 | }
|
112 |
|
113 | console.warn("no userId in context or in entryProps...")
|
114 |
|
115 | };
|
116 |
|
117 |
|
118 | return Object.assign(entryProps, {
|
119 |
|
120 | // we need to adjust the writing into the table
|
121 | setEntry: (args, context, tableName, isOffline) => {
|
122 |
|
123 | setUserIdFromContext(context);
|
124 |
|
125 |
|
126 | return setEntry(
|
127 | tableName, //"code-architect-dev-data-layer",
|
128 | props.primaryKey, // schema.Entry.ENTITY, //pkEntity
|
129 | args[props.primaryKey], // pkId
|
130 | IC_USER_ID, //schema.Data.ENTITY, // skEntity
|
131 | `${securedEntryProps.userId}|${props.rangeKey}|${args[props.rangeKey]}`, // skId
|
132 | Object.keys(args).reduce((result, key) => {
|
133 | if (Object.keys(props.data).find(datakey => datakey === key) !== undefined) {
|
134 | result[key] = args[key];
|
135 | }
|
136 | return result;
|
137 | },{}), // jsonData,
|
138 | isOffline
|
139 |
|
140 | );
|
141 | },
|
142 |
|
143 | deleteEntry: (args, context, tableName, isOffline) => {
|
144 |
|
145 | setUserIdFromContext(context);
|
146 |
|
147 | return deleteEntry(
|
148 | tableName, //"code-architect-dev-data-layer",
|
149 | props.primaryKey, // schema.Entry.ENTITY, //pkEntity
|
150 | args[props.primaryKey], // pkId
|
151 | IC_USER_ID, //schema.Data.ENTITY, // skEntity
|
152 | `${securedEntryProps.userId}|${props.rangeKey}|${args[props.rangeKey]}`, // skId
|
153 | isOffline
|
154 | );
|
155 | },
|
156 |
|
157 | listEntries: (args, context, tableName, key, isOffline) => {
|
158 |
|
159 | setUserIdFromContext(context);
|
160 |
|
161 | const entity = key === "pk" ? props.primaryKey : `${IC_USER_ID}|${securedEntryProps.userId}|${props.rangeKey}`;
|
162 | const range = key === "pk" ? `${IC_USER_ID}|${securedEntryProps.userId}|${props.rangeKey}` : props.primaryKey;
|
163 |
|
164 |
|
165 | return ddbListEntries(
|
166 | tableName, //tablename
|
167 | key, // key
|
168 | entity, //entity
|
169 | args[key === "pk" ? props.primaryKey : props.rangeKey], //value
|
170 | range, //rangeEntity
|
171 | isOffline
|
172 | ).then(results => {
|
173 |
|
174 | console.log("promised: ", results);
|
175 | return results.map(item => {
|
176 | const data = item.jsonData !== undefined ? JSON.parse(item.jsonData) : {};
|
177 | data[props.primaryKey] = item.pk.substring(item.pk.lastIndexOf("|")+1);
|
178 | data[props.rangeKey] = item.sk.substring(item.sk.lastIndexOf("|")+1);
|
179 | return data;
|
180 | });
|
181 |
|
182 | });
|
183 |
|
184 | },
|
185 |
|
186 | }, mwProps);
|
187 | // we provide the newly set middleware as last prop to overwrite the other values!
|
188 |
|
189 | };
|
190 |
|
191 |
|
192 | export const isSecuredEntry = (component) => {
|
193 |
|
194 | return component !== undefined && component.instanceType === ENTRY_INSTANCE_TYPE;
|
195 | };
|
196 |
|
197 |
|
198 |
|
199 | const complementedProps = {
|
200 |
|
201 | /*
|
202 | createEntryFields: () => {
|
203 | const fields = Object.keys(props.data).reduce((result, key)=> {
|
204 | if (key !== securedEntryProps.origRangeKey) {
|
205 | result[key] = {type: props.data[key]};
|
206 | }
|
207 |
|
208 |
|
209 | return result;
|
210 | }, {});
|
211 |
|
212 | fields[props.primaryKey] = {type: GraphQLString};
|
213 | fields[IC_USER_ID] = {type: GraphQLString};
|
214 |
|
215 | return fields;
|
216 | },
|
217 |
|
218 | createEntryType: (prefix) => {
|
219 | return new GraphQLObjectType({
|
220 | name: prefix+props.id,
|
221 | fields: () => complementedProps.createEntryFields()
|
222 | })
|
223 | },
|
224 |
|
225 | createKeyArgs: () => {
|
226 |
|
227 | const args = {};
|
228 |
|
229 | args[props.primaryKey] = {name: props.primaryKey, type: GraphQLString};
|
230 | args[IC_USER_ID] = {name: IC_USER_ID, type: GraphQLString};
|
231 |
|
232 | return args;
|
233 | },* /
|
234 |
|
235 | getEntryListQuery: (dictKey) => {
|
236 | const fields = entryProps.createEntryFields();
|
237 | //console.log("fields: ", fields);
|
238 |
|
239 | return getEntryListQuery(
|
240 | props.id,
|
241 | dictKey,
|
242 | fields,
|
243 | {
|
244 | userId: securedEntryProps.userId
|
245 | } //context
|
246 | );
|
247 | },
|
248 |
|
249 | setEntryMutation: (values) => {
|
250 | const fields = entryProps.createEntryFields();
|
251 | //console.log("fields: ", fields);
|
252 |
|
253 | return setEntryMutation(
|
254 | props.id,
|
255 | values,
|
256 | fields,
|
257 | {
|
258 | userId: securedEntryProps.userId
|
259 | } //context
|
260 | );
|
261 |
|
262 | },
|
263 |
|
264 | /*
|
265 |
|
266 | // let's overwrite how the user can get the
|
267 | getEntryListQuery: (dictKey) => {
|
268 | const fields = complementedProps.createEntryFields();
|
269 | //console.log("fields: ", fields);
|
270 |
|
271 | // TODO, complement dictKey or even change the whole query ...
|
272 | return getEntryListQuery(
|
273 | props.id,
|
274 | Object.keys(dictKey).reduce((res, key) => {
|
275 | // we replace the rangeKey with the
|
276 | if (key === securedEntryProps.origRangeKey) {
|
277 | res[props.rangeKey] = `${securedEntryProps.clientId}|${securedEntryProps.origRangeKey}|${dictKey[key]}`
|
278 | } else {
|
279 | res[key] = dictKey[key];
|
280 | }
|
281 | return res;
|
282 | }, {}),
|
283 | fields
|
284 | );
|
285 | },
|
286 |
|
287 | // this creates the input for the gql-tag: how the query is sent to apollo
|
288 | setEntryMutation: (values) => {
|
289 | const fields = complementedProps.createEntryFields();
|
290 |
|
291 |
|
292 | return setEntryMutation(
|
293 | props.id,
|
294 | Object.keys(values).reduce((res, key) => {
|
295 | // we replace the rangeKey with the
|
296 | if (key === securedEntryProps.origRangeKey) {
|
297 | res[props.rangeKey] = `${securedEntryProps.clientId}|${securedEntryProps.origRangeKey}|${values[key]}`
|
298 | } else {
|
299 | res[key] = values[key];
|
300 | }
|
301 | return res;
|
302 | }, {}),
|
303 | fields,
|
304 | {
|
305 | // we need to pass the clientId into the context of the gql-query for we don't have the value there yet!
|
306 | clientId: securedEntryProps.clientId
|
307 | } //context
|
308 | );
|
309 | }*/
|
310 | }; |
\ | No newline at end of file |