├── .editorconfig ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bower.json ├── create-nojekyll.js ├── dist-browser ├── cuba.d.ts ├── cuba.js ├── filter.d.ts ├── model.d.ts ├── storage.d.ts └── util.d.ts ├── dist-node ├── cuba.d.ts ├── cuba.js ├── filter.d.ts ├── filter.js ├── model.d.ts ├── model.js ├── security.d.ts ├── security.js ├── storage.d.ts ├── storage.js ├── util.d.ts └── util.js ├── docs ├── .nojekyll ├── assets │ ├── css │ │ └── main.css │ ├── images │ │ ├── icons.png │ │ ├── icons@2x.png │ │ ├── widgets.png │ │ └── widgets@2x.png │ └── js │ │ ├── main.js │ │ └── search.js ├── classes │ ├── _cuba_.cubaapp.html │ └── _storage_.defaultstorage.html ├── enums │ ├── _model_.permissiontype.html │ ├── _model_.predefinedview.html │ └── _model_.roletype.html ├── globals.html ├── index.html ├── interfaces │ ├── _cuba_.appconfig.html │ ├── _cuba_.entitiesloadoptions.html │ ├── _cuba_.fetchoptions.html │ ├── _cuba_.loginoptions.html │ ├── _cuba_.responseerror.html │ ├── _filter_.condition.html │ ├── _filter_.conditionsgroup.html │ ├── _filter_.entityfilter.html │ ├── _model_.entitieswithcount.html │ ├── _model_.entitymessages.html │ ├── _model_.enuminfo.html │ ├── _model_.enumvalueinfo.html │ ├── _model_.metaclassinfo.html │ ├── _model_.metapropertyinfo.html │ ├── _model_.permissioninfo.html │ ├── _model_.roleinfo.html │ ├── _model_.rolesinfo.html │ ├── _model_.serializedentityprops.html │ ├── _model_.userinfo.html │ └── _model_.view.html └── modules │ ├── _cuba_.html │ ├── _filter_.html │ ├── _model_.html │ ├── _security_.html │ ├── _storage_.html │ └── _util_.html ├── examples ├── node │ ├── README.md │ ├── index.js │ ├── package-lock.json │ └── package.json └── vanillajs-browser │ └── index.html ├── package-lock.json ├── package.json ├── src ├── cuba.ts ├── filter.ts ├── model.ts ├── security.ts ├── storage.ts └── util.ts ├── test-app ├── .gitignore ├── build.gradle ├── extra.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── modules │ ├── core │ │ ├── db │ │ │ └── init │ │ │ │ └── hsql │ │ │ │ ├── 10.create-db.sql │ │ │ │ ├── 20.create-db.sql │ │ │ │ └── 30.create-db.sql │ │ ├── src │ │ │ └── com │ │ │ │ └── company │ │ │ │ └── restmock │ │ │ │ ├── app.properties │ │ │ │ ├── service │ │ │ │ └── DummyServiceBean.java │ │ │ │ └── spring.xml │ │ ├── test │ │ │ └── com │ │ │ │ └── company │ │ │ │ └── restmock │ │ │ │ ├── RestmockTestContainer.java │ │ │ │ └── core │ │ │ │ └── SampleIntegrationTest.java │ │ └── web │ │ │ ├── META-INF │ │ │ └── context.xml │ │ │ └── WEB-INF │ │ │ └── web.xml │ ├── global │ │ └── src │ │ │ └── com │ │ │ └── company │ │ │ └── restmock │ │ │ ├── metadata.xml │ │ │ ├── persistence.xml │ │ │ ├── service │ │ │ └── DummyService.java │ │ │ └── views.xml │ ├── gui │ │ └── src │ │ │ └── com │ │ │ └── company │ │ │ └── restmock │ │ │ └── screens.xml │ └── web │ │ ├── src │ │ └── com │ │ │ └── company │ │ │ └── restmock │ │ │ ├── rest-queries.xml │ │ │ ├── rest-services.xml │ │ │ ├── web-app.properties │ │ │ ├── web-dispatcher-spring.xml │ │ │ ├── web-menu.xml │ │ │ ├── web-permissions.xml │ │ │ ├── web-screens.xml │ │ │ ├── web-spring.xml │ │ │ └── web │ │ │ └── messages.properties │ │ └── web │ │ ├── META-INF │ │ └── context.xml │ │ └── WEB-INF │ │ └── web.xml ├── settings.gradle ├── studio-intellij.xml └── studio-settings.xml ├── test ├── cuba.spec.js ├── security.spec.js ├── storage.spec.js └── utlil.spec.js ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | indent_style = space 6 | indent_size = 2 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .local-storage 3 | node_modules 4 | npm-debug.log 5 | .nyc_output 6 | coverage 7 | .gradle -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .editorconfig 3 | .gradle 4 | .travis.yml 5 | node_modules 6 | tsconfig.json 7 | tslint.json 8 | 9 | src 10 | test 11 | test-app 12 | .nyc_output 13 | .local-storage 14 | coverage 15 | docs 16 | examples 17 | 18 | gradle 19 | gradlew 20 | gradlew.bat 21 | build.gradle -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - '8' 5 | script: npm run test:integration 6 | caches: 7 | directories: 8 | - node_modules 9 | - $HOME/.gradle/caches/ 10 | - $HOME/.gradle/wrapper/ -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | ## 0.7.0 3 | - Added `setSessionLocale` (issue [cuba-platform/front-generator#34](https://github.com/cuba-platform/front-generator/issues/34)) 4 | - Added feature detection mechanism (issue [#20](https://github.com/cuba-platform/cuba-rest-js/issues/20)) 5 | ## 0.6.0 6 | - Added `getFileUploadURL` and `getFile` methods (issue [#14](https://github.com/cuba-platform/cuba-rest-js/issues/14)) 7 | ## 0.5.3 8 | - Moved `PropertyType` type from `cuba-labs/cuba-react`. Added types `double`, `decimal`, `time`. Issue [#12](https://github.com/cuba-platform/cuba-rest-js/issues/12). 9 | ## 0.5.2 10 | - Added `searchEntitiesWithCount` method (issue [#10](https://github.com/cuba-platform/cuba-rest-js/issues/10)) 11 | ## 0.5.1 12 | - Typings for entities messages 13 | ## 0.5.0 14 | - Added `SerializedEntity` type 15 | - Added generic type parameter for fetching methods 16 | ## 0.4.1 17 | - Added `PredefinedView` enumeration 18 | ## 0.4.0 19 | - Added typings for browser dist 20 | - Added `loadEntityViews` and `loadEntityView` methods 21 | ## 0.3.0 22 | - Added methods to load entities and query results with count: `loadEntitiesWithCount`, `queryWithCount` 23 | - Ability to abort request via [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) 24 | ## 0.2.0 25 | - Added ability to specify custom token endpoint 26 | - Added `searchEntities` method (see [PL-8727](https://youtrack.cuba-platform.com/issue/PL-8727)) 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > :bulb: Moved to [cuba-platform/frontend/packages/cuba-rest-js](https://github.com/cuba-platform/frontend/tree/master/packages/cuba-rest-js) 2 | 3 | # CUBA REST JS 4 | 5 | [![Build Status](https://travis-ci.org/cuba-platform/cuba-rest-js.svg?branch=master)](https://travis-ci.org/cuba-platform/cuba-rest-js) 6 | 7 | JavaScript library for web and Node.js which facilitates CUBA Platfotm's REST API usage. 8 | 9 | ## Installation 10 | 11 | ### npm 12 | 13 | ```bash 14 | npm install @cuba-platform/rest --save 15 | ``` 16 | Import as module 17 | ```javascript 18 | const cuba = require('@cuba-platform/rest'); 19 | ``` 20 | 21 | Or using ES6 imports: 22 | 23 | ```javascript 24 | import * as cuba from '@cuba-platform/rest'; 25 | ``` 26 | 27 | ### bower 28 | ```bash 29 | bower install cuba-platform/cuba-rest-js 30 | ``` 31 | ```html 32 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /docs/interfaces/_cuba_.loginoptions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | LoginOptions | @cuba-platform/rest 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 65 |

Interface LoginOptions

66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |

Hierarchy

74 |
    75 |
  • 76 | LoginOptions 77 |
  • 78 |
79 |
80 |
81 |

Index

82 |
83 |
84 |
85 |

Properties

86 | 89 |
90 |
91 |
92 |
93 |
94 |

Properties

95 |
96 | 97 |

tokenEndpoint

98 |
tokenEndpoint: string
99 | 104 |
105 |
106 |
107 | 186 |
187 |
188 | 248 |
249 |

Generated using TypeDoc

250 |
251 |
252 | 253 | 254 | 255 | -------------------------------------------------------------------------------- /docs/interfaces/_filter_.condition.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Condition | @cuba-platform/rest 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 65 |

Interface Condition

66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |

Hierarchy

74 |
    75 |
  • 76 | Condition 77 |
  • 78 |
79 |
80 |
81 |

Index

82 |
83 |
84 |
85 |

Properties

86 | 91 |
92 |
93 |
94 |
95 |
96 |

Properties

97 |
98 | 99 |

operator

100 |
operator: OperatorType
101 | 106 |
107 |
108 | 109 |

property

110 |
property: string
111 | 116 |
117 |
118 | 119 |

value

120 |
value: string
121 | 126 |
127 |
128 |
129 | 190 |
191 |
192 | 252 |
253 |

Generated using TypeDoc

254 |
255 |
256 | 257 | 258 | 259 | -------------------------------------------------------------------------------- /docs/interfaces/_filter_.conditionsgroup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ConditionsGroup | @cuba-platform/rest 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 65 |

Interface ConditionsGroup

66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |

Hierarchy

74 |
    75 |
  • 76 | ConditionsGroup 77 |
  • 78 |
79 |
80 |
81 |

Index

82 |
83 |
84 |
85 |

Properties

86 | 90 |
91 |
92 |
93 |
94 |
95 |

Properties

96 |
97 | 98 |

conditions

99 |
conditions: Condition[]
100 | 105 |
106 |
107 | 108 |

group

109 |
group: GroupType
110 | 115 |
116 |
117 |
118 | 176 |
177 |
178 | 238 |
239 |

Generated using TypeDoc

240 |
241 |
242 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /docs/interfaces/_filter_.entityfilter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EntityFilter | @cuba-platform/rest 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 65 |

Interface EntityFilter

66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |

Hierarchy

74 |
    75 |
  • 76 | EntityFilter 77 |
  • 78 |
79 |
80 |
81 |

Index

82 |
83 |
84 |
85 |

Properties

86 | 89 |
90 |
91 |
92 |
93 |
94 |

Properties

95 |
96 | 97 |

conditions

98 |
conditions: Array<Condition | ConditionsGroup>
99 | 104 |
105 |
106 |
107 | 162 |
163 |
164 | 224 |
225 |

Generated using TypeDoc

226 |
227 |
228 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /docs/modules/_filter_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "filter" | @cuba-platform/rest 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "filter"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |

Index

71 |
72 |
73 |
74 |

Interfaces

75 | 80 |
81 |
82 |

Type aliases

83 | 87 |
88 |
89 |
90 |
91 |
92 |

Type aliases

93 |
94 | 95 |

GroupType

96 |
GroupType: "AND" | "OR"
97 | 102 |
103 |
104 | 105 |

OperatorType

106 |
OperatorType: "=" | ">" | ">=" | "<" | "<=" | "<>" | "startsWith" | "endsWith" | "contains" | "doesNotContain" | "in" | "notIn" | "notEmpty"
107 | 112 |
113 |
114 |
115 | 161 |
162 |
163 | 223 |
224 |

Generated using TypeDoc

225 |
226 |
227 | 228 | 229 | 230 | -------------------------------------------------------------------------------- /docs/modules/_storage_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "storage" | @cuba-platform/rest 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "storage"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |

Index

71 |
72 |
73 |
74 |

Classes

75 | 78 |
79 |
80 |
81 |
82 |
83 | 117 |
118 |
119 | 179 |
180 |

Generated using TypeDoc

181 |
182 |
183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /examples/node/README.md: -------------------------------------------------------------------------------- 1 | ```bash 2 | npm install 3 | node index.js 4 | ``` -------------------------------------------------------------------------------- /examples/node/index.js: -------------------------------------------------------------------------------- 1 | global.fetch = require('node-fetch'); 2 | global.localStorage = new require('node-localstorage').LocalStorage('./.local-storage'); 3 | 4 | const cuba = require('../../dist-node/cuba.js'); 5 | 6 | const app = cuba.initializeApp({apiUrl: 'http://localhost:8080/app/rest/'}); 7 | 8 | app.getUserInfo().then((d) => { 9 | console.log(d); 10 | }); 11 | 12 | app.login('admin', 'admin').then((d) => { 13 | console.log(d); 14 | }); -------------------------------------------------------------------------------- /examples/node/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cuba-rest-js-node-example", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "dependencies": { 6 | "encoding": { 7 | "version": "0.1.12", 8 | "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", 9 | "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=" 10 | }, 11 | "graceful-fs": { 12 | "version": "4.1.11", 13 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 14 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" 15 | }, 16 | "iconv-lite": { 17 | "version": "0.4.18", 18 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", 19 | "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==" 20 | }, 21 | "imurmurhash": { 22 | "version": "0.1.4", 23 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 24 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" 25 | }, 26 | "is-stream": { 27 | "version": "1.1.0", 28 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 29 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" 30 | }, 31 | "node-fetch": { 32 | "version": "1.7.1", 33 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.1.tgz", 34 | "integrity": "sha512-j8XsFGCLw79vWXkZtMSmmLaOk9z5SQ9bV/tkbZVCqvgwzrjAGq66igobLofHtF63NvMTp2WjytpsNTGKa+XRIQ==" 35 | }, 36 | "node-localstorage": { 37 | "version": "1.3.0", 38 | "resolved": "https://registry.npmjs.org/node-localstorage/-/node-localstorage-1.3.0.tgz", 39 | "integrity": "sha1-LkNqro3Mms6XtDxlwWwNV3vgpVw=" 40 | }, 41 | "slide": { 42 | "version": "1.1.6", 43 | "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", 44 | "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" 45 | }, 46 | "write-file-atomic": { 47 | "version": "1.3.4", 48 | "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", 49 | "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=" 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /examples/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cuba-rest-js-node-example", 3 | "version": "1.0.0", 4 | "description": "Example of cuba-rest-js in node js app", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "license": "Apache-2.0", 10 | "dependencies": { 11 | "node-fetch": "^1.7.1", 12 | "node-localstorage": "^1.3.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/vanillajs-browser/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CUBA JS SDK demo 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 |
14 | 15 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cuba-platform/rest", 3 | "version": "0.7.0-dev.4", 4 | "description": "JavaScript library for working with CUBA Platform's REST API v2", 5 | "main": "dist-node/cuba.js", 6 | "typings": "dist-node/cuba.d.ts", 7 | "scripts": { 8 | "lint": "tslint -c tslint.json src/**/*.ts", 9 | "start-test-app": "cd test-app && ./gradlew clean && ./gradlew setupTomcat && ./gradlew startDb && ./gradlew createDb && ./gradlew restartAndWaitForInitialization", 10 | "teardown-test-app": "cd test-app && ./gradlew stop && ./gradlew stopDb", 11 | "test:integration": "npm run start-test-app && nyc mocha -t 30000 && npm run teardown-test-app", 12 | "test": "nyc mocha", 13 | "prepare-browser-test": "browserify test/cuba.test.js > test/cuba-browser.test.js", 14 | "compile": "tsc", 15 | "types:browser": "tsc --declarationDir dist-browser --emitDeclarationOnly true", 16 | "dist": "npm run compile && browserify --standalone cuba dist-node/cuba.js > dist-browser/cuba.js", 17 | "generate-docs": "typedoc --module commonjs --out docs src && node create-nojekyll.js" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/cuba-platform/cuba-rest-js.git" 22 | }, 23 | "devDependencies": { 24 | "browserify": "^16.2.3", 25 | "chai": "^4.2.0", 26 | "mocha": "~5.0.5", 27 | "node-fetch": "^2.6.0", 28 | "nyc": "~14.1.1", 29 | "tslint": "~5.17.0", 30 | "typescript": "3.5.2" 31 | }, 32 | "engines": { 33 | "node": ">=6" 34 | }, 35 | "publishConfig": { 36 | "access": "public" 37 | }, 38 | "nyc": { 39 | "check-coverage": true, 40 | "statements": 79, 41 | "branches": 74, 42 | "functions": 69, 43 | "lines": 82 44 | }, 45 | "author": "Vlad Minaev ", 46 | "license": "Apache-2.0", 47 | "homepage": "https://github.com/cuba-platform/cuba-rest-js" 48 | } 49 | -------------------------------------------------------------------------------- /src/filter.ts: -------------------------------------------------------------------------------- 1 | export type OperatorType = '=' | '>' | '>=' | '<' | '<=' | '<>' | 'startsWith' | 'endsWith' | 'contains' 2 | | 'doesNotContain' | 'in' | 'notIn' | 'notEmpty'; 3 | 4 | export type GroupType = 'AND' | 'OR'; 5 | 6 | export interface EntityFilter { 7 | conditions: Array; 8 | } 9 | 10 | export interface ConditionsGroup { 11 | group: GroupType; 12 | conditions: Condition[]; 13 | } 14 | 15 | export interface Condition { 16 | property: string; 17 | operator: OperatorType; 18 | value: string | number | string[] | number[] | null; 19 | } 20 | -------------------------------------------------------------------------------- /src/model.ts: -------------------------------------------------------------------------------- 1 | export type Cardinality = 'NONE' | 'ONE_TO_ONE' | 'MANY_TO_ONE' | 'ONE_TO_MANY' | 'MANY_TO_MANY'; 2 | 3 | export type AttributeType = 'DATATYPE' | 'ENUM' | 'ASSOCIATION' | 'COMPOSITION'; 4 | 5 | export type PropertyType = 'string' | 'int' | 'double' | 'decimal' | 'date' | 'time' | 'dateTime' | 'boolean'; 6 | 7 | export interface SerializedEntityProps { 8 | _entityName: string; 9 | _instanceName: string; 10 | } 11 | 12 | export type SerializedEntity = SerializedEntityProps & T; 13 | 14 | export interface EntitiesWithCount { 15 | result: Array>; 16 | count: number; 17 | } 18 | 19 | export interface MetaPropertyInfo { 20 | name: string; 21 | type: string; 22 | mandatory: boolean; 23 | readOnly: boolean; 24 | isTransient: boolean; 25 | description: string; 26 | attributeType: AttributeType; 27 | cardinality: Cardinality; 28 | } 29 | 30 | export interface MetaClassInfo { 31 | entityName: string; 32 | properties: MetaPropertyInfo[]; 33 | } 34 | 35 | export interface UserInfo { 36 | id: string; 37 | login: string; 38 | name: string; 39 | firstName: string; 40 | middleName: string; 41 | lastName: string; 42 | position: string; 43 | email: string; 44 | timeZone: string; 45 | language: string; 46 | _instanceName: string; 47 | locale: string; 48 | } 49 | 50 | export type EntityOperationType = 'create' | 'read' | 'update' | 'delete'; 51 | 52 | export enum PermissionType { 53 | SCREEN = 'SCREEN', 54 | ENTITY_OP = 'ENTITY_OP', 55 | ENTITY_ATTR = 'ENTITY_ATTR', 56 | SPECIFIC = 'SPECIFIC', 57 | UI = 'UI' 58 | } 59 | 60 | export type BasePermissionValue = 'DENY' | 'ALLOW'; 61 | export type EntityAttrPermissionValue = 'DENY' | 'VIEW' | 'MODIFY'; 62 | export type UiPermissionValue = 'HIDE' | 'READ_ONLY' | 'SHOW'; 63 | 64 | export interface PermissionInfo { 65 | type: PermissionType; 66 | target: string; 67 | value: BasePermissionValue | EntityAttrPermissionValue | UiPermissionValue; 68 | intValue: number; 69 | } 70 | 71 | export enum RoleType { 72 | STANDARD = 'STANDARD', 73 | SUPER = 'SUPER', 74 | READONLY = 'READONLY', 75 | DENYING = 'DENYING', 76 | STRICTLY_DENYING = 'STRICTLY_DENYING' 77 | } 78 | 79 | export interface RoleInfo { 80 | roleType: RoleType | null; 81 | } 82 | 83 | export interface RolesInfo { 84 | permissions: PermissionInfo[]; 85 | roles: RoleInfo[]; 86 | } 87 | 88 | export interface EnumValueInfo { 89 | name: string; 90 | id: string | number; 91 | caption: string; 92 | } 93 | 94 | export interface EnumInfo { 95 | name: string; 96 | values: EnumValueInfo[]; 97 | } 98 | 99 | export type ViewProperty = string | {name: string, view: View}; 100 | 101 | export interface View { 102 | name: string; 103 | entity: string; 104 | properties: ViewProperty[]; 105 | } 106 | 107 | export enum PredefinedView { 108 | MINIMAL = '_minimal', 109 | LOCAL = '_local', 110 | BASE = '_base', // Available since CUBA 6.7 111 | } 112 | 113 | export interface EntityMessages { 114 | [messageKey: string]: string; 115 | } 116 | -------------------------------------------------------------------------------- /src/security.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BasePermissionValue, 3 | EntityAttrPermissionValue, 4 | EntityOperationType, 5 | PermissionInfo, 6 | PermissionType, 7 | RoleInfo, 8 | RoleType 9 | } from './model'; 10 | 11 | /** 12 | * 13 | * Define which type of attribute render allowed for user 14 | * 15 | * @param entityName CUBA model entity 16 | * @param attributeName 17 | * @param perms - list of user permissions 18 | * @param roles - list of user roles 19 | * @return attribute could be not allowed to display (DENY), allowed for modification (MODIFY) 20 | * or allowed in read only mode (VIEW). 21 | */ 22 | export function getAttributePermission(entityName: string, 23 | attributeName: string, 24 | perms: PermissionInfo[] | undefined, 25 | roles: RoleInfo[] | undefined): EntityAttrPermissionValue { 26 | 27 | if (!perms || !roles) return 'DENY'; 28 | 29 | if (hasRole(roles, RoleType.SUPER)) { 30 | return 'MODIFY'; 31 | } 32 | 33 | const perm = getMaxAllowedAttrPerm(entityName, attributeName, perms); 34 | 35 | // return 'DENY' if no permission exist and user in STRICTLY_DENYING role 36 | if (hasRole(roles, RoleType.STRICTLY_DENYING) && perm === null) { 37 | return 'DENY'; 38 | } 39 | 40 | return perm == null ? 'MODIFY' : perm.value as EntityAttrPermissionValue; 41 | } 42 | 43 | /** 44 | * Define if operation (one of CRUD) on entity allowed or not for user 45 | * 46 | * @param entityName CUBA model entity 47 | * @param operation - operation to be checked (CRUD) 48 | * @param perms - list of user permissions 49 | * @param roles - list of user roles 50 | */ 51 | export function isOperationAllowed(entityName: string, 52 | operation: EntityOperationType, 53 | perms: PermissionInfo[] | undefined, 54 | roles: RoleInfo[] | undefined): boolean { 55 | 56 | if (!perms || !roles) return false; 57 | 58 | if (hasRole(roles, RoleType.SUPER)) return true; 59 | 60 | const perm = getMaxAllowedOpPerm(entityName, operation, perms); 61 | 62 | // readonly role not affect read operation 63 | if (hasRole(roles, RoleType.READONLY) && operation !== 'read') { 64 | // operation (except read) is disabled for readonly role if no perm is set 65 | if (perm == null) return false; 66 | } 67 | 68 | if (hasRole(roles, RoleType.DENYING) || hasRole(roles, RoleType.STRICTLY_DENYING)) { 69 | // operation is disabled for denying roles if no perm is set 70 | if (perm == null) return false; 71 | } 72 | 73 | return perm == null || perm.value as BasePermissionValue !== 'DENY' ? true : false; 74 | } 75 | 76 | function getMaxAllowedOpPerm(entityName: string, 77 | operation: EntityOperationType, 78 | perms: PermissionInfo[]): PermissionInfo | null { 79 | 80 | const opFqn = `${entityName}:${operation}`; 81 | 82 | return perms 83 | .filter(perm => perm.type === PermissionType.ENTITY_OP && perm.target === opFqn) 84 | .reduce((resultPerm, perm) => { 85 | // assign result perm to maximum allowed permission between current and resultPerm 86 | if (resultPerm == null) return perm; 87 | if (perm.value as BasePermissionValue === 'ALLOW') return perm; 88 | return resultPerm; 89 | }, null); 90 | } 91 | 92 | function getMaxAllowedAttrPerm(entityName: string, 93 | attributeName: string, 94 | perms: PermissionInfo[]): PermissionInfo | null { 95 | 96 | const attrFqn = `${entityName}:${attributeName}`; 97 | 98 | return perms 99 | .filter(perm => perm.type === PermissionType.ENTITY_ATTR && perm.target === attrFqn) 100 | .reduce((resultPerm, perm) => { 101 | 102 | if (resultPerm === null) return perm; 103 | 104 | // assign result perm to maximum allowed permission between current and resultPerm 105 | const resultPermValue: EntityAttrPermissionValue = resultPerm.value as EntityAttrPermissionValue; 106 | const currentPermValue: EntityAttrPermissionValue = perm.value as EntityAttrPermissionValue; 107 | 108 | if (currentPermValue === 'MODIFY') return perm; 109 | if (currentPermValue === 'VIEW' && resultPermValue === 'DENY') return perm; 110 | return resultPerm; 111 | 112 | }, null); 113 | } 114 | 115 | function hasRole(roles: RoleInfo[], roleType: RoleType): boolean { 116 | return roles.some(r => r.roleType === roleType); 117 | } 118 | -------------------------------------------------------------------------------- /src/storage.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple im-memory storage compatible with localStorage/sessionStorage API. 3 | */ 4 | export class DefaultStorage implements Storage { 5 | 6 | private items = {}; 7 | 8 | get length(): number { 9 | return Object.keys(this.items).length; 10 | } 11 | 12 | public clear(): void { 13 | this.items = {}; 14 | } 15 | 16 | public getItem(key: string): string | any { 17 | return this.items[key]; 18 | } 19 | 20 | /** 21 | * @deprecated operation not supported 22 | */ 23 | public key(index: number): string | any { 24 | throw new Error('Unsupported operation'); 25 | } 26 | 27 | public removeItem(key: string): void { 28 | delete this.items[key]; 29 | } 30 | 31 | public setItem(key: string, data: string): void { 32 | this.items[key] = data; 33 | } 34 | 35 | [key: string]: any; 36 | [index: number]: string; 37 | } 38 | -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | declare const Buffer; 2 | declare const global; 3 | 4 | export function base64encode(str: string): string { 5 | /* tslint:disable:no-string-literal */ 6 | if (typeof btoa === 'function') { 7 | return btoa(str); 8 | } else if (global['Buffer']) { // prevent Buffer from being injected by browserify 9 | return new global['Buffer'](str).toString('base64'); 10 | } else { 11 | throw new Error('Unable to encode to base64'); 12 | } 13 | /* tslint:enable:no-string-literal */ 14 | } 15 | 16 | /** 17 | * Compares version strings. Intended to be used only for comparing versions consisting of major, minor and 18 | * (optional) patch version (dot-separated) and optional `-SNAPSHOT` suffix. Does not conform to 19 | * Semantic Versioning Specification and will produce incorrect results in some cases not covered above 20 | * (e.g. it doesn't take into account any text including pre-release identifiers, so 7.2.0-beta will be considered 21 | * equal to 7.2.0). 22 | * 23 | * @param testVersion 24 | * @param minimumVersion 25 | * 26 | * @returns true if testVersion is greater or equal than minimumVersion 27 | */ 28 | export function matchesVersion(testVersion: string, minimumVersion: string): boolean { 29 | if (!testVersion) { 30 | return false; 31 | } 32 | 33 | if (!minimumVersion) { 34 | throw new Error('Cannot determine required REST API version: the minimum version is not valid'); 35 | } 36 | 37 | const testVersionComponents = testVersion.split('.'); 38 | const requiredVersionComponents = minimumVersion.split('.'); 39 | 40 | for (let i = 0; i < requiredVersionComponents.length; i++) { 41 | const match = parseInt(requiredVersionComponents[i], 10); 42 | const test = parseInt(testVersionComponents[i], 10); 43 | 44 | if (isNaN(match) || match < 0) { 45 | throw new Error('Cannot determine required REST API version: the minimum version is not valid'); 46 | } 47 | 48 | if ((test === undefined || test === null || isNaN(test)) && match > 0) { 49 | // Required version has more components than test version, and current required version component is > 0 50 | return false; 51 | } 52 | 53 | if (test > match) { 54 | return true; 55 | } else if (test < match) { 56 | return false; 57 | } 58 | } 59 | 60 | // Versions are equal 61 | return true; 62 | } 63 | 64 | export function encodeGetParams(data): string { 65 | return Object 66 | .keys(data) 67 | .map((key) => { 68 | return encodeURIComponent(key) + "=" + (encodeURIComponent(serialize(data[key]))); 69 | }) 70 | .join("&"); 71 | } 72 | 73 | function serialize(rawParam): string { 74 | if (rawParam == null) { 75 | return ''; 76 | } 77 | if (typeof rawParam === 'object') { 78 | return JSON.stringify(rawParam); 79 | } 80 | return rawParam; 81 | } 82 | -------------------------------------------------------------------------------- /test-app/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .studio 3 | *.ipr 4 | *.iml 5 | *.iws 6 | build/* 7 | deploy/* 8 | modules/*/build/* 9 | out 10 | test-run -------------------------------------------------------------------------------- /test-app/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | buildscript { 3 | ext.cubaVersion = '7.2-SNAPSHOT' 4 | repositories { 5 | maven { 6 | url 'https://repo.cuba-platform.com/content/groups/work' 7 | credentials { 8 | username(rootProject.hasProperty('repoUser') ? rootProject['repoUser'] : 'cuba') 9 | password(rootProject.hasProperty('repoPass') ? rootProject['repoPass'] : 'cuba123') 10 | } 11 | } 12 | 13 | } 14 | dependencies { 15 | classpath "com.haulmont.gradle:cuba-plugin:$cubaVersion" 16 | } 17 | } 18 | 19 | def modulePrefix = 'app' 20 | 21 | def globalModule = project(":${modulePrefix}-global" ) 22 | def coreModule = project(":${modulePrefix}-core" ) 23 | def guiModule = project(":${modulePrefix}-gui" ) 24 | def webModule = project(":${modulePrefix}-web" ) 25 | 26 | def servletApi = 'javax.servlet:javax.servlet-api:3.1.0' 27 | 28 | 29 | apply(plugin: 'cuba') 30 | 31 | cuba { 32 | artifact { 33 | group = 'com.company.restmock' 34 | version = '0.1' 35 | isSnapshot = true 36 | } 37 | tomcat { 38 | dir = "$project.rootDir/deploy/tomcat" 39 | } 40 | } 41 | 42 | dependencies { 43 | appComponent("com.haulmont.cuba:cuba-global:$cubaVersion") 44 | appComponent('com.haulmont.addon.restapi:restapi-global:7.2-SNAPSHOT') 45 | 46 | } 47 | 48 | def hsql = 'org.hsqldb:hsqldb:2.4.1' 49 | 50 | configure([globalModule, coreModule, guiModule, webModule]) { 51 | apply(plugin: 'java') 52 | apply(plugin: 'maven') 53 | apply(plugin: 'cuba') 54 | 55 | dependencies { 56 | testCompile('junit:junit:4.12') 57 | } 58 | 59 | task sourceJar(type: Jar) { 60 | from file('src') 61 | classifier = 'sources' 62 | } 63 | 64 | artifacts { 65 | archives sourceJar 66 | } 67 | } 68 | 69 | configure(globalModule) { 70 | dependencies { 71 | if (!JavaVersion.current().isJava8()) { 72 | runtime('javax.xml.bind:jaxb-api:2.3.1') 73 | runtime('org.glassfish.jaxb:jaxb-runtime:2.3.1') 74 | } 75 | } 76 | entitiesEnhancing { 77 | main { enabled = true } 78 | } 79 | 80 | 81 | } 82 | 83 | configure(coreModule) { 84 | 85 | configurations { 86 | jdbc 87 | dbscripts 88 | } 89 | 90 | dependencies { 91 | compile(globalModule) 92 | compileOnly(servletApi) 93 | jdbc(hsql) 94 | testRuntime(hsql) 95 | 96 | } 97 | 98 | task cleanConf(description: 'Cleans up conf directory') { 99 | doLast { 100 | def dir = new File(cuba.tomcat.dir, "/conf/${modulePrefix}-core" ) 101 | if (dir.isDirectory()) { 102 | ant.delete(includeemptydirs: true) { 103 | fileset(dir: dir, includes: '**/*', excludes: 'local.app.properties') 104 | } 105 | } 106 | } 107 | } 108 | 109 | task deploy(dependsOn: [assemble, cleanConf], type: CubaDeployment) { 110 | appName = "${modulePrefix}-core" 111 | appJars(modulePrefix + '-global', modulePrefix + '-core') 112 | } 113 | 114 | task createDb(dependsOn: assembleDbScripts, description: 'Creates local database', type: CubaDbCreation) { 115 | dbms = 'hsql' 116 | host = 'localhost' 117 | dbName = 'restmock' 118 | dbUser = 'sa' 119 | dbPassword = '' 120 | } 121 | 122 | task updateDb(dependsOn: assembleDbScripts, description: 'Updates local database', type: CubaDbUpdate) { 123 | dbms = 'hsql' 124 | host = 'localhost' 125 | dbName = 'restmock' 126 | dbUser = 'sa' 127 | dbPassword = '' 128 | } 129 | 130 | task startDb(description: 'Starts local HSQLDB server', type: CubaHsqlStart) { 131 | dbPort = 9001 132 | dbName = 'restmock' 133 | } 134 | 135 | task stopDb(description: 'Stops local HSQLDB server', type: CubaHsqlStop) { 136 | dbPort = 9001 137 | dbName = 'restmock' 138 | } 139 | } 140 | 141 | configure(guiModule) { 142 | dependencies { 143 | compile(globalModule) 144 | 145 | } 146 | 147 | task deployConf(type: Copy) { 148 | from file('src') 149 | include "com/company/restmock/**" 150 | into "$cuba.tomcat.dir/conf/${modulePrefix}" 151 | } 152 | } 153 | 154 | configure(webModule) { 155 | configurations { 156 | webcontent 157 | } 158 | 159 | dependencies { 160 | compileOnly(servletApi) 161 | compile(guiModule) 162 | 163 | } 164 | 165 | task webArchive(type: Zip) { 166 | from file("$buildDir/web") 167 | from file('web') 168 | classifier = 'web' 169 | } 170 | 171 | artifacts { 172 | archives webArchive 173 | } 174 | 175 | task deployConf(type: Copy) { 176 | from file('src') 177 | include "com/company/restmock/**" 178 | into "$cuba.tomcat.dir/conf/${modulePrefix}" 179 | } 180 | 181 | task clearMessagesCache(type: CubaClearMessagesCache) { 182 | appName = "${modulePrefix}" 183 | } 184 | deployConf.dependsOn clearMessagesCache 185 | 186 | task cleanConf(description: 'Cleans up conf directory') { 187 | doLast { 188 | def dir = new File(cuba.tomcat.dir, "/conf/${modulePrefix}" ) 189 | if (dir.isDirectory()) { 190 | ant.delete(includeemptydirs: true) { 191 | fileset(dir: dir, includes: '**/*', excludes: 'local.app.properties') 192 | } 193 | } 194 | } 195 | } 196 | 197 | task deploy(dependsOn: [assemble, cleanConf], type: CubaDeployment) { 198 | appName = "${modulePrefix}" 199 | appJars(modulePrefix + '-global', modulePrefix + '-gui', modulePrefix + '-web') 200 | } 201 | } 202 | 203 | task undeploy(type: Delete, dependsOn: ":${modulePrefix}-web:cleanConf" ) { 204 | delete("$cuba.tomcat.dir/shared") 205 | delete("$cuba.tomcat.dir/webapps/${modulePrefix}-core" ) 206 | delete("$cuba.tomcat.dir/webapps/${modulePrefix}" ) 207 | } 208 | 209 | task restart(dependsOn: ['stop', ":${modulePrefix}-core:deploy" , ":${modulePrefix}-web:deploy" ], description: 'Redeploys applications and restarts local Tomcat') { 210 | doLast { 211 | ant.waitfor(maxwait: 6, maxwaitunit: 'second', checkevery: 2, checkeveryunit: 'second') { 212 | not { 213 | socket(server: 'localhost', port: '8787') 214 | } 215 | } 216 | } 217 | } 218 | restart.finalizedBy start 219 | 220 | task startAndWaitForInitialization( 221 | dependsOn: ['start'], 222 | description: 'Starts local Tomcat and waits until the app is initialized' 223 | ) { 224 | ant.waitfor(maxwait: 10, maxwaitunit: 'second', checkevery: 1, checkeveryunit: 'second') { 225 | http(url: 'http://localhost:8080/app/rest/health') 226 | } 227 | } 228 | 229 | task restartAndWaitForInitialization(dependsOn: ['stop', ":${modulePrefix}-core:deploy" , ":${modulePrefix}-web:deploy" ], description: 'Redeploys application,' + 230 | ' restarts local Tomcat, waits until app initialized') { 231 | doLast { 232 | ant.waitfor(maxwait: 6, maxwaitunit: 'second', checkevery: 2, checkeveryunit: 'second') { 233 | not { 234 | socket(server: 'localhost', port: '8787') 235 | } 236 | } 237 | } 238 | } 239 | restartAndWaitForInitialization.finalizedBy startAndWaitForInitialization 240 | 241 | 242 | apply from: 'extra.gradle' 243 | -------------------------------------------------------------------------------- /test-app/extra.gradle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuba-platform/cuba-rest-js/c84f5571758c2daf61efd786f98f35b72faa7310/test-app/extra.gradle -------------------------------------------------------------------------------- /test-app/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuba-platform/cuba-rest-js/c84f5571758c2daf61efd786f98f35b72faa7310/test-app/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /test-app/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Feb 06 01:04:28 SAMT 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip 7 | -------------------------------------------------------------------------------- /test-app/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /test-app/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /test-app/modules/core/db/init/hsql/10.create-db.sql: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test-app/modules/core/db/init/hsql/20.create-db.sql: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test-app/modules/core/db/init/hsql/30.create-db.sql: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test-app/modules/core/src/com/company/restmock/app.properties: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Configuration # 3 | ############################################################################### 4 | 5 | cuba.dbmsType = hsql 6 | 7 | cuba.springContextConfig = +com/company/restmock/spring.xml 8 | 9 | cuba.persistenceConfig = +com/company/restmock/persistence.xml 10 | 11 | cuba.metadataConfig = +com/company/restmock/metadata.xml 12 | 13 | cuba.viewsConfig = +com/company/restmock/views.xml 14 | 15 | cuba.mainMessagePack = +com.company.restmock.core 16 | 17 | cuba.keyForSecurityTokenEncryption = H0bsi9JIe46DRr2D 18 | 19 | cuba.anonymousSessionId = eacbb4e0-a57c-c716-de3b-05c1511db5df 20 | 21 | ############################################################################### 22 | # Other # 23 | ############################################################################### 24 | 25 | cuba.webContextName = app-core 26 | cuba.availableLocales = English|en 27 | cuba.localeSelectVisible = false -------------------------------------------------------------------------------- /test-app/modules/core/src/com/company/restmock/service/DummyServiceBean.java: -------------------------------------------------------------------------------- 1 | package com.company.restmock.service; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | @Service(DummyService.NAME) 6 | public class DummyServiceBean implements DummyService { 7 | 8 | @Override 9 | public void voidNoParams() { 10 | } 11 | 12 | @Override 13 | public void voidWithParams(String stringParam, int intParam) { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /test-app/modules/core/src/com/company/restmock/spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test-app/modules/core/test/com/company/restmock/RestmockTestContainer.java: -------------------------------------------------------------------------------- 1 | package com.company.restmock; 2 | 3 | import com.haulmont.bali.util.Dom4j; 4 | import com.haulmont.cuba.testsupport.TestContainer; 5 | import org.dom4j.Document; 6 | import org.dom4j.Element; 7 | 8 | import java.io.File; 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | 12 | public class RestmockTestContainer extends TestContainer { 13 | 14 | public RestmockTestContainer() { 15 | super(); 16 | appComponents = new ArrayList<>(Arrays.asList( 17 | "com.haulmont.cuba" 18 | // add CUBA premium add-ons here 19 | // "com.haulmont.bpm", 20 | // "com.haulmont.charts", 21 | // "com.haulmont.fts", 22 | // "com.haulmont.reports", 23 | // and custom app components if any 24 | )); 25 | appPropertiesFiles = Arrays.asList( 26 | // List the files defined in your web.xml 27 | // in appPropertiesConfig context parameter of the core module 28 | "com/company/restmock/app.properties", 29 | // Add this file which is located in CUBA and defines some properties 30 | // specifically for test environment. You can replace it with your own 31 | // or add another one in the end. 32 | "test-app.properties"); 33 | initDbProperties(); 34 | } 35 | 36 | private void initDbProperties() { 37 | File contextXmlFile = new File("modules/core/web/META-INF/context.xml"); 38 | if (!contextXmlFile.exists()) { 39 | contextXmlFile = new File("web/META-INF/context.xml"); 40 | } 41 | if (!contextXmlFile.exists()) { 42 | throw new RuntimeException("Cannot find 'context.xml' file to read database connection properties. " + 43 | "You can set them explicitly in this method."); 44 | } 45 | Document contextXmlDoc = Dom4j.readDocument(contextXmlFile); 46 | Element resourceElem = contextXmlDoc.getRootElement().element("Resource"); 47 | 48 | dbDriver = resourceElem.attributeValue("driverClassName"); 49 | dbUrl = resourceElem.attributeValue("url"); 50 | dbUser = resourceElem.attributeValue("username"); 51 | dbPassword = resourceElem.attributeValue("password"); 52 | } 53 | 54 | public static class Common extends RestmockTestContainer { 55 | 56 | public static final RestmockTestContainer.Common INSTANCE = new RestmockTestContainer.Common(); 57 | 58 | private static volatile boolean initialized; 59 | 60 | private Common() { 61 | } 62 | 63 | @Override 64 | public void before() throws Throwable { 65 | if (!initialized) { 66 | super.before(); 67 | initialized = true; 68 | } 69 | setupContext(); 70 | } 71 | 72 | @Override 73 | public void after() { 74 | cleanupContext(); 75 | // never stops - do not call super 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /test-app/modules/core/test/com/company/restmock/core/SampleIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.company.restmock.core; 2 | 3 | import com.company.restmock.RestmockTestContainer; 4 | import com.haulmont.cuba.core.EntityManager; 5 | import com.haulmont.cuba.core.Persistence; 6 | import com.haulmont.cuba.core.Transaction; 7 | import com.haulmont.cuba.core.TypedQuery; 8 | import com.haulmont.cuba.core.global.AppBeans; 9 | import com.haulmont.cuba.core.global.DataManager; 10 | import com.haulmont.cuba.core.global.Metadata; 11 | import com.haulmont.cuba.security.entity.User; 12 | import org.junit.After; 13 | import org.junit.Before; 14 | import org.junit.ClassRule; 15 | import org.junit.Test; 16 | 17 | import java.util.List; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | 21 | public class SampleIntegrationTest { 22 | 23 | @ClassRule 24 | public static RestmockTestContainer cont = RestmockTestContainer.Common.INSTANCE; 25 | 26 | private Metadata metadata; 27 | private Persistence persistence; 28 | private DataManager dataManager; 29 | 30 | @Before 31 | public void setUp() throws Exception { 32 | metadata = cont.metadata(); 33 | persistence = cont.persistence(); 34 | dataManager = AppBeans.get(DataManager.class); 35 | } 36 | 37 | @After 38 | public void tearDown() throws Exception { 39 | } 40 | 41 | @Test 42 | public void testLoadUser() { 43 | try (Transaction tx = persistence.createTransaction()) { 44 | EntityManager em = persistence.getEntityManager(); 45 | TypedQuery query = em.createQuery( 46 | "select u from sec$User u where u.login = :userLogin", User.class); 47 | query.setParameter("userLogin", "admin"); 48 | List users = query.getResultList(); 49 | tx.commit(); 50 | assertEquals(1, users.size()); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /test-app/modules/core/web/META-INF/context.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test-app/modules/core/web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | appPropertiesConfig 10 | 11 | 12 | classpath:com/company/restmock/app.properties 13 | /WEB-INF/local.app.properties 14 | "file:${catalina.base}/conf/app-core/local.app.properties" 15 | 16 | 17 | 18 | 19 | appComponents 20 | com.haulmont.cuba com.haulmont.addon.restapi 21 | 22 | 23 | com.haulmont.cuba.core.sys.AppContextLoader 24 | 25 | 26 | 27 | remoting 28 | com.haulmont.cuba.core.sys.remoting.RemotingServlet 29 | 1 30 | 31 | 32 | 33 | remoting 34 | /remoting/* 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /test-app/modules/global/src/com/company/restmock/metadata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /test-app/modules/global/src/com/company/restmock/persistence.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test-app/modules/global/src/com/company/restmock/service/DummyService.java: -------------------------------------------------------------------------------- 1 | package com.company.restmock.service; 2 | 3 | 4 | public interface DummyService { 5 | String NAME = "restmock_DummyService"; 6 | 7 | void voidNoParams(); 8 | 9 | void voidWithParams(String stringParam, int intParam); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /test-app/modules/global/src/com/company/restmock/views.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test-app/modules/gui/src/com/company/restmock/screens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test-app/modules/web/src/com/company/restmock/rest-queries.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test-app/modules/web/src/com/company/restmock/rest-services.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /test-app/modules/web/src/com/company/restmock/web-app.properties: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Configuration # 3 | ############################################################################### 4 | 5 | cuba.springContextConfig = +com/company/restmock/web-spring.xml 6 | 7 | cuba.dispatcherSpringContextConfig = +com/company/restmock/web-dispatcher-spring.xml 8 | 9 | cuba.persistenceConfig = +com/company/restmock/persistence.xml 10 | 11 | cuba.metadataConfig = +com/company/restmock/metadata.xml 12 | 13 | cuba.viewsConfig = +com/company/restmock/views.xml 14 | 15 | cuba.windowConfig = +com/company/restmock/web-screens.xml 16 | 17 | cuba.menuConfig = +com/company/restmock/web-menu.xml 18 | 19 | cuba.permissionConfig = +com/company/restmock/web-permissions.xml 20 | 21 | cuba.mainMessagePack = +com.company.restmock.web 22 | 23 | cuba.anonymousSessionId = eacbb4e0-a57c-c716-de3b-05c1511db5df 24 | 25 | cuba.creditsConfig = + 26 | 27 | ############################################################################### 28 | # Other # 29 | ############################################################################### 30 | 31 | # Middleware connection 32 | cuba.connectionUrlList = http://localhost:8080/app-core 33 | 34 | # Set to false if the middleware works on different JVM 35 | cuba.useLocalServiceInvocation = true 36 | 37 | cuba.webContextName = app 38 | cuba.availableLocales = English|en 39 | cuba.localeSelectVisible = false 40 | 41 | 42 | # REST 43 | cuba.rest.anonymousEnabled = true 44 | cuba.rest.queriesConfig = +com/company/restmock/rest-queries.xml 45 | cuba.rest.servicesConfig = +com/company/restmock/rest-services.xml 46 | cuba.themeConfig=com/haulmont/cuba/havana-theme.properties com/haulmont/cuba/halo-theme.properties com/haulmont/cuba/hover-theme.properties 47 | cuba.web.loginScreenId=loginWindow 48 | cuba.web.mainScreenId=mainWindow 49 | cuba.gui.genericFilterApplyImmediately=false 50 | -------------------------------------------------------------------------------- /test-app/modules/web/src/com/company/restmock/web-dispatcher-spring.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /test-app/modules/web/src/com/company/restmock/web-menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /test-app/modules/web/src/com/company/restmock/web-permissions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test-app/modules/web/src/com/company/restmock/web-screens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /test-app/modules/web/src/com/company/restmock/web-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test-app/modules/web/src/com/company/restmock/web/messages.properties: -------------------------------------------------------------------------------- 1 | 2 | application.caption = CUBA Application 3 | application.logoImage = branding/app-icon-menu.png 4 | 5 | loginWindow.caption = CUBA Login 6 | loginWindow.welcomeLabel = Welcome to CUBA! 7 | loginWindow.logoImage = branding/app-icon-login.png 8 | 9 | menu-config.application-restmock = Application 10 | -------------------------------------------------------------------------------- /test-app/modules/web/web/META-INF/context.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /test-app/modules/web/web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | appPropertiesConfig 10 | 11 | 12 | classpath:com/company/restmock/web-app.properties 13 | /WEB-INF/local.app.properties 14 | "file:${catalina.base}/conf/app/local.app.properties" 15 | 16 | 17 | 18 | 19 | appComponents 20 | com.haulmont.cuba com.haulmont.addon.restapi 21 | 22 | 23 | com.vaadin.server.communication.JSR356WebsocketInitializer 24 | 25 | 26 | com.haulmont.cuba.web.sys.WebAppContextLoader 27 | 28 | 29 | app_servlet 30 | com.haulmont.cuba.web.sys.CubaApplicationServlet 31 | 32 | true 33 | 34 | 35 | dispatcher 36 | com.haulmont.cuba.web.sys.CubaDispatcherServlet 37 | 1 38 | 39 | 40 | dispatcher 41 | /dispatch/* 42 | 43 | 44 | app_servlet 45 | /* 46 | 47 | 48 | 49 | cuba_filter 50 | com.haulmont.cuba.web.sys.CubaHttpFilter 51 | true 52 | 53 | 54 | cuba_filter 55 | /* 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /test-app/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'rest-mock' 2 | def modulePrefix = 'app' 3 | include(":${modulePrefix}-global" , ":${modulePrefix}-core" , ":${modulePrefix}-gui" , ":${modulePrefix}-web" ) 4 | project(":${modulePrefix}-global" ).projectDir = new File(settingsDir, 'modules/global') 5 | project(":${modulePrefix}-core" ).projectDir = new File(settingsDir, 'modules/core') 6 | project(":${modulePrefix}-gui" ).projectDir = new File(settingsDir, 'modules/gui') 7 | project(":${modulePrefix}-web" ).projectDir = new File(settingsDir, 'modules/web') -------------------------------------------------------------------------------- /test-app/studio-intellij.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | -------------------------------------------------------------------------------- /test-app/studio-settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/cuba.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const assert = require('assert'); 4 | const cuba = require('../dist-node/cuba.js'); 5 | global.fetch = require('node-fetch'); 6 | 7 | const apiUrl = 'http://localhost:8080/app/rest/'; 8 | 9 | 10 | describe('cuba', function () { 11 | 12 | describe('.initializeApp()', function () { 13 | it('simple initialization', function () { 14 | const app = cuba.initializeApp(); 15 | assert.strictEqual(typeof app, 'object'); 16 | cuba.removeApp(); 17 | }); 18 | it('initialization with the same name fails', function (done) { 19 | try { 20 | cuba.initializeApp(); 21 | cuba.initializeApp(); 22 | done('initialized twice'); 23 | } catch (e) { 24 | done() 25 | } 26 | cuba.removeApp(); 27 | }); 28 | it('initialization with same explicit name fails', function(done) { 29 | assert.throws(function() { 30 | cuba.initializeApp({name: 'app2'}); 31 | cuba.initializeApp({name: 'app2'}); 32 | done('initialized twice'); 33 | }, Error); 34 | done(); 35 | }); 36 | it('initialization with explicit parameters', function(done) { 37 | const app = cuba.initializeApp({ 38 | apiUrl: apiUrl, 39 | name: 'AppCreatedWithExplicitParams', 40 | restClientId: 'client', 41 | restClientSecret: 'secret', 42 | defaultLocale: 'en', 43 | storage: { 44 | clear: () => { 45 | done(); 46 | } 47 | } 48 | }); 49 | assert.strictEqual(typeof app, 'object'); 50 | cuba.removeApp('AppCreatedWithExplicitParams'); 51 | }) 52 | }); 53 | 54 | describe('.getApp()', function () { 55 | it('initialize and retrieve - default config', function () { 56 | let app = cuba.initializeApp(); 57 | assert.strictEqual(app, cuba.getApp()); 58 | cuba.removeApp(); 59 | }); 60 | }); 61 | 62 | describe('.removeApp()', function() { 63 | it('throws when trying to get non-existent app', function (done) { 64 | assert.throws(function() { 65 | cuba.removeApp('Non-existent app name'); 66 | }, Error); 67 | done(); 68 | }); 69 | }); 70 | 71 | describe('.getBasicAuthHeaders()', function() { 72 | it('uses default locale if not passed explicitly', function() { 73 | const headers = cuba.getBasicAuthHeaders('client', 'secret'); 74 | assert.equal(headers['Accept-Language'], 'en'); 75 | }); 76 | }); 77 | }); 78 | 79 | describe('CubaApp', function () { 80 | 81 | let app; 82 | 83 | before(function () { 84 | app = new cuba.CubaApp('', apiUrl); 85 | return app.login('admin', 'admin'); 86 | }); 87 | 88 | describe('.login()', function () { 89 | it('shouldn\'t work with bad credentials', function (done) { 90 | const newApp = new cuba.CubaApp('', apiUrl); 91 | newApp.login('admin', 'admin2') 92 | .then(() => { 93 | done('works with bad credentials'); 94 | }) 95 | .catch(() => { 96 | done() 97 | }); 98 | }); 99 | it('should not work with empty credentials', function(done) { 100 | const newApp = new cuba.CubaApp('', apiUrl); 101 | newApp.login(null, null) 102 | .then(() => { 103 | done('works with empty credentials'); 104 | }) 105 | .catch(() => { 106 | done(); 107 | }); 108 | }); 109 | it('should work with right credentials', function () { 110 | const newApp = new cuba.CubaApp('', apiUrl); 111 | return newApp.login('admin', 'admin'); 112 | }); 113 | }); 114 | 115 | 116 | it('.loadMetadata()', function () { 117 | return app.loadMetadata(); 118 | }); 119 | 120 | it('.loadMessages()', function () { 121 | return app.loadEntitiesMessages(); 122 | }); 123 | 124 | it('.loadEnums()', function () { 125 | return app.loadEnums(); 126 | }); 127 | 128 | it('.getUserInfo()', function () { 129 | return app.getUserInfo(); 130 | }); 131 | 132 | it('.loadEntity()', function (done) { 133 | app.loadEntity('sec$User', 'a405db59-e674-4f63-8afe-269dda788fe8') 134 | .then((entity) => { 135 | assert(entity._instanceName != null); 136 | done(); 137 | }) 138 | .catch((e) => { 139 | done(e) 140 | }); 141 | }); 142 | 143 | describe('.commitEntity()', function () { 144 | it('should create new entity and pass persisted one in promise', function (done) { 145 | const role = { 146 | name: 'Manager', 147 | description: 'Role for managers', 148 | type: 'READONLY' 149 | }; 150 | 151 | app.commitEntity('sec$Role', role) 152 | .then(function (createdEntity) { 153 | app.loadEntity('sec$Role', createdEntity.id).then((entity) => { 154 | assert.strictEqual(entity.name, role.name); 155 | assert(entity.id != null); 156 | done(); 157 | }); 158 | }) 159 | .catch(function (e) { 160 | done(e); 161 | }); 162 | }); 163 | 164 | it('should update existing entity', function (done) { 165 | const admRole = { 166 | id: '0c018061-b26f-4de2-a5be-dff348347f93', 167 | description: 'Updated role description' 168 | }; 169 | app.commitEntity('sec$Role', admRole) 170 | .then(function () { 171 | app.loadEntity('sec$Role', admRole.id).then((updatedRole) => { 172 | assert(updatedRole.description === admRole.description); 173 | done(); 174 | }); 175 | }) 176 | .catch(function (e) { 177 | done(e); 178 | }) 179 | }); 180 | }); 181 | 182 | describe('.deleteEntity()', function () { 183 | it('should delete entity', function (done) { 184 | app.commitEntity('sec$Role', {name: 'newRole'}).then(function (newRole) { 185 | app.deleteEntity('sec$Role', newRole.id) 186 | .then(function () { 187 | done(); 188 | }) 189 | .catch(function (e) { 190 | done(e); 191 | }); 192 | }) 193 | }); 194 | 195 | }); 196 | 197 | describe('.loadEntities()', function () { 198 | it('should load list of entities', function (done) { 199 | const options = { 200 | view: '_minimal', 201 | limit: 1, 202 | }; 203 | app.loadEntities('sec$User', options) 204 | .then(function (users) { 205 | assert.strictEqual(users.length, 1); 206 | assert.ok(!users[0].hasOwnProperty('password')); 207 | assert(users[0]._instanceName != null); 208 | done(); 209 | }) 210 | .catch(function (e) { 211 | done(e); 212 | }); 213 | }); 214 | }); 215 | 216 | describe('.loadEntitiesWithCount()', function () { 217 | it('should return entities and count', function (done) { 218 | app.loadEntitiesWithCount('sec$User') 219 | .then(function (resp) { 220 | assert(Array.isArray(resp.result), '.result is not array'); 221 | assert(resp.result.length === 2, 'result array should contain 2 entities'); 222 | assert(resp.count === 2, 'count should be 2'); 223 | assert(resp.result[0]._instanceName != null); 224 | done(); 225 | }) 226 | .catch(function (e) { 227 | done(e) 228 | }); 229 | }) 230 | }); 231 | 232 | const simpleFilter = { 233 | conditions: [{ 234 | property: 'name', 235 | operator: 'contains', 236 | value: 'adm' 237 | }] 238 | }; 239 | 240 | const groupConditionsFilter = { 241 | conditions: [{ 242 | group: 'OR', 243 | conditions: [{ 244 | property: 'name', 245 | operator: 'contains', 246 | value: 'adm' 247 | }, { 248 | property: 'active', 249 | operator: '=', 250 | value: true 251 | }] 252 | }] 253 | }; 254 | 255 | describe('.searchEntities()', function () { 256 | it('should search entities by a simple condition', function () { 257 | return app.searchEntities('sec$User', simpleFilter); 258 | }); 259 | it('should search group conditions', function () { 260 | return app.searchEntities('sec$User', groupConditionsFilter); 261 | }) 262 | }); 263 | 264 | describe('.searchEntitiesWithCount()', function () { 265 | it('should search entities by a simple condition', function (done) { 266 | app.searchEntitiesWithCount('sec$User', simpleFilter) 267 | .then(function (resp) { 268 | assert(Array.isArray(resp.result), '.result is not array'); 269 | assert(resp.result.length === 1, 'result array should contain 1 entities, contains ' + resp.result.length); 270 | assert(resp.count === 1, 'count should be 1'); 271 | assert(resp.result[0]._instanceName != null); 272 | done(); 273 | }) 274 | .catch(function (e) { 275 | done(e) 276 | }); 277 | }); 278 | it('should search group conditions', function (done) { 279 | app.searchEntitiesWithCount('sec$User', groupConditionsFilter) 280 | .then(function (resp) { 281 | assert(Array.isArray(resp.result), '.result is not array'); 282 | assert(resp.result.length === 2, 'result array should contain 2 entities, contains ' + resp.result.length); 283 | assert(resp.count === 2, 'count should be 2'); 284 | assert(resp.result[0]._instanceName != null); 285 | done(); 286 | }) 287 | .catch(function (e) { 288 | done(e) 289 | }); 290 | }) 291 | }); 292 | 293 | describe('.query()', function () { 294 | it('should load query results', function () { 295 | return app.query('sec$User', 'allUsers') 296 | }); 297 | it('should work with params', function (done) { 298 | app.query('sec$User', 'userByLogin', {login: 'admin'}) 299 | .then(function (users) { 300 | users.forEach((u) => { 301 | assert(u.login === 'admin'); 302 | }); 303 | done(); 304 | }) 305 | .catch((e) => { 306 | done(e); 307 | }); 308 | }) 309 | }); 310 | 311 | describe('.invokeService()', function () { 312 | it('should invoke service without params and void result', function () { 313 | return app.invokeService('restmock_DummyService', 'voidNoParams'); 314 | }); 315 | it('should invoke service with params', function() { 316 | return app.invokeService('restmock_DummyService', 'voidWithParams', { 317 | stringParam: 'stringParam', 318 | intParam: 42 319 | }); 320 | }); 321 | it('should not fail if null passed as params', function () { 322 | return app.invokeService('restmock_DummyService', 'voidNoParams', null); 323 | }) 324 | }); 325 | 326 | describe('.loadEntityViews()', function () { 327 | it('should load entity views', async function () { 328 | const views = await app.loadEntityViews('sec$User'); 329 | assert(Array.isArray(views)); 330 | }) 331 | }); 332 | 333 | describe('.loadEntityView()', function () { 334 | it('should load particular view', async function () { 335 | const view = await app.loadEntityView('sec$User', 'user.browse'); 336 | assert(typeof view === 'object'); 337 | }) 338 | }); 339 | 340 | describe('.setSessionLocale()', function () { 341 | it('should set session locale', function () { 342 | return app.setSessionLocale(); 343 | }); 344 | }); 345 | 346 | describe('.getApiVersion()', function () { 347 | it('should get API version', async function () { 348 | const version = await app.getApiVersion(); 349 | assert(version); 350 | assert(version.length); 351 | assert(version.length > 0); 352 | }); 353 | }); 354 | 355 | describe('.refreshApiVersion()', function () { 356 | it('should refresh API version', async function () { 357 | const version = await app.refreshApiVersion(); 358 | assert.equal(version, app.apiVersion); 359 | }) 360 | }); 361 | 362 | describe('.onLocaleChange()', function() { 363 | it('invokes a callback on locale change', function(done) { 364 | const callback = () => done(); 365 | app.onLocaleChange(callback); 366 | app.locale = 'en'; 367 | }); 368 | }); 369 | 370 | }); 371 | 372 | describe('CubaApp version <7.2.0', function () { 373 | 374 | let app; 375 | const initApiVersion = '5.5.5'; 376 | 377 | before(function () { 378 | app = new cuba.CubaApp('', apiUrl, undefined, undefined, undefined, undefined, initApiVersion); 379 | return app.login('admin', 'admin'); 380 | }); 381 | 382 | describe('.setSessionLocal()', function(done) { 383 | it('should fail if version doesn\'t match', function(done) { 384 | app.setSessionLocale() 385 | .then(() => { 386 | done('did not fail'); 387 | }) 388 | .catch(reason => { 389 | assert(reason === cuba.CubaApp.NOT_SUPPORTED_BY_API_VERSION); 390 | done(); 391 | }); 392 | }); 393 | }); 394 | 395 | }); 396 | 397 | describe('CubaApp not logged in', function() { 398 | describe('.setSessionLocal()', function() { 399 | it('should fail if not logged in', function(done) { 400 | const app = new cuba.CubaApp('', apiUrl); 401 | app.setSessionLocale() 402 | .then(() => { 403 | done('did not fail'); 404 | }) 405 | .catch(reason => { 406 | done(); 407 | }) 408 | }); 409 | }); 410 | }); 411 | -------------------------------------------------------------------------------- /test/security.spec.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const security = require('../dist-node/security'); 3 | 4 | describe('security', function () { 5 | it('should return correct attribute permission', function () { 6 | 7 | expect(security.getAttributePermission('scr$Car', 'mileage', undefined, undefined)).to.equal('DENY'); 8 | expect(security.getAttributePermission('scr$Car', 'mileage', [], [])).to.equal('MODIFY'); 9 | 10 | let perms = [{ 11 | type: "ENTITY_ATTR", 12 | target: "scr$Car:mileage", 13 | value: "DENY", 14 | intValue: 0 15 | }]; 16 | 17 | // we don't disable attr for DENYING role, only for STRICTLY_DENYING 18 | expect(security.getAttributePermission('scr$Car', 'ecoRank', perms, 19 | [{roleType: 'DENYING'}])) 20 | .to.equal('MODIFY'); 21 | 22 | // always max permission if SUPER role exist 23 | expect(security.getAttributePermission('scr$Car', 'mileage', [], 24 | [{roleType: 'STRICTLY_DENYING'}, {roleType: 'SUPER'}])) 25 | .to.equal('MODIFY'); 26 | 27 | const rolesStrictDeny = [{roleType: 'STRICTLY_DENYING'}]; 28 | 29 | expect(security.getAttributePermission('scr$Car', 'mileage', [], rolesStrictDeny)) 30 | .to.equal('DENY'); 31 | expect(security.getAttributePermission('scr$Car', 'mileage', perms, rolesStrictDeny)) 32 | .to.equal('DENY'); 33 | expect(security.getAttributePermission('scr$Car', 'ecoRank', perms, rolesStrictDeny)) 34 | .to.equal('DENY'); 35 | 36 | 37 | perms = [{ 38 | type: "ENTITY_ATTR", 39 | target: "scr$Car:mileage", 40 | value: "VIEW", 41 | intValue: 0 42 | }]; 43 | 44 | expect(security.getAttributePermission('scr$Car', 'mileage', perms, rolesStrictDeny)) 45 | .to.equal('VIEW'); 46 | expect(security.getAttributePermission('scr$Car', 'ecoRank', perms, rolesStrictDeny)) 47 | .to.equal('DENY'); 48 | 49 | perms = [{ 50 | type: "ENTITY_ATTR", 51 | target: "scr$Car:mileage", 52 | value: "VIEW", 53 | intValue: 1 54 | }, { 55 | type: "ENTITY_ATTR", 56 | target: "scr$Car:mileage", 57 | value: "MODIFY", 58 | intValue: 2 59 | }]; 60 | 61 | expect(security.getAttributePermission('scr$Car', 'mileage', perms, rolesStrictDeny)) 62 | .to.equal('MODIFY'); 63 | expect(security.getAttributePermission('scr$Car', 'ecoRank', perms, rolesStrictDeny)) 64 | .to.equal('DENY'); 65 | }); 66 | 67 | it('should define if operation allowed or not', function () { 68 | expect(security.isOperationAllowed('scr$Car', 'create', undefined, undefined)) 69 | .to.eq(false); 70 | expect(security.isOperationAllowed('scr$Car', 'create', [], [])) 71 | .to.eq(true); 72 | 73 | expect(security.isOperationAllowed('scr$Car', 'create', [], [])) 74 | .to.eq(true); 75 | expect(security.isOperationAllowed('scr$Car', 'create', [], 76 | [{roleType: 'READONLY'}])) 77 | .to.eq(false); 78 | 79 | // read op allowed for READONLY role 80 | expect(security.isOperationAllowed('scr$Car', 'read', [], 81 | [{roleType: 'READONLY'}])) 82 | .to.eq(true); 83 | 84 | // op not allowed for DENY\STRICT if permission not exist 85 | expect(security.isOperationAllowed('scr$Car', 'read', [], 86 | [{roleType: 'DENYING'}])) 87 | .to.eq(false); 88 | 89 | expect(security.isOperationAllowed('scr$Car', 'create', [], [])) 90 | .to.eq(true); 91 | 92 | // if has SUPER - allow all 93 | expect(security.isOperationAllowed('scr$Car', 'create', [], 94 | [{roleType: 'READONLY'}, {roleType: 'SUPER'}])) 95 | .to.eq(true); 96 | 97 | let perms = [{ 98 | type: "ENTITY_OP", 99 | target: "scr$Car:create", 100 | value: "DENY", 101 | intValue: 0 102 | }]; 103 | expect(security.isOperationAllowed('scr$Car', 'create', perms, [])) 104 | .to.eq(false); 105 | 106 | /* roles are ignored if we have allow perm */ 107 | 108 | perms = [{ 109 | type: "ENTITY_OP", 110 | target: "scr$Car:create", 111 | value: "DENY", 112 | intValue: 0 113 | }, { 114 | type: "ENTITY_OP", 115 | target: "scr$Car:create", 116 | value: "ALLOW", 117 | intValue: 0 118 | }, { 119 | type: "ENTITY_OP", 120 | target: "scr$Car:read", 121 | value: "ALLOW", 122 | intValue: 0 123 | }]; 124 | expect(security.isOperationAllowed('scr$Car', 'create', perms, [])) 125 | .to.eq(true); 126 | expect(security.isOperationAllowed('scr$Car', 'create', perms, 127 | [{roleType: 'READONLY'}])) 128 | .to.eq(true); 129 | expect(security.isOperationAllowed('scr$Car', 'read', perms, 130 | [{roleType: 'READONLY'}])) 131 | .to.eq(true); 132 | expect(security.isOperationAllowed('scr$Car', 'create', perms, 133 | [{roleType: 'READONLY'}, {roleType: 'DENYING'}])) 134 | .to.eq(true); 135 | 136 | 137 | }); 138 | }); 139 | -------------------------------------------------------------------------------- /test/storage.spec.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const cuba = require('../dist-node/cuba'); 3 | 4 | describe('DefaultStorage', function () { 5 | describe('constructor', function () { 6 | it('creation', function () { 7 | assert.equal(typeof new cuba.DefaultStorage(), 'object'); 8 | }); 9 | }); 10 | 11 | describe('.length', function () { 12 | const storage = new cuba.DefaultStorage(); 13 | it('should be 0 for just created instance', function () { 14 | assert.equal(storage.length, 0); 15 | }); 16 | it('should be incremented on items addition', function () { 17 | storage.setItem('item1', 'value1'); 18 | storage.setItem('item2', 'value2'); 19 | assert.equal(storage.length, 2); 20 | }); 21 | it('should be decremented on items removing', function () { 22 | storage.removeItem('item2'); 23 | assert.equal(storage.length, 1) 24 | }) 25 | }); 26 | 27 | describe('.setItem()', function () { 28 | const storage = new cuba.DefaultStorage(); 29 | it('should add item', function () { 30 | storage.setItem('key1', 'value'); 31 | assert.equal(storage.getItem('key1'), 'value'); 32 | }); 33 | }); 34 | 35 | describe('.removeItem()', function() { 36 | const storage = new cuba.DefaultStorage(); 37 | it('should remove item', function() { 38 | storage.setItem('item1', 'value1'); 39 | storage.removeItem('item1'); 40 | assert.equal(typeof storage.getItem('item1'), 'undefined'); 41 | }); 42 | }); 43 | 44 | describe('.clear()', function () { 45 | it('clears all items', function () { 46 | const storage = new cuba.DefaultStorage(); 47 | storage.setItem('item1', 1); 48 | storage.setItem('item2', 2); 49 | storage.clear(); 50 | assert.equal(typeof storage.getItem('item1'), 'undefined'); 51 | assert.equal(typeof storage.getItem('item2'), 'undefined'); 52 | assert.equal(storage.length, 0); 53 | }); 54 | }); 55 | 56 | describe('.key()', function () { 57 | it('should throw an exception since not implemented', function () { 58 | const storage = new cuba.DefaultStorage(); 59 | storage.setItem('item1', 'value1'); 60 | assert.throws(() => storage.key(0), Error); 61 | }); 62 | }) 63 | 64 | }); -------------------------------------------------------------------------------- /test/utlil.spec.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const util = require('../dist-node/util'); 4 | 5 | describe('util', function() { 6 | 7 | it('.base64()', function() { 8 | assert.equal(util.base64encode('lorem ipsum'), 'bG9yZW0gaXBzdW0='); 9 | }); 10 | 11 | describe('.encodeGetParams()', function() { 12 | it ('converts own properties to get params list', function() { 13 | assert.equal(util.encodeGetParams({a: 'b'}), 'a=b'); 14 | }); 15 | it ('encodes URL unsafe symbols', function() { 16 | assert.equal(util.encodeGetParams({a: '?', b: 'абв'}), 'a=%3F&b=%D0%B0%D0%B1%D0%B2'); 17 | }); 18 | it ('serializes nested objects as JSON', function() { 19 | assert.equal(util.encodeGetParams({a: {c: 'd', f: '%'}}), "a=%7B%22c%22%3A%22d%22%2C%22f%22%3A%22%25%22%7D"); 20 | }); 21 | }); 22 | 23 | describe('.matchesVersion()', function () { 24 | it('should compare versions correctly', async function () { 25 | const matchesVersion = util.matchesVersion; 26 | assert(matchesVersion('7.2.0', '7.2.0')); 27 | assert(matchesVersion('7.2.1', '7.2.0')); 28 | assert(matchesVersion('7.3.0', '7.2.0')); 29 | assert(matchesVersion('7.3.0', '7.2.9')); 30 | assert(matchesVersion('7.2.10', '7.2.2')); 31 | assert(matchesVersion('7.2.0', '7.2')); 32 | assert(matchesVersion('7.10.0', '7.9.0')); 33 | assert(matchesVersion('7.02.0', '7.2.0')); 34 | assert(matchesVersion('8.2.0', '7.2.0')); 35 | assert(matchesVersion('7.2-SNAPSHOT', '7.2.0')); 36 | assert(matchesVersion('7.2.0-SNAPSHOT', '7.2.0')); 37 | assert(matchesVersion('7.2beta', '7.2.0')); 38 | assert(matchesVersion('7.2.beta', '7.2.0')); 39 | 40 | assert(!matchesVersion('7.2.0', '7.2.1')); 41 | assert(!matchesVersion('7.2.0', '7.3.0')); 42 | assert(!matchesVersion('7.2.0', '8.2.0')); 43 | assert(!matchesVersion('7.2-SNAPSHOT', '7.2.1')); 44 | assert(!matchesVersion('7.2-SNAPSHOT', '7.3.0')); 45 | assert(!matchesVersion('7.2.0-SNAPSHOT', '7.2.1')); 46 | assert(!matchesVersion('0', '7.2.0')); 47 | assert(!matchesVersion(undefined, '7.2.0')); 48 | assert(!matchesVersion(null, '7.2.0')); 49 | assert(!matchesVersion('A string that cannot be converted to a semver', '7.2.0')); 50 | 51 | assert.throws(() => matchesVersion('7.2.0', undefined)); 52 | assert.throws(() => matchesVersion('7.2.0', null)); 53 | assert.throws(() => matchesVersion('7.2.0', 'A string that cannot be converted to a semver')); 54 | }) 55 | }); 56 | 57 | 58 | }); 59 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES5", 4 | "noEmitOnError": true, 5 | "removeComments": false, 6 | "declaration": true, 7 | "outDir": "dist-node", 8 | "lib": [ 9 | "DOM", 10 | "ES5", 11 | "ES2015.Promise", 12 | "ES2015.Symbol", 13 | "ES2015.Iterable" 14 | ] 15 | }, 16 | "include": [ 17 | "src/**/*" 18 | ], 19 | "exclude": [ 20 | "node_modules" 21 | ] 22 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rules": { 4 | "max-line-length": [true, 120], 5 | "object-literal-sort-keys": false, 6 | "no-string-literal": false, 7 | "quotemark": false, 8 | "interface-name": false, 9 | "ordered-imports": false, 10 | "trailing-comma": false, 11 | "no-trailing-whitespace": false, 12 | "curly": { 13 | "options": "ignore-same-line" 14 | }, 15 | "arrow-parens": false 16 | } 17 | } 18 | --------------------------------------------------------------------------------