1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | var TraceUtils = require('@themost/common/utils').TraceUtils;
|
11 | var LangUtils = require('@themost/common/utils').LangUtils;
|
12 | var HttpBadRequestError = require('@themost/common/errors').HttpBadRequestError;
|
13 | var HttpUnauthorizedError = require('@themost/common/errors').HttpUnauthorizedError;
|
14 | var HttpConsumer = require('./consumers').HttpConsumer;
|
15 | var DataTypeValidator = require('@themost/data/data-validator').DataTypeValidator;
|
16 | var MinLengthValidator = require('@themost/data/data-validator').MinLengthValidator;
|
17 | var MaxLengthValidator = require('@themost/data/data-validator').MaxLengthValidator;
|
18 | var MinValueValidator = require('@themost/data/data-validator').MinValueValidator;
|
19 | var MaxValueValidator = require('@themost/data/data-validator').MaxValueValidator;
|
20 | var RequiredValidator = require('@themost/data/data-validator').RequiredValidator;
|
21 | var PatternValidator = require('@themost/data/data-validator').PatternValidator;
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 | function DecoratorError() {
|
30 | DecoratorError.super_.call(this, 'Decorator is not valid on this declaration type.');
|
31 | }
|
32 | LangUtils.inherits(DecoratorError, Error);
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 | function httpController(name) {
|
39 | return function (target, key, descriptor) {
|
40 | if (typeof target === 'function') {
|
41 | target.httpController = true;
|
42 | }
|
43 |
|
44 | Object.defineProperty(target, 'httpControllerName', {
|
45 | value: name,
|
46 | configurable: false,
|
47 | enumerable: true,
|
48 | writable: true
|
49 | });
|
50 | return descriptor;
|
51 | }
|
52 | }
|
53 |
|
54 | function httpGet() {
|
55 | return function (target, key, descriptor) {
|
56 | if (typeof descriptor.value === 'function') {
|
57 | descriptor.value.httpGet = true;
|
58 | }
|
59 | return descriptor;
|
60 | }
|
61 | }
|
62 |
|
63 |
|
64 |
|
65 | function httpAny() {
|
66 | return function (target, key, descriptor) {
|
67 | if (typeof descriptor.value === 'function') {
|
68 | descriptor.value.httpGet = true;
|
69 | descriptor.value.httpPost = true;
|
70 | descriptor.value.httpPut = true;
|
71 | descriptor.value.httpDelete = true;
|
72 | descriptor.value.httpOptions = true;
|
73 | descriptor.value.httpHead = true;
|
74 | }
|
75 | return descriptor;
|
76 | }
|
77 | }
|
78 |
|
79 |
|
80 |
|
81 | function httpPost() {
|
82 | return function (target, key, descriptor) {
|
83 | if (typeof descriptor.value === 'function') {
|
84 | descriptor.value.httpPost = true;
|
85 | }
|
86 | return descriptor;
|
87 | }
|
88 | }
|
89 |
|
90 |
|
91 |
|
92 | function httpPatch() {
|
93 | return function (target, key, descriptor) {
|
94 | if (typeof descriptor.value === 'function') {
|
95 | descriptor.value.httpPatch = true;
|
96 | }
|
97 | return descriptor;
|
98 | }
|
99 | }
|
100 |
|
101 |
|
102 |
|
103 | function httpPut() {
|
104 | return function (target, key, descriptor) {
|
105 | if (typeof descriptor.value === 'function') {
|
106 | descriptor.value.httpPut = true;
|
107 | }
|
108 | return descriptor;
|
109 | }
|
110 | }
|
111 |
|
112 |
|
113 |
|
114 | function httpDelete() {
|
115 | return function (target, key, descriptor) {
|
116 | if (typeof descriptor.value === 'function') {
|
117 | descriptor.value.httpDelete = true;
|
118 | }
|
119 | return descriptor;
|
120 | }
|
121 | }
|
122 |
|
123 |
|
124 |
|
125 | function httpOptions() {
|
126 | return function (target, key, descriptor) {
|
127 | if (typeof descriptor.value === 'function') {
|
128 | descriptor.value.httpOptions = true;
|
129 | }
|
130 | return descriptor;
|
131 | }
|
132 | }
|
133 |
|
134 |
|
135 |
|
136 | function httpHead() {
|
137 | return function (target, key, descriptor) {
|
138 | if (typeof descriptor.value === 'function') {
|
139 | descriptor.value.httpHead = true;
|
140 | }
|
141 | return descriptor;
|
142 | }
|
143 | }
|
144 |
|
145 |
|
146 |
|
147 | function httpAction(name) {
|
148 | if (typeof name !== 'string') {
|
149 | throw new TypeError('Action name must be a string');
|
150 | }
|
151 | return function (target, key, descriptor) {
|
152 | if (typeof descriptor.value !== 'function') {
|
153 | throw new Error('Decorator is not valid on this declaration type.');
|
154 | }
|
155 | descriptor.value.httpAction = name;
|
156 | return descriptor;
|
157 | }
|
158 | }
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 | function httpParamAlias(name, alias) {
|
166 | if (typeof name !== 'string') {
|
167 | throw new TypeError('Parameter name must be a string');
|
168 | }
|
169 | if (typeof alias !== 'string') {
|
170 | throw new TypeError('Parameter alias must be a string');
|
171 | }
|
172 | return function (target, key, descriptor) {
|
173 | if (typeof descriptor.value !== 'function') {
|
174 | throw new Error('Decorator is not valid on this declaration type.');
|
175 | }
|
176 | descriptor.value.httpParamAlias = descriptor.value.httpParamAlias || { };
|
177 | descriptor.value.httpParamAlias[name] = alias;
|
178 | return descriptor;
|
179 | }
|
180 | }
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 | function HttpParamAttributeOptions() {
|
197 |
|
198 | }
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 | function httpParam(options) {
|
205 | if (typeof options !== 'object') { throw new TypeError('Parameter options must be an object'); }
|
206 | if (typeof options.name !== 'string') { throw new TypeError('Parameter name must be a string'); }
|
207 | return function (target, key, descriptor) {
|
208 | if (typeof descriptor.value !== 'function') {
|
209 | throw new Error('Decorator is not valid on this declaration type.');
|
210 | }
|
211 |
|
212 | descriptor.value.httpParams = descriptor.value.httpParams || { };
|
213 | descriptor.value.httpParams[options.name] = Object.assign({"type":"Text"}, options);
|
214 | if (typeof descriptor.value.httpParam === 'undefined') {
|
215 | descriptor.value.httpParam = new HttpConsumer(function (context) {
|
216 | var httpParamValidationFailedCallback = function httpParamValidationFailedCallback(context, httpParam, validationResult) {
|
217 | TraceUtils.error(JSON.stringify(Object.assign(validationResult, {
|
218 | "param":httpParam,
|
219 | "request": {
|
220 | "url":context.request.url,
|
221 | "method":context.request.method
|
222 | }
|
223 | })));
|
224 | return Promise.reject(new HttpBadRequestError('Bad request parameter', httpParam.message || validationResult.message));
|
225 | };
|
226 | var methodParams = LangUtils.getFunctionParams(descriptor.value);
|
227 | var httpParams = descriptor.value.httpParams;
|
228 | if (methodParams.length>0) {
|
229 | var k = 0, httpParam, validator, validationResult, functionParam, contextParam;
|
230 | while (k < methodParams.length) {
|
231 | functionParam = methodParams[k];
|
232 | if (typeof context.getParam === 'function') {
|
233 | contextParam = context.getParam(functionParam);
|
234 | }
|
235 | else {
|
236 | contextParam = context.params[functionParam];
|
237 | }
|
238 | if (httpParams) {
|
239 | httpParam = httpParams[functionParam];
|
240 | if (httpParam) {
|
241 | if (typeof httpParam.type === 'string') {
|
242 |
|
243 | validator = new DataTypeValidator(httpParam.type);
|
244 | validator.setContext(context);
|
245 | validationResult = validator.validateSync(contextParam);
|
246 | if (validationResult) {
|
247 | return httpParamValidationFailedCallback(context, httpParam, validationResult);
|
248 | }
|
249 | }
|
250 | if (httpParam.pattern instanceof RegExp) {
|
251 |
|
252 | validator = new PatternValidator(httpParam.pattern);
|
253 | validator.setContext(context);
|
254 | validationResult = validator.validateSync(contextParam);
|
255 | if (validationResult) {
|
256 | return httpParamValidationFailedCallback(context, httpParam, validationResult);
|
257 | }
|
258 | }
|
259 | if (typeof httpParam.minLength === 'number') {
|
260 |
|
261 | validator = new MinLengthValidator(httpParam.minLength);
|
262 | validator.setContext(context);
|
263 | validationResult = validator.validateSync(contextParam);
|
264 | if (validationResult) {
|
265 | return httpParamValidationFailedCallback(context, httpParam, validationResult);
|
266 | }
|
267 | }
|
268 | if (typeof httpParam.maxLength === 'number') {
|
269 |
|
270 | validator = new MaxLengthValidator(httpParam.maxLength);
|
271 | validator.setContext(context);
|
272 | validationResult = validator.validateSync(contextParam);
|
273 | if (validationResult) {
|
274 | return httpParamValidationFailedCallback(context, httpParam, validationResult);
|
275 | }
|
276 | }
|
277 | if (typeof httpParam.minValue !== 'undefined') {
|
278 |
|
279 | validator = new MinValueValidator(httpParam.minValue);
|
280 | validator.setContext(context);
|
281 | validationResult = validator.validateSync(contextParam);
|
282 | if (validationResult) {
|
283 | return httpParamValidationFailedCallback(context, httpParam, validationResult);
|
284 | }
|
285 | }
|
286 | if (typeof httpParam.maxValue !== 'undefined') {
|
287 |
|
288 | validator = new MaxValueValidator(httpParam.required);
|
289 | validator.setContext(context);
|
290 | validationResult = validator.validateSync(contextParam);
|
291 | if (validationResult) {
|
292 | return httpParamValidationFailedCallback(context, httpParam, validationResult);
|
293 | }
|
294 | }
|
295 |
|
296 | if ((typeof httpParam.required !== 'undefined') && (httpParam.required === true)) {
|
297 |
|
298 | validator = new RequiredValidator();
|
299 | validator.setContext(context);
|
300 | validationResult = validator.validateSync(contextParam);
|
301 | if (validationResult) {
|
302 | return httpParamValidationFailedCallback(context, httpParam, validationResult);
|
303 | }
|
304 | }
|
305 | }
|
306 | }
|
307 | k += 1;
|
308 | }
|
309 | }
|
310 | return Promise.resolve();
|
311 | });
|
312 | }
|
313 | return descriptor;
|
314 | }
|
315 | }
|
316 |
|
317 |
|
318 |
|
319 |
|
320 |
|
321 | function httpAuthorize(value) {
|
322 | return function (target, key, descriptor) {
|
323 | if (typeof descriptor.value !== 'function') {
|
324 | throw new Error('Decorator is not valid on this declaration type.');
|
325 | }
|
326 | var authorize = true;
|
327 | if (typeof value === 'boolean') {
|
328 | authorize = value;
|
329 | }
|
330 | if (authorize) {
|
331 | descriptor.value.authorize = new HttpConsumer(function (context) {
|
332 | if (context.user && context.user.name !== 'anonymous') {
|
333 | return Promise.resolve();
|
334 | }
|
335 | return Promise.reject(new HttpUnauthorizedError());
|
336 | });
|
337 | }
|
338 | return descriptor;
|
339 | };
|
340 | }
|
341 |
|
342 |
|
343 |
|
344 |
|
345 |
|
346 |
|
347 |
|
348 | function defineDecorator(proto, key, decorator) {
|
349 | if ((typeof proto !== 'object') && (typeof proto !== 'function')) {
|
350 | throw new DecoratorError('Invalid prototype. Expected object or function.');
|
351 | }
|
352 | if (typeof key !== 'string') {
|
353 | throw new DecoratorError('Invalid property name. Expected string.');
|
354 | }
|
355 | if (typeof decorator !== 'function') {
|
356 | throw new DecoratorError('Invalid decorator. Expected function.');
|
357 | }
|
358 | decorator(proto, key, Object.getOwnPropertyDescriptor(proto, key));
|
359 | }
|
360 |
|
361 |
|
362 |
|
363 |
|
364 |
|
365 |
|
366 | function httpActionConsumer(name, consumer) {
|
367 | return function (target, key, descriptor) {
|
368 | if (typeof descriptor.value !== 'function') {
|
369 | throw new Error('Decorator is not valid on this declaration type.');
|
370 | }
|
371 | if (consumer instanceof HttpConsumer) {
|
372 |
|
373 | descriptor.value[name] = consumer;
|
374 |
|
375 | return descriptor;
|
376 | }
|
377 |
|
378 | if (typeof consumer !== 'function') {
|
379 | throw new Error('Consumer may be a function.');
|
380 | }
|
381 | descriptor.value[name] = new HttpConsumer(consumer);
|
382 | return descriptor;
|
383 | };
|
384 | }
|
385 |
|
386 |
|
387 |
|
388 |
|
389 |
|
390 |
|
391 |
|
392 |
|
393 | function httpRoute(url, format, index) {
|
394 | return function (target, key, descriptor) {
|
395 | if (typeof descriptor.value === 'function') {
|
396 | Object.defineProperty(descriptor.value, 'httpRoute', {
|
397 | get: function () {
|
398 | |
399 |
|
400 |
|
401 | var route = {
|
402 | url: url,
|
403 | controller: target.httpControllerName || target.name,
|
404 | action: descriptor.value.httpAction,
|
405 | format: format
|
406 | };
|
407 | if (descriptor.value.hasOwnProperty('httpAny') === false) {
|
408 |
|
409 | if (descriptor.value.hasOwnProperty('httpHead') === false) {
|
410 | descriptor.value.httpHead = true;
|
411 | }
|
412 |
|
413 | if (descriptor.value.hasOwnProperty('httpOptions') === false) {
|
414 | descriptor.value.httpOptions = true;
|
415 | }
|
416 |
|
417 | var allowString = [
|
418 | 'httpGet',
|
419 | 'httpHead',
|
420 | 'httpOptions',
|
421 | 'httpPost',
|
422 | 'httpPut',
|
423 | 'httpDelete',
|
424 | 'httpPatch' ].filter( function(httpKey) {
|
425 | return descriptor.value.hasOwnProperty(httpKey) && descriptor.value[httpKey];
|
426 | }).map(function(httpKey) {
|
427 | return httpKey.replace(/^http/,'').toUpperCase();
|
428 | }).join(',');
|
429 |
|
430 | Object.assign(route, {
|
431 | allow: allowString
|
432 | });
|
433 | }
|
434 | return route;
|
435 | },
|
436 | configurable: false,
|
437 | enumerable: true
|
438 | });
|
439 |
|
440 | Object.defineProperty(descriptor.value, 'httpRouteIndex', {
|
441 | value: index || 0
|
442 | });
|
443 | }
|
444 | return descriptor;
|
445 | }
|
446 | }
|
447 |
|
448 |
|
449 | if (typeof Object.defineDecorator === 'undefined') {
|
450 | |
451 |
|
452 |
|
453 |
|
454 |
|
455 |
|
456 |
|
457 |
|
458 | Object.defineDecorator = defineDecorator;
|
459 | }
|
460 |
|
461 | module.exports.DecoratorError = DecoratorError;
|
462 | module.exports.httpGet = httpGet;
|
463 | module.exports.httpAny = httpAny;
|
464 | module.exports.httpPost = httpPost;
|
465 | module.exports.httpPut = httpPut;
|
466 | module.exports.httpPatch = httpPatch;
|
467 | module.exports.httpDelete = httpDelete;
|
468 | module.exports.httpOptions = httpOptions;
|
469 | module.exports.httpHead = httpHead;
|
470 | module.exports.httpAction = httpAction;
|
471 | module.exports.httpRoute = httpRoute;
|
472 | module.exports.httpController = httpController;
|
473 | module.exports.httpParamAlias = httpParamAlias;
|
474 | module.exports.httpParam = httpParam;
|
475 | module.exports.httpAuthorize = httpAuthorize;
|
476 | module.exports.defineDecorator = defineDecorator;
|
477 | module.exports.httpActionConsumer = httpActionConsumer;
|