Compare commits

...

70 Commits

Author SHA1 Message Date
Diana Lau 13371fd2a1
Merge pull request #4343 from achrinzafork/chore/update-lts
chore: update LTS status to End-of-Life
2021-03-05 20:01:03 -05:00
Rifa Achrinza 1316be55c5 chore: update LTS status to End-of-Life
see https://github.com/strongloop/loopback-next/issues/6957
Co-authored-by: Diana Lau <dhmlau@ca.ibm.com>
2021-03-04 18:21:00 +08:00
jannyHou a22d4f9197 3.28.0
* upgrade nodemailer to greater than 6.4.16 (jannyHou)
 * chore: sync LoopBack 4 with Node.js v14 EOL (Rifa Achrinza)
 * chore: add Node.js 14 to travis (Diana Lau)
 * Remove "major" and "p1" from stalebot (Miroslav Bajtoš)
2020-11-25 17:06:34 -05:00
Diana Lau 223dd5d58e
Merge pull request #4338 from achrinzafork/chore/update-module-lts-node14
chore: sync LoopBack 4 with Node.js v14 EOL
2020-11-25 09:29:27 -05:00
Janny fbd9783e47
Merge pull request #4340 from strongloop/upgrade-nodemailer
chore: upgrade nodemailer
2020-11-24 15:34:12 -05:00
jannyHou 6f04b61f88 upgrade nodemailer to greater than 6.4.16
Signed-off-by: jannyHou <juehou@ca.ibm.com>
2020-11-24 11:56:27 -05:00
Rifa Achrinza ab3e159fed chore: sync LoopBack 4 with Node.js v14 EOL
see https://github.com/strongloop/loopback-next/issues/6709
2020-11-03 17:22:07 +08:00
Diana Lau 5b61efb855
Merge pull request #4334 from strongloop/travis
chore: add Node.js 14 to travis
2020-09-10 15:24:16 -04:00
Diana Lau e457e2651d chore: add Node.js 14 to travis 2020-07-28 13:31:44 -04:00
Miroslav Bajtoš ab2e462ca6
Merge pull request #4318 from strongloop/bajtos-patch-1
Remove "major" and "p1" from stalebot
2020-03-10 16:41:24 +01:00
Miroslav Bajtoš f2f7332916
Remove "major" and "p1" from stalebot
LoopBack 3 is in Maintenance LTS mode, only critical bugs and critical
security fixes will be provided. Major and p1 issues are not qualified
and if nobody submits a pull request for them, then they should be
automatically closed as stale.
2020-03-10 15:56:10 +01:00
Miroslav Bajtoš 06fcaa144e
3.27.0
* Update LTS status in README (Miroslav Bajtoš)
 * chore: update copyright year (Diana Lau)
 * feat: change hasone relation error message (Sujesh T)
 * chore: disable security issue reporting (Nora)
 * chore: fix eslint violations (Nora)
 * fixup! manual fixes (Miroslav Bajtoš)
 * fixup! eslint --fix . (Miroslav Bajtoš)
 * chore: update eslint & eslint-config to latest (Miroslav Bajtoš)
 * chore: update dev-dependencies (Miroslav Bajtoš)
 * chore: update chai to v4, dirty-chai to v2 (Miroslav Bajtoš)
 * Updated "ismail" package to v3.2 (Stanislav Sarbinski)
 * Introduce issue templates for bugs, features, etc. (Miroslav Bajtoš)
 * Improve PULL_REQUEST_TEMPLATE (Miroslav Bajtoš)
 * test: use Chromium (not Chrome) when available (Miroslav Bajtoš)
 * test: disable Chrome sandboxing when inside Docker (Miroslav Bajtoš)
 * test: switch from PhantomJS to HeadlessChrome (Miroslav Bajtoš)
2020-03-06 10:00:20 +01:00
Miroslav Bajtoš d929b57da4
Merge pull request #4315 from strongloop/feat/maintenance-lts
Update LTS status in README
2020-03-06 09:59:09 +01:00
Miroslav Bajtoš 58f65454e9
Update LTS status in README 2020-03-05 13:40:44 +01:00
Diana Lau cdf48b648e
Merge pull request #4303 from strongloop/copyright
chore: update copyright year
2020-01-23 15:07:27 -05:00
Diana Lau f788aae464 chore: update copyright year 2020-01-21 14:19:18 -05:00
Diana Lau 6a7fc529fc
Merge pull request #4290 from sujeshthekkepatt/fix/hasone-relation-error-message
feat: change hasone relation error message
2019-12-15 19:32:43 -05:00
Sujesh T b93187b0f9 feat: change hasone relation error message
The current hasone error message is not appropriate one.
So adds a better message.
2019-12-02 23:28:02 +05:30
Nora 2db09a3d00
Merge pull request #4281 from strongloop/chore/improve-issue-templates
chore: disable security issue reporting
2019-11-19 15:41:03 -05:00
Nora 4edcc4f14c chore: disable security issue reporting 2019-11-18 23:48:24 -05:00
Nora b848bd9d9f
Merge pull request #4283 from strongloop/fix-comma-dangle
chore: fix eslint violations
2019-11-18 23:44:59 -05:00
Nora aa76a19e33 chore: fix eslint violations
Fix comma-dangle violations.
2019-11-17 14:04:57 -05:00
Miroslav Bajtoš f2f0b3aa91
Merge pull request #4267 from strongloop/update-dev-deps
Update dev dependencies + switch from "var" to "const"
2019-10-08 08:21:20 +02:00
Miroslav Bajtoš 82cd6681f6
fixup! manual fixes
Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-10-07 11:54:59 +02:00
Miroslav Bajtoš 397d141036
fixup! eslint --fix .
Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-10-07 11:54:59 +02:00
Miroslav Bajtoš aec86ccc3f
chore: update eslint & eslint-config to latest
Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-10-07 11:54:59 +02:00
Miroslav Bajtoš 5dd9561cb6
chore: update dev-dependencies
Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-10-07 11:54:59 +02:00
Miroslav Bajtoš dd6d2a5e6c
chore: update chai to v4, dirty-chai to v2
Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-10-07 11:54:59 +02:00
Miroslav Bajtoš da51c992ba
Merge pull request #4241 from Sarbinski/issue-4239/update-ismail-lib-for-mail-validation
Updated "isemail" package to ver. 3.2.x
2019-10-07 11:39:17 +02:00
Stanislav Sarbinski 4846048e48
Updated "ismail" package to v3.2 2019-10-07 11:19:19 +02:00
Miroslav Bajtoš edb925529e
Merge pull request #4266 from strongloop/improve/github-templates
Improve issue & pull-request templates
2019-10-07 11:10:33 +02:00
Miroslav Bajtoš bd276d551a
Introduce issue templates for bugs, features, etc.
Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-10-07 10:35:17 +02:00
Miroslav Bajtoš 83612aac8f
Improve PULL_REQUEST_TEMPLATE
Make it easier for contributors to mix the text provided by GitHub
from the commit messages with the template content.

Rework the checklist to follow the style we use in loopback-next.

Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-10-04 10:43:05 +02:00
Miroslav Bajtoš af9f776ed0
Merge pull request #4262 from strongloop/fix/ci
test: switch from PhantomJS to HeadlessChrome
2019-10-03 15:20:30 +02:00
Miroslav Bajtoš 387835faef
test: use Chromium (not Chrome) when available
Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-10-01 09:27:03 +02:00
Miroslav Bajtoš 8311138f3e
test: disable Chrome sandboxing when inside Docker
See the discussion in
https://github.com/docker/for-linux/issues/496

Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-10-01 09:27:02 +02:00
Miroslav Bajtoš cceb8a3c26
test: switch from PhantomJS to HeadlessChrome
Rework browser tests to run in Headless Chrome instead of PhantomJS,
because the latter is no longer maintained.

This allows us to remove transpilation to ES5 via babelify, which
significantly improves speed of our tests.

Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-10-01 09:12:17 +02:00
Miroslav Bajtoš 9b1d4885ab
3.26.0
* fix: disallow queries in username and email fields (Hage Yaapa)
 * Ignore failing downstream dependencies (Miroslav Bajtoš)
 * Upgrade nyc to version 14 (Miroslav Bajtoš)
 * Update Karma dependencies to latest versions (Miroslav Bajtoš)
 * Drop Node.js 6.x from the supported versions (Miroslav Bajtoš)
 * Fix Model.exists() to work with remote connector (Maxim Sharai)
 * chore: update copyrights years (Agnes Lin)
 * Update LTS status (Diana Lau)
 * Enable Node.js 12.x on Travis CI (Miroslav Bajtoš)
 * chore: update copyright year (Diana Lau)
 * chore: update LB3 EOL date (Diana Lau)
2019-05-31 09:04:12 +02:00
Hage Yaapa 58a0e6c8e9 fix: disallow queries in username and email fields
Username and email fields should not allow queries.
2019-05-30 19:54:01 +05:30
Miroslav Bajtoš e682914ecd
Merge pull request #4196 from strongloop/ignore-failing-downstream-builds
Ignore failing downstream dependencies
2019-05-14 18:49:25 +02:00
Miroslav Bajtoš 716347e25c
Ignore failing downstream dependencies
The following dependencies are always failing the CI builds, let's
ignore them when testing changes in `loopback` package:

- bluemix-service-broker
- gateway-director-bluemix
- plan-manager

Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-05-14 16:17:23 +02:00
Miroslav Bajtoš cd8db0b5cf
Merge pull request #4194 from strongloop/update-karma-nyc
Drop Node.js 6.x + update Karma and nyc dependencies to their latest versions
2019-05-14 09:45:23 +02:00
Miroslav Bajtoš 686c6fe88e
Upgrade nyc to version 14 2019-05-14 09:03:36 +02:00
Miroslav Bajtoš c9a277884e
Update Karma dependencies to latest versions 2019-05-14 09:03:36 +02:00
Miroslav Bajtoš a685553b49
Drop Node.js 6.x from the supported versions
Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-05-14 09:03:36 +02:00
Miroslav Bajtoš 4b3a3a347c
Merge pull request #4120 from angfal/fix/remote_exists
Fix Model.exists() to work with remote connector
2019-05-13 15:55:45 +02:00
Maxim Sharai e8d115bdc2
Fix Model.exists() to work with remote connector 2019-05-13 15:47:38 +02:00
Agnes Lin ae3fff9e7b
Merge pull request #4191 from strongloop/copyrights
chore: update copyrights years
2019-05-07 10:24:44 -04:00
Agnes Lin 0e0ca455ac chore: update copyrights years 2019-05-06 16:10:57 -04:00
Diana Lau e82a74cce3
Merge pull request #4189 from strongloop/eol
Update LTS status
2019-05-03 09:37:14 -04:00
Diana Lau 182ab7fb22 Update LTS status 2019-05-03 08:18:45 -04:00
Miroslav Bajtoš 3a2a645e0c
Merge pull request #4186 from strongloop/chore/add-node-12
Enable Node.js 12.x on Travis CI
2019-04-29 09:22:42 +02:00
Miroslav Bajtoš f19a8ab6fe
Enable Node.js 12.x on Travis CI 2019-04-29 09:13:05 +02:00
Diana Lau 66ec2aa57f
Merge pull request #4183 from strongloop/copyright
chore: update copyright year
2019-04-17 13:24:02 -04:00
Diana Lau f6ba1afe91 chore: update copyright year 2019-04-17 12:10:45 -04:00
Diana Lau b05d7320d7
Merge pull request #4159 from strongloop/lts
chore: update LB3 EOL date
2019-03-18 15:13:46 -04:00
Diana Lau a175b36939 chore: update LB3 EOL date 2019-03-18 12:25:14 -04:00
Miroslav Bajtoš 34acd02a7e
3.25.1
* Back-ticks added to highlight example JSON (Quentin Presley)
 * Add same change to description for findOne (Quentin Presley)
 * Update the description for persisted-models (Quentin Presley)
 * handle $2b$ in hashed password check (Sylvain Dumont)
2019-03-15 16:08:23 +01:00
Miroslav Bajtoš a9a86fe380
Merge pull request #4158 from strongloop/fixFilterDef
Update the description for persisted-models
2019-03-15 16:05:37 +01:00
Quentin Presley b83f5635cf Back-ticks added to highlight example JSON 2019-03-15 07:46:15 -07:00
Quentin Presley 6caf506769 Add same change to description for findOne 2019-03-15 07:43:13 -07:00
Quentin Presley b91938ecdf Update the description for persisted-models 2019-03-15 07:39:40 -07:00
Janny c8a31e2725
Merge pull request #4146 from sylvaindumont/patch-1
handle $2b$ in hashed password check
2019-02-25 13:01:53 -05:00
Sylvain Dumont 4226da5fc4
handle $2b$ in hashed password check
bcrypt made $2b$ the default in bcrypt 2.0.0
2019-02-23 16:14:24 +01:00
Miroslav Bajtoš 1e33ec596f
3.25.0
* Support middleware injected by AppDynamics. (Mike Li)
2019-02-05 14:23:17 +01:00
Miroslav Bajtoš c38900b785
Merge pull request #4119 from studykik/fix/appdynamics-proxy
Support middleware injected by AppDynamics
2019-02-05 14:22:15 +01:00
Mike Li edb8dbc517 Support middleware injected by AppDynamics.
AppDynamics injects a proxy object into the router stack, which it
uses for its network analysis.  This is similar to how NewRelic
adds a sentinel handler to the router stack. This commit adds a
similar workaround so that loopback can find the original layer.
2019-01-25 11:12:41 -08:00
Miroslav Bajtoš b77907ffa5
3.24.2
* Fix crash when modifying an unknown user (Matheus Horstmann)
2019-01-11 16:04:43 +01:00
Miroslav Bajtoš 242c20fecf
Merge pull request #4108 from horstmannmat/fix_4105
Fix crash when modifying a user with an unknown id
2019-01-11 16:04:15 +01:00
Matheus Horstmann 2532b0b67e
Fix crash when modifying an unknown user
Signed-off-by: Matheus Horstmann <mch15@inf.ufpr.br>
Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-01-11 15:45:00 +01:00
111 changed files with 2989 additions and 2647 deletions

View File

@ -1,37 +0,0 @@
<!--
Questions:
https://groups.google.com/forum/#!forum/loopbackjs
https://gitter.im/strongloop/loopback
Immediate support:
https://strongloop.com/api-connect-faqs/
https://strongloop.com/node-js/subscription-plans/
-->
# Description/Steps to reproduce
<!--
If feature: A description of the feature
If bug: Steps to reproduce
-->
# Link to reproduction sandbox
<!--
Link to an app sandbox for reproduction
Note: Failure to provide a sandbox application for reproduction purposes will result in the issue being closed.
-->
# Expected result
<!--
Also include actual results if bug
-->
# Additional information
<!--
Copy+paste the output of these two commands:
node -e 'console.log(process.platform, process.arch, process.versions.node)'
npm ls --prod --depth 0 | grep loopback
-->

53
.github/ISSUE_TEMPLATE/Bug_report.md vendored Normal file
View File

@ -0,0 +1,53 @@
---
name: Bug report
about: Create a report to help us improve
labels: bug
---
<!-- 🚨 STOP 🚨 STOP 🚨 STOP 🚨
Are you using LoopBack version 4? Please report the bug here:
https://github.com/strongloop/loopback-next/issues/new
HELP US HELP YOU, PLEASE
- Do a quick search to avoid duplicate issues
- Provide as much information as possible (reproduction sandbox, use case for features, etc.)
- Consider using a more suitable venue for questions such as Stack Overflow, Gitter, etc.
Please fill in the *entire* template below.
-->
## Steps to reproduce
<!-- Describe how to reproduce the issue -->
## Current Behavior
<!-- Describe the observed result -->
## Expected Behavior
<!-- Describe what did you expect instead, what is the desired outcome? -->
## Link to reproduction sandbox
<!--
See https://loopback.io/doc/en/contrib/Reporting-issues.html#loopback-3x-bugs
Note: Failure to provide a sandbox application for reproduction purposes will result in the issue being closed.
-->
## Additional information
<!--
Copy+paste the output of these two commands:
node -e 'console.log(process.platform, process.arch, process.versions.node)'
npm ls --prod --depth 0 | grep loopback
-->
## Related Issues
<!-- Did you find other bugs that looked similar? -->
_See [Reporting Issues](http://loopback.io/doc/en/contrib/Reporting-issues.html) for more tips on writing good issues_

View File

@ -0,0 +1,34 @@
---
name: Feature request
about: Suggest an idea for this project
labels: feature
---
<!-- 🚨 STOP 🚨 STOP 🚨 STOP 🚨
LoopBack version 3 is in LTS mode, we are not accepting new features.
We are actively developing version 4, you can find the new GitHub
repository here: https://github.com/strongloop/loopback-next
-->
## Suggestion
<!-- A summary of what you'd like to see added or changed -->
## Use Cases
<!--
What do you want to use this for?
What shortcomings exist with current approaches?
-->
## Examples
<!-- Show how this would be used and what the behavior would be -->
## Acceptance criteria
TBD - will be filled by the team.

27
.github/ISSUE_TEMPLATE/Question.md vendored Normal file
View File

@ -0,0 +1,27 @@
---
name: Question
about: The issue tracker is not for questions. Please use Stack Overflow or other resources for help.
labels: question
---
<!-- 🚨 STOP 🚨 STOP 🚨 STOP 🚨
THE ISSUE TRACKER IS NOT FOR QUESTIONS.
DO NOT CREATE A NEW ISSUE TO ASK A QUESTION.
Please use one of the following resources for help:
**Questions**
- https://stackoverflow.com/tags/loopbackjs
- https://groups.google.com/forum/#!forum/loopbackjs
- https://gitter.im/strongloop/loopback
**Immediate support**
- https://strongloop.com/api-connect-faqs/
- https://strongloop.com/node-js/subscription-plans/
-->

16
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,16 @@
blank_issues_enabled: false
contact_links:
- name: Report a security vulnerability
url: https://loopback.io/doc/en/contrib/Reporting-issues.html#security-issues
about: >
LoopBack 3 has reached End-of-Life. No new security fixes will be provided
or accepted.
Do not report security vulnerabilities using GitHub issues. Please send an
email to `reachsl@us.ibm.com` instead.
- name: Get help on StackOverflow
url: https://stackoverflow.com/tags/loopbackjs
about: Please ask and answer questions on StackOverflow.
- name: Join our mailing list
url: https://groups.google.com/forum/#!forum/loopbackjs
about: You can also post your question to our mailing list.

View File

@ -1,25 +1,18 @@
### Description
#### Related issues
<!--
Please use the following link syntaxes:
Please provide a high-level description of the changes made by your pull request.
- connect to #49 (to reference issues in the current repository)
- connect to strongloop/loopback#49 (to reference issues in another repository)
Include references to all related GitHub issues and other pull requests, for example:
Fixes #123
Implements #254
See also #23
-->
- connect to <link_to_referenced_issue>
## Checklist
### Checklist
<!--
- Please mark your choice with an "x" (i.e. [x], see
https://github.com/blog/1375-task-lists-in-gfm-issues-pulls-comments)
- PR's without test coverage will be closed.
-->
👉 [Read and sign the CLA (Contributor License Agreement)](https://cla.strongloop.com/agreements/strongloop/loopback) 👈
- [ ] `npm test` passes on your machine
- [ ] New tests added or existing tests modified to cover all changes
- [ ] Code conforms with the [style
guide](http://loopback.io/doc/en/contrib/style-guide.html)
- [ ] Code conforms with the [style guide](https://loopback.io/doc/en/contrib/style-guide-es6.html)
- [ ] Commit messages are following our [guidelines](https://loopback.io/doc/en/contrib/git-commit-messages.html)

2
.github/stale.yml vendored
View File

@ -7,8 +7,6 @@ exemptLabels:
- pinned
- security
- critical
- p1
- major
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable

View File

@ -1,22 +1,15 @@
sudo: false
language: node_js
node_js:
- "6"
- "8"
- "10"
- "12"
- "14"
addons:
chrome: stable
after_success: npm run coverage
# see https://www.npmjs.com/package/phantomjs-prebuilt#continuous-integration
cache:
directories:
- travis_phantomjs
before_install:
- npm config set registry http://ci.strongloop.com:4873/
# Upgrade PhantomJS to v2.1.1.
- "export PHANTOMJS_VERSION=2.1.1"
- "export PATH=$PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64/bin:$PATH"
- "if [ $(phantomjs --version) != $PHANTOMJS_VERSION ]; then rm -rf $PWD/travis_phantomjs; mkdir -p $PWD/travis_phantomjs; fi"
- "if [ $(phantomjs --version) != $PHANTOMJS_VERSION ]; then wget https://github.com/Medium/phantomjs/releases/download/v$PHANTOMJS_VERSION/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 -O $PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2; fi"
- "if [ $(phantomjs --version) != $PHANTOMJS_VERSION ]; then tar -xvf $PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 -C $PWD/travis_phantomjs; fi"
- "phantomjs --version"

View File

@ -1,3 +1,101 @@
2020-11-25, Version 3.28.0
==========================
* upgrade nodemailer to greater than 6.4.16 (jannyHou)
* chore: sync LoopBack 4 with Node.js v14 EOL (Rifa Achrinza)
* chore: add Node.js 14 to travis (Diana Lau)
* Remove "major" and "p1" from stalebot (Miroslav Bajtoš)
2020-03-06, Version 3.27.0
==========================
* Update LTS status in README (Miroslav Bajtoš)
* chore: update copyright year (Diana Lau)
* feat: change hasone relation error message (Sujesh T)
* chore: disable security issue reporting (Nora)
* chore: fix eslint violations (Nora)
* fixup! manual fixes (Miroslav Bajtoš)
* fixup! eslint --fix . (Miroslav Bajtoš)
* chore: update eslint & eslint-config to latest (Miroslav Bajtoš)
* chore: update dev-dependencies (Miroslav Bajtoš)
* chore: update chai to v4, dirty-chai to v2 (Miroslav Bajtoš)
* Updated "ismail" package to v3.2 (Stanislav Sarbinski)
* Introduce issue templates for bugs, features, etc. (Miroslav Bajtoš)
* Improve PULL_REQUEST_TEMPLATE (Miroslav Bajtoš)
* test: use Chromium (not Chrome) when available (Miroslav Bajtoš)
* test: disable Chrome sandboxing when inside Docker (Miroslav Bajtoš)
* test: switch from PhantomJS to HeadlessChrome (Miroslav Bajtoš)
2019-05-31, Version 3.26.0
==========================
* fix: disallow queries in username and email fields (Hage Yaapa)
* Ignore failing downstream dependencies (Miroslav Bajtoš)
* Upgrade nyc to version 14 (Miroslav Bajtoš)
* Update Karma dependencies to latest versions (Miroslav Bajtoš)
* Drop Node.js 6.x from the supported versions (Miroslav Bajtoš)
* Fix Model.exists() to work with remote connector (Maxim Sharai)
* chore: update copyrights years (Agnes Lin)
* Update LTS status (Diana Lau)
* Enable Node.js 12.x on Travis CI (Miroslav Bajtoš)
* chore: update copyright year (Diana Lau)
* chore: update LB3 EOL date (Diana Lau)
2019-03-15, Version 3.25.1
==========================
* Back-ticks added to highlight example JSON (Quentin Presley)
* Add same change to description for findOne (Quentin Presley)
* Update the description for persisted-models (Quentin Presley)
* handle $2b$ in hashed password check (Sylvain Dumont)
2019-02-05, Version 3.25.0
==========================
* Support middleware injected by AppDynamics. (Mike Li)
2019-01-11, Version 3.24.2
==========================
* Fix crash when modifying an unknown user (Matheus Horstmann)
2019-01-08, Version 3.24.1
==========================

View File

@ -1,10 +1,10 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
/* global module:false */
'use strict';
module.exports = function(grunt) {
// Do not report warnings from unit-tests exercising deprecated paths
process.env.NO_DEPRECATION = 'loopback';
@ -31,11 +31,6 @@ module.exports = function(grunt) {
},
},
},
run: {
optionalInstall: {
exec: 'npm install --no-save --silent karma-phantomjs-launcher phantomjs-prebuilt',
},
},
eslint: {
gruntfile: {
src: 'Gruntfile.js',
@ -109,7 +104,7 @@ module.exports = function(grunt) {
karma: {
'unit-once': {
configFile: 'test/karma.conf.js',
browsers: ['PhantomJS'],
browsers: ['ChromeDocker'],
singleRun: true,
reporters: ['dots', 'junit'],
@ -216,7 +211,6 @@ module.exports = function(grunt) {
});
// These plugins provide necessary tasks.
grunt.loadNpmTasks('grunt-run');
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-eslint');
@ -224,8 +218,8 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-karma');
grunt.registerTask('e2e-server', function() {
var done = this.async();
var app = require('./test/fixtures/e2e/app');
const done = this.async();
const app = require('./test/fixtures/e2e/app');
app.listen(0, function() {
process.env.PORT = this.address().port;
done();
@ -242,14 +236,12 @@ module.exports = function(grunt) {
// Default task.
grunt.registerTask('default', ['browserify']);
grunt.registerTask('phantomTests', ['run', 'karma:unit-once']);
grunt.registerTask('test', [
'eslint',
process.env.JENKINS_HOME ? 'mochaTest:unit-xml' : 'mochaTest:unit',
process.env.JENKINS_HOME && (/^win/.test(process.platform) ||
/^s390x/.test(process.arch) || /^ppc64/.test(process.arch)) ?
'skip-karma' : 'phantomTests',
'skip-karma' : 'karma:unit-once',
]);
// alias for sl-ci-run and `npm test`

View File

@ -4,13 +4,18 @@
[![Module LTS Adopted'](https://img.shields.io/badge/Module%20LTS-Adopted-brightgreen.svg?style=flat)](http://github.com/CloudNativeJS/ModuleLTS)
[![IBM Support](https://img.shields.io/badge/IBM%20Support-Frameworks-brightgreen.svg?style=flat)](http://ibm.biz/node-support)
**This module is in Active LTS mode, new features are no longer accepted.**
<br/>(See [Module Long Term Support Policy](#module-long-term-support-policy)
below.)
**⚠️ LoopBack 3 has reached end of life. We are no longer accepting pull requests or providing
support for community users. The only exception is fixes for critical bugs and security
vulnerabilities provided as part of support for IBM API Connect customers.
We urge all LoopBack 3 users to migrate their applications to LoopBack 4 as soon as possible.
Learn more about
<a href="https://loopback.io/doc/en/contrib/Long-term-support.html">LoopBack's long term support policy.</a>
will be provided or accepted. (See
[Module Long Term Support Policy](#module-long-term-support-policy) below.)**
LoopBack 3 users looking for new features are encouraged to upgrade
to LoopBack 4. Refer to
[loopback-next#1849](https://github.com/strongloop/loopback-next/issues/1849)
We urge all LoopBack 3 users to migrate their applications to LoopBack 4 as
soon as possible. Refer to our
[Migration Guide](https://loopback.io/doc/en/lb4/migration-overview.html)
for more information on how to upgrade.
## Overview
@ -38,15 +43,15 @@ For more details, see [https://loopback.io/](https://loopback.io/).
## Module Long Term Support Policy
LoopBack 3.x is now in active LTS.
LoopBack 3.x has reached End-of-Life.
This module adopts the [Module Long Term Support (LTS)](http://github.com/CloudNativeJS/ModuleLTS) policy, with the following End Of Life (EOL) dates:
| Version | Status | Published | EOL |
| ---------- | --------------- | --------- | -------------------- |
| LoopBack 4 | Current | Oct 2018 | Apr 2021 _(minimum)_ |
| Loopback 3 | Active LTS | Dec 2016 | Dec 2019 |
| Loopback 2 | Maintenance LTS | Jul 2014 | Apr 2019 |
| LoopBack 4 | Current | Oct 2018 | Apr 2023 _(minimum)_ |
| LoopBack 3 | End-of-Life | Dec 2016 | Dec 2020 |
| LoopBack 2 | End-of-Life | Jul 2014 | Apr 2019 |
Learn more about our LTS plan in [docs](https://loopback.io/doc/en/contrib/Long-term-support.html).

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -8,11 +8,11 @@
*/
'use strict';
var g = require('../../lib/globalize');
var loopback = require('../../lib/loopback');
var assert = require('assert');
var uid = require('uid2');
var DEFAULT_TOKEN_LEN = 64;
const g = require('../../lib/globalize');
const loopback = require('../../lib/loopback');
const assert = require('assert');
const uid = require('uid2');
const DEFAULT_TOKEN_LEN = 64;
/**
* Token based authentication and access control.
@ -93,11 +93,11 @@ module.exports = function(AccessToken) {
*/
AccessToken.getIdForRequest = function(req, options) {
options = options || {};
var params = options.params || [];
var headers = options.headers || [];
var cookies = options.cookies || [];
var i = 0;
var length, id;
let params = options.params || [];
let headers = options.headers || [];
let cookies = options.cookies || [];
let i = 0;
let length, id;
// https://github.com/strongloop/loopback/issues/1326
if (options.searchDefaultTokenKeys !== false) {
@ -107,7 +107,7 @@ module.exports = function(AccessToken) {
}
for (length = params.length; i < length; i++) {
var param = params[i];
const param = params[i];
// replacement for deprecated req.param()
id = req.params && req.params[param] !== undefined ? req.params[param] :
req.body && req.body[param] !== undefined ? req.body[param] :
@ -134,7 +134,7 @@ module.exports = function(AccessToken) {
id = id.substring(7);
if (options.bearerTokenBase64Encoded) {
// Decode from base64
var buf = new Buffer(id, 'base64');
const buf = new Buffer(id, 'base64');
id = buf.toString('utf8');
}
} else if (/^Basic /i.test(id)) {
@ -147,7 +147,7 @@ module.exports = function(AccessToken) {
// "a2b2c3:" (curl http://a2b2c3@localhost:3000/)
// "token:a2b2c3" (curl http://token:a2b2c3@localhost:3000/)
// ":a2b2c3"
var parts = /^([^:]*):(.*)$/.exec(id);
const parts = /^([^:]*):(.*)$/.exec(id);
if (parts) {
id = parts[2].length > parts[1].length ? parts[2] : parts[1];
}
@ -186,7 +186,7 @@ module.exports = function(AccessToken) {
} else if (isValid) {
cb(null, token);
} else {
var e = new Error(g.f('Invalid Access Token'));
const e = new Error(g.f('Invalid Access Token'));
e.status = e.statusCode = 401;
e.code = 'INVALID_TOKEN';
cb(e);
@ -213,7 +213,7 @@ module.exports = function(AccessToken) {
options = {};
}
var id = this.getIdForRequest(req, options);
const id = this.getIdForRequest(req, options);
if (id) {
this.resolve(id, cb);
@ -233,15 +233,15 @@ module.exports = function(AccessToken) {
try {
assert(
this.created && typeof this.created.getTime === 'function',
'token.created must be a valid Date'
'token.created must be a valid Date',
);
assert(this.ttl !== 0, 'token.ttl must be not be 0');
assert(this.ttl, 'token.ttl must exist');
assert(this.ttl >= -1, 'token.ttl must be >= -1');
var AccessToken = this.constructor;
var userRelation = AccessToken.relations.user; // may not be set up
var User = userRelation && userRelation.modelTo;
const AccessToken = this.constructor;
const userRelation = AccessToken.relations.user; // may not be set up
let User = userRelation && userRelation.modelTo;
// redefine user model if accessToken's principalType is available
if (this.principalType) {
@ -253,13 +253,13 @@ module.exports = function(AccessToken) {
}
}
var now = Date.now();
var created = this.created.getTime();
var elapsedSeconds = (now - created) / 1000;
var secondsToLive = this.ttl;
var eternalTokensAllowed = !!(User && User.settings.allowEternalTokens);
var isEternalToken = secondsToLive === -1;
var isValid = isEternalToken ?
const now = Date.now();
const created = this.created.getTime();
const elapsedSeconds = (now - created) / 1000;
const secondsToLive = this.ttl;
const eternalTokensAllowed = !!(User && User.settings.allowEternalTokens);
const isEternalToken = secondsToLive === -1;
const isValid = isEternalToken ?
eternalTokensAllowed :
elapsedSeconds < secondsToLive;

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -30,20 +30,20 @@
Map to oAuth 2.0 scopes
*/
var g = require('../../lib/globalize');
var loopback = require('../../lib/loopback');
var utils = require('../../lib/utils');
var async = require('async');
var extend = require('util')._extend;
var assert = require('assert');
var debug = require('debug')('loopback:security:acl');
const g = require('../../lib/globalize');
const loopback = require('../../lib/loopback');
const utils = require('../../lib/utils');
const async = require('async');
const extend = require('util')._extend;
const assert = require('assert');
const debug = require('debug')('loopback:security:acl');
var ctx = require('../../lib/access-context');
var AccessContext = ctx.AccessContext;
var Principal = ctx.Principal;
var AccessRequest = ctx.AccessRequest;
const ctx = require('../../lib/access-context');
const AccessContext = ctx.AccessContext;
const Principal = ctx.Principal;
const AccessRequest = ctx.AccessRequest;
var Role = loopback.Role;
const Role = loopback.Role;
assert(Role, 'Role model must be defined before ACL model');
/**
@ -107,18 +107,18 @@ module.exports = function(ACL) {
* @returns {Number}
*/
ACL.getMatchingScore = function getMatchingScore(rule, req) {
var props = ['model', 'property', 'accessType'];
var score = 0;
const props = ['model', 'property', 'accessType'];
let score = 0;
for (var i = 0; i < props.length; i++) {
for (let i = 0; i < props.length; i++) {
// Shift the score by 4 for each of the properties as the weight
score = score * 4;
var ruleValue = rule[props[i]] || ACL.ALL;
var requestedValue = req[props[i]] || ACL.ALL;
var isMatchingMethodName = props[i] === 'property' &&
const ruleValue = rule[props[i]] || ACL.ALL;
const requestedValue = req[props[i]] || ACL.ALL;
const isMatchingMethodName = props[i] === 'property' &&
req.methodNames.indexOf(ruleValue) !== -1;
var isMatchingAccessType = ruleValue === requestedValue;
let isMatchingAccessType = ruleValue === requestedValue;
if (props[i] === 'accessType' && !isMatchingAccessType) {
switch (ruleValue) {
case ACL.EXECUTE:
@ -219,11 +219,11 @@ module.exports = function(ACL) {
acls = acls.sort(function(rule1, rule2) {
return ACL.getMatchingScore(rule2, req) - ACL.getMatchingScore(rule1, req);
});
var permission = ACL.DEFAULT;
var score = 0;
let permission = ACL.DEFAULT;
let score = 0;
for (var i = 0; i < acls.length; i++) {
var candidate = acls[i];
for (let i = 0; i < acls.length; i++) {
const candidate = acls[i];
score = ACL.getMatchingScore(candidate, req);
if (score < 0) {
// the highest scored ACL did not match
@ -239,8 +239,8 @@ module.exports = function(ACL) {
break;
}
// For wildcard match, find the strongest permission
var candidateOrder = AccessContext.permissionOrder[candidate.permission];
var permissionOrder = AccessContext.permissionOrder[permission];
const candidateOrder = AccessContext.permissionOrder[candidate.permission];
const permissionOrder = AccessContext.permissionOrder[permission];
if (candidateOrder > permissionOrder) {
permission = candidate.permission;
break;
@ -255,7 +255,7 @@ module.exports = function(ACL) {
debug('with score:', acl.score(req));
});
}
var res = new AccessRequest({
const res = new AccessRequest({
model: req.model,
property: req.property,
accessType: req.accessType,
@ -276,11 +276,11 @@ module.exports = function(ACL) {
* @return {Object[]} An array of ACLs
*/
ACL.getStaticACLs = function getStaticACLs(model, property) {
var modelClass = this.registry.findModel(model);
var staticACLs = [];
const modelClass = this.registry.findModel(model);
const staticACLs = [];
if (modelClass && modelClass.settings.acls) {
modelClass.settings.acls.forEach(function(acl) {
var prop = acl.property;
let prop = acl.property;
// We support static ACL property with array of string values.
if (Array.isArray(prop) && prop.indexOf(property) >= 0)
prop = property;
@ -296,7 +296,7 @@ module.exports = function(ACL) {
}
});
}
var prop = modelClass && (
const prop = modelClass && (
// regular property
modelClass.definition.properties[property] ||
// relation/scope
@ -339,17 +339,17 @@ module.exports = function(ACL) {
principalId = principalId.toString();
}
property = property || ACL.ALL;
var propertyQuery = (property === ACL.ALL) ? undefined : {inq: [property, ACL.ALL]};
const propertyQuery = (property === ACL.ALL) ? undefined : {inq: [property, ACL.ALL]};
accessType = accessType || ACL.ALL;
var accessTypeQuery = (accessType === ACL.ALL) ? undefined :
const accessTypeQuery = (accessType === ACL.ALL) ? undefined :
{inq: [accessType, ACL.ALL, ACL.EXECUTE]};
var req = new AccessRequest({model, property, accessType, registry: this.registry});
const req = new AccessRequest({model, property, accessType, registry: this.registry});
var acls = this.getStaticACLs(model, property);
let acls = this.getStaticACLs(model, property);
// resolved is an instance of AccessRequest
var resolved = this.resolvePermission(acls, req);
let resolved = this.resolvePermission(acls, req);
if (resolved && resolved.permission === ACL.DENY) {
debug('Permission denied by statically resolved permission');
@ -360,7 +360,7 @@ module.exports = function(ACL) {
return callback.promise;
}
var self = this;
const self = this;
this.find({where: {principalType: principalType, principalId: principalId,
model: model, property: propertyQuery, accessType: accessTypeQuery}},
function(err, dynACLs) {
@ -431,33 +431,33 @@ module.exports = function(ACL) {
*/
ACL.checkAccessForContext = function(context, callback) {
if (!callback) callback = utils.createPromiseCallback();
var self = this;
const self = this;
self.resolveRelatedModels();
var roleModel = self.roleModel;
const roleModel = self.roleModel;
if (!(context instanceof AccessContext)) {
context.registry = this.registry;
context = new AccessContext(context);
}
var authorizedRoles = {};
var remotingContext = context.remotingContext;
var model = context.model;
var modelDefaultPermission = model && model.settings.defaultPermission;
var property = context.property;
var accessType = context.accessType;
var modelName = context.modelName;
let authorizedRoles = {};
const remotingContext = context.remotingContext;
const model = context.model;
const modelDefaultPermission = model && model.settings.defaultPermission;
const property = context.property;
const accessType = context.accessType;
const modelName = context.modelName;
var methodNames = context.methodNames;
var propertyQuery = (property === ACL.ALL) ? undefined : {inq: methodNames.concat([ACL.ALL])};
const methodNames = context.methodNames;
const propertyQuery = (property === ACL.ALL) ? undefined : {inq: methodNames.concat([ACL.ALL])};
var accessTypeQuery = (accessType === ACL.ALL) ?
const accessTypeQuery = (accessType === ACL.ALL) ?
undefined :
(accessType === ACL.REPLICATE) ?
{inq: [ACL.REPLICATE, ACL.WRITE, ACL.ALL]} :
{inq: [accessType, ACL.ALL]};
var req = new AccessRequest({
const req = new AccessRequest({
model: modelName,
property,
accessType,
@ -475,8 +475,8 @@ module.exports = function(ACL) {
return callback.promise;
}
var effectiveACLs = [];
var staticACLs = self.getStaticACLs(model.modelName, property);
const effectiveACLs = [];
const staticACLs = self.getStaticACLs(model.modelName, property);
const query = {
where: {
@ -488,16 +488,16 @@ module.exports = function(ACL) {
this.find(query, function(err, acls) {
if (err) return callback(err);
var inRoleTasks = [];
const inRoleTasks = [];
acls = acls.concat(staticACLs);
acls.forEach(function(acl) {
// Check exact matches
for (var i = 0; i < context.principals.length; i++) {
var p = context.principals[i];
var typeMatch = p.type === acl.principalType;
var idMatch = String(p.id) === String(acl.principalId);
for (let i = 0; i < context.principals.length; i++) {
const p = context.principals[i];
const typeMatch = p.type === acl.principalType;
const idMatch = String(p.id) === String(acl.principalId);
if (typeMatch && idMatch) {
effectiveACLs.push(acl);
return;
@ -525,7 +525,7 @@ module.exports = function(ACL) {
if (err) return callback(err, null);
// resolved is an instance of AccessRequest
var resolved = self.resolvePermission(effectiveACLs, req);
const resolved = self.resolvePermission(effectiveACLs, req);
debug('---Resolved---');
resolved.debug();
@ -562,7 +562,7 @@ module.exports = function(ACL) {
ACL.checkAccessForToken = function(token, model, modelId, method, callback) {
assert(token, 'Access token is required');
if (!callback) callback = utils.createPromiseCallback();
var context = new AccessContext({
const context = new AccessContext({
registry: this.registry,
accessToken: token,
model: model,
@ -580,7 +580,7 @@ module.exports = function(ACL) {
ACL.resolveRelatedModels = function() {
if (!this.roleModel) {
var reg = this.registry;
const reg = this.registry;
this.roleModel = reg.getModelByType('Role');
this.roleMappingModel = reg.getModelByType('RoleMapping');
this.userModel = reg.getModelByType('User');
@ -607,25 +607,25 @@ module.exports = function(ACL) {
break;
case ACL.USER:
this.userModel.findOne(
{where: {or: [{username: id}, {email: id}, {id: id}]}}, cb
{where: {or: [{username: id}, {email: id}, {id: id}]}}, cb,
);
break;
case ACL.APP:
this.applicationModel.findOne(
{where: {or: [{name: id}, {email: id}, {id: id}]}}, cb
{where: {or: [{name: id}, {email: id}, {id: id}]}}, cb,
);
break;
default:
// try resolving a user model with a name matching the principalType
var userModel = this.registry.findModel(type);
const userModel = this.registry.findModel(type);
if (userModel) {
userModel.findOne(
{where: {or: [{username: id}, {email: id}, {id: id}]}},
cb
cb,
);
} else {
process.nextTick(function() {
var err = new Error(g.f('Invalid principal type: %s', type));
const err = new Error(g.f('Invalid principal type: %s', type));
err.statusCode = 400;
err.code = 'INVALID_PRINCIPAL_TYPE';
cb(err);
@ -646,7 +646,7 @@ module.exports = function(ACL) {
*/
ACL.isMappedToRole = function(principalType, principalId, role, cb) {
cb = cb || utils.createPromiseCallback();
var self = this;
const self = this;
this.resolvePrincipal(principalType, principalId,
function(err, principal) {
if (err) return cb(err);

View File

@ -1,26 +1,26 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var utils = require('../../lib/utils');
const assert = require('assert');
const utils = require('../../lib/utils');
/*!
* Application management functions
*/
var crypto = require('crypto');
const crypto = require('crypto');
function generateKey(hmacKey, algorithm, encoding) {
hmacKey = hmacKey || 'loopback';
algorithm = algorithm || 'sha1';
encoding = encoding || 'hex';
var hmac = crypto.createHmac(algorithm, hmacKey);
var buf = crypto.randomBytes(32);
const hmac = crypto.createHmac(algorithm, hmacKey);
const buf = crypto.randomBytes(32);
hmac.update(buf);
var key = hmac.digest(encoding);
const key = hmac.digest(encoding);
return key;
}
@ -83,7 +83,7 @@ module.exports = function(Application) {
return next();
}
var app = ctx.instance;
const app = ctx.instance;
app.created = app.modified = new Date();
if (!app.id) {
app.id = generateKey('id', 'md5');
@ -115,8 +115,8 @@ module.exports = function(Application) {
}
cb = cb || utils.createPromiseCallback();
var props = {owner: owner, name: name};
for (var p in options) {
const props = {owner: owner, name: name};
for (const p in options) {
if (!(p in props)) {
props[p] = options[p];
}
@ -182,9 +182,9 @@ module.exports = function(Application) {
cb(err, null);
return cb.promise;
}
var result = null;
var keyNames = ['clientKey', 'javaScriptKey', 'restApiKey', 'windowsKey', 'masterKey'];
for (var i = 0; i < keyNames.length; i++) {
let result = null;
const keyNames = ['clientKey', 'javaScriptKey', 'restApiKey', 'windowsKey', 'masterKey'];
for (let i = 0; i < keyNames.length; i++) {
if (app[keyNames[i]] === key) {
result = {
application: app,

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -8,15 +8,15 @@
*/
'use strict';
var g = require('../../lib/globalize');
var PersistedModel = require('../../lib/loopback').PersistedModel;
var loopback = require('../../lib/loopback');
var utils = require('../../lib/utils');
var crypto = require('crypto');
var CJSON = {stringify: require('canonical-json')};
var async = require('async');
var assert = require('assert');
var debug = require('debug')('loopback:change');
const g = require('../../lib/globalize');
const PersistedModel = require('../../lib/loopback').PersistedModel;
const loopback = require('../../lib/loopback');
const utils = require('../../lib/utils');
const crypto = require('crypto');
const CJSON = {stringify: require('canonical-json')};
const async = require('async');
const assert = require('assert');
const debug = require('debug')('loopback:change');
/**
* Change list entry.
@ -58,10 +58,10 @@ module.exports = function(Change) {
Change.setup = function() {
PersistedModel.setup.call(this);
var Change = this;
const Change = this;
Change.getter.id = function() {
var hasModel = this.modelName && this.modelId;
const hasModel = this.modelName && this.modelId;
if (!hasModel) return null;
return Change.idForModel(this.modelName, this.modelId);
@ -80,12 +80,12 @@ module.exports = function(Change) {
*/
Change.rectifyModelChanges = function(modelName, modelIds, callback) {
var Change = this;
var errors = [];
const Change = this;
const errors = [];
callback = callback || utils.createPromiseCallback();
var tasks = modelIds.map(function(id) {
const tasks = modelIds.map(function(id) {
return function(cb) {
Change.findOrCreateChange(modelName, id, function(err, change) {
if (err) return next(err);
@ -106,13 +106,13 @@ module.exports = function(Change) {
async.parallel(tasks, function(err) {
if (err) return callback(err);
if (errors.length) {
var desc = errors
const desc = errors
.map(function(e) {
return '#' + e.modelId + ' - ' + e.toString();
})
.join('\n');
var msg = g.f('Cannot rectify %s changes:\n%s', modelName, desc);
const msg = g.f('Cannot rectify %s changes:\n%s', modelName, desc);
err = new Error(msg);
err.details = {errors: errors};
return callback(err);
@ -148,15 +148,15 @@ module.exports = function(Change) {
Change.findOrCreateChange = function(modelName, modelId, callback) {
assert(this.registry.findModel(modelName), modelName + ' does not exist');
callback = callback || utils.createPromiseCallback();
var id = this.idForModel(modelName, modelId);
var Change = this;
const id = this.idForModel(modelName, modelId);
const Change = this;
this.findById(id, function(err, change) {
if (err) return callback(err);
if (change) {
callback(null, change);
} else {
var ch = new Change({
const ch = new Change({
id: id,
modelName: modelName,
modelId: modelId,
@ -177,8 +177,8 @@ module.exports = function(Change) {
*/
Change.prototype.rectify = function(cb) {
var change = this;
var currentRev = this.rev;
const change = this;
const currentRev = this.rev;
change.debug('rectify change');
@ -216,7 +216,7 @@ module.exports = function(Change) {
function(err, checkpoint) {
if (err) return cb(err);
doRectify(checkpoint, rev);
}
},
);
}
@ -274,8 +274,8 @@ module.exports = function(Change) {
Change.prototype.currentRevision = function(cb) {
cb = cb || utils.createPromiseCallback();
var model = this.getModelCtor();
var id = this.getModelId();
const model = this.getModelCtor();
const id = this.getModelId();
model.findById(id, function(err, inst) {
if (err) return cb(err);
if (inst) {
@ -345,8 +345,8 @@ module.exports = function(Change) {
Change.prototype.equals = function(change) {
if (!change) return false;
var thisRev = this.rev || null;
var thatRev = change.rev || null;
const thisRev = this.rev || null;
const thatRev = change.rev || null;
return thisRev === thatRev;
};
@ -423,8 +423,8 @@ module.exports = function(Change) {
callback(null, {deltas: [], conflicts: []});
return callback.promise;
}
var remoteChangeIndex = {};
var modelIds = [];
const remoteChangeIndex = {};
const modelIds = [];
remoteChanges.forEach(function(ch) {
modelIds.push(ch.modelId);
remoteChangeIndex[ch.modelId] = new Change(ch);
@ -439,18 +439,18 @@ module.exports = function(Change) {
},
}, function(err, allLocalChanges) {
if (err) return callback(err);
var deltas = [];
var conflicts = [];
var localModelIds = [];
const deltas = [];
const conflicts = [];
const localModelIds = [];
var localChanges = allLocalChanges.filter(function(c) {
const localChanges = allLocalChanges.filter(function(c) {
return c.checkpoint >= since;
});
localChanges.forEach(function(localChange) {
localChange = new Change(localChange);
localModelIds.push(localChange.modelId);
var remoteChange = remoteChangeIndex[localChange.modelId];
const remoteChange = remoteChangeIndex[localChange.modelId];
if (remoteChange && !localChange.equals(remoteChange)) {
if (remoteChange.conflictsWith(localChange)) {
remoteChange.debug('remote conflict');
@ -466,8 +466,8 @@ module.exports = function(Change) {
modelIds.forEach(function(id) {
if (localModelIds.indexOf(id) !== -1) return;
var d = remoteChangeIndex[id];
var oldChange = allLocalChanges.filter(function(c) {
const d = remoteChangeIndex[id];
const oldChange = allLocalChanges.filter(function(c) {
return c.modelId === id;
})[0];
@ -495,14 +495,14 @@ module.exports = function(Change) {
Change.rectifyAll = function(cb) {
debug('rectify all');
var Change = this;
const Change = this;
// this should be optimized
this.find(function(err, changes) {
if (err) return cb(err);
async.each(
changes,
function(c, next) { c.rectify(next); },
cb
cb,
);
});
};
@ -513,7 +513,7 @@ module.exports = function(Change) {
*/
Change.getCheckpointModel = function() {
var checkpointModel = this.Checkpoint;
let checkpointModel = this.Checkpoint;
if (checkpointModel) return checkpointModel;
// FIXME(bajtos) This code creates multiple different models with the same
// model name, which is not a valid supported usage of juggler's API.
@ -526,7 +526,7 @@ module.exports = function(Change) {
Change.prototype.debug = function() {
if (debug.enabled) {
var args = Array.prototype.slice.call(arguments);
const args = Array.prototype.slice.call(arguments);
args[0] = args[0] + ' %s';
args.push(this.modelName);
debug.apply(this, args);
@ -551,16 +551,16 @@ module.exports = function(Change) {
Change.prototype.getModelId = function() {
// TODO(ritch) get rid of the need to create an instance
var Model = this.getModelCtor();
var id = this.modelId;
var m = new Model();
const Model = this.getModelCtor();
const id = this.modelId;
const m = new Model();
m.setId(id);
return m.getId();
};
Change.prototype.getModel = function(callback) {
var Model = this.constructor.settings.trackModel;
var id = this.getModelId();
const Model = this.constructor.settings.trackModel;
const id = this.getModelId();
Model.findById(id, callback);
};
@ -595,10 +595,10 @@ module.exports = function(Change) {
*/
Conflict.prototype.models = function(cb) {
var conflict = this;
var SourceModel = this.SourceModel;
var TargetModel = this.TargetModel;
var source, target;
const conflict = this;
const SourceModel = this.SourceModel;
const TargetModel = this.TargetModel;
let source, target;
async.parallel([
getSourceModel,
@ -637,8 +637,8 @@ module.exports = function(Change) {
*/
Conflict.prototype.changes = function(cb) {
var conflict = this;
var sourceChange, targetChange;
const conflict = this;
let sourceChange, targetChange;
async.parallel([
getSourceChange,
@ -646,7 +646,7 @@ module.exports = function(Change) {
], done);
function getSourceChange(cb) {
var SourceModel = conflict.SourceModel;
const SourceModel = conflict.SourceModel;
SourceModel.findLastChange(conflict.modelId, function(err, change) {
if (err) return cb(err);
sourceChange = change;
@ -655,7 +655,7 @@ module.exports = function(Change) {
}
function getTargetChange(cb) {
var TargetModel = conflict.TargetModel;
const TargetModel = conflict.TargetModel;
TargetModel.findLastChange(conflict.modelId, function(err, change) {
if (err) return cb(err);
targetChange = change;
@ -684,7 +684,7 @@ module.exports = function(Change) {
*/
Conflict.prototype.resolve = function(cb) {
var conflict = this;
const conflict = this;
conflict.TargetModel.findLastChange(
this.modelId,
function(err, targetChange) {
@ -692,9 +692,9 @@ module.exports = function(Change) {
conflict.SourceModel.updateLastChange(
conflict.modelId,
{prev: targetChange.rev},
cb
cb,
);
}
},
);
};
@ -718,16 +718,16 @@ module.exports = function(Change) {
* @param {Error} err
*/
Conflict.prototype.resolveUsingTarget = function(cb) {
var conflict = this;
const conflict = this;
conflict.models(function(err, source, target) {
if (err) return done(err);
if (target === null) {
return conflict.SourceModel.deleteById(conflict.modelId, done);
}
var inst = new conflict.SourceModel(
const inst = new conflict.SourceModel(
target.toObject(),
{persisted: true}
{persisted: true},
);
inst.save(done);
});
@ -751,7 +751,7 @@ module.exports = function(Change) {
* @returns {Conflict} A new Conflict instance.
*/
Conflict.prototype.swapParties = function() {
var Ctor = this.constructor;
const Ctor = this.constructor;
return new Ctor(this.modelId, this.TargetModel, this.SourceModel);
};
@ -765,14 +765,14 @@ module.exports = function(Change) {
*/
Conflict.prototype.resolveManually = function(data, cb) {
var conflict = this;
const conflict = this;
if (!data) {
return conflict.SourceModel.deleteById(conflict.modelId, done);
}
conflict.models(function(err, source, target) {
if (err) return done(err);
var inst = source || new conflict.SourceModel(target);
const inst = source || new conflict.SourceModel(target);
inst.setAttributes(data);
inst.save(function(err) {
if (err) return done(err);
@ -801,11 +801,11 @@ module.exports = function(Change) {
*/
Conflict.prototype.type = function(cb) {
var conflict = this;
const conflict = this;
this.changes(function(err, sourceChange, targetChange) {
if (err) return cb(err);
var sourceChangeType = sourceChange.type();
var targetChangeType = targetChange.type();
const sourceChangeType = sourceChange.type();
const targetChangeType = targetChange.type();
if (sourceChangeType === Change.UPDATE && targetChangeType === Change.UPDATE) {
return cb(null, Change.UPDATE);
}

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -8,7 +8,7 @@
*/
'use strict';
var assert = require('assert');
const assert = require('assert');
/**
* Checkpoint list entry.
@ -35,15 +35,15 @@ module.exports = function(Checkpoint) {
* @param {Number} checkpoint The current checkpoint seq
*/
Checkpoint.current = function(cb) {
var Checkpoint = this;
const Checkpoint = this;
Checkpoint._getSingleton(function(err, cp) {
cb(err, cp.seq);
});
};
Checkpoint._getSingleton = function(cb) {
var query = {limit: 1}; // match all instances, return only one
var initialData = {seq: 1};
const query = {limit: 1}; // match all instances, return only one
const initialData = {seq: 1};
this.findOrCreate(query, initialData, cb);
};
@ -54,10 +54,10 @@ module.exports = function(Checkpoint) {
* @param {Object} checkpoint The current checkpoint
*/
Checkpoint.bumpLastSeq = function(cb) {
var Checkpoint = this;
const Checkpoint = this;
Checkpoint._getSingleton(function(err, cp) {
if (err) return cb(err);
var originalSeq = cp.seq;
const originalSeq = cp.seq;
cp.seq++;
// Update the checkpoint but only if it was not changed under our hands
Checkpoint.updateAll({id: cp.id, seq: originalSeq}, {seq: cp.seq}, function(err, info) {

View File

@ -1,10 +1,10 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('../../lib/globalize');
const g = require('../../lib/globalize');
/**
* Email model. Extends LoopBack base [Model](#model-new-model).

View File

@ -1,10 +1,10 @@
// Copyright IBM Corp. 2016,2018. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('../../lib/globalize');
const g = require('../../lib/globalize');
/**
* Data model for key-value databases.
@ -226,17 +226,17 @@ function throwNotAttached(modelName, methodName) {
'The %s method has not been setup. ' +
'The {{KeyValueModel}} has not been correctly attached ' +
'to a {{DataSource}}!',
modelName, methodName, methodName
modelName, methodName, methodName,
));
}
function convertNullToNotFoundError(ctx, cb) {
if (ctx.result !== null) return cb();
var modelName = ctx.method.sharedClass.name;
var id = ctx.getArgByName('id');
var msg = g.f('Unknown "%s" {{key}} "%s".', modelName, id);
var error = new Error(msg);
const modelName = ctx.method.sharedClass.name;
const id = ctx.getArgByName('id');
const msg = g.f('Unknown "%s" {{key}} "%s".', modelName, id);
const error = new Error(msg);
error.statusCode = error.status = 404;
error.code = 'KEY_NOT_FOUND';
cb(error);

View File

@ -1,11 +1,11 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../lib/loopback');
var utils = require('../../lib/utils');
const loopback = require('../../lib/loopback');
const utils = require('../../lib/utils');
/**
* The `RoleMapping` model extends from the built in `loopback.Model` type.
@ -26,7 +26,7 @@ module.exports = function(RoleMapping) {
RoleMapping.resolveRelatedModels = function() {
if (!this.userModel) {
var reg = this.registry;
const reg = this.registry;
this.roleModel = reg.getModelByType('Role');
this.userModel = reg.getModelByType('User');
this.applicationModel = reg.getModelByType('Application');
@ -44,7 +44,7 @@ module.exports = function(RoleMapping) {
this.constructor.resolveRelatedModels();
if (this.principalType === RoleMapping.APPLICATION) {
var applicationModel = this.constructor.applicationModel;
const applicationModel = this.constructor.applicationModel;
applicationModel.findById(this.principalId, callback);
} else {
process.nextTick(function() {
@ -63,7 +63,7 @@ module.exports = function(RoleMapping) {
RoleMapping.prototype.user = function(callback) {
callback = callback || utils.createPromiseCallback();
this.constructor.resolveRelatedModels();
var userModel;
let userModel;
if (this.principalType === RoleMapping.USER) {
userModel = this.constructor.userModel;
@ -94,7 +94,7 @@ module.exports = function(RoleMapping) {
this.constructor.resolveRelatedModels();
if (this.principalType === RoleMapping.ROLE) {
var roleModel = this.constructor.roleModel;
const roleModel = this.constructor.roleModel;
roleModel.findById(this.principalId, callback);
} else {
process.nextTick(function() {

View File

@ -1,18 +1,18 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../lib/loopback');
var debug = require('debug')('loopback:security:role');
var assert = require('assert');
var async = require('async');
var utils = require('../../lib/utils');
var ctx = require('../../lib/access-context');
var AccessContext = ctx.AccessContext;
var Principal = ctx.Principal;
var RoleMapping = loopback.RoleMapping;
const loopback = require('../../lib/loopback');
const debug = require('debug')('loopback:security:role');
const assert = require('assert');
const async = require('async');
const utils = require('../../lib/utils');
const ctx = require('../../lib/access-context');
const AccessContext = ctx.AccessContext;
const Principal = ctx.Principal;
const RoleMapping = loopback.RoleMapping;
assert(RoleMapping, 'RoleMapping model must be defined before Role model');
@ -24,7 +24,7 @@ assert(RoleMapping, 'RoleMapping model must be defined before Role model');
module.exports = function(Role) {
Role.resolveRelatedModels = function() {
if (!this.userModel) {
var reg = this.registry;
const reg = this.registry;
this.roleMappingModel = reg.getModelByType('RoleMapping');
this.userModel = reg.getModelByType('User');
this.applicationModel = reg.getModelByType('Application');
@ -74,29 +74,29 @@ module.exports = function(Role) {
query.where = query.where || {};
roleModel.resolveRelatedModels();
var relsToModels = {
const relsToModels = {
users: roleModel.userModel,
applications: roleModel.applicationModel,
roles: roleModel,
};
var ACL = loopback.ACL;
var relsToTypes = {
const ACL = loopback.ACL;
const relsToTypes = {
users: ACL.USER,
applications: ACL.APP,
roles: ACL.ROLE,
};
var principalModel = relsToModels[rel];
var principalType = relsToTypes[rel];
let principalModel = relsToModels[rel];
let principalType = relsToTypes[rel];
// redefine user model and user type if user principalType is custom (available and not "USER")
var isCustomUserPrincipalType = rel === 'users' &&
const isCustomUserPrincipalType = rel === 'users' &&
query.where.principalType &&
query.where.principalType !== RoleMapping.USER;
if (isCustomUserPrincipalType) {
var registry = this.constructor.registry;
const registry = this.constructor.registry;
principalModel = registry.findModel(query.where.principalType);
principalType = query.where.principalType;
}
@ -133,11 +133,10 @@ module.exports = function(Role) {
roleModel.roleMappingModel.find({
where: {roleId: context.id, principalType: principalType},
}, function(err, mappings) {
var ids;
if (err) {
return callback(err);
}
ids = mappings.map(function(m) {
const ids = mappings.map(function(m) {
return m.principalId;
});
query.where = query.where || {};
@ -177,18 +176,18 @@ module.exports = function(Role) {
});
return;
}
var modelClass = context.model;
var modelId = context.modelId;
var user = context.getUser();
var userId = user && user.id;
var principalType = user && user.principalType;
var opts = {accessToken: context.accessToken};
const modelClass = context.model;
const modelId = context.modelId;
const user = context.getUser();
const userId = user && user.id;
const principalType = user && user.principalType;
const opts = {accessToken: context.accessToken};
Role.isOwner(modelClass, modelId, userId, principalType, opts, callback);
});
function isUserClass(modelClass) {
if (!modelClass) return false;
var User = modelClass.modelBuilder.models.User;
const User = modelClass.modelBuilder.models.User;
if (!User) return false;
return modelClass == User || modelClass.prototype instanceof User;
}
@ -222,7 +221,7 @@ module.exports = function(Role) {
* @promise
*/
Role.isOwner = function isOwner(modelClass, modelId, userId, principalType, options, callback) {
var _this = this;
const _this = this;
if (!callback && typeof options === 'function') {
callback = options;
@ -253,8 +252,8 @@ module.exports = function(Role) {
// 1. the app has a single user model and principalType is 'USER'
// 2. the app has multiple user models and principalType is not 'USER'
// multiple user models
var isMultipleUsers = _isMultipleUsers();
var isPrincipalTypeValid =
const isMultipleUsers = _isMultipleUsers();
const isPrincipalTypeValid =
(!isMultipleUsers && principalType === Principal.USER) ||
(isMultipleUsers && principalType !== Principal.USER);
@ -271,7 +270,7 @@ module.exports = function(Role) {
// Is the modelClass User or a subclass of User?
if (isUserClass(modelClass)) {
var userModelName = modelClass.modelName;
const userModelName = modelClass.modelName;
// matching ids is enough if principalType is USER or matches given user model name
if (principalType === Principal.USER || principalType === userModelName) {
process.nextTick(function() {
@ -289,7 +288,7 @@ module.exports = function(Role) {
}
debug('Model found: %j', inst);
var ownerRelations = modelClass.settings.ownerRelations;
const ownerRelations = modelClass.settings.ownerRelations;
if (!ownerRelations) {
return legacyOwnershipCheck(inst);
} else {
@ -308,24 +307,24 @@ module.exports = function(Role) {
// ownership check induced the whole isOwner() to resolve as false.
// This behaviour will be pruned at next LoopBack major release.
function legacyOwnershipCheck(inst) {
var ownerId = inst.userId || inst.owner;
const ownerId = inst.userId || inst.owner;
if (principalType === Principal.USER && ownerId && 'function' !== typeof ownerId) {
return callback(null, matches(ownerId, userId));
}
// Try to follow belongsTo
for (var r in modelClass.relations) {
var rel = modelClass.relations[r];
for (const r in modelClass.relations) {
const rel = modelClass.relations[r];
// relation should be belongsTo and target a User based class
var belongsToUser = rel.type === 'belongsTo' && isUserClass(rel.modelTo);
const belongsToUser = rel.type === 'belongsTo' && isUserClass(rel.modelTo);
if (!belongsToUser) {
continue;
}
// checking related user
var relatedUser = rel.modelTo;
var userModelName = relatedUser.modelName;
var isMultipleUsers = _isMultipleUsers(relatedUser);
const relatedUser = rel.modelTo;
const userModelName = relatedUser.modelName;
const isMultipleUsers = _isMultipleUsers(relatedUser);
// a relation can be considered for isOwner resolution if:
// 1. the app has a single user model and principalType is 'USER'
// 2. the app has multiple user models and principalType is the related user model name
@ -349,20 +348,20 @@ module.exports = function(Role) {
}
function checkOwnership(inst) {
var ownerRelations = inst.constructor.settings.ownerRelations;
const ownerRelations = inst.constructor.settings.ownerRelations;
// collecting related users
var relWithUsers = [];
for (var r in modelClass.relations) {
var rel = modelClass.relations[r];
const relWithUsers = [];
for (const r in modelClass.relations) {
const rel = modelClass.relations[r];
// relation should be belongsTo and target a User based class
if (rel.type !== 'belongsTo' || !isUserClass(rel.modelTo)) {
continue;
}
// checking related user
var relatedUser = rel.modelTo;
var userModelName = relatedUser.modelName;
var isMultipleUsers = _isMultipleUsers(relatedUser);
const relatedUser = rel.modelTo;
const userModelName = relatedUser.modelName;
const isMultipleUsers = _isMultipleUsers(relatedUser);
// a relation can be considered for isOwner resolution if:
// 1. the app has a single user model and principalType is 'USER'
// 2. the app has multiple user models and principalType is the related user model name
@ -403,8 +402,8 @@ module.exports = function(Role) {
// user model by type. The relation with AccessToken is used to check
// if polymorphism is used, and thus if multiple users.
function _isMultipleUsers(userModel) {
var oneOfUserModels = userModel || _this.registry.getModelByType('User');
var accessTokensRel = oneOfUserModels.relations.accessTokens;
const oneOfUserModels = userModel || _this.registry.getModelByType('User');
const accessTokensRel = oneOfUserModels.relations.accessTokens;
return !!(accessTokensRel && accessTokensRel.polymorphic);
}
};
@ -480,15 +479,15 @@ module.exports = function(Role) {
debug('isInRole(): %s', role);
context.debug();
var resolver = Role.resolvers[role];
const resolver = Role.resolvers[role];
if (resolver) {
debug('Custom resolver found for role %s', role);
var promise = resolver(role, context, callback);
const promise = resolver(role, context, callback);
if (promise && typeof promise.then === 'function') {
promise.then(
function(result) { callback(null, result); },
callback
callback,
);
}
return callback.promise;
@ -502,9 +501,9 @@ module.exports = function(Role) {
return callback.promise;
}
var inRole = context.principals.some(function(p) {
var principalType = p.type || undefined;
var principalId = p.id || undefined;
const inRole = context.principals.some(function(p) {
const principalType = p.type || undefined;
const principalId = p.id || undefined;
// Check if it's the same role
return principalType === RoleMapping.ROLE && principalId === role;
@ -518,7 +517,7 @@ module.exports = function(Role) {
return callback.promise;
}
var roleMappingModel = this.roleMappingModel;
const roleMappingModel = this.roleMappingModel;
this.findOne({where: {name: role}}, function(err, result) {
if (err) {
if (callback) callback(err);
@ -532,10 +531,10 @@ module.exports = function(Role) {
// Iterate through the list of principals
async.some(context.principals, function(p, done) {
var principalType = p.type || undefined;
var principalId = p.id || undefined;
var roleId = result.id.toString();
var principalIdIsString = typeof principalId === 'string';
const principalType = p.type || undefined;
let principalId = p.id || undefined;
const roleId = result.id.toString();
const principalIdIsString = typeof principalId === 'string';
if (principalId !== null && principalId !== undefined && !principalIdIsString) {
principalId = principalId.toString();
@ -585,18 +584,18 @@ module.exports = function(Role) {
if (!(context instanceof AccessContext)) {
context = new AccessContext(context);
}
var roles = [];
const roles = [];
this.resolveRelatedModels();
var addRole = function(role) {
const addRole = function(role) {
if (role && roles.indexOf(role) === -1) {
roles.push(role);
}
};
var self = this;
const self = this;
// Check against the smart roles
var inRoleTasks = [];
const inRoleTasks = [];
Object.keys(Role.resolvers).forEach(function(role) {
inRoleTasks.push(function(done) {
self.isInRole(role, context, function(err, inRole) {
@ -613,11 +612,11 @@ module.exports = function(Role) {
});
});
var roleMappingModel = this.roleMappingModel;
const roleMappingModel = this.roleMappingModel;
context.principals.forEach(function(p) {
// Check against the role mappings
var principalType = p.type || undefined;
var principalId = p.id == null ? undefined : p.id;
const principalType = p.type || undefined;
let principalId = p.id == null ? undefined : p.id;
if (typeof principalId !== 'string' && principalId != null) {
principalId = principalId.toString();
@ -631,7 +630,7 @@ module.exports = function(Role) {
if (principalType && principalId) {
// Please find() treat undefined matches all values
inRoleTasks.push(function(done) {
var filter = {where: {principalType: principalType, principalId: principalId}};
const filter = {where: {principalType: principalType, principalId: principalId}};
if (options.returnOnlyRoleNames === true) {
filter.include = ['role'];
}
@ -642,7 +641,7 @@ module.exports = function(Role) {
return;
}
mappings.forEach(function(m) {
var role;
let role;
if (options.returnOnlyRoleNames === true) {
role = m.toJSON().role.name;
} else {

View File

@ -1,11 +1,11 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var loopback = require('../../lib/loopback');
const assert = require('assert');
const loopback = require('../../lib/loopback');
/**
* Resource owner grants/delegates permissions to client applications
@ -21,7 +21,7 @@ var loopback = require('../../lib/loopback');
module.exports = function(Scope) {
Scope.resolveRelatedModels = function() {
if (!this.aclModel) {
var reg = this.registry;
const reg = this.registry;
this.aclModel = reg.getModelByType(loopback.ACL);
}
};
@ -38,7 +38,7 @@ module.exports = function(Scope) {
*/
Scope.checkPermission = function(scope, model, property, accessType, callback) {
this.resolveRelatedModels();
var aclModel = this.aclModel;
const aclModel = this.aclModel;
assert(aclModel,
'ACL model must be defined before Scope.checkPermission is called');
@ -47,7 +47,7 @@ module.exports = function(Scope) {
if (callback) callback(err);
} else {
aclModel.checkPermission(
aclModel.SCOPE, scope.id, model, property, accessType, callback
aclModel.SCOPE, scope.id, model, property, accessType, callback,
);
}
});

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -8,18 +8,18 @@
*/
'use strict';
var g = require('../../lib/globalize');
var isEmail = require('isemail');
var loopback = require('../../lib/loopback');
var utils = require('../../lib/utils');
var path = require('path');
var qs = require('querystring');
var SALT_WORK_FACTOR = 10;
var crypto = require('crypto');
const g = require('../../lib/globalize');
const isEmail = require('isemail');
const loopback = require('../../lib/loopback');
const utils = require('../../lib/utils');
const path = require('path');
const qs = require('querystring');
const SALT_WORK_FACTOR = 10;
const crypto = require('crypto');
// bcrypt's max length is 72 bytes;
// See https://github.com/kelektiv/node.bcrypt.js/blob/45f498ef6dc6e8234e58e07834ce06a50ff16352/src/node_blf.h#L59
var MAX_PASSWORD_LENGTH = 72;
var bcrypt;
const MAX_PASSWORD_LENGTH = 72;
let bcrypt;
try {
// Try the native module first
bcrypt = require('bcrypt');
@ -32,12 +32,12 @@ try {
bcrypt = require('bcryptjs');
}
var DEFAULT_TTL = 1209600; // 2 weeks in seconds
var DEFAULT_RESET_PW_TTL = 15 * 60; // 15 mins in seconds
var DEFAULT_MAX_TTL = 31556926; // 1 year in seconds
var assert = require('assert');
const DEFAULT_TTL = 1209600; // 2 weeks in seconds
const DEFAULT_RESET_PW_TTL = 15 * 60; // 15 mins in seconds
const DEFAULT_MAX_TTL = 31556926; // 1 year in seconds
const assert = require('assert');
var debug = require('debug')('loopback:user');
const debug = require('debug')('loopback:user');
/**
* Built-in User model.
@ -123,18 +123,18 @@ module.exports = function(User) {
tokenData = {};
}
var userSettings = this.constructor.settings;
const userSettings = this.constructor.settings;
tokenData.ttl = Math.min(tokenData.ttl || userSettings.ttl, userSettings.maxTTL);
this.accessTokens.create(tokenData, options, cb);
return cb.promise;
};
function splitPrincipal(name, realmDelimiter) {
var parts = [null, name];
const parts = [null, name];
if (!realmDelimiter) {
return parts;
}
var index = name.indexOf(realmDelimiter);
const index = name.indexOf(realmDelimiter);
if (index !== -1) {
parts[0] = name.substring(0, index);
parts[1] = name.substring(index + realmDelimiter.length);
@ -150,7 +150,7 @@ module.exports = function(User) {
* @returns {Object} The normalized credential object
*/
User.normalizeCredentials = function(credentials, realmRequired, realmDelimiter) {
var query = {};
const query = {};
credentials = credentials || {};
if (!realmRequired) {
if (credentials.email) {
@ -162,7 +162,7 @@ module.exports = function(User) {
if (credentials.realm) {
query.realm = credentials.realm;
}
var parts;
let parts;
if (credentials.email) {
parts = splitPrincipal(credentials.email, realmDelimiter);
query.email = parts[1];
@ -205,7 +205,7 @@ module.exports = function(User) {
*/
User.login = function(credentials, include, fn) {
var self = this;
const self = this;
if (typeof include === 'function') {
fn = include;
include = undefined;
@ -222,33 +222,54 @@ module.exports = function(User) {
include = include.toLowerCase();
}
var realmDelimiter;
let realmDelimiter;
// Check if realm is required
var realmRequired = !!(self.settings.realmRequired ||
const realmRequired = !!(self.settings.realmRequired ||
self.settings.realmDelimiter);
if (realmRequired) {
realmDelimiter = self.settings.realmDelimiter;
}
var query = self.normalizeCredentials(credentials, realmRequired,
const query = self.normalizeCredentials(credentials, realmRequired,
realmDelimiter);
if (realmRequired && !query.realm) {
var err1 = new Error(g.f('{{realm}} is required'));
if (realmRequired) {
if (!query.realm) {
const err1 = new Error(g.f('{{realm}} is required'));
err1.statusCode = 400;
err1.code = 'REALM_REQUIRED';
fn(err1);
return fn.promise;
} else if (typeof query.realm !== 'string') {
const err5 = new Error(g.f('Invalid realm'));
err5.statusCode = 400;
err5.code = 'INVALID_REALM';
fn(err5);
return fn.promise;
}
}
if (!query.email && !query.username) {
var err2 = new Error(g.f('{{username}} or {{email}} is required'));
const err2 = new Error(g.f('{{username}} or {{email}} is required'));
err2.statusCode = 400;
err2.code = 'USERNAME_EMAIL_REQUIRED';
fn(err2);
return fn.promise;
}
if (query.username && typeof query.username !== 'string') {
const err3 = new Error(g.f('Invalid username'));
err3.statusCode = 400;
err3.code = 'INVALID_USERNAME';
fn(err3);
return fn.promise;
} else if (query.email && typeof query.email !== 'string') {
const err4 = new Error(g.f('Invalid email'));
err4.statusCode = 400;
err4.code = 'INVALID_EMAIL';
fn(err4);
return fn.promise;
}
self.findOne({where: query}, function(err, user) {
var defaultError = new Error(g.f('login failed'));
const defaultError = new Error(g.f('login failed'));
defaultError.statusCode = 401;
defaultError.code = 'LOGIN_FAILED';
@ -323,7 +344,7 @@ module.exports = function(User) {
User.logout = function(tokenId, fn) {
fn = fn || utils.createPromiseCallback();
var err;
let err;
if (!tokenId) {
err = new Error(g.f('{{accessToken}} is required to logout'));
err.statusCode = 401;
@ -349,12 +370,12 @@ module.exports = function(User) {
// Do nothing when the access control was disabled for this user model.
if (!ctx.Model.relations.accessTokens) return next();
var AccessToken = ctx.Model.relations.accessTokens.modelTo;
var pkName = ctx.Model.definition.idName() || 'id';
const AccessToken = ctx.Model.relations.accessTokens.modelTo;
const pkName = ctx.Model.definition.idName() || 'id';
ctx.Model.find({where: ctx.where, fields: [pkName]}, function(err, list) {
if (err) return next(err);
var ids = list.map(function(u) { return u[pkName]; });
const ids = list.map(function(u) { return u[pkName]; });
ctx.where = {};
ctx.where[pkName] = {inq: ids};
@ -699,9 +720,9 @@ module.exports = function(User) {
}
cb = cb || utils.createPromiseCallback();
var user = this;
var userModel = this.constructor;
var registry = userModel.registry;
const user = this;
const userModel = this.constructor;
const registry = userModel.registry;
verifyOptions = Object.assign({}, verifyOptions);
// final assertion is performed once all options are assigned
assert(typeof verifyOptions === 'object',
@ -722,19 +743,19 @@ module.exports = function(User) {
verifyOptions.mailer = verifyOptions.mailer || userModel.email ||
registry.getModelByType(loopback.Email);
var pkName = userModel.definition.idName() || 'id';
const pkName = userModel.definition.idName() || 'id';
verifyOptions.redirect = verifyOptions.redirect || '/';
var defaultTemplate = path.join(__dirname, '..', '..', 'templates', 'verify.ejs');
const defaultTemplate = path.join(__dirname, '..', '..', 'templates', 'verify.ejs');
verifyOptions.template = path.resolve(verifyOptions.template || defaultTemplate);
verifyOptions.user = user;
verifyOptions.protocol = verifyOptions.protocol || 'http';
var app = userModel.app;
const app = userModel.app;
verifyOptions.host = verifyOptions.host || (app && app.get('host')) || 'localhost';
verifyOptions.port = verifyOptions.port || (app && app.get('port')) || 3000;
verifyOptions.restApiRoot = verifyOptions.restApiRoot || (app && app.get('restApiRoot')) || '/api';
var displayPort = (
const displayPort = (
(verifyOptions.protocol === 'http' && verifyOptions.port == '80') ||
(verifyOptions.protocol === 'https' && verifyOptions.port == '443')
) ? '' : ':' + verifyOptions.port;
@ -745,14 +766,14 @@ module.exports = function(User) {
throw new Error(
'Cannot build user verification URL, ' +
'the default confirm method is not public. ' +
'Please provide the URL in verifyOptions.verifyHref.'
'Please provide the URL in verifyOptions.verifyHref.',
);
}
const urlPath = joinUrlPath(
verifyOptions.restApiRoot,
userModel.http.path,
confirmMethod.http.path
confirmMethod.http.path,
);
verifyOptions.verifyHref =
@ -775,7 +796,7 @@ module.exports = function(User) {
assertVerifyOptions(verifyOptions);
// argument "options" is passed depending on verifyOptions.generateVerificationToken function requirements
var tokenGenerator = verifyOptions.generateVerificationToken;
const tokenGenerator = verifyOptions.generateVerificationToken;
if (tokenGenerator.length == 3) {
tokenGenerator(user, options, addTokenToUserAndSave);
} else {
@ -803,7 +824,7 @@ module.exports = function(User) {
verifyOptions.text = verifyOptions.text.replace(/\{href\}/g, verifyOptions.verifyHref);
// argument "options" is passed depending on templateFn function requirements
var templateFn = verifyOptions.templateFn;
const templateFn = verifyOptions.templateFn;
if (templateFn.length == 3) {
templateFn(verifyOptions, options, setHtmlContentAndSend);
} else {
@ -820,7 +841,7 @@ module.exports = function(User) {
delete verifyOptions.template;
// argument "options" is passed depending on Email.send function requirements
var Email = verifyOptions.mailer;
const Email = verifyOptions.mailer;
if (Email.send.length == 3) {
Email.send(verifyOptions, options, handleAfterSend);
} else {
@ -852,8 +873,8 @@ module.exports = function(User) {
}
function createVerificationEmailBody(verifyOptions, options, cb) {
var template = loopback.template(verifyOptions.template);
var body = template(verifyOptions);
const template = loopback.template(verifyOptions.template);
const body = template(verifyOptions);
cb(null, body);
}
@ -931,11 +952,11 @@ module.exports = function(User) {
User.resetPassword = function(options, cb) {
cb = cb || utils.createPromiseCallback();
var UserModel = this;
var ttl = UserModel.settings.resetPasswordTokenTTL || DEFAULT_RESET_PW_TTL;
const UserModel = this;
const ttl = UserModel.settings.resetPasswordTokenTTL || DEFAULT_RESET_PW_TTL;
options = options || {};
if (typeof options.email !== 'string') {
var err = new Error(g.f('Email is required'));
const err = new Error(g.f('Email is required'));
err.statusCode = 400;
err.code = 'EMAIL_REQUIRED';
cb(err);
@ -949,7 +970,7 @@ module.exports = function(User) {
} catch (err) {
return cb(err);
}
var where = {
const where = {
email: options.email,
};
if (options.realm) {
@ -1010,12 +1031,12 @@ module.exports = function(User) {
*/
User.hashPassword = function(plain) {
this.validatePassword(plain);
var salt = bcrypt.genSaltSync(this.settings.saltWorkFactor || SALT_WORK_FACTOR);
const salt = bcrypt.genSaltSync(this.settings.saltWorkFactor || SALT_WORK_FACTOR);
return bcrypt.hashSync(plain, salt);
};
User.validatePassword = function(plain) {
var err;
let err;
if (!plain || typeof plain !== 'string') {
err = new Error(g.f('Invalid password.'));
err.code = 'INVALID_PASSWORD';
@ -1024,7 +1045,7 @@ module.exports = function(User) {
}
// Bcrypt only supports up to 72 bytes; the rest is silently dropped.
var len = Buffer.byteLength(plain, 'utf8');
const len = Buffer.byteLength(plain, 'utf8');
if (len > MAX_PASSWORD_LENGTH) {
err = new Error(g.f('The password entered was too long. Max length is %d (entered %d)',
MAX_PASSWORD_LENGTH, len));
@ -1043,20 +1064,20 @@ module.exports = function(User) {
if (!Array.isArray(userIds) || !userIds.length)
return process.nextTick(cb);
var accessTokenRelation = this.relations.accessTokens;
const accessTokenRelation = this.relations.accessTokens;
if (!accessTokenRelation)
return process.nextTick(cb);
var AccessToken = accessTokenRelation.modelTo;
var query = {userId: {inq: userIds}};
var tokenPK = AccessToken.definition.idName() || 'id';
const AccessToken = accessTokenRelation.modelTo;
const query = {userId: {inq: userIds}};
const tokenPK = AccessToken.definition.idName() || 'id';
if (options.accessToken && tokenPK in options.accessToken) {
query[tokenPK] = {neq: options.accessToken[tokenPK]};
}
// add principalType in AccessToken.query if using polymorphic relations
// between AccessToken and User
var relatedUser = AccessToken.relations.user;
var isRelationPolymorphic = relatedUser && relatedUser.polymorphic &&
const relatedUser = AccessToken.relations.user;
const isRelationPolymorphic = relatedUser && relatedUser.polymorphic &&
!relatedUser.modelTo;
if (isRelationPolymorphic) {
query.principalType = this.modelName;
@ -1071,7 +1092,7 @@ module.exports = function(User) {
User.setup = function() {
// We need to call the base class's setup method
User.base.setup.call(this);
var UserModel = this;
const UserModel = this;
// max ttl
this.settings.maxTTL = this.settings.maxTTL || DEFAULT_MAX_TTL;
@ -1089,7 +1110,7 @@ module.exports = function(User) {
if (typeof plain !== 'string') {
return;
}
if (plain.indexOf('$2a$') === 0 && plain.length === 60) {
if ((plain.indexOf('$2a$') === 0 || plain.indexOf('$2b$') === 0) && plain.length === 60) {
// The password is already hashed. It can be the case
// when the instance is loaded from DB
this.$password = plain;
@ -1100,7 +1121,7 @@ module.exports = function(User) {
// Make sure emailVerified is not set by creation
UserModel.beforeRemote('create', function(ctx, user, next) {
var body = ctx.req.body;
const body = ctx.req.body;
if (body && body.emailVerified) {
body.emailVerified = false;
}
@ -1127,7 +1148,7 @@ module.exports = function(User) {
'{{(`include=user`)}}\n\n'),
},
http: {verb: 'post'},
}
},
);
UserModel.remoteMethod(
@ -1136,9 +1157,9 @@ module.exports = function(User) {
description: 'Logout a user with access token.',
accepts: [
{arg: 'access_token', type: 'string', http: function(ctx) {
var req = ctx && ctx.req;
var accessToken = req && req.accessToken;
var tokenID = accessToken ? accessToken.id : undefined;
const req = ctx && ctx.req;
const accessToken = req && req.accessToken;
const tokenID = accessToken ? accessToken.id : undefined;
return tokenID;
}, description: 'Do not supply this argument, it is automatically extracted ' +
@ -1146,7 +1167,7 @@ module.exports = function(User) {
},
],
http: {verb: 'all'},
}
},
);
UserModel.remoteMethod(
@ -1158,7 +1179,7 @@ module.exports = function(User) {
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
http: {verb: 'post'},
}
},
);
UserModel.remoteMethod(
@ -1171,7 +1192,7 @@ module.exports = function(User) {
{arg: 'redirect', type: 'string'},
],
http: {verb: 'get', path: '/confirm'},
}
},
);
UserModel.remoteMethod(
@ -1182,7 +1203,7 @@ module.exports = function(User) {
{arg: 'options', type: 'object', required: true, http: {source: 'body'}},
],
http: {verb: 'post', path: '/reset'},
}
},
);
UserModel.remoteMethod(
@ -1196,7 +1217,7 @@ module.exports = function(User) {
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
http: {verb: 'POST', path: '/change-password'},
}
},
);
const setPasswordScopes = UserModel.settings.restrictResetPasswordTokenScope ?
@ -1213,7 +1234,7 @@ module.exports = function(User) {
],
accessScopes: setPasswordScopes,
http: {verb: 'POST', path: '/reset-password'},
}
},
);
function getUserIdFromRequestContext(ctx) {
@ -1316,7 +1337,7 @@ module.exports = function(User) {
// This is a programmer's error, use the default status code 500
return next(new Error(
'Invalid use of "options.setPassword". Only "password" can be ' +
'changed when using this option.'
'changed when using this option.',
));
}
@ -1329,7 +1350,7 @@ module.exports = function(User) {
const err = new Error(
'Changing user password via patch/replace API is not allowed. ' +
'Use changePassword() or setPassword() instead.'
'Use changePassword() or setPassword() instead.',
);
err.statusCode = 401;
err.code = 'PASSWORD_CHANGE_NOT_ALLOWED';
@ -1340,8 +1361,8 @@ module.exports = function(User) {
if (ctx.isNewInstance) return next();
if (!ctx.where && !ctx.instance) return next();
var pkName = ctx.Model.definition.idName() || 'id';
var where = ctx.where;
const pkName = ctx.Model.definition.idName() || 'id';
let where = ctx.where;
if (!where) {
where = {};
where[pkName] = ctx.instance[pkName];
@ -1350,15 +1371,22 @@ module.exports = function(User) {
ctx.Model.find({where: where}, ctx.options, function(err, userInstances) {
if (err) return next(err);
ctx.hookState.originalUserData = userInstances.map(function(u) {
var user = {};
const user = {};
user[pkName] = u[pkName];
user.email = u.email;
user.password = u.password;
return user;
});
var emailChanged;
let emailChanged;
if (ctx.instance) {
// Check if map does not return an empty array
// Fix server crashes when try to PUT a non existent id
if (ctx.hookState.originalUserData.length > 0) {
emailChanged = ctx.instance.email !== ctx.hookState.originalUserData[0].email;
} else {
emailChanged = true;
}
if (emailChanged && ctx.Model.settings.emailVerificationRequired) {
ctx.instance.emailVerified = false;
}
@ -1379,15 +1407,15 @@ module.exports = function(User) {
if (!ctx.instance && !ctx.data) return next();
if (!ctx.hookState.originalUserData) return next();
var pkName = ctx.Model.definition.idName() || 'id';
var newEmail = (ctx.instance || ctx.data).email;
var newPassword = (ctx.instance || ctx.data).password;
const pkName = ctx.Model.definition.idName() || 'id';
const newEmail = (ctx.instance || ctx.data).email;
const newPassword = (ctx.instance || ctx.data).password;
if (!newEmail && !newPassword) return next();
if (ctx.options.preserveAccessTokens) return next();
var userIdsToExpire = ctx.hookState.originalUserData.filter(function(u) {
const userIdsToExpire = ctx.hookState.originalUserData.filter(function(u) {
return (newEmail && u.email !== newEmail) ||
(newPassword && u.password !== newPassword);
}).map(function(u) {
@ -1398,7 +1426,7 @@ module.exports = function(User) {
};
function emailValidator(err, done) {
var value = this.email;
const value = this.email;
if (value == null)
return;
if (typeof value !== 'string')
@ -1409,9 +1437,9 @@ function emailValidator(err, done) {
}
function joinUrlPath(args) {
var result = arguments[0];
for (var ix = 1; ix < arguments.length; ix++) {
var next = arguments[ix];
let result = arguments[0];
for (let ix = 1; ix < arguments.length; ix++) {
const next = arguments[ix];
result += result[result.length - 1] === '/' && next[0] === '/' ?
next.slice(1) : next;
}

View File

@ -1,14 +1,14 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('../../lib/globalize');
var loopback = require('../../');
var client = loopback();
var CartItem = require('./models').CartItem;
var remote = loopback.createDataSource({
const g = require('../../lib/globalize');
const loopback = require('../../');
const client = loopback();
const CartItem = require('./models').CartItem;
const remote = loopback.createDataSource({
connector: loopback.Remote,
url: 'http://localhost:3000',
});

View File

@ -1,12 +1,12 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../');
const loopback = require('../../');
var CartItem = exports.CartItem = loopback.PersistedModel.extend('CartItem', {
const CartItem = exports.CartItem = loopback.PersistedModel.extend('CartItem', {
tax: {type: Number, default: 0.1},
price: Number,
item: String,
@ -17,7 +17,7 @@ var CartItem = exports.CartItem = loopback.PersistedModel.extend('CartItem', {
CartItem.sum = function(cartId, callback) {
this.find({where: {cartId: cartId}}, function(err, items) {
if (err) return callback(err);
var total = items
const total = items
.map(function(item) {
return item.total();
})
@ -33,8 +33,7 @@ CartItem.remoteMethod('sum',
{
accepts: {arg: 'cartId', type: 'number'},
returns: {arg: 'total', type: 'number'},
}
);
});
CartItem.prototype.total = function() {
return this.price * this.qty * (1 + this.tax);

View File

@ -1,13 +1,13 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../');
var server = module.exports = loopback();
var CartItem = require('./models').CartItem;
var memory = loopback.createDataSource({
const loopback = require('../../');
const server = module.exports = loopback();
const CartItem = require('./models').CartItem;
const memory = loopback.createDataSource({
connector: loopback.Memory,
});

View File

@ -1,21 +1,21 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('../../lib/globalize');
var loopback = require('../../');
var app = loopback();
const g = require('../../lib/globalize');
const loopback = require('../../');
const app = loopback();
app.use(loopback.rest());
var schema = {
const schema = {
name: String,
};
app.dataSource('db', {connector: 'memory'});
var Color = app.registry.createModel('color', schema);
const Color = app.registry.createModel('color', schema);
app.model(Color, {dataSource: 'db'});
Color.create({name: 'red'});

View File

@ -1,23 +1,23 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('../../lib/globalize');
var models = require('../../lib/models');
var loopback = require('../../');
var app = loopback();
const g = require('../../lib/globalize');
const models = require('../../lib/models');
const loopback = require('../../');
const app = loopback();
app.use(loopback.rest());
var dataSource = loopback.createDataSource('db', {connector: loopback.Memory});
const dataSource = loopback.createDataSource('db', {connector: loopback.Memory});
var Application = models.Application(dataSource);
const Application = models.Application(dataSource);
app.model(Application);
var data = {
const data = {
pushSettings: [{
'platform': 'apns',
'apns': {

View File

@ -1,22 +1,22 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../');
var app = loopback();
var db = app.dataSource('db', {connector: 'memory'});
var Color = app.registry.createModel('color', {}, {trackChanges: true});
const loopback = require('../../');
const app = loopback();
const db = app.dataSource('db', {connector: 'memory'});
const Color = app.registry.createModel('color', {}, {trackChanges: true});
app.model(Color, {dataSource: 'db'});
var Color2 = app.registry.createModel('color2', {}, {trackChanges: true});
const Color2 = app.registry.createModel('color2', {}, {trackChanges: true});
app.model(Color2, {dataSource: 'db'});
var target = Color2;
var source = Color;
var SPEED = process.env.SPEED || 100;
var conflicts;
const target = Color2;
const source = Color;
const SPEED = process.env.SPEED || 100;
let conflicts;
var steps = [
const steps = [
createSomeInitialSourceData,
@ -137,7 +137,7 @@ function list(model, msg) {
function run(steps) {
setInterval(function() {
var step = steps.shift();
const step = steps.shift();
if (step) {
console.log(step.name);
step();

View File

@ -1,18 +1,18 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('../../lib/globalize');
var loopback = require('../../');
var app = loopback();
const g = require('../../lib/globalize');
const loopback = require('../../');
const app = loopback();
app.use(loopback.rest());
var dataSource = app.dataSource('db', {adapter: 'memory'});
const dataSource = app.dataSource('db', {adapter: 'memory'});
var Color = dataSource.define('color', {
const Color = dataSource.define('color', {
'name': String,
});

View File

@ -1,12 +1,12 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var loopback = require('./loopback');
var debug = require('debug')('loopback:security:access-context');
const assert = require('assert');
const loopback = require('./loopback');
const debug = require('debug')('loopback:security:access-context');
const DEFAULT_SCOPES = ['DEFAULT'];
@ -50,7 +50,7 @@ function AccessContext(context) {
'Application registry is mandatory in AccessContext but missing in provided context');
this.registry = context.registry;
this.principals = context.principals || [];
var model = context.model;
let model = context.model;
model = ('string' === typeof model) ? this.registry.getModel(model) : model;
this.model = model;
this.modelName = model && model.modelName;
@ -77,9 +77,9 @@ function AccessContext(context) {
'AccessToken model must be defined before AccessContext model');
this.accessToken = context.accessToken || loopback.AccessToken.ANONYMOUS;
var principalType = context.principalType || Principal.USER;
var principalId = context.principalId || undefined;
var principalName = context.principalName || undefined;
const principalType = context.principalType || Principal.USER;
const principalId = context.principalId || undefined;
const principalName = context.principalName || undefined;
if (principalId != null) {
this.addPrincipal(principalType, principalId, principalName);
}
@ -126,9 +126,9 @@ AccessContext.permissionOrder = {
* @returns {boolean}
*/
AccessContext.prototype.addPrincipal = function(principalType, principalId, principalName) {
var principal = new Principal(principalType, principalId, principalName);
for (var i = 0; i < this.principals.length; i++) {
var p = this.principals[i];
const principal = new Principal(principalType, principalId, principalName);
for (let i = 0; i < this.principals.length; i++) {
const p = this.principals[i];
if (p.equals(principal)) {
return false;
}
@ -142,7 +142,7 @@ AccessContext.prototype.addPrincipal = function(principalType, principalId, prin
* @returns {*}
*/
AccessContext.prototype.getUserId = function() {
var user = this.getUser();
const user = this.getUser();
return user && user.id;
};
@ -151,10 +151,10 @@ AccessContext.prototype.getUserId = function() {
* @returns {*}
*/
AccessContext.prototype.getUser = function() {
var BaseUser = this.registry.getModel('User');
for (var i = 0; i < this.principals.length; i++) {
var p = this.principals[i];
var isBuiltinPrincipal = p.type === Principal.APP ||
const BaseUser = this.registry.getModel('User');
for (let i = 0; i < this.principals.length; i++) {
const p = this.principals[i];
const isBuiltinPrincipal = p.type === Principal.APP ||
p.type === Principal.ROLE ||
p.type == Principal.SCOPE;
if (isBuiltinPrincipal) continue;
@ -165,7 +165,7 @@ AccessContext.prototype.getUser = function() {
}
// or permit to resolve a valid user model
var userModel = this.registry.findModel(p.type);
const userModel = this.registry.findModel(p.type);
if (!userModel) continue;
if (userModel.prototype instanceof BaseUser) {
return {id: p.id, principalType: p.type};
@ -178,8 +178,8 @@ AccessContext.prototype.getUser = function() {
* @returns {*}
*/
AccessContext.prototype.getAppId = function() {
for (var i = 0; i < this.principals.length; i++) {
var p = this.principals[i];
for (let i = 0; i < this.principals.length; i++) {
const p = this.principals[i];
if (p.type === Principal.APPLICATION) {
return p.id;
}
@ -325,7 +325,7 @@ function AccessRequest(model, property, accessType, permission, methodNames, reg
}
if (arguments.length === 1 && typeof model === 'object') {
// The argument is an object that contains all required properties
var obj = model || {};
const obj = model || {};
this.model = obj.model || AccessContext.ALL;
this.property = obj.property || AccessContext.ALL;
this.accessType = obj.accessType || AccessContext.ALL;
@ -363,10 +363,10 @@ AccessRequest.prototype.isWildcard = function() {
*/
AccessRequest.prototype.exactlyMatches = function(acl) {
var matchesModel = acl.model === this.model;
var matchesProperty = acl.property === this.property;
var matchesMethodName = this.methodNames.indexOf(acl.property) !== -1;
var matchesAccessType = acl.accessType === this.accessType;
const matchesModel = acl.model === this.model;
const matchesProperty = acl.property === this.property;
const matchesMethodName = this.methodNames.indexOf(acl.property) !== -1;
const matchesAccessType = acl.accessType === this.accessType;
if (matchesModel && matchesAccessType) {
return matchesProperty || matchesMethodName;
@ -388,9 +388,9 @@ AccessRequest.prototype.settleDefaultPermission = function(defaultPermission) {
if (this.permission !== 'DEFAULT')
return;
var modelName = this.model;
const modelName = this.model;
if (!defaultPermission) {
var modelClass = this.registry.findModel(modelName);
const modelClass = this.registry.findModel(modelName);
defaultPermission = modelClass && modelClass.settings.defaultPermission;
}

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -8,17 +8,17 @@
*/
'use strict';
var g = require('./globalize');
var DataSource = require('loopback-datasource-juggler').DataSource;
var Registry = require('./registry');
var assert = require('assert');
var fs = require('fs');
var extend = require('util')._extend;
var RemoteObjects = require('strong-remoting');
var classify = require('underscore.string/classify');
var camelize = require('underscore.string/camelize');
var path = require('path');
var util = require('util');
const g = require('./globalize');
const DataSource = require('loopback-datasource-juggler').DataSource;
const Registry = require('./registry');
const assert = require('assert');
const fs = require('fs');
const extend = require('util')._extend;
const RemoteObjects = require('strong-remoting');
const classify = require('underscore.string/classify');
const camelize = require('underscore.string/camelize');
const path = require('path');
const util = require('util');
/**
* The `App` object represents a Loopback application.
@ -49,7 +49,7 @@ function App() {
* Export the app prototype.
*/
var app = module.exports = {};
const app = module.exports = {};
/**
* Lazily load a set of [remote objects](http://apidocs.strongloop.com/strong-remoting/#remoteobjectsoptions).
@ -62,7 +62,7 @@ app.remotes = function() {
if (this._remotes) {
return this._remotes;
} else {
var options = {};
let options = {};
if (this.get) {
options = this.get('remoting');
@ -78,7 +78,7 @@ app.remotes = function() {
app.disuse = function(route) {
if (this.stack) {
for (var i = 0; i < this.stack.length; i++) {
for (let i = 0; i < this.stack.length; i++) {
if (this.stack[i].route === route) {
this.stack.splice(i, 1);
}
@ -111,11 +111,11 @@ app.disuse = function(route) {
*/
app.model = function(Model, config) {
var isPublic = true;
var registry = this.registry;
let isPublic = true;
const registry = this.registry;
if (typeof Model === 'string') {
var msg = 'app.model(modelName, settings) is no longer supported. ' +
const msg = 'app.model(modelName, settings) is no longer supported. ' +
'Use app.registry.createModel(modelName, definition) and ' +
'app.model(ModelCtor, config) instead.';
throw new Error(msg);
@ -130,7 +130,7 @@ app.model = function(Model, config) {
Model.modelName + ' must be a descendant of loopback.Model');
}
var modelName = Model.modelName;
const modelName = Model.modelName;
this.models[modelName] =
this.models[classify(modelName)] =
this.models[camelize(modelName)] = Model;
@ -149,7 +149,7 @@ app.model = function(Model, config) {
this.emit('modelRemoted', Model.sharedClass);
}
var self = this;
const self = this;
Model.on('remoteMethodDisabled', function(model, methodName) {
clearHandlerCache(self);
self.emit('remoteMethodDisabled', model, methodName);
@ -266,7 +266,7 @@ app.models = function() {
*/
app.dataSource = function(name, config) {
try {
var ds = dataSourcesFromConfig(name, config, this.connectors, this.registry);
const ds = dataSourcesFromConfig(name, config, this.connectors, this.registry);
this.dataSources[name] =
this.dataSources[classify(name)] =
this.dataSources[camelize(name)] = ds;
@ -307,7 +307,7 @@ app.connector = function(name, connector) {
*/
app.remoteObjects = function() {
var result = {};
const result = {};
this.remotes().classes().forEach(function(sharedClass) {
result[sharedClass.name] = sharedClass.ctor;
@ -322,13 +322,13 @@ app.remoteObjects = function() {
*/
app.handler = function(type, options) {
var handlers = this._handlers || (this._handlers = {});
const handlers = this._handlers || (this._handlers = {});
if (handlers[type]) {
return handlers[type];
}
var remotes = this.remotes();
var handler = this._handlers[type] = remotes.handler(type, options);
const remotes = this.remotes();
const handler = this._handlers[type] = remotes.handler(type, options);
remotes.classes().forEach(function(sharedClass) {
sharedClass.ctor.emit('mounted', app, sharedClass, remotes);
@ -348,18 +348,18 @@ app.dataSources = app.datasources = {};
*/
app.enableAuth = function(options) {
var AUTH_MODELS = ['User', 'AccessToken', 'ACL', 'Role', 'RoleMapping'];
const AUTH_MODELS = ['User', 'AccessToken', 'ACL', 'Role', 'RoleMapping'];
var remotes = this.remotes();
var app = this;
const remotes = this.remotes();
const app = this;
if (options && options.dataSource) {
var appModels = app.registry.modelBuilder.models;
const appModels = app.registry.modelBuilder.models;
AUTH_MODELS.forEach(function(m) {
var Model = app.registry.findModel(m);
const Model = app.registry.findModel(m);
if (!Model) {
throw new Error(
g.f('Authentication requires model %s to be defined.', m)
g.f('Authentication requires model %s to be defined.', m),
);
}
@ -367,10 +367,10 @@ app.enableAuth = function(options) {
// Find descendants of Model that are attached,
// for example "Customer" extending "User" model
for (var name in appModels) {
var candidate = appModels[name];
var isSubclass = candidate.prototype instanceof Model;
var isAttached = !!candidate.dataSource || !!candidate.app;
for (const name in appModels) {
const candidate = appModels[name];
const isSubclass = candidate.prototype instanceof Model;
const isAttached = !!candidate.dataSource || !!candidate.app;
if (isSubclass && isAttached) return;
}
@ -382,22 +382,22 @@ app.enableAuth = function(options) {
}
remotes.authorization = function(ctx, next) {
var method = ctx.method;
var req = ctx.req;
var Model = method.ctor;
var modelInstance = ctx.instance;
const method = ctx.method;
const req = ctx.req;
const Model = method.ctor;
const modelInstance = ctx.instance;
var modelId = modelInstance && modelInstance.id ||
const modelId = modelInstance && modelInstance.id ||
// replacement for deprecated req.param()
(req.params && req.params.id !== undefined ? req.params.id :
req.body && req.body.id !== undefined ? req.body.id :
req.query && req.query.id !== undefined ? req.query.id :
undefined);
var modelName = Model.modelName;
const modelName = Model.modelName;
var modelSettings = Model.settings || {};
var errStatusCode = modelSettings.aclErrorStatus || app.get('aclErrorStatus') || 401;
const modelSettings = Model.settings || {};
let errStatusCode = modelSettings.aclErrorStatus || app.get('aclErrorStatus') || 401;
if (!req.accessToken) {
errStatusCode = 401;
}
@ -415,7 +415,7 @@ app.enableAuth = function(options) {
} else if (allowed) {
next();
} else {
var messages = {
const messages = {
403: {
message: g.f('Access Denied'),
code: 'ACCESS_DENIED',
@ -430,12 +430,12 @@ app.enableAuth = function(options) {
},
};
var e = new Error(messages[errStatusCode].message || messages[403].message);
const e = new Error(messages[errStatusCode].message || messages[403].message);
e.statusCode = errStatusCode;
e.code = messages[errStatusCode].code || messages[403].code;
next(e);
}
}
},
);
} else {
next();
@ -486,7 +486,7 @@ app._verifyAuthModelRelations = function() {
'custom User subclass, but does not fix AccessToken relations ' +
'to use this new model.\n' +
'Learn more at http://ibm.biz/setup-loopback-auth',
Model.modelName, userName, userName
Model.modelName, userName, userName,
);
return;
}
@ -495,7 +495,7 @@ app._verifyAuthModelRelations = function() {
'The model %j does not have "belongsTo User-like model" relation ' +
'configured.\n' +
'Learn more at http://ibm.biz/setup-loopback-auth',
Model.modelName
Model.modelName,
);
}
@ -509,7 +509,7 @@ app._verifyAuthModelRelations = function() {
'The app configuration follows the multiple user models setup ' +
'as described in http://ibm.biz/setup-loopback-auth',
'The built-in role resolver $owner is not currently compatible ' +
'with this configuration and should not be used in production.'
'with this configuration and should not be used in production.',
);
}
return;
@ -526,7 +526,7 @@ app._verifyAuthModelRelations = function() {
'AccessToken subclass, but does not fix User relations to use this ' +
'new model.\n' +
'Learn more at http://ibm.biz/setup-loopback-auth',
Model.modelName, accessTokenName, accessTokenName
Model.modelName, accessTokenName, accessTokenName,
);
return;
}
@ -535,19 +535,19 @@ app._verifyAuthModelRelations = function() {
'The model %j does not have "hasMany AccessToken-like models" relation ' +
'configured.\n' +
'Learn more at http://ibm.biz/setup-loopback-auth',
Model.modelName
Model.modelName,
);
}
};
app.boot = function(options) {
throw new Error(
g.f('{{`app.boot`}} was removed, use the new module {{loopback-boot}} instead')
g.f('{{`app.boot`}} was removed, use the new module {{loopback-boot}} instead'),
);
};
function dataSourcesFromConfig(name, config, connectorRegistry, registry) {
var connectorPath;
let connectorPath;
assert(typeof config === 'object',
'can not create data source without config object');
@ -574,7 +574,7 @@ function configureModel(ModelCtor, config, app) {
assert(ModelCtor.prototype instanceof ModelCtor.registry.getModel('Model'),
ModelCtor.modelName + ' must be a descendant of loopback.Model');
var dataSource = config.dataSource;
let dataSource = config.dataSource;
if (dataSource) {
if (typeof dataSource === 'string') {
@ -584,7 +584,7 @@ function configureModel(ModelCtor, config, app) {
assert(
dataSource instanceof DataSource,
ModelCtor.modelName + ' is referencing a dataSource that does not exist: "' +
config.dataSource + '"'
config.dataSource + '"',
);
}
@ -627,15 +627,15 @@ function clearHandlerCache(app) {
* as the request handler.
*/
app.listen = function(cb) {
var self = this;
const self = this;
var server = require('http').createServer(this);
const server = require('http').createServer(this);
server.on('listening', function() {
self.set('port', this.address().port);
var listeningOnAll = false;
var host = self.get('host');
let listeningOnAll = false;
let host = self.get('host');
if (!host) {
listeningOnAll = true;
host = this.address().address;
@ -650,17 +650,17 @@ app.listen = function(cb) {
// that can be copied and pasted into the browser.
host = 'localhost';
}
var url = 'http://' + host + ':' + self.get('port') + '/';
const url = 'http://' + host + ':' + self.get('port') + '/';
self.set('url', url);
}
});
var useAppConfig =
const useAppConfig =
arguments.length === 0 ||
(arguments.length == 1 && typeof arguments[0] == 'function');
if (useAppConfig) {
var port = this.get('port');
let port = this.get('port');
// NOTE(bajtos) port:undefined no longer works on node@6,
// we must pass port:0 explicitly
if (port === undefined) port = 0;

View File

@ -1,11 +1,11 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var EventEmitter = require('events').EventEmitter;
var util = require('util');
const EventEmitter = require('events').EventEmitter;
const util = require('util');
module.exports = browserExpress;

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -12,57 +12,57 @@ module.exports = function(registry) {
registry.KeyValueModel = createModel(
require('../common/models/key-value-model.json'),
require('../common/models/key-value-model.js')
require('../common/models/key-value-model.js'),
);
registry.Email = createModel(
require('../common/models/email.json'),
require('../common/models/email.js')
require('../common/models/email.js'),
);
registry.Application = createModel(
require('../common/models/application.json'),
require('../common/models/application.js')
require('../common/models/application.js'),
);
registry.AccessToken = createModel(
require('../common/models/access-token.json'),
require('../common/models/access-token.js')
require('../common/models/access-token.js'),
);
registry.User = createModel(
require('../common/models/user.json'),
require('../common/models/user.js')
require('../common/models/user.js'),
);
registry.RoleMapping = createModel(
require('../common/models/role-mapping.json'),
require('../common/models/role-mapping.js')
require('../common/models/role-mapping.js'),
);
registry.Role = createModel(
require('../common/models/role.json'),
require('../common/models/role.js')
require('../common/models/role.js'),
);
registry.ACL = createModel(
require('../common/models/acl.json'),
require('../common/models/acl.js')
require('../common/models/acl.js'),
);
registry.Scope = createModel(
require('../common/models/scope.json'),
require('../common/models/scope.js')
require('../common/models/scope.js'),
);
registry.Change = createModel(
require('../common/models/change.json'),
require('../common/models/change.js')
require('../common/models/change.js'),
);
registry.Checkpoint = createModel(
require('../common/models/checkpoint.json'),
require('../common/models/checkpoint.js')
require('../common/models/checkpoint.js'),
);
function createModel(definitionJson, customizeFn) {
@ -74,7 +74,7 @@ module.exports = function(registry) {
// object instance it loaded during the first call.
definitionJson = cloneDeepJson(definitionJson);
var Model = registry.createModel(definitionJson);
const Model = registry.createModel(definitionJson);
customizeFn(Model);
return Model;
}

View File

@ -1,19 +1,19 @@
// Copyright IBM Corp. 2017,2018. All Rights Reserved.
// Copyright IBM Corp. 2017,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var util = require('util');
var extend = require('util')._extend;
var g = require('./globalize');
const util = require('util');
const extend = require('util')._extend;
const g = require('./globalize');
module.exports = function(modelCtor, remotingConfig, modelConfig) {
var settings = {};
const settings = {};
// apply config.json settings
var configHasSharedMethodsSettings = remotingConfig &&
const configHasSharedMethodsSettings = remotingConfig &&
remotingConfig.sharedMethods &&
typeof remotingConfig.sharedMethods === 'object';
if (configHasSharedMethodsSettings)
@ -21,7 +21,7 @@ module.exports = function(modelCtor, remotingConfig, modelConfig) {
// apply model-config.json settings
const options = modelConfig.options;
var modelConfigHasSharedMethodsSettings = options &&
const modelConfigHasSharedMethodsSettings = options &&
options.remoting &&
options.remoting.sharedMethods &&
typeof options.remoting.sharedMethods === 'object';
@ -30,30 +30,30 @@ module.exports = function(modelCtor, remotingConfig, modelConfig) {
// validate setting values
Object.keys(settings).forEach(function(setting) {
var settingValue = settings[setting];
var settingValueType = typeof settingValue;
const settingValue = settings[setting];
const settingValueType = typeof settingValue;
if (settingValueType !== 'boolean')
throw new TypeError(g.f('Expected boolean, got %s', settingValueType));
});
// set sharedMethod.shared using the merged settings
var sharedMethods = modelCtor.sharedClass.methods({includeDisabled: true});
const sharedMethods = modelCtor.sharedClass.methods({includeDisabled: true});
// re-map glob style values to regular expressions
var tests = Object
const tests = Object
.keys(settings)
.filter(function(setting) {
return settings.hasOwnProperty(setting) && setting.indexOf('*') >= 0;
})
.map(function(setting) {
// Turn * into an testable regexp string
var glob = escapeRegExp(setting).replace(/\*/g, '(.)*');
const glob = escapeRegExp(setting).replace(/\*/g, '(.)*');
return {regex: new RegExp(glob), setting: settings[setting]};
}) || [];
sharedMethods.forEach(function(sharedMethod) {
// use the specific setting if it exists
var methodName = sharedMethod.isStatic ? sharedMethod.name : 'prototype.' + sharedMethod.name;
var hasSpecificSetting = settings.hasOwnProperty(methodName);
const methodName = sharedMethod.isStatic ? sharedMethod.name : 'prototype.' + sharedMethod.name;
const hasSpecificSetting = settings.hasOwnProperty(methodName);
if (hasSpecificSetting) {
if (settings[methodName] === false) {
sharedMethod.sharedClass.disableMethodByName(methodName);

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -14,11 +14,11 @@ module.exports = Connector;
* Module dependencies.
*/
var EventEmitter = require('events').EventEmitter;
var debug = require('debug')('connector');
var util = require('util');
var inherits = util.inherits;
var assert = require('assert');
const EventEmitter = require('events').EventEmitter;
const debug = require('debug')('connector');
const util = require('util');
const inherits = util.inherits;
const assert = require('assert');
/**
* Create a new `Connector` with the given `options`.
@ -45,7 +45,7 @@ inherits(Connector, EventEmitter);
*/
Connector._createJDBAdapter = function(jdbModule) {
var fauxSchema = {};
const fauxSchema = {};
jdbModule.initialize(fauxSchema, function() {
// connected
});

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -8,11 +8,11 @@
*/
'use strict';
var g = require('../globalize');
var mailer = require('nodemailer');
var assert = require('assert');
var debug = require('debug')('loopback:connector:mail');
var loopback = require('../loopback');
const g = require('../globalize');
const mailer = require('nodemailer');
const assert = require('assert');
const debug = require('debug')('loopback:connector:mail');
const loopback = require('../loopback');
/**
* Export the MailConnector class.
@ -27,7 +27,7 @@ module.exports = MailConnector;
function MailConnector(settings) {
assert(typeof settings === 'object', 'cannot initialize MailConnector without a settings object');
var transports = settings.transports;
let transports = settings.transports;
// if transports is not in settings object AND settings.transport exists
if (!transports && settings.transport) {
@ -74,17 +74,17 @@ MailConnector.prototype.DataAccessObject = Mailer;
*/
MailConnector.prototype.setupTransport = function(setting) {
var connector = this;
const connector = this;
connector.transports = connector.transports || [];
connector.transportsIndex = connector.transportsIndex || {};
var transport;
var transportType = (setting.type || 'STUB').toLowerCase();
let transport;
const transportType = (setting.type || 'STUB').toLowerCase();
if (transportType === 'smtp') {
transport = mailer.createTransport(setting);
} else {
var transportModuleName = 'nodemailer-' + transportType + '-transport';
var transportModule = require(transportModuleName);
const transportModuleName = 'nodemailer-' + transportType + '-transport';
const transportModule = require(transportModuleName);
transport = mailer.createTransport(transportModule(setting));
}
@ -138,12 +138,12 @@ MailConnector.prototype.defaultTransport = function() {
*/
Mailer.send = function(options, fn) {
var dataSource = this.dataSource;
var settings = dataSource && dataSource.settings;
var connector = dataSource.connector;
const dataSource = this.dataSource;
const settings = dataSource && dataSource.settings;
const connector = dataSource.connector;
assert(connector, 'Cannot send mail without a connector!');
var transport = connector.transportForName(options.transport);
let transport = connector.transportForName(options.transport);
if (!transport) {
transport = connector.defaultTransport();

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -14,12 +14,12 @@ module.exports = Memory;
* Module dependencies.
*/
var Connector = require('./base-connector');
var debug = require('debug')('memory');
var util = require('util');
var inherits = util.inherits;
var assert = require('assert');
var JdbMemory = require('loopback-datasource-juggler/lib/connectors/memory');
const Connector = require('./base-connector');
const debug = require('debug')('memory');
const util = require('util');
const inherits = util.inherits;
const assert = require('assert');
const JdbMemory = require('loopback-datasource-juggler/lib/connectors/memory');
/**
* Create a new `Memory` connector with the given `options`.

View File

@ -1,12 +1,12 @@
// Copyright IBM Corp. 2016,2018. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('./globalize');
var juggler = require('loopback-datasource-juggler');
var remoting = require('strong-remoting');
const g = require('./globalize');
const juggler = require('loopback-datasource-juggler');
const remoting = require('strong-remoting');
module.exports = function(loopback) {
juggler.getCurrentContext =
@ -15,7 +15,7 @@ module.exports = function(loopback) {
throw new Error(g.f(
'%s was removed in version 3.0. See %s for more details.',
'loopback.getCurrentContext()',
'http://loopback.io/doc/en/lb2/Using-current-context.html'
'http://loopback.io/doc/en/lb2/Using-current-context.html',
));
};
@ -23,7 +23,7 @@ module.exports = function(loopback) {
throw new Error(g.f(
'%s was removed in version 3.0. See %s for more details.',
'loopback.runInContext()',
'http://loopback.io/doc/en/lb2/Using-current-context.html'
'http://loopback.io/doc/en/lb2/Using-current-context.html',
));
};
@ -31,7 +31,7 @@ module.exports = function(loopback) {
throw new Error(g.f(
'%s was removed in version 3.0. See %s for more details.',
'loopback.createContext()',
'http://loopback.io/doc/en/lb2/Using-current-context.html'
'http://loopback.io/doc/en/lb2/Using-current-context.html',
));
};
};

View File

@ -1,11 +1,11 @@
// Copyright IBM Corp. 2016,2018. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var path = require('path');
var SG = require('strong-globalize');
const path = require('path');
const SG = require('strong-globalize');
SG.SetRootDir(path.join(__dirname, '..'), {autonomousMsgLoading: 'all'});
module.exports = SG();

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -8,17 +8,17 @@
*/
'use strict';
var express = require('express');
var loopbackExpress = require('./server-app');
var proto = require('./application');
var fs = require('fs');
var ejs = require('ejs');
var path = require('path');
var merge = require('util')._extend;
var assert = require('assert');
var Registry = require('./registry');
var juggler = require('loopback-datasource-juggler');
var configureSharedMethods = require('./configure-shared-methods');
const express = require('express');
const loopbackExpress = require('./server-app');
const proto = require('./application');
const fs = require('fs');
const ejs = require('ejs');
const path = require('path');
const merge = require('util')._extend;
const assert = require('assert');
const Registry = require('./registry');
const juggler = require('loopback-datasource-juggler');
const configureSharedMethods = require('./configure-shared-methods');
/**
* LoopBack core module. It provides static properties and
@ -40,7 +40,7 @@ var configureSharedMethods = require('./configure-shared-methods');
* @header loopback
*/
var loopback = module.exports = createApplication;
const loopback = module.exports = createApplication;
/*!
* Framework version.
@ -73,7 +73,7 @@ Object.defineProperties(loopback, {
*/
function createApplication(options) {
var app = loopbackExpress();
const app = loopbackExpress();
merge(app, proto);
@ -107,7 +107,7 @@ function createApplication(options) {
if (loopback.localRegistry || options && options.localRegistry === true) {
// setup the app registry
var registry = app.registry = new Registry();
const registry = app.registry = new Registry();
if (options && options.loadBuiltinModels === true) {
require('./builtin-models')(registry);
}
@ -119,8 +119,8 @@ function createApplication(options) {
}
function mixin(source) {
for (var key in source) {
var desc = Object.getOwnPropertyDescriptor(source, key);
for (const key in source) {
const desc = Object.getOwnPropertyDescriptor(source, key);
// Fix for legacy (pre-ES5) browsers like PhantomJS
if (!desc) continue;
@ -204,8 +204,8 @@ loopback.remoteMethod = function(fn, options) {
*/
loopback.template = function(file) {
var templates = this._templates || (this._templates = {});
var str = templates[file] || (templates[file] = fs.readFileSync(file, 'utf8'));
const templates = this._templates || (this._templates = {});
const str = templates[file] || (templates[file] = fs.readFileSync(file, 'utf8'));
return ejs.compile(str, {
filename: file,
});

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -7,14 +7,14 @@
* Module Dependencies.
*/
'use strict';
var g = require('./globalize');
var assert = require('assert');
var debug = require('debug')('loopback:model');
var RemoteObjects = require('strong-remoting');
var SharedClass = require('strong-remoting').SharedClass;
var extend = require('util')._extend;
const g = require('./globalize');
const assert = require('assert');
const debug = require('debug')('loopback:model');
const RemoteObjects = require('strong-remoting');
const SharedClass = require('strong-remoting').SharedClass;
const extend = require('util')._extend;
var deprecated = require('depd')('loopback');
const deprecated = require('depd')('loopback');
module.exports = function(registry) {
/**
@ -104,7 +104,7 @@ module.exports = function(registry) {
* @property {Array.<Object>} settings.acls Array of ACLs for the model.
* @class
*/
var Model = registry.modelBuilder.define('Model');
const Model = registry.modelBuilder.define('Model');
Model.registry = registry;
@ -115,23 +115,23 @@ module.exports = function(registry) {
*/
Model.setup = function() {
var ModelCtor = this;
var Parent = this.super_;
const ModelCtor = this;
const Parent = this.super_;
if (!ModelCtor.registry && Parent && Parent.registry) {
ModelCtor.registry = Parent.registry;
}
var options = this.settings;
var typeName = this.modelName;
const options = this.settings;
const typeName = this.modelName;
// support remoting prototype methods
// it's important to setup this function *before* calling `new SharedClass`
// otherwise remoting metadata from our base model is picked up
ModelCtor.sharedCtor = function(data, id, options, fn) {
var ModelCtor = this;
const ModelCtor = this;
var isRemoteInvocationWithOptions = typeof data !== 'object' &&
const isRemoteInvocationWithOptions = typeof data !== 'object' &&
typeof id === 'object' &&
typeof options === 'function';
if (isRemoteInvocationWithOptions) {
@ -161,13 +161,13 @@ module.exports = function(registry) {
}
if (id != null && data) {
var model = new ModelCtor(data);
const model = new ModelCtor(data);
model.id = id;
fn(null, model);
} else if (data) {
fn(null, new ModelCtor(data));
} else if (id != null) {
var filter = {};
const filter = {};
ModelCtor.findById(id, filter, options, function(err, model) {
if (err) {
fn(err);
@ -185,7 +185,7 @@ module.exports = function(registry) {
}
};
var idDesc = ModelCtor.modelName + ' id';
const idDesc = ModelCtor.modelName + ' id';
ModelCtor.sharedCtor.accepts = [
{arg: 'id', type: 'any', required: true, http: {source: 'path'},
description: idDesc},
@ -199,21 +199,21 @@ module.exports = function(registry) {
ModelCtor.sharedCtor.returns = {root: true};
var remotingOptions = {};
const remotingOptions = {};
extend(remotingOptions, options.remoting || {});
// create a sharedClass
var sharedClass = ModelCtor.sharedClass = new SharedClass(
const sharedClass = ModelCtor.sharedClass = new SharedClass(
ModelCtor.modelName,
ModelCtor,
remotingOptions
remotingOptions,
);
// before remote hook
ModelCtor.beforeRemote = function(name, fn) {
var className = this.modelName;
const className = this.modelName;
this._runWhenAttachedToApp(function(app) {
var remotes = app.remotes();
const remotes = app.remotes();
remotes.before(className + '.' + name, function(ctx, next) {
return fn(ctx, ctx.result, next);
});
@ -222,9 +222,9 @@ module.exports = function(registry) {
// after remote hook
ModelCtor.afterRemote = function(name, fn) {
var className = this.modelName;
const className = this.modelName;
this._runWhenAttachedToApp(function(app) {
var remotes = app.remotes();
const remotes = app.remotes();
remotes.after(className + '.' + name, function(ctx, next) {
return fn(ctx, ctx.result, next);
});
@ -232,16 +232,16 @@ module.exports = function(registry) {
};
ModelCtor.afterRemoteError = function(name, fn) {
var className = this.modelName;
const className = this.modelName;
this._runWhenAttachedToApp(function(app) {
var remotes = app.remotes();
const remotes = app.remotes();
remotes.afterError(className + '.' + name, fn);
});
};
ModelCtor._runWhenAttachedToApp = function(fn) {
if (this.app) return fn(this.app);
var self = this;
const self = this;
self.once('attached', function() {
fn(self.app);
});
@ -250,19 +250,19 @@ module.exports = function(registry) {
if ('injectOptionsFromRemoteContext' in options) {
console.warn(g.f(
'%s is using model setting %s which is no longer available.',
typeName, 'injectOptionsFromRemoteContext'
typeName, 'injectOptionsFromRemoteContext',
));
console.warn(g.f(
'Please rework your app to use the offical solution for injecting ' +
'"options" argument from request context,\nsee %s',
'http://loopback.io/doc/en/lb3/Using-current-context.html'
'http://loopback.io/doc/en/lb3/Using-current-context.html',
));
}
// resolve relation functions
sharedClass.resolve(function resolver(define) {
var relations = ModelCtor.relations || {};
var defineRaw = define;
const relations = ModelCtor.relations || {};
const defineRaw = define;
define = function(name, options, fn) {
if (options.accepts) {
options = extend({}, options);
@ -272,8 +272,8 @@ module.exports = function(registry) {
};
// get the relations
for (var relationName in relations) {
var relation = relations[relationName];
for (const relationName in relations) {
const relation = relations[relationName];
if (relation.type === 'belongsTo') {
ModelCtor.belongsToRemoting(relationName, relation, define);
} else if (
@ -295,8 +295,8 @@ module.exports = function(registry) {
}
// handle scopes
var scopes = ModelCtor.scopes || {};
for (var scopeName in scopes) {
const scopes = ModelCtor.scopes || {};
for (const scopeName in scopes) {
ModelCtor.scopeRemoting(scopeName, scopes[scopeName], define);
}
});
@ -307,9 +307,9 @@ module.exports = function(registry) {
/*!
* Get the reference to ACL in a lazy fashion to avoid race condition in require
*/
var _aclModel = null;
let _aclModel = null;
Model._ACL = function getACL(ACL) {
var registry = this.registry;
const registry = this.registry;
if (ACL !== undefined) {
// The function is used as a setter
_aclModel = ACL;
@ -317,7 +317,7 @@ module.exports = function(registry) {
if (_aclModel) {
return _aclModel;
}
var aclModel = registry.getModel('ACL');
const aclModel = registry.getModel('ACL');
_aclModel = registry.getModelByType(aclModel);
return _aclModel;
};
@ -335,9 +335,9 @@ module.exports = function(registry) {
*/
Model.checkAccess = function(token, modelId, sharedMethod, ctx, callback) {
var ANONYMOUS = registry.getModel('AccessToken').ANONYMOUS;
const ANONYMOUS = registry.getModel('AccessToken').ANONYMOUS;
token = token || ANONYMOUS;
var aclModel = Model._ACL();
const aclModel = Model._ACL();
ctx = ctx || {};
if (typeof ctx === 'function' && callback === undefined) {
@ -373,10 +373,10 @@ module.exports = function(registry) {
}
assert(
typeof method === 'object',
'method is a required argument and must be a RemoteMethod object'
'method is a required argument and must be a RemoteMethod object',
);
var ACL = Model._ACL();
const ACL = Model._ACL();
// Check the explicit setting of accessType
if (method.accessType) {
@ -390,7 +390,7 @@ module.exports = function(registry) {
}
// Default GET requests to READ
var verb = method.http && method.http.verb;
let verb = method.http && method.http.verb;
if (typeof verb === 'string') {
verb = verb.toUpperCase();
}
@ -438,7 +438,7 @@ module.exports = function(registry) {
*/
Model.getApp = function(callback) {
var self = this;
const self = this;
self._runWhenAttachedToApp(function(app) {
assert(self.app);
assert.equal(app, self.app);
@ -463,7 +463,7 @@ module.exports = function(registry) {
Model.remoteMethod = function(name, options) {
if (options.isStatic === undefined) {
var m = name.match(/^prototype\.(.*)$/);
const m = name.match(/^prototype\.(.*)$/);
options.isStatic = !m;
name = options.isStatic ? name : m[1];
}
@ -492,13 +492,13 @@ module.exports = function(registry) {
}
function createOptionsViaModelMethod(ctx) {
var ModelCtor = (ctx.method && ctx.method.ctor) || this;
const ModelCtor = (ctx.method && ctx.method.ctor) || this;
/**
* Configure default values for juggler settings to protect user-supplied
* input from attacking juggler
*/
var DEFAULT_OPTIONS = {
const DEFAULT_OPTIONS = {
// Default to `true` so that hidden properties cannot be used in query
prohibitHiddenPropertiesInQuery: ModelCtor._getProhibitHiddenPropertiesInQuery({}, true),
// Default to `12` for the max depth of a query object
@ -526,7 +526,7 @@ module.exports = function(registry) {
Model.disableRemoteMethod = function(name, isStatic) {
deprecated('Model.disableRemoteMethod is deprecated. ' +
'Use Model.disableRemoteMethodByName instead.');
var key = this.sharedClass.getKeyFromMethodNameAndTarget(name, isStatic);
const key = this.sharedClass.getKeyFromMethodNameAndTarget(name, isStatic);
this.sharedClass.disableMethodByName(key);
this.emit('remoteMethodDisabled', this.sharedClass, key);
};
@ -544,10 +544,10 @@ module.exports = function(registry) {
};
Model.belongsToRemoting = function(relationName, relation, define) {
var modelName = relation.modelTo && relation.modelTo.modelName;
let modelName = relation.modelTo && relation.modelTo.modelName;
modelName = modelName || 'PersistedModel';
var fn = this.prototype[relationName];
var pathName = (relation.options.http && relation.options.http.path) || relationName;
const fn = this.prototype[relationName];
const pathName = (relation.options.http && relation.options.http.path) || relationName;
define('__get__' + relationName, {
isStatic: false,
http: {verb: 'get', path: '/' + pathName},
@ -564,17 +564,19 @@ module.exports = function(registry) {
function convertNullToNotFoundError(toModelName, ctx, cb) {
if (ctx.result !== null) return cb();
var fk = ctx.getArgByName('fk');
var msg = g.f('Unknown "%s" id "%s".', toModelName, fk);
var error = new Error(msg);
const fk = ctx.getArgByName('fk');
const msg = fk ?
g.f('Unknown "%s" id "%s".', toModelName, fk) :
g.f('No "%s" instance(s) found', toModelName);
const error = new Error(msg);
error.statusCode = error.status = 404;
error.code = 'MODEL_NOT_FOUND';
cb(error);
}
Model.hasOneRemoting = function(relationName, relation, define) {
var pathName = (relation.options.http && relation.options.http.path) || relationName;
var toModelName = relation.modelTo.modelName;
const pathName = (relation.options.http && relation.options.http.path) || relationName;
const toModelName = relation.modelTo.modelName;
define('__get__' + relationName, {
isStatic: false,
@ -631,10 +633,10 @@ module.exports = function(registry) {
};
Model.hasManyRemoting = function(relationName, relation, define) {
var pathName = (relation.options.http && relation.options.http.path) || relationName;
var toModelName = relation.modelTo.modelName;
const pathName = (relation.options.http && relation.options.http.path) || relationName;
const toModelName = relation.modelTo.modelName;
var findByIdFunc = this.prototype['__findById__' + relationName];
const findByIdFunc = this.prototype['__findById__' + relationName];
define('__findById__' + relationName, {
isStatic: false,
http: {verb: 'get', path: '/' + pathName + '/:fk'},
@ -653,7 +655,7 @@ module.exports = function(registry) {
rest: {after: convertNullToNotFoundError.bind(null, toModelName)},
}, findByIdFunc);
var destroyByIdFunc = this.prototype['__destroyById__' + relationName];
const destroyByIdFunc = this.prototype['__destroyById__' + relationName];
define('__destroyById__' + relationName, {
isStatic: false,
http: {verb: 'delete', path: '/' + pathName + '/:fk'},
@ -671,7 +673,7 @@ module.exports = function(registry) {
returns: [],
}, destroyByIdFunc);
var updateByIdFunc = this.prototype['__updateById__' + relationName];
const updateByIdFunc = this.prototype['__updateById__' + relationName];
define('__updateById__' + relationName, {
isStatic: false,
http: {verb: 'put', path: '/' + pathName + '/:fk'},
@ -689,9 +691,9 @@ module.exports = function(registry) {
}, updateByIdFunc);
if (relation.modelThrough || relation.type === 'referencesMany') {
var modelThrough = relation.modelThrough || relation.modelTo;
const modelThrough = relation.modelThrough || relation.modelTo;
var accepts = [];
const accepts = [];
if (relation.type === 'hasMany' && relation.modelThrough) {
// Restrict: only hasManyThrough relation can have additional properties
accepts.push({
@ -700,7 +702,7 @@ module.exports = function(registry) {
});
}
var addFunc = this.prototype['__link__' + relationName];
const addFunc = this.prototype['__link__' + relationName];
define('__link__' + relationName, {
isStatic: false,
http: {verb: 'put', path: '/' + pathName + '/rel/:fk'},
@ -716,7 +718,7 @@ module.exports = function(registry) {
returns: {arg: relationName, type: modelThrough.modelName, root: true},
}, addFunc);
var removeFunc = this.prototype['__unlink__' + relationName];
const removeFunc = this.prototype['__unlink__' + relationName];
define('__unlink__' + relationName, {
isStatic: false,
http: {verb: 'delete', path: '/' + pathName + '/rel/:fk'},
@ -736,7 +738,7 @@ module.exports = function(registry) {
// FIXME: [rfeng] How to map a function with callback(err, true|false) to HEAD?
// true --> 200 and false --> 404?
var existsFunc = this.prototype['__exists__' + relationName];
const existsFunc = this.prototype['__exists__' + relationName];
define('__exists__' + relationName, {
isStatic: false,
http: {verb: 'head', path: '/' + pathName + '/rel/:fk'},
@ -756,10 +758,10 @@ module.exports = function(registry) {
// After hook to map exists to 200/404 for HEAD
after: function(ctx, cb) {
if (ctx.result === false) {
var modelName = ctx.method.sharedClass.name;
var id = ctx.getArgByName('id');
var msg = g.f('Unknown "%s" {{id}} "%s".', modelName, id);
var error = new Error(msg);
const modelName = ctx.method.sharedClass.name;
const id = ctx.getArgByName('id');
const msg = g.f('Unknown "%s" {{id}} "%s".', modelName, id);
const error = new Error(msg);
error.statusCode = error.status = 404;
error.code = 'MODEL_NOT_FOUND';
cb(error);
@ -773,17 +775,17 @@ module.exports = function(registry) {
};
Model.scopeRemoting = function(scopeName, scope, define) {
var pathName =
const pathName =
(scope.options && scope.options.http && scope.options.http.path) || scopeName;
var modelTo = scope.modelTo;
let modelTo = scope.modelTo;
var isStatic = scope.isStatic;
var toModelName = scope.modelTo.modelName;
const isStatic = scope.isStatic;
let toModelName = scope.modelTo.modelName;
// https://github.com/strongloop/loopback/issues/811
// Check if the scope is for a hasMany relation
var relation = this.relations[scopeName];
const relation = this.relations[scopeName];
if (relation && relation.modelTo) {
// For a relation with through model, the toModelName should be the one
// from the target model
@ -884,22 +886,22 @@ module.exports = function(registry) {
}
options = options || {};
var regExp = /^__([^_]+)__([^_]+)$/;
var relation = this.relations[relationName];
const regExp = /^__([^_]+)__([^_]+)$/;
const relation = this.relations[relationName];
if (relation && relation._nestRemotingProcessed) {
return; // Prevent unwanted circular traversals!
} else if (relation && relation.modelTo && relation.modelTo.sharedClass) {
relation._nestRemotingProcessed = true;
var self = this;
var sharedClass = this.sharedClass;
var sharedToClass = relation.modelTo.sharedClass;
var toModelName = relation.modelTo.modelName;
const self = this;
const sharedClass = this.sharedClass;
const sharedToClass = relation.modelTo.sharedClass;
const toModelName = relation.modelTo.modelName;
var pathName = options.pathName || relation.options.path || relationName;
var paramName = options.paramName || 'nk';
const pathName = options.pathName || relation.options.path || relationName;
const paramName = options.paramName || 'nk';
var http = [].concat(sharedToClass.http || [])[0];
var httpPath, acceptArgs;
const http = [].concat(sharedToClass.http || [])[0];
let httpPath, acceptArgs;
if (relation.multiple) {
httpPath = pathName + '/:' + paramName;
@ -921,30 +923,30 @@ module.exports = function(registry) {
// A method should return the method name to use, if it is to be
// included as a nested method - a falsy return value will skip.
var filter = filterCallback || options.filterMethod || function(method, relation) {
var matches = method.name.match(regExp);
const filter = filterCallback || options.filterMethod || function(method, relation) {
const matches = method.name.match(regExp);
if (matches) {
return '__' + matches[1] + '__' + relation.name + '__' + matches[2];
}
};
sharedToClass.methods().forEach(function(method) {
var methodName;
let methodName;
if (!method.isStatic && (methodName = filter(method, relation))) {
var prefix = relation.multiple ? '__findById__' : '__get__';
var getterName = options.getterName || (prefix + relationName);
const prefix = relation.multiple ? '__findById__' : '__get__';
const getterName = options.getterName || (prefix + relationName);
var getterFn = relation.modelFrom.prototype[getterName];
const getterFn = relation.modelFrom.prototype[getterName];
if (typeof getterFn !== 'function') {
throw new Error(g.f('Invalid remote method: `%s`', getterName));
}
var nestedFn = relation.modelTo.prototype[method.name];
const nestedFn = relation.modelTo.prototype[method.name];
if (typeof nestedFn !== 'function') {
throw new Error(g.f('Invalid remote method: `%s`', method.name));
}
var opts = {};
const opts = {};
opts.accepts = acceptArgs.concat(method.accepts || []);
opts.returns = [].concat(method.returns || []);
@ -954,10 +956,10 @@ module.exports = function(registry) {
opts.rest.delegateTo = method;
opts.http = [];
var routes = [].concat(method.http || []);
const routes = [].concat(method.http || []);
routes.forEach(function(route) {
if (route.path) {
var copy = extend({}, route);
const copy = extend({}, route);
copy.path = httpPath + route.path;
opts.http.push(copy);
}
@ -1015,19 +1017,19 @@ module.exports = function(registry) {
if (options.hooks === false) return; // don't inherit before/after hooks
self.once('mounted', function(app, sc, remotes) {
var listenerTree = extend({}, remotes.listenerTree || {});
const listenerTree = extend({}, remotes.listenerTree || {});
listenerTree.before = listenerTree.before || {};
listenerTree.after = listenerTree.after || {};
var beforeListeners = listenerTree.before[toModelName] || {};
var afterListeners = listenerTree.after[toModelName] || {};
const beforeListeners = listenerTree.before[toModelName] || {};
const afterListeners = listenerTree.after[toModelName] || {};
sharedClass.methods().forEach(function(method) {
var delegateTo = method.rest && method.rest.delegateTo;
const delegateTo = method.rest && method.rest.delegateTo;
if (delegateTo && delegateTo.ctor == relation.modelTo) {
var before = method.isStatic ? beforeListeners : beforeListeners['prototype'];
var after = method.isStatic ? afterListeners : afterListeners['prototype'];
var m = method.isStatic ? method.name : 'prototype.' + method.name;
const before = method.isStatic ? beforeListeners : beforeListeners['prototype'];
const after = method.isStatic ? afterListeners : afterListeners['prototype'];
const m = method.isStatic ? method.name : 'prototype.' + method.name;
if (before && before[delegateTo.name]) {
self.beforeRemote(m, function(ctx, result, next) {
before[delegateTo.name]._listeners.call(null, ctx, next);
@ -1042,7 +1044,7 @@ module.exports = function(registry) {
});
});
} else {
var msg = g.f('Relation `%s` does not exist for model `%s`', relationName, this.modelName);
const msg = g.f('Relation `%s` does not exist for model `%s`', relationName, this.modelName);
throw new Error(msg);
}
};

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -7,20 +7,20 @@
* Module Dependencies.
*/
'use strict';
var g = require('./globalize');
var runtime = require('./runtime');
var assert = require('assert');
var async = require('async');
var deprecated = require('depd')('loopback');
var debug = require('debug')('loopback:persisted-model');
var PassThrough = require('stream').PassThrough;
var utils = require('./utils');
var filterNodes = require('loopback-filters');
const g = require('./globalize');
const runtime = require('./runtime');
const assert = require('assert');
const async = require('async');
const deprecated = require('depd')('loopback');
const debug = require('debug')('loopback:persisted-model');
const PassThrough = require('stream').PassThrough;
const utils = require('./utils');
const filterNodes = require('loopback-filters');
var REPLICATION_CHUNK_SIZE = -1;
const REPLICATION_CHUNK_SIZE = -1;
module.exports = function(registry) {
var Model = registry.getModel('Model');
const Model = registry.getModel('Model');
/**
* Extends Model with basic query and CRUD support.
@ -38,7 +38,7 @@ module.exports = function(registry) {
* @class PersistedModel
*/
var PersistedModel = Model.extend('PersistedModel');
const PersistedModel = Model.extend('PersistedModel');
/*!
* Setup the `PersistedModel` constructor.
@ -48,7 +48,7 @@ module.exports = function(registry) {
// call Model.setup first
Model.setup.call(this);
var PersistedModel = this;
const PersistedModel = this;
// enable change tracking (usually for replication)
if (this.settings.trackChanges) {
@ -72,7 +72,7 @@ module.exports = function(registry) {
g.f('Cannot call %s.%s().' +
' The %s method has not been setup.' +
' The {{PersistedModel}} has not been correctly attached to a {{DataSource}}!',
modelName, methodName, methodName)
modelName, methodName, methodName),
);
}
@ -85,10 +85,10 @@ module.exports = function(registry) {
function convertNullToNotFoundError(ctx, cb) {
if (ctx.result !== null) return cb();
var modelName = ctx.method.sharedClass.name;
var id = ctx.getArgByName('id');
var msg = g.f('Unknown "%s" {{id}} "%s".', modelName, id);
var error = new Error(msg);
const modelName = ctx.method.sharedClass.name;
const id = ctx.getArgByName('id');
const msg = g.f('Unknown "%s" {{id}} "%s".', modelName, id);
const error = new Error(msg);
error.statusCode = error.status = 404;
error.code = 'MODEL_NOT_FOUND';
cb(error);
@ -403,7 +403,7 @@ module.exports = function(registry) {
*/
PersistedModel.prototype.save = function(options, callback) {
var Model = this.constructor;
const Model = this.constructor;
if (typeof options == 'function') {
callback = options;
@ -421,9 +421,9 @@ module.exports = function(registry) {
options.throws = false;
}
var inst = this;
var data = inst.toObject(true);
var id = this.getId();
const inst = this;
const data = inst.toObject(true);
const id = this.getId();
if (!id) {
return Model.create(this, callback);
@ -438,7 +438,7 @@ module.exports = function(registry) {
if (valid) {
save();
} else {
var err = new Model.ValidationError(inst);
const err = new Model.ValidationError(inst);
// throws option is dangerous for async usage
if (options.throws) {
throw err;
@ -581,7 +581,7 @@ module.exports = function(registry) {
*/
PersistedModel.prototype.setId = function(val) {
var ds = this.getDataSource();
const ds = this.getDataSource();
this[this.getIdName()] = val;
};
@ -592,7 +592,7 @@ module.exports = function(registry) {
*/
PersistedModel.prototype.getId = function() {
var data = this.toObject();
const data = this.toObject();
if (!data) return;
return data[this.getIdName()];
};
@ -614,8 +614,8 @@ module.exports = function(registry) {
*/
PersistedModel.getIdName = function() {
var Model = this;
var ds = Model.getDataSource();
const Model = this;
const ds = Model.getDataSource();
if (ds.idName) {
return ds.idName(Model.modelName);
@ -625,9 +625,9 @@ module.exports = function(registry) {
};
PersistedModel.setupRemoting = function() {
var PersistedModel = this;
var typeName = PersistedModel.modelName;
var options = PersistedModel.settings;
const PersistedModel = this;
const typeName = PersistedModel.modelName;
const options = PersistedModel.settings;
// if there is atleast one updateOnly property, then we set
// createOnlyInstance flag in __create__ to indicate loopback-swagger
@ -640,7 +640,7 @@ module.exports = function(registry) {
options.replaceOnPUT = options.replaceOnPUT !== false;
function setRemoting(scope, name, options) {
var fn = scope[name];
const fn = scope[name];
fn._delegate = true;
options.isStatic = scope === PersistedModel;
PersistedModel.remoteMethod(name, options);
@ -662,7 +662,7 @@ module.exports = function(registry) {
http: {verb: 'post', path: '/'},
});
var upsertOptions = {
const upsertOptions = {
aliases: ['upsert', 'updateOrCreate'],
description: 'Patch an existing model instance or insert a new one ' +
'into the data source.',
@ -683,7 +683,7 @@ module.exports = function(registry) {
}
setRemoting(PersistedModel, 'patchOrCreate', upsertOptions);
var replaceOrCreateOptions = {
const replaceOrCreateOptions = {
description: 'Replace an existing model instance or insert a new one into the data source.',
accessType: 'WRITE',
accepts: [
@ -724,7 +724,8 @@ module.exports = function(registry) {
description: 'Check whether a model instance exists in the data source.',
accessType: 'READ',
accepts: [
{arg: 'id', type: 'any', description: 'Model id', required: true},
{arg: 'id', type: 'any', description: 'Model id', required: true,
http: {source: 'path'}},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
returns: {arg: 'exists', type: 'boolean'},
@ -740,10 +741,10 @@ module.exports = function(registry) {
return cb();
}
if (!ctx.result.exists) {
var modelName = ctx.method.sharedClass.name;
var id = ctx.getArgByName('id');
var msg = 'Unknown "' + modelName + '" id "' + id + '".';
var error = new Error(msg);
const modelName = ctx.method.sharedClass.name;
const id = ctx.getArgByName('id');
const msg = 'Unknown "' + modelName + '" id "' + id + '".';
const error = new Error(msg);
error.statusCode = error.status = 404;
error.code = 'MODEL_NOT_FOUND';
cb(error);
@ -771,7 +772,7 @@ module.exports = function(registry) {
rest: {after: convertNullToNotFoundError},
});
var replaceByIdOptions = {
const replaceByIdOptions = {
description: 'Replace attributes for a model instance and persist it into the data source.',
accessType: 'WRITE',
accepts: [
@ -797,7 +798,9 @@ module.exports = function(registry) {
accepts: [
{arg: 'filter', type: 'object', description:
'Filter defining fields, where, include, order, offset, and limit - must be a ' +
'JSON-encoded string ({"something":"value"})'},
'JSON-encoded string (`{"where":{"something":"value"}}`). ' +
'See https://loopback.io/doc/en/lb3/Querying-data.html#using-stringified-json-in-rest-queries ' +
'for more details.'},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
returns: {arg: 'data', type: [typeName], root: true},
@ -810,7 +813,9 @@ module.exports = function(registry) {
accepts: [
{arg: 'filter', type: 'object', description:
'Filter defining fields, where, include, order, offset, and limit - must be a ' +
'JSON-encoded string ({"something":"value"})'},
'JSON-encoded string (`{"where":{"something":"value"}}`). ' +
'See https://loopback.io/doc/en/lb3/Querying-data.html#using-stringified-json-in-rest-queries ' +
'for more details.'},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
returns: {arg: 'data', type: typeName, root: true},
@ -884,7 +889,7 @@ module.exports = function(registry) {
http: {verb: 'get', path: '/count'},
});
var updateAttributesOptions = {
const updateAttributesOptions = {
aliases: ['updateAttributes'],
description: 'Patch attributes for a model instance and persist it into ' +
'the data source.',
@ -1033,7 +1038,7 @@ module.exports = function(registry) {
*/
PersistedModel.diff = function(since, remoteChanges, callback) {
var Change = this.getChangeModel();
const Change = this.getChangeModel();
Change.diff(this.modelName, since, remoteChanges, callback);
};
@ -1059,9 +1064,9 @@ module.exports = function(registry) {
filter = {};
}
var idName = this.dataSource.idName(this.modelName);
var Change = this.getChangeModel();
var model = this;
const idName = this.dataSource.idName(this.modelName);
const Change = this.getChangeModel();
const model = this;
const changeFilter = this.createChangeFilter(since, filter);
filter = filter || {};
@ -1073,13 +1078,13 @@ module.exports = function(registry) {
Change.find(changeFilter, function(err, changes) {
if (err) return callback(err);
if (!Array.isArray(changes) || changes.length === 0) return callback(null, []);
var ids = changes.map(function(change) {
const ids = changes.map(function(change) {
return change.getModelId();
});
filter.where[idName] = {inq: ids};
model.find(filter, function(err, models) {
if (err) return callback(err);
var modelIds = models.map(function(m) {
const modelIds = models.map(function(m) {
return m[idName].toString();
});
callback(null, changes.filter(function(ch) {
@ -1097,7 +1102,7 @@ module.exports = function(registry) {
*/
PersistedModel.checkpoint = function(cb) {
var Checkpoint = this.getChangeModel().getCheckpointModel();
const Checkpoint = this.getChangeModel().getCheckpointModel();
Checkpoint.bumpLastSeq(cb);
};
@ -1110,7 +1115,7 @@ module.exports = function(registry) {
*/
PersistedModel.currentCheckpoint = function(cb) {
var Checkpoint = this.getChangeModel().getCheckpointModel();
const Checkpoint = this.getChangeModel().getCheckpointModel();
Checkpoint.current(cb);
};
@ -1131,7 +1136,7 @@ module.exports = function(registry) {
*/
PersistedModel.replicate = function(since, targetModel, options, callback) {
var lastArg = arguments[arguments.length - 1];
const lastArg = arguments[arguments.length - 1];
if (typeof lastArg === 'function' && arguments.length > 1) {
callback = lastArg;
@ -1152,7 +1157,7 @@ module.exports = function(registry) {
options = options || {};
var sourceModel = this;
const sourceModel = this;
callback = callback || utils.createPromiseCallback();
debug('replicating %s since %s to %s since %s',
@ -1176,7 +1181,7 @@ module.exports = function(registry) {
// until no changes were replicated, but at most MAX_ATTEMPTS times
// to prevent starvation. In most cases, the second run will find no changes
// to replicate and we are done.
var MAX_ATTEMPTS = 3;
const MAX_ATTEMPTS = 3;
run(1, since);
return callback.promise;
@ -1186,7 +1191,7 @@ module.exports = function(registry) {
tryReplicate(sourceModel, targetModel, since, options, next);
function next(err, conflicts, cps, updates) {
var finished = err || conflicts.length ||
const finished = err || conflicts.length ||
!updates || updates.length === 0 ||
attempt >= MAX_ATTEMPTS;
@ -1198,10 +1203,10 @@ module.exports = function(registry) {
};
function tryReplicate(sourceModel, targetModel, since, options, callback) {
var Change = sourceModel.getChangeModel();
var TargetChange = targetModel.getChangeModel();
var changeTrackingEnabled = Change && TargetChange;
var replicationChunkSize = REPLICATION_CHUNK_SIZE;
const Change = sourceModel.getChangeModel();
const TargetChange = targetModel.getChangeModel();
const changeTrackingEnabled = Change && TargetChange;
let replicationChunkSize = REPLICATION_CHUNK_SIZE;
if (sourceModel.settings && sourceModel.settings.replicationChunkSize) {
replicationChunkSize = sourceModel.settings.replicationChunkSize;
@ -1209,12 +1214,12 @@ module.exports = function(registry) {
assert(
changeTrackingEnabled,
'You must enable change tracking before replicating'
'You must enable change tracking before replicating',
);
var diff, updates, newSourceCp, newTargetCp;
let diff, updates, newSourceCp, newTargetCp;
var tasks = [
const tasks = [
checkpoints,
getSourceChanges,
getDiffFromTarget,
@ -1231,7 +1236,7 @@ module.exports = function(registry) {
function(filter, pagingCallback) {
sourceModel.changes(since.source, filter, pagingCallback);
},
debug.enabled ? log : cb
debug.enabled ? log : cb,
);
function log(err, result) {
@ -1249,7 +1254,7 @@ module.exports = function(registry) {
function(smallArray, chunkCallback) {
return targetModel.diff(since.target, smallArray, chunkCallback);
},
debug.enabled ? log : cb
debug.enabled ? log : cb,
);
function log(err, result) {
@ -1278,7 +1283,7 @@ module.exports = function(registry) {
function(smallArray, chunkCallback) {
return sourceModel.createUpdates(smallArray, chunkCallback);
},
cb
cb,
);
} else {
// nothing to replicate
@ -1299,7 +1304,7 @@ module.exports = function(registry) {
});
},
function(notUsed, err) {
var conflicts = err && err.details && err.details.conflicts;
const conflicts = err && err.details && err.details.conflicts;
if (conflicts && err.statusCode == 409) {
diff.conflicts = conflicts;
// filter out updates that were not applied
@ -1311,12 +1316,12 @@ module.exports = function(registry) {
return cb();
}
cb(err);
}
},
);
}
function checkpoints() {
var cb = arguments[arguments.length - 1];
const cb = arguments[arguments.length - 1];
sourceModel.checkpoint(function(err, source) {
if (err) return cb(err);
newSourceCp = source.seq;
@ -1340,9 +1345,9 @@ module.exports = function(registry) {
debug('\t\tnew checkpoints: { source: %j, target: %j }',
newSourceCp, newTargetCp);
var conflicts = diff.conflicts.map(function(change) {
const conflicts = diff.conflicts.map(function(change) {
return new Change.Conflict(
change.modelId, sourceModel, targetModel
change.modelId, sourceModel, targetModel,
);
});
@ -1351,7 +1356,7 @@ module.exports = function(registry) {
}
if (callback) {
var newCheckpoints = {source: newSourceCp, target: newTargetCp};
const newCheckpoints = {source: newSourceCp, target: newTargetCp};
callback(null, conflicts, newCheckpoints, updates);
}
}
@ -1366,15 +1371,15 @@ module.exports = function(registry) {
*/
PersistedModel.createUpdates = function(deltas, cb) {
var Change = this.getChangeModel();
var updates = [];
var Model = this;
var tasks = [];
const Change = this.getChangeModel();
const updates = [];
const Model = this;
const tasks = [];
deltas.forEach(function(change) {
change = new Change(change);
var type = change.type();
var update = {type: type, change: change};
const type = change.type();
const update = {type: type, change: change};
switch (type) {
case Change.CREATE:
case Change.UPDATE:
@ -1418,12 +1423,12 @@ module.exports = function(registry) {
*/
PersistedModel.bulkUpdate = function(updates, options, callback) {
var tasks = [];
var Model = this;
var Change = this.getChangeModel();
var conflicts = [];
const tasks = [];
const Model = this;
const Change = this.getChangeModel();
const conflicts = [];
var lastArg = arguments[arguments.length - 1];
const lastArg = arguments[arguments.length - 1];
if (typeof lastArg === 'function' && arguments.length > 1) {
callback = lastArg;
@ -1439,8 +1444,8 @@ module.exports = function(registry) {
if (err) return callback(err);
updates.forEach(function(update) {
var id = update.change.modelId;
var current = currentMap[id];
const id = update.change.modelId;
const current = currentMap[id];
switch (update.type) {
case Change.UPDATE:
tasks.push(function(cb) {
@ -1475,13 +1480,13 @@ module.exports = function(registry) {
};
function buildLookupOfAffectedModelData(Model, updates, callback) {
var idName = Model.dataSource.idName(Model.modelName);
var affectedIds = updates.map(function(u) { return u.change.modelId; });
var whereAffected = {};
const idName = Model.dataSource.idName(Model.modelName);
const affectedIds = updates.map(function(u) { return u.change.modelId; });
const whereAffected = {};
whereAffected[idName] = {inq: affectedIds};
Model.find({where: whereAffected}, function(err, affectedList) {
if (err) return callback(err);
var dataLookup = {};
const dataLookup = {};
affectedList.forEach(function(it) {
dataLookup[it[idName]] = it;
});
@ -1490,8 +1495,8 @@ module.exports = function(registry) {
}
function applyUpdate(Model, id, current, data, change, conflicts, options, cb) {
var Change = Model.getChangeModel();
var rev = current ? Change.revisionForInst(current) : null;
const Change = Model.getChangeModel();
const rev = current ? Change.revisionForInst(current) : null;
if (rev !== change.prev) {
debug('Detected non-rectified change of %s %j',
@ -1510,7 +1515,7 @@ module.exports = function(registry) {
Model.updateAll(current.toObject(), data, options, function(err, result) {
if (err) return cb(err);
var count = result && result.count;
const count = result && result.count;
switch (count) {
case 1:
// The happy path, exactly one record was updated
@ -1530,7 +1535,7 @@ module.exports = function(registry) {
return cb(new Error(
g.f('Cannot apply bulk updates, ' +
'the connector does not correctly report ' +
'the number of updated records.')
'the number of updated records.'),
));
default:
@ -1538,7 +1543,7 @@ module.exports = function(registry) {
Model.modelName, count);
return cb(new Error(
g.f('Bulk update failed, the connector has modified unexpected ' +
'number of records: %s', JSON.stringify(count))
'number of records: %s', JSON.stringify(count)),
));
}
});
@ -1568,7 +1573,7 @@ module.exports = function(registry) {
Model.modelName, id);
conflicts.push(change);
var Change = Model.getChangeModel();
const Change = Model.getChangeModel();
return Change.rectifyModelChanges(Model.modelName, [id], cb);
}
}
@ -1580,8 +1585,8 @@ module.exports = function(registry) {
return cb();
}
var Change = Model.getChangeModel();
var rev = Change.revisionForInst(current);
const Change = Model.getChangeModel();
const rev = Change.revisionForInst(current);
if (rev !== change.prev) {
debug('Detected non-rectified change of %s %j',
Model.modelName, id);
@ -1594,7 +1599,7 @@ module.exports = function(registry) {
Model.deleteAll(current.toObject(), options, function(err, result) {
if (err) return cb(err);
var count = result && result.count;
const count = result && result.count;
switch (count) {
case 1:
// The happy path, exactly one record was updated
@ -1614,7 +1619,7 @@ module.exports = function(registry) {
return cb(new Error(
g.f('Cannot apply bulk updates, ' +
'the connector does not correctly report ' +
'the number of deleted records.')
'the number of deleted records.'),
));
default:
@ -1622,7 +1627,7 @@ module.exports = function(registry) {
Model.modelName, count);
return cb(new Error(
g.f('Bulk update failed, the connector has deleted unexpected ' +
'number of records: %s', JSON.stringify(count))
'number of records: %s', JSON.stringify(count)),
));
}
});
@ -1635,8 +1640,8 @@ module.exports = function(registry) {
*/
PersistedModel.getChangeModel = function() {
var changeModel = this.Change;
var isSetup = changeModel && changeModel.dataSource;
const changeModel = this.Change;
const isSetup = changeModel && changeModel.dataSource;
assert(isSetup, 'Cannot get a setup Change model for ' + this.modelName);
@ -1652,15 +1657,15 @@ module.exports = function(registry) {
*/
PersistedModel.getSourceId = function(cb) {
var dataSource = this.dataSource;
const dataSource = this.dataSource;
if (!dataSource) {
this.once('dataSourceAttached', this.getSourceId.bind(this, cb));
}
assert(
dataSource.connector.name,
'Model.getSourceId: cannot get id without dataSource.connector.name'
'Model.getSourceId: cannot get id without dataSource.connector.name',
);
var id = [dataSource.connector.name, this.modelName].join('-');
const id = [dataSource.connector.name, this.modelName].join('-');
cb(null, id);
};
@ -1669,17 +1674,17 @@ module.exports = function(registry) {
*/
PersistedModel.enableChangeTracking = function() {
var Model = this;
var Change = this.Change || this._defineChangeModel();
var cleanupInterval = Model.settings.changeCleanupInterval || 30000;
const Model = this;
const Change = this.Change || this._defineChangeModel();
const cleanupInterval = Model.settings.changeCleanupInterval || 30000;
assert(this.dataSource, 'Cannot enableChangeTracking(): ' + this.modelName +
' is not attached to a dataSource');
var idName = this.getIdName();
var idProp = this.definition.properties[idName];
var idType = idProp && idProp.type;
var idDefn = idProp && idProp.defaultFn;
const idName = this.getIdName();
const idProp = this.definition.properties[idName];
const idType = idProp && idProp.type;
const idDefn = idProp && idProp.defaultFn;
if (idType !== String || !(idDefn === 'uuid' || idDefn === 'guid')) {
deprecated('The model ' + this.modelName + ' is tracking changes, ' +
'which requires a string id with GUID/UUID default value.');
@ -1709,8 +1714,8 @@ module.exports = function(registry) {
};
function rectifyOnSave(ctx, next) {
var instance = ctx.instance || ctx.currentInstance;
var id = instance ? instance.getId() :
const instance = ctx.instance || ctx.currentInstance;
const id = instance ? instance.getId() :
getIdFromWhereByModelId(ctx.Model, ctx.where);
if (debug.enabled) {
@ -1735,7 +1740,7 @@ module.exports = function(registry) {
}
function rectifyOnDelete(ctx, next) {
var id = ctx.instance ? ctx.instance.getId() :
const id = ctx.instance ? ctx.instance.getId() :
getIdFromWhereByModelId(ctx.Model, ctx.where);
if (debug.enabled) {
@ -1759,10 +1764,10 @@ module.exports = function(registry) {
}
function getIdFromWhereByModelId(Model, where) {
var idName = Model.getIdName();
const idName = Model.getIdName();
if (!(idName in where)) return undefined;
var id = where[idName];
const id = where[idName];
// TODO(bajtos) support object values that are not LB conditions
if (typeof id === 'string' || typeof id === 'number') {
return id;
@ -1771,7 +1776,7 @@ module.exports = function(registry) {
}
PersistedModel._defineChangeModel = function() {
var BaseChangeModel = this.registry.getModel('Change');
const BaseChangeModel = this.registry.getModel('Change');
assert(BaseChangeModel,
'Change model must be defined before enabling change replication');
@ -1781,7 +1786,7 @@ module.exports = function(registry) {
this.Change = BaseChangeModel.extend(
this.modelName + '-change',
additionalChangeModelProperties,
{trackModel: this}
{trackModel: this},
);
if (this.dataSource) {
@ -1789,7 +1794,7 @@ module.exports = function(registry) {
}
// Re-attach related models whenever our datasource is changed.
var self = this;
const self = this;
this.on('dataSourceAttached', function() {
attachRelatedModels(self);
});
@ -1827,17 +1832,17 @@ module.exports = function(registry) {
*/
PersistedModel.rectifyChange = function(id, callback) {
var Change = this.getChangeModel();
const Change = this.getChangeModel();
Change.rectifyModelChanges(this.modelName, [id], callback);
};
PersistedModel.findLastChange = function(id, cb) {
var Change = this.getChangeModel();
const Change = this.getChangeModel();
Change.findOne({where: {modelId: id}}, cb);
};
PersistedModel.updateLastChange = function(id, data, cb) {
var self = this;
const self = this;
this.findLastChange(id, function(err, inst) {
if (err) return cb(err);
if (!inst) {
@ -1868,9 +1873,9 @@ module.exports = function(registry) {
}
cb = cb || utils.createPromiseCallback();
var idName = this.getIdName();
var Model = this;
var changes = new PassThrough({objectMode: true});
const idName = this.getIdName();
const Model = this;
const changes = new PassThrough({objectMode: true});
changes._destroy = function() {
changes.end();
@ -1895,7 +1900,7 @@ module.exports = function(registry) {
return cb.promise;
function changeHandler(ctx, next) {
var change = createChangeObject(ctx, 'save');
const change = createChangeObject(ctx, 'save');
if (change) {
changes.write(change);
}
@ -1904,7 +1909,7 @@ module.exports = function(registry) {
}
function deleteHandler(ctx, next) {
var change = createChangeObject(ctx, 'delete');
const change = createChangeObject(ctx, 'delete');
if (change) {
changes.write(change);
}
@ -1913,13 +1918,13 @@ module.exports = function(registry) {
}
function createChangeObject(ctx, type) {
var where = ctx.where;
var data = ctx.instance || ctx.data;
var whereId = where && where[idName];
const where = ctx.where;
let data = ctx.instance || ctx.data;
const whereId = where && where[idName];
// the data includes the id
// or the where includes the id
var target;
let target;
if (data && (data[idName] || data[idName] === 0)) {
target = data[idName];
@ -1927,18 +1932,18 @@ module.exports = function(registry) {
target = where[idName];
}
var hasTarget = target === 0 || !!target;
const hasTarget = target === 0 || !!target;
// apply filtering if options is set
if (options) {
var filtered = filterNodes([data], options);
const filtered = filterNodes([data], options);
if (filtered.length !== 1) {
return null;
}
data = filtered[0];
}
var change = {
const change = {
target: target,
where: where,
data: data,

View File

@ -1,17 +1,17 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('./globalize');
var assert = require('assert');
var extend = require('util')._extend;
var juggler = require('loopback-datasource-juggler');
var debug = require('debug')('loopback:registry');
var DataSource = juggler.DataSource;
var ModelBuilder = juggler.ModelBuilder;
var deprecated = require('depd')('strong-remoting');
const g = require('./globalize');
const assert = require('assert');
const extend = require('util')._extend;
const juggler = require('loopback-datasource-juggler');
const debug = require('debug')('loopback:registry');
const DataSource = juggler.DataSource;
const ModelBuilder = juggler.ModelBuilder;
const deprecated = require('depd')('strong-remoting');
module.exports = Registry;
@ -97,7 +97,7 @@ function Registry() {
Registry.prototype.createModel = function(name, properties, options) {
if (arguments.length === 1 && typeof name === 'object') {
var config = name;
const config = name;
name = config.name;
properties = config.properties;
options = buildModelOptionsFromConfig(config);
@ -107,10 +107,10 @@ Registry.prototype.createModel = function(name, properties, options) {
}
options = options || {};
var BaseModel = options.base || options.super;
let BaseModel = options.base || options.super;
if (typeof BaseModel === 'string') {
var baseName = BaseModel;
const baseName = BaseModel;
BaseModel = this.findModel(BaseModel);
if (!BaseModel) {
throw new Error(g.f('Model not found: model `%s` is extending an unknown model `%s`.',
@ -119,7 +119,7 @@ Registry.prototype.createModel = function(name, properties, options) {
}
BaseModel = BaseModel || this.getModel('PersistedModel');
var model = BaseModel.extend(name, properties, options);
const model = BaseModel.extend(name, properties, options);
model.registry = this;
this._defineRemoteMethods(model, model.settings.methods);
@ -128,8 +128,8 @@ Registry.prototype.createModel = function(name, properties, options) {
};
function buildModelOptionsFromConfig(config) {
var options = extend({}, config.options);
for (var key in config) {
const options = extend({}, config.options);
for (const key in config) {
if (['name', 'properties', 'options'].indexOf(key) !== -1) {
// Skip items which have special meaning
continue;
@ -152,7 +152,7 @@ function buildModelOptionsFromConfig(config) {
* @param {Object} acl
*/
function addACL(acls, acl) {
for (var i = 0, n = acls.length; i < n; i++) {
for (let i = 0, n = acls.length; i < n; i++) {
// Check if there is a matching acl to be overriden
if (acls[i].property === acl.property &&
acls[i].accessType === acl.accessType &&
@ -176,14 +176,14 @@ function addACL(acls, acl) {
*/
Registry.prototype.configureModel = function(ModelCtor, config) {
var settings = ModelCtor.settings;
var modelName = ModelCtor.modelName;
const settings = ModelCtor.settings;
const modelName = ModelCtor.modelName;
ModelCtor.config = config;
// Relations
if (typeof config.relations === 'object' && config.relations !== null) {
var relations = settings.relations = settings.relations || {};
const relations = settings.relations = settings.relations || {};
Object.keys(config.relations).forEach(function(key) {
// FIXME: [rfeng] We probably should check if the relation exists
relations[key] = extend(relations[key] || {}, config.relations[key]);
@ -195,7 +195,7 @@ Registry.prototype.configureModel = function(ModelCtor, config) {
// ACLs
if (Array.isArray(config.acls)) {
var acls = settings.acls = settings.acls || [];
const acls = settings.acls = settings.acls || [];
config.acls.forEach(function(acl) {
addACL(acls, acl);
});
@ -205,7 +205,7 @@ Registry.prototype.configureModel = function(ModelCtor, config) {
}
// Settings
var excludedProperties = {
const excludedProperties = {
base: true,
'super': true,
relations: true,
@ -213,7 +213,7 @@ Registry.prototype.configureModel = function(ModelCtor, config) {
dataSource: true,
};
if (typeof config.options === 'object' && config.options !== null) {
for (var p in config.options) {
for (const p in config.options) {
if (!(p in excludedProperties)) {
settings[p] = config.options[p];
} else {
@ -244,17 +244,17 @@ Registry.prototype.configureModel = function(ModelCtor, config) {
g.warn(
'The configuration of `%s` is missing {{`dataSource`}} property.\n' +
'Use `null` or `false` to mark models not attached to any data source.',
modelName
modelName,
);
}
var newMethodNames = config.methods && Object.keys(config.methods);
var hasNewMethods = newMethodNames && newMethodNames.length;
var hasDescendants = this.getModelByType(ModelCtor) !== ModelCtor;
const newMethodNames = config.methods && Object.keys(config.methods);
const hasNewMethods = newMethodNames && newMethodNames.length;
const hasDescendants = this.getModelByType(ModelCtor) !== ModelCtor;
if (hasNewMethods && hasDescendants) {
g.warn(
'Child models of `%s` will not inherit newly defined remote methods %s.',
modelName, newMethodNames
modelName, newMethodNames,
);
}
@ -271,9 +271,9 @@ Registry.prototype._defineRemoteMethods = function(ModelCtor, methods) {
}
Object.keys(methods).forEach(function(key) {
var meta = methods[key];
var m = key.match(/^prototype\.(.*)$/);
var isStatic = !m;
let meta = methods[key];
const m = key.match(/^prototype\.(.*)$/);
const isStatic = !m;
if (typeof meta.isStatic !== 'boolean') {
key = isStatic ? key : m[1];
@ -313,7 +313,7 @@ Registry.prototype.findModel = function(modelName) {
* @header loopback.getModel(modelName)
*/
Registry.prototype.getModel = function(modelName) {
var model = this.findModel(modelName);
const model = this.findModel(modelName);
if (model) return model;
throw new Error(g.f('Model not found: %s', modelName));
@ -329,8 +329,8 @@ Registry.prototype.getModel = function(modelName) {
* @header loopback.getModelByType(modelType)
*/
Registry.prototype.getModelByType = function(modelType) {
var type = typeof modelType;
var accepted = ['function', 'string'];
const type = typeof modelType;
const accepted = ['function', 'string'];
assert(accepted.indexOf(type) > -1,
'The model type must be a constructor or model name');
@ -339,8 +339,8 @@ Registry.prototype.getModelByType = function(modelType) {
modelType = this.getModel(modelType);
}
var models = this.modelBuilder.models;
for (var m in models) {
const models = this.modelBuilder.models;
for (const m in models) {
if (models[m].prototype instanceof modelType) {
return models[m];
}
@ -359,15 +359,15 @@ Registry.prototype.getModelByType = function(modelType) {
*/
Registry.prototype.createDataSource = function(name, options) {
var self = this;
const self = this;
var ds = new DataSource(name, options, self.modelBuilder);
const ds = new DataSource(name, options, self.modelBuilder);
ds.createModel = function(name, properties, settings) {
settings = settings || {};
var BaseModel = settings.base || settings.super;
let BaseModel = settings.base || settings.super;
if (!BaseModel) {
// Check the connector types
var connectorTypes = ds.getTypes();
const connectorTypes = ds.getTypes();
if (Array.isArray(connectorTypes) && connectorTypes.indexOf('db') !== -1) {
// Only set up the base model to PersistedModel if the connector is DB
BaseModel = self.PersistedModel;
@ -376,13 +376,13 @@ Registry.prototype.createDataSource = function(name, options) {
}
settings.base = BaseModel;
}
var ModelCtor = self.createModel(name, properties, settings);
const ModelCtor = self.createModel(name, properties, settings);
ModelCtor.attachTo(ds);
return ModelCtor;
};
if (ds.settings && ds.settings.defaultForType) {
var msg = g.f('{{DataSource}} option {{"defaultForType"}} is no longer supported');
const msg = g.f('{{DataSource}} option {{"defaultForType"}} is no longer supported');
throw new Error(msg);
}
@ -398,7 +398,7 @@ Registry.prototype.createDataSource = function(name, options) {
Registry.prototype.memory = function(name) {
name = name || 'default';
var memory = (
let memory = (
this._memoryDataSources || (this._memoryDataSources = {})
)[name];

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -10,7 +10,7 @@
*/
'use strict';
var runtime = exports;
const runtime = exports;
/**
* True if running in a browser environment; false otherwise.

View File

@ -1,23 +1,23 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('./globalize');
var assert = require('assert');
var express = require('express');
var merge = require('util')._extend;
var mergePhaseNameLists = require('loopback-phase').mergePhaseNameLists;
var debug = require('debug')('loopback:app');
var stableSortInPlace = require('stable').inplace;
const g = require('./globalize');
const assert = require('assert');
const express = require('express');
const merge = require('util')._extend;
const mergePhaseNameLists = require('loopback-phase').mergePhaseNameLists;
const debug = require('debug')('loopback:app');
const stableSortInPlace = require('stable').inplace;
var BUILTIN_MIDDLEWARE = {builtin: true};
const BUILTIN_MIDDLEWARE = {builtin: true};
var proto = {};
const proto = {};
module.exports = function loopbackExpress() {
var app = express();
const app = express();
app.__expressLazyRouter = app.lazyrouter;
merge(app, proto);
return app;
@ -64,23 +64,23 @@ proto.middlewareFromConfig = function(factory, config) {
if (config.enabled === false)
return;
var params = config.params;
let params = config.params;
if (params === undefined) {
params = [];
} else if (!Array.isArray(params)) {
params = [params];
}
var handler = factory.apply(null, params);
let handler = factory.apply(null, params);
// Check if methods/verbs filter exists
var verbs = config.methods || config.verbs;
let verbs = config.methods || config.verbs;
if (Array.isArray(verbs)) {
verbs = verbs.map(function(verb) {
return verb && verb.toUpperCase();
});
if (verbs.indexOf('ALL') === -1) {
var originalHandler = handler;
const originalHandler = handler;
if (handler.length <= 3) {
// Regular handler
handler = function(req, res, next) {
@ -145,7 +145,7 @@ proto.defineMiddlewarePhases = function(nameOrArray) {
mergePhaseNameLists(this._requestHandlingPhases, nameOrArray);
} else {
// add the new phase before 'routes'
var routesIx = this._requestHandlingPhases.indexOf('routes');
const routesIx = this._requestHandlingPhases.indexOf('routes');
this._requestHandlingPhases.splice(routesIx - 1, 0, nameOrArray);
}
@ -181,10 +181,10 @@ proto.middleware = function(name, paths, handler) {
paths = '/';
}
var fullPhaseName = name;
var handlerName = handler.name || '<anonymous>';
const fullPhaseName = name;
const handlerName = handler.name || '<anonymous>';
var m = name.match(/^(.+):(before|after)$/);
const m = name.match(/^(.+):(before|after)$/);
if (m) {
name = m[1];
}
@ -197,7 +197,7 @@ proto.middleware = function(name, paths, handler) {
this._skipLayerSorting = true;
this.use(paths, handler);
var layer = this._findLayerByHandler(handler);
const layer = this._findLayerByHandler(handler);
if (layer) {
// Set the phase name for sorting
layer.phase = fullPhaseName;
@ -221,17 +221,20 @@ proto.middleware = function(name, paths, handler) {
*/
proto._findLayerByHandler = function(handler) {
// Other handlers can be added to the stack, for example,
// NewRelic adds sentinel handler. We need to search the stack
for (var k = this._router.stack.length - 1; k >= 0; k--) {
if (this._router.stack[k].handle === handler ||
// NewRelic replaces the handle and keeps it as __NR_original
this._router.stack[k].handle['__NR_original'] === handler
) {
// NewRelic adds sentinel handler, and AppDynamics adds
// some additional proxy info. We need to search the stack
for (let k = this._router.stack.length - 1; k >= 0; k--) {
const isOriginal = this._router.stack[k].handle === handler;
const isNewRelic = this._router.stack[k].handle['__NR_original'] === handler;
const isAppDynamics = this._router.stack[k].handle['__appdynamicsProxyInfo__'] &&
this._router.stack[k].handle['__appdynamicsProxyInfo__']['orig'] === handler;
if (isOriginal || isNewRelic || isAppDynamics) {
return this._router.stack[k];
} else {
// Aggressively check if the original handler has been wrapped
// into a new function with a property pointing to the original handler
for (var p in this._router.stack[k].handle) {
for (const p in this._router.stack[k].handle) {
if (this._router.stack[k].handle[p] === handler) {
return this._router.stack[k];
}
@ -243,12 +246,12 @@ proto._findLayerByHandler = function(handler) {
// Install our custom PhaseList-based handler into the app
proto.lazyrouter = function() {
var self = this;
const self = this;
if (self._router) return;
self.__expressLazyRouter();
var router = self._router;
const router = self._router;
// Mark all middleware added by Router ctor as builtin
// The sorting algo will keep them at beginning of the list
@ -258,14 +261,14 @@ proto.lazyrouter = function() {
router.__expressUse = router.use;
router.use = function useAndSort() {
var retval = this.__expressUse.apply(this, arguments);
const retval = this.__expressUse.apply(this, arguments);
self._sortLayersByPhase();
return retval;
};
router.__expressRoute = router.route;
router.route = function routeAndSort() {
var retval = this.__expressRoute.apply(this, arguments);
const retval = this.__expressRoute.apply(this, arguments);
self._sortLayersByPhase();
return retval;
};
@ -279,19 +282,19 @@ proto.lazyrouter = function() {
proto._sortLayersByPhase = function() {
if (this._skipLayerSorting) return;
var phaseOrder = {};
const phaseOrder = {};
this._requestHandlingPhases.forEach(function(name, ix) {
phaseOrder[name + ':before'] = ix * 3;
phaseOrder[name] = ix * 3 + 1;
phaseOrder[name + ':after'] = ix * 3 + 2;
});
var router = this._router;
const router = this._router;
stableSortInPlace(router.stack, compareLayers);
function compareLayers(left, right) {
var leftPhase = left.phase;
var rightPhase = right.phase;
const leftPhase = left.phase;
const rightPhase = right.phase;
if (leftPhase === rightPhase) return 0;

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -10,12 +10,12 @@ exports.uploadInChunks = uploadInChunks;
exports.downloadInChunks = downloadInChunks;
exports.concatResults = concatResults;
var Promise = require('bluebird');
var async = require('async');
const Promise = require('bluebird');
const async = require('async');
function createPromiseCallback() {
var cb;
var promise = new Promise(function(resolve, reject) {
let cb;
const promise = new Promise(function(resolve, reject) {
cb = function(err, data) {
if (err) return reject(err);
return resolve(data);
@ -28,7 +28,7 @@ function createPromiseCallback() {
function throwPromiseNotDefined() {
throw new Error(
'Your Node runtime does support ES6 Promises. ' +
'Set "global.Promise" to your preferred implementation of promises.'
'Set "global.Promise" to your preferred implementation of promises.',
);
}
@ -40,23 +40,23 @@ function throwPromiseNotDefined() {
* @param {Function} cb - the callback
*/
function uploadInChunks(largeArray, chunkSize, processFunction, cb) {
var chunkArrays = [];
const chunkArrays = [];
if (!chunkSize || chunkSize < 1 || largeArray.length <= chunkSize) {
// if chunking not required
processFunction(largeArray, cb);
} else {
// copying so that the largeArray object does not get affected during splice
var copyOfLargeArray = [].concat(largeArray);
const copyOfLargeArray = [].concat(largeArray);
// chunking to smaller arrays
while (copyOfLargeArray.length > 0) {
chunkArrays.push(copyOfLargeArray.splice(0, chunkSize));
}
var tasks = chunkArrays.map(function(chunkArray) {
const tasks = chunkArrays.map(function(chunkArray) {
return function(previousResults, chunkCallback) {
var lastArg = arguments[arguments.length - 1];
const lastArg = arguments[arguments.length - 1];
if (typeof lastArg === 'function') {
chunkCallback = lastArg;
@ -92,7 +92,7 @@ function uploadInChunks(largeArray, chunkSize, processFunction, cb) {
* @param {Function} cb - the callback
*/
function downloadInChunks(filter, chunkSize, processFunction, cb) {
var results = [];
let results = [];
filter = filter ? JSON.parse(JSON.stringify(filter)) : {};
if (!chunkSize || chunkSize < 1) {

View File

@ -1,6 +1,6 @@
{
"name": "loopback",
"version": "3.24.1",
"version": "3.28.0",
"description": "LoopBack: Open Source Framework for Node.js",
"homepage": "http://loopback.io",
"keywords": [
@ -34,7 +34,7 @@
"test": "nyc grunt mocha-and-karma"
},
"engines": {
"node": ">=6"
"node": ">=8"
},
"dependencies": {
"async": "^2.0.1",
@ -47,12 +47,12 @@
"ejs": "^2.3.1",
"express": "^4.14.0",
"inflection": "^1.6.0",
"isemail": "^2.2.1",
"isemail": "^3.2.0",
"loopback-connector-remote": "^3.0.0",
"loopback-datasource-juggler": "^3.28.0",
"loopback-filters": "^1.0.0",
"loopback-phase": "^3.0.0",
"nodemailer": "^4.0.1",
"nodemailer": "^6.4.16",
"nodemailer-direct-transport": "^3.3.2",
"nodemailer-stub-transport": "^1.1.0",
"serve-favicon": "^2.2.0",
@ -63,44 +63,42 @@
"underscore.string": "^3.3.5"
},
"devDependencies": {
"babel-preset-es2015": "^6.22.0",
"babelify": "^7.3.0",
"browserify": "^13.1.0",
"chai": "^3.5.0",
"browserify": "^16.5.0",
"chai": "^4.2.0",
"cookie-parser": "^1.3.4",
"coveralls": "^3.0.2",
"dirty-chai": "^1.2.2",
"eslint": "^5.3.0",
"eslint-config-loopback": "^12.0.0",
"eslint-plugin-mocha": "^5.1.0",
"dirty-chai": "^2.0.1",
"eslint": "^6.5.1",
"eslint-config-loopback": "^13.1.0",
"express-session": "^1.14.0",
"grunt": "^1.0.1",
"grunt-browserify": "^5.0.0",
"grunt-cli": "^1.2.0",
"grunt-contrib-uglify": "^3.4.0",
"grunt-contrib-uglify": "^4.0.1",
"grunt-contrib-watch": "^1.0.0",
"grunt-eslint": "^21.0.0",
"grunt-karma": "^2.0.0",
"grunt-eslint": "^22.0.0",
"grunt-karma": "^3.0.2",
"grunt-mocha-test": "^0.13.3",
"grunt-run": "^0.8.1",
"karma": "^1.1.2",
"karma-browserify": "^5.1.1",
"karma-chrome-launcher": "^1.0.1",
"is-docker": "^2.0.0",
"karma": "^4.1.0",
"karma-browserify": "^6.0.0",
"karma-chrome-launcher": "^3.1.0",
"karma-es6-shim": "^1.0.0",
"karma-firefox-launcher": "^1.0.0",
"karma-html2js-preprocessor": "^1.0.0",
"karma-junit-reporter": "~1.0.0",
"karma-junit-reporter": "^1.2.0",
"karma-mocha": "^1.1.1",
"karma-script-launcher": "^1.0.0",
"loopback-boot": "^2.7.0",
"loopback-context": "^1.0.0",
"mocha": "^5.2.0",
"nyc": "^10.1.2",
"sinon": "^6.1.4",
"mocha": "^6.2.1",
"nyc": "^14.1.1",
"sinon": "^7.5.0",
"sinon-chai": "^3.2.0",
"strong-error-handler": "^3.0.0",
"strong-task-emitter": "^0.0.8",
"supertest": "^3.0.0"
"supertest": "^4.0.2",
"which": "^2.0.1"
},
"repository": {
"type": "git",
@ -121,5 +119,13 @@
}
},
"copyright.owner": "IBM Corp.",
"license": "MIT"
"license": "MIT",
"author": "IBM Corp.",
"ci": {
"downstreamIgnoreList": [
"bluemix-service-broker",
"gateway-director-bluemix",
"plan-manager"
]
}
}

View File

@ -1,15 +1,15 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('../../lib/globalize');
const g = require('../../lib/globalize');
module.exports = function() {
throw new Error(g.f(
'%s middleware was removed in version 3.0. See %s for more details.',
'loopback#context',
'http://loopback.io/doc/en/lb2/Using-current-context.html'
'http://loopback.io/doc/en/lb2/Using-current-context.html',
));
};

View File

@ -1,11 +1,11 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var favicon = require('serve-favicon');
var path = require('path');
const favicon = require('serve-favicon');
const path = require('path');
/**
* Serve the LoopBack favicon.

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -8,9 +8,9 @@
*/
'use strict';
var g = require('../../lib/globalize');
var loopback = require('../../lib/loopback');
var async = require('async');
const g = require('../../lib/globalize');
const loopback = require('../../lib/loopback');
const async = require('async');
/*!
* Export the middleware.
@ -30,27 +30,27 @@ module.exports = rest;
*/
function rest() {
var handlers; // Cached handlers
let handlers; // Cached handlers
return function restApiHandler(req, res, next) {
var app = req.app;
var registry = app.registry;
const app = req.app;
const registry = app.registry;
if (!handlers) {
handlers = [];
var remotingOptions = app.get('remoting') || {};
const remotingOptions = app.get('remoting') || {};
var contextOptions = remotingOptions.context;
const contextOptions = remotingOptions.context;
if (contextOptions !== undefined && contextOptions !== false) {
throw new Error(g.f(
'%s was removed in version 3.0. See %s for more details.',
'remoting.context option',
'http://loopback.io/doc/en/lb2/Using-current-context.html'
'http://loopback.io/doc/en/lb2/Using-current-context.html',
));
}
if (app.isAuthEnabled) {
var AccessToken = registry.getModelByType('AccessToken');
const AccessToken = registry.getModelByType('AccessToken');
handlers.push(loopback.token({model: AccessToken, app: app}));
}

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -24,7 +24,7 @@ module.exports = status;
* @header loopback.status()
*/
function status() {
var started = new Date();
const started = new Date();
return function(req, res) {
res.send({

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -8,10 +8,10 @@
*/
'use strict';
var g = require('../../lib/globalize');
var loopback = require('../../lib/loopback');
var assert = require('assert');
var debug = require('debug')('loopback:middleware:token');
const g = require('../../lib/globalize');
const loopback = require('../../lib/loopback');
const assert = require('assert');
const debug = require('debug')('loopback:middleware:token');
/*!
* Export the middleware.
@ -28,7 +28,7 @@ function rewriteUserLiteral(req, currentUserLiteral, next) {
if (req.accessToken && req.accessToken.userId) {
// Replace /me/ with /current-user-id/
var urlBeforeRewrite = req.url;
const urlBeforeRewrite = req.url;
req.url = req.url.replace(literalRegExp,
'/' + req.accessToken.userId + '$1');
@ -40,10 +40,10 @@ function rewriteUserLiteral(req, currentUserLiteral, next) {
debug(
'URL %s matches current-user literal %s,' +
' but no (valid) access token was provided.',
req.url, currentUserLiteral
req.url, currentUserLiteral,
);
var e = new Error(g.f('Authorization Required'));
const e = new Error(g.f('Authorization Required'));
e.status = e.statusCode = 401;
e.code = 'AUTHORIZATION_REQUIRED';
return next(e);
@ -97,9 +97,9 @@ function escapeRegExp(str) {
function token(options) {
options = options || {};
var TokenModel;
let TokenModel;
var currentUserLiteral = options.currentUserLiteral;
let currentUserLiteral = options.currentUserLiteral;
if (currentUserLiteral && (typeof currentUserLiteral !== 'string')) {
debug('Set currentUserLiteral to \'me\' as the value is not a string.');
currentUserLiteral = 'me';
@ -111,12 +111,12 @@ function token(options) {
if (options.bearerTokenBase64Encoded === undefined) {
options.bearerTokenBase64Encoded = true;
}
var enableDoublecheck = !!options.enableDoublecheck;
var overwriteExistingToken = !!options.overwriteExistingToken;
const enableDoublecheck = !!options.enableDoublecheck;
const overwriteExistingToken = !!options.overwriteExistingToken;
return function(req, res, next) {
var app = req.app;
var registry = app.registry;
const app = req.app;
const registry = app.registry;
if (!TokenModel) {
TokenModel = registry.getModel(options.model || 'AccessToken');
}
@ -141,7 +141,7 @@ function token(options) {
TokenModel.findForRequest(req, options, function(err, token) {
req.accessToken = token || null;
var ctx = req.loopbackContext;
const ctx = req.loopbackContext;
if (ctx && ctx.active) ctx.set('accessToken', token);
if (err) return next(err);

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -18,7 +18,7 @@ module.exports = urlNotFound;
*/
function urlNotFound() {
return function raiseUrlNotFoundError(req, res, next) {
var error = new Error('Cannot ' + req.method + ' ' + req.url);
const error = new Error('Cannot ' + req.method + ' ' + req.url);
error.status = 404;
next(error);
};

View File

@ -1,18 +1,18 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../');
var lt = require('./helpers/loopback-testing-helper');
var path = require('path');
var ACCESS_CONTROL_APP = path.join(__dirname, 'fixtures', 'access-control');
var app = require(path.join(ACCESS_CONTROL_APP, 'server/server.js'));
var assert = require('assert');
var USER = {email: 'test@test.test', password: 'test'};
var CURRENT_USER = {email: 'current@test.test', password: 'test'};
var debug = require('debug')('loopback:test:access-control.integration');
const loopback = require('../');
const lt = require('./helpers/loopback-testing-helper');
const path = require('path');
const ACCESS_CONTROL_APP = path.join(__dirname, 'fixtures', 'access-control');
const app = require(path.join(ACCESS_CONTROL_APP, 'server/server.js'));
const assert = require('assert');
const USER = {email: 'test@test.test', password: 'test'};
const CURRENT_USER = {email: 'current@test.test', password: 'test'};
const debug = require('debug')('loopback:test:access-control.integration');
describe('access control - integration', function() {
lt.beforeEach.withApp(app);
@ -75,11 +75,11 @@ describe('access control - integration', function() {
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'GET', urlForUser);
lt.it.shouldBeAllowedWhenCalledAnonymously(
'POST', '/api/users', newUserData()
'POST', '/api/users', newUserData(),
);
lt.it.shouldBeAllowedWhenCalledByUser(
CURRENT_USER, 'POST', '/api/users', newUserData()
CURRENT_USER, 'POST', '/api/users', newUserData(),
);
lt.it.shouldBeAllowedWhenCalledByUser(CURRENT_USER, 'POST', '/api/users/logout');
@ -110,7 +110,7 @@ describe('access control - integration', function() {
this.res.statusCode,
this.res.headers,
this.res.text);
var user = this.res.body;
const user = this.res.body;
assert.equal(user.password, undefined);
});
});
@ -137,7 +137,7 @@ describe('access control - integration', function() {
return '/api/users/' + this.randomUser.id;
}
var userCounter;
var userCounter; // eslint-disable-line no-var
function newUserData() {
userCounter = userCounter ? ++userCounter : 1;
@ -149,14 +149,14 @@ describe('access control - integration', function() {
});
describe('/banks', function() {
var SPECIAL_USER = {email: 'special@test.test', password: 'test'};
const SPECIAL_USER = {email: 'special@test.test', password: 'test'};
// define dynamic role that would only grant access when the authenticated user's email is equal to
// SPECIAL_USER's email
before(function() {
var roleModel = app.registry.getModel('Role');
var userModel = app.registry.getModel('user');
const roleModel = app.registry.getModel('Role');
const userModel = app.registry.getModel('user');
roleModel.registerResolver('$dynamic-role', function(role, context, callback) {
if (!(context && context.accessToken && context.accessToken.userId)) {
@ -164,7 +164,7 @@ describe('access control - integration', function() {
if (callback) callback(null, false);
});
}
var accessToken = context.accessToken;
const accessToken = context.accessToken;
userModel.findById(accessToken.userId, function(err, user) {
if (err) {
return callback(err, false);
@ -210,9 +210,9 @@ describe('access control - integration', function() {
});
describe('/accounts with replaceOnPUT true', function() {
var count = 0;
let count = 0;
before(function() {
var roleModel = loopback.getModelByType(loopback.Role);
const roleModel = loopback.getModelByType(loopback.Role);
roleModel.registerResolver('$dummy', function(role, context, callback) {
process.nextTick(function() {
if (context.remotingContext) {
@ -250,9 +250,9 @@ describe('access control - integration', function() {
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'PATCH', urlForAccount);
lt.describe.whenLoggedInAsUser(CURRENT_USER, function() {
var actId;
let actId;
beforeEach(function(done) {
var self = this;
const self = this;
// Create an account under the given user
app.models.accountWithReplaceOnPUTtrue.create({
userId: self.user.id,
@ -314,9 +314,9 @@ describe('access control - integration', function() {
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'PATCH', urlForAccount);
lt.describe.whenLoggedInAsUser(CURRENT_USER, function() {
var actId;
let actId;
beforeEach(function(done) {
var self = this;
const self = this;
// Create an account under the given user
app.models.accountWithReplaceOnPUTfalse.create({
userId: self.user.id,

View File

@ -1,23 +1,23 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var expect = require('./helpers/expect');
var cookieParser = require('cookie-parser');
var LoopBackContext = require('loopback-context');
var contextMiddleware = require('loopback-context').perRequest;
var loopback = require('../');
var extend = require('util')._extend;
var session = require('express-session');
var request = require('supertest');
const assert = require('assert');
const expect = require('./helpers/expect');
const cookieParser = require('cookie-parser');
const LoopBackContext = require('loopback-context');
const contextMiddleware = require('loopback-context').perRequest;
const loopback = require('../');
const extend = require('util')._extend;
const session = require('express-session');
const request = require('supertest');
var Token, ACL, User, TestModel;
let Token, ACL, User, TestModel;
describe('loopback.token(options)', function() {
var app;
let app;
beforeEach(function(done) {
app = loopback({localRegistry: true, loadBuiltinModels: true});
app.dataSource('db', {connector: 'memory'});
@ -52,7 +52,7 @@ describe('loopback.token(options)', function() {
});
it('defaults to built-in AccessToken model', function() {
var BuiltInToken = app.registry.getModel('AccessToken');
const BuiltInToken = app.registry.getModel('AccessToken');
app.model(BuiltInToken, {dataSource: 'db'});
app.enableAuth({dataSource: 'db'});
@ -140,13 +140,13 @@ describe('loopback.token(options)', function() {
it('does not search default keys when searchDefaultTokenKeys is false',
function(done) {
var tokenId = this.token.id;
var app = createTestApp(
const tokenId = this.token.id;
const app = createTestApp(
this.token,
{token: {searchDefaultTokenKeys: false}},
done
done,
);
var agent = request.agent(app);
const agent = request.agent(app);
// Set the token cookie
agent.get('/token').expect(200).end(function(err, res) {
@ -165,7 +165,7 @@ describe('loopback.token(options)', function() {
it('populates req.token from an authorization header with bearer token with base64',
function(done) {
var token = this.token.id;
let token = this.token.id;
token = 'Bearer ' + new Buffer(token).toString('base64');
createTestAppAndRequest(this.token, done)
.get('/')
@ -175,7 +175,7 @@ describe('loopback.token(options)', function() {
});
it('populates req.token from an authorization header with bearer token', function(done) {
var token = this.token.id;
let token = this.token.id;
token = 'Bearer ' + token;
createTestAppAndRequest(this.token, {token: {bearerTokenBase64Encoded: false}}, done)
.get('/')
@ -186,7 +186,7 @@ describe('loopback.token(options)', function() {
describe('populating req.token from HTTP Basic Auth formatted authorization header', function() {
it('parses "standalone-token"', function(done) {
var token = this.token.id;
let token = this.token.id;
token = 'Basic ' + new Buffer(token).toString('base64');
createTestAppAndRequest(this.token, done)
.get('/')
@ -196,7 +196,7 @@ describe('loopback.token(options)', function() {
});
it('parses "token-and-empty-password:"', function(done) {
var token = this.token.id + ':';
let token = this.token.id + ':';
token = 'Basic ' + new Buffer(token).toString('base64');
createTestAppAndRequest(this.token, done)
.get('/')
@ -206,7 +206,7 @@ describe('loopback.token(options)', function() {
});
it('parses "ignored-user:token-is-password"', function(done) {
var token = 'username:' + this.token.id;
let token = 'username:' + this.token.id;
token = 'Basic ' + new Buffer(token).toString('base64');
createTestAppAndRequest(this.token, done)
.get('/')
@ -216,7 +216,7 @@ describe('loopback.token(options)', function() {
});
it('parses "token-is-username:ignored-password"', function(done) {
var token = this.token.id + ':password';
let token = this.token.id + ':password';
token = 'Basic ' + new Buffer(token).toString('base64');
createTestAppAndRequest(this.token, done)
.get('/')
@ -227,7 +227,7 @@ describe('loopback.token(options)', function() {
});
it('populates req.token from a secure cookie', function(done) {
var app = createTestApp(this.token, done);
const app = createTestApp(this.token, done);
request(app)
.get('/token')
@ -240,8 +240,8 @@ describe('loopback.token(options)', function() {
});
it('populates req.token from a header or a secure cookie', function(done) {
var app = createTestApp(this.token, done);
var id = this.token.id;
const app = createTestApp(this.token, done);
const id = this.token.id;
request(app)
.get('/token')
.end(function(err, res) {
@ -255,9 +255,9 @@ describe('loopback.token(options)', function() {
it('rewrites url for the current user literal at the end without query',
function(done) {
var app = createTestApp(this.token, done);
var id = this.token.id;
var userId = this.token.userId;
const app = createTestApp(this.token, done);
const id = this.token.id;
const userId = this.token.userId;
request(app)
.get('/users/me')
.set('authorization', id)
@ -271,9 +271,9 @@ describe('loopback.token(options)', function() {
it('rewrites url for the current user literal at the end with query',
function(done) {
var app = createTestApp(this.token, done);
var id = this.token.id;
var userId = this.token.userId;
const app = createTestApp(this.token, done);
const id = this.token.id;
const userId = this.token.userId;
request(app)
.get('/users/me?state=1')
.set('authorization', id)
@ -287,9 +287,9 @@ describe('loopback.token(options)', function() {
it('rewrites url for the current user literal in the middle',
function(done) {
var app = createTestApp(this.token, done);
var id = this.token.id;
var userId = this.token.userId;
const app = createTestApp(this.token, done);
const id = this.token.id;
const userId = this.token.userId;
request(app)
.get('/users/me/1')
.set('authorization', id)
@ -303,7 +303,7 @@ describe('loopback.token(options)', function() {
it('generates a 401 on a current user literal route without an authToken',
function(done) {
var app = createTestApp(null, done);
const app = createTestApp(null, done);
request(app)
.get('/users/me')
.set('authorization', null)
@ -313,7 +313,7 @@ describe('loopback.token(options)', function() {
it('generates a 401 on a current user literal route with empty authToken',
function(done) {
var app = createTestApp(null, done);
const app = createTestApp(null, done);
request(app)
.get('/users/me')
.set('authorization', '')
@ -323,7 +323,7 @@ describe('loopback.token(options)', function() {
it('generates a 401 on a current user literal route with invalid authToken',
function(done) {
var app = createTestApp(this.token, done);
const app = createTestApp(this.token, done);
request(app)
.get('/users/me')
.set('Authorization', 'invald-token-id')
@ -332,7 +332,7 @@ describe('loopback.token(options)', function() {
});
it('skips when req.token is already present', function(done) {
var tokenStub = {id: 'stub id'};
const tokenStub = {id: 'stub id'};
app.use(function(req, res, next) {
req.accessToken = tokenStub;
@ -358,7 +358,7 @@ describe('loopback.token(options)', function() {
describe('loading multiple instances of token middleware', function() {
it('skips when req.token is already present and no further options are set',
function(done) {
var tokenStub = {id: 'stub id'};
const tokenStub = {id: 'stub id'};
app.use(function(req, res, next) {
req.accessToken = tokenStub;
@ -384,7 +384,7 @@ describe('loopback.token(options)', function() {
it('does not overwrite valid existing token (has "id" property) ' +
' when overwriteExistingToken is falsy',
function(done) {
var tokenStub = {id: 'stub id'};
const tokenStub = {id: 'stub id'};
app.use(function(req, res, next) {
req.accessToken = tokenStub;
@ -413,7 +413,7 @@ describe('loopback.token(options)', function() {
it('overwrites invalid existing token (is !== undefined and has no "id" property) ' +
' when enableDoublecheck is true',
function(done) {
var token = this.token;
const token = this.token;
app.use(function(req, res, next) {
req.accessToken = null;
next();
@ -446,8 +446,8 @@ describe('loopback.token(options)', function() {
it('overwrites existing token when enableDoublecheck ' +
'and overwriteExistingToken options are truthy',
function(done) {
var token = this.token;
var tokenStub = {id: 'stub id'};
const token = this.token;
const tokenStub = {id: 'stub id'};
app.use(function(req, res, next) {
req.accessToken = tokenStub;
@ -521,7 +521,7 @@ describe('AccessToken', function() {
it('allows eternal tokens when enabled by User.allowEternalTokens',
function(done) {
var Token = givenLocalTokenModel();
const Token = givenLocalTokenModel();
// Overwrite User settings - enable eternal tokens
Token.app.models.User.settings.allowEternalTokens = true;
@ -541,8 +541,8 @@ describe('AccessToken', function() {
beforeEach(createTestingToken);
it('supports two-arg variant with no options', function(done) {
var expectedTokenId = this.token.id;
var req = mockRequest({
const expectedTokenId = this.token.id;
const req = mockRequest({
headers: {'authorization': expectedTokenId},
});
@ -556,14 +556,14 @@ describe('AccessToken', function() {
});
it('allows getIdForRequest() to be overridden', function(done) {
var expectedTokenId = this.token.id;
var current = Token.getIdForRequest;
var called = false;
const expectedTokenId = this.token.id;
const current = Token.getIdForRequest;
let called = false;
Token.getIdForRequest = function(req, options) {
called = true;
return expectedTokenId;
};
var req = mockRequest({
const req = mockRequest({
headers: {'authorization': 'dummy'},
});
@ -579,16 +579,16 @@ describe('AccessToken', function() {
});
it('allows resolve() to be overridden', function(done) {
var expectedTokenId = this.token.id;
var current = Token.resolve;
var called = false;
const expectedTokenId = this.token.id;
const current = Token.resolve;
let called = false;
Token.resolve = function(id, cb) {
called = true;
process.nextTick(function() {
cb(null, {id: expectedTokenId});
});
};
var req = mockRequest({
const req = mockRequest({
headers: {'authorization': expectedTokenId},
});
@ -615,14 +615,14 @@ describe('AccessToken', function() {
param: function(name) { return this._params[name]; },
header: function(name) { return this.headers[name]; },
},
opts
opts,
);
}
});
});
describe('app.enableAuth()', function() {
var app;
let app;
beforeEach(function setupAuthWithModels() {
app = loopback({localRegistry: true, loadBuiltinModels: true});
app.dataSource('db', {connector: 'memory'});
@ -653,7 +653,7 @@ describe('app.enableAuth()', function() {
return done(err);
}
var errorResponse = res.body.error;
const errorResponse = res.body.error;
assert(errorResponse);
assert.equal(errorResponse.code, 'AUTHORIZATION_REQUIRED');
@ -671,7 +671,7 @@ describe('app.enableAuth()', function() {
return done(err);
}
var errorResponse = res.body.error;
const errorResponse = res.body.error;
assert(errorResponse);
assert.equal(errorResponse.code, 'ACCESS_DENIED');
@ -689,7 +689,7 @@ describe('app.enableAuth()', function() {
return done(err);
}
var errorResponse = res.body.error;
const errorResponse = res.body.error;
assert(errorResponse);
assert.equal(errorResponse.code, 'MODEL_NOT_FOUND');
@ -707,7 +707,7 @@ describe('app.enableAuth()', function() {
return done(err);
}
var errorResponse = res.body.error;
const errorResponse = res.body.error;
assert(errorResponse);
assert.equal(errorResponse.code, 'AUTHORIZATION_REQUIRED');
@ -716,9 +716,9 @@ describe('app.enableAuth()', function() {
});
it('stores token in the context', function(done) {
var TestModel = app.registry.createModel('TestModel', {base: 'Model'});
const TestModel = app.registry.createModel('TestModel', {base: 'Model'});
TestModel.getToken = function(cb) {
var ctx = LoopBackContext.getCurrentContext();
const ctx = LoopBackContext.getCurrentContext();
cb(null, ctx && ctx.get('accessToken') || null);
};
TestModel.remoteMethod('getToken', {
@ -733,7 +733,7 @@ describe('app.enableAuth()', function() {
app.use(loopback.token({model: Token}));
app.use(loopback.rest());
var token = this.token;
const token = this.token;
request(app)
.get('/TestModels/token?_format=json')
.set('authorization', token.id)
@ -772,7 +772,7 @@ describe('app.enableAuth()', function() {
});
function createTestingToken(done) {
var test = this;
const test = this;
Token.create({userId: '123'}, function(err, token) {
if (err) return done(err);
@ -783,7 +783,7 @@ function createTestingToken(done) {
}
function createTestAppAndRequest(testToken, settings, done) {
var app = createTestApp(testToken, settings, done);
const app = createTestApp(testToken, settings, done);
return request(app);
}
@ -793,14 +793,14 @@ function createTestApp(testToken, settings, done) {
settings = {};
}
var appSettings = settings.app || {};
var modelSettings = settings.model || {};
var tokenSettings = extend({
const appSettings = settings.app || {};
const modelSettings = settings.model || {};
const tokenSettings = extend({
model: Token,
currentUserLiteral: 'me',
}, settings.token);
var app = loopback({localRegistry: true, loadBuiltinModels: true});
const app = loopback({localRegistry: true, loadBuiltinModels: true});
app.dataSource('db', {connector: 'memory'});
app.use(cookieParser('secret'));
@ -824,7 +824,7 @@ function createTestApp(testToken, settings, done) {
res.status(req.accessToken ? 200 : 401).end();
});
app.use('/users/:uid', function(req, res) {
var result = {userId: req.params.uid};
const result = {userId: req.params.uid};
if (req.query.state) {
result.state = req.query.state;
} else if (req.url !== '/') {
@ -839,7 +839,7 @@ function createTestApp(testToken, settings, done) {
app.set(key, appSettings[key]);
});
var modelOptions = {
const modelOptions = {
acls: [
{
principalType: 'ROLE',
@ -855,20 +855,20 @@ function createTestApp(testToken, settings, done) {
modelOptions[key] = modelSettings[key];
});
var TestModel = app.registry.createModel('test', {}, modelOptions);
const TestModel = app.registry.createModel('test', {}, modelOptions);
app.model(TestModel, {dataSource: 'db'});
return app;
}
function givenLocalTokenModel() {
var app = loopback({localRegistry: true, loadBuiltinModels: true});
const app = loopback({localRegistry: true, loadBuiltinModels: true});
app.dataSource('db', {connector: 'memory'});
var User = app.registry.getModel('User');
const User = app.registry.getModel('User');
app.model(User, {dataSource: 'db'});
var Token = app.registry.getModel('AccessToken');
const Token = app.registry.getModel('AccessToken');
app.model(Token, {dataSource: 'db'});
return Token;

View File

@ -1,27 +1,27 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var expect = require('./helpers/expect');
var loopback = require('../index');
var Scope = loopback.Scope;
var ACL = loopback.ACL;
var request = require('supertest');
var Promise = require('bluebird');
var supertest = require('supertest');
var Role = loopback.Role;
var RoleMapping = loopback.RoleMapping;
var User = loopback.User;
var async = require('async');
const assert = require('assert');
const expect = require('./helpers/expect');
const loopback = require('../index');
const Scope = loopback.Scope;
const ACL = loopback.ACL;
const request = require('supertest');
const Promise = require('bluebird');
const supertest = require('supertest');
const Role = loopback.Role;
const RoleMapping = loopback.RoleMapping;
const User = loopback.User;
const async = require('async');
// Speed up the password hashing algorithm for tests
User.settings.saltWorkFactor = 4;
var ds = null;
var testModel;
let ds = null;
let testModel;
describe('ACL model', function() {
it('provides DEFAULT_SCOPE constant', () => {
@ -144,7 +144,7 @@ describe('security ACLs', function() {
});
it('supports checkAccessForContext() returning a promise', function() {
var testModel = ds.createModel('testModel', {
const testModel = ds.createModel('testModel', {
acls: [
{principalType: ACL.USER, principalId: 'u001',
accessType: ACL.ALL, permission: ACL.ALLOW},
@ -162,7 +162,7 @@ describe('security ACLs', function() {
});
it('should order ACL entries based on the matching score', function() {
var acls = [
let acls = [
{
'model': 'account',
'accessType': '*',
@ -184,7 +184,7 @@ describe('security ACLs', function() {
'principalType': 'ROLE',
'principalId': '$everyone',
}];
var req = {
const req = {
model: 'account',
property: 'find',
accessType: 'WRITE',
@ -192,7 +192,7 @@ describe('security ACLs', function() {
acls = acls.map(function(a) { return new ACL(a); });
var perm = ACL.resolvePermission(acls, req);
const perm = ACL.resolvePermission(acls, req);
// remove the registry from AccessRequest instance to ease asserting
delete perm.registry;
assert.deepEqual(perm, {model: 'account',
@ -214,7 +214,7 @@ describe('security ACLs', function() {
});
it('should order ACL entries based on the matching score even with wildcard req', function() {
var acls = [
let acls = [
{
'model': 'account',
'accessType': '*',
@ -229,7 +229,7 @@ describe('security ACLs', function() {
'principalType': 'ROLE',
'principalId': '$owner',
}];
var req = {
const req = {
model: 'account',
property: '*',
accessType: 'WRITE',
@ -237,7 +237,7 @@ describe('security ACLs', function() {
acls = acls.map(function(a) { return new ACL(a); });
var perm = ACL.resolvePermission(acls, req);
const perm = ACL.resolvePermission(acls, req);
// remove the registry from AccessRequest instance to ease asserting.
// Check the above test case for more info.
delete perm.registry;
@ -311,7 +311,7 @@ describe('security ACLs', function() {
});
it('should honor defaultPermission from the model', function(done) {
var Customer = ds.createModel('Customer', {
const Customer = ds.createModel('Customer', {
name: {
type: String,
acls: [
@ -347,7 +347,7 @@ describe('security ACLs', function() {
});
it('should honor static ACLs from the model', function(done) {
var Customer = ds.createModel('Customer', {
const Customer = ds.createModel('Customer', {
name: {
type: String,
acls: [
@ -394,7 +394,7 @@ describe('security ACLs', function() {
});
it('should filter static ACLs by model/property', function() {
var Model1 = ds.createModel('Model1', {
const Model1 = ds.createModel('Model1', {
name: {
type: String,
acls: [
@ -415,7 +415,7 @@ describe('security ACLs', function() {
],
});
var staticACLs = ACL.getStaticACLs('Model1', 'name');
let staticACLs = ACL.getStaticACLs('Model1', 'name');
assert(staticACLs.length === 3);
staticACLs = ACL.getStaticACLs('Model1', 'findOne');
@ -427,16 +427,16 @@ describe('security ACLs', function() {
});
it('should check access against LDL, ACL, and Role', function(done) {
var log = function() {};
const log = function() {};
// Create
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function(err, user) {
log('User: ', user.toObject());
var userId = user.id;
const userId = user.id;
// Define a model with static ACLs
var Customer = ds.createModel('Customer', {
const Customer = ds.createModel('Customer', {
name: {
type: String,
acls: [
@ -514,10 +514,10 @@ describe('security ACLs', function() {
describe('access check', function() {
it('should occur before other remote hooks', function(done) {
var app = loopback();
var MyTestModel = app.registry.createModel('MyTestModel');
var checkAccessCalled = false;
var beforeHookCalled = false;
const app = loopback();
const MyTestModel = app.registry.createModel('MyTestModel');
let checkAccessCalled = false;
let beforeHookCalled = false;
app.use(loopback.rest());
app.set('remoting', {errorHandler: {debug: true, log: false}});
@ -527,9 +527,9 @@ describe('access check', function() {
// fake / spy on the checkAccess method
MyTestModel.checkAccess = function() {
var cb = arguments[arguments.length - 1];
const cb = arguments[arguments.length - 1];
checkAccessCalled = true;
var allowed = true;
const allowed = true;
cb(null, allowed);
};
@ -554,8 +554,8 @@ describe('access check', function() {
});
describe('authorized roles propagation in RemotingContext', function() {
var app, request, accessToken;
var models = {};
let app, request, accessToken;
let models = {};
beforeEach(setupAppAndRequest);
@ -567,13 +567,13 @@ describe('authorized roles propagation in RemotingContext', function() {
])
.then(makeAuthorizedHttpRequestOnMyTestModel)
.then(function() {
var ctx = models.MyTestModel.lastRemotingContext;
const ctx = models.MyTestModel.lastRemotingContext;
expect(ctx.args.options.authorizedRoles).to.eql(
{
$everyone: true,
$authenticated: true,
myRole: true,
}
},
);
});
});
@ -586,12 +586,12 @@ describe('authorized roles propagation in RemotingContext', function() {
])
.then(makeAuthorizedHttpRequestOnMyTestModel)
.then(function() {
var ctx = models.MyTestModel.lastRemotingContext;
const ctx = models.MyTestModel.lastRemotingContext;
expect(ctx.args.options.authorizedRoles).to.eql(
{
$everyone: true,
myRole: true,
}
},
);
});
});
@ -607,10 +607,10 @@ describe('authorized roles propagation in RemotingContext', function() {
])
.then(makeAuthorizedHttpRequestOnMyTestModel)
.then(function() {
var ctx = models.MyTestModel.lastRemotingContext;
const ctx = models.MyTestModel.lastRemotingContext;
expect(ctx.args.options.authorizedRoles).to.eql(
// '$everyone' is not expected as default permission is DENY
{myRole: true}
{myRole: true},
);
});
});

View File

@ -1,39 +1,39 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var async = require('async');
var path = require('path');
const assert = require('assert');
const async = require('async');
const path = require('path');
var http = require('http');
var express = require('express');
var loopback = require('../');
var PersistedModel = loopback.PersistedModel;
const http = require('http');
const express = require('express');
const loopback = require('../');
const PersistedModel = loopback.PersistedModel;
var describe = require('./util/describe');
var expect = require('./helpers/expect');
var it = require('./util/it');
var request = require('supertest');
const describe = require('./util/describe');
const expect = require('./helpers/expect');
const it = require('./util/it');
const request = require('supertest');
const sinon = require('sinon');
describe('app', function() {
var app;
let app;
beforeEach(function() {
app = loopback({localRegistry: true, loadBuiltinModels: true});
});
describe.onServer('.middleware(phase, handler)', function() {
var steps;
let steps;
beforeEach(function setup() {
steps = [];
});
it('runs middleware in phases', function(done) {
var PHASES = [
const PHASES = [
'initial', 'session', 'auth', 'parse',
'routes', 'files', 'final',
];
@ -88,10 +88,10 @@ describe('app', function() {
return namedHandler(name);
}
var myHandler;
let myHandler;
app.middleware('routes:before',
myHandler = handlerThatAddsHandler('my-handler'));
var found = app._findLayerByHandler(myHandler);
const found = app._findLayerByHandler(myHandler);
expect(found).to.be.an('object');
expect(myHandler).to.equal(found.handle);
expect(found).have.property('phase', 'routes:before');
@ -106,13 +106,35 @@ describe('app', function() {
it('allows handlers to be wrapped as __NR_handler on express stack',
function(done) {
var myHandler = namedHandler('my-handler');
var wrappedHandler = function(req, res, next) {
const myHandler = namedHandler('my-handler');
const wrappedHandler = function(req, res, next) {
myHandler(req, res, next);
};
wrappedHandler['__NR_handler'] = myHandler;
app.middleware('routes:before', wrappedHandler);
var found = app._findLayerByHandler(myHandler);
const found = app._findLayerByHandler(myHandler);
expect(found).to.be.an('object');
expect(found).have.property('phase', 'routes:before');
executeMiddlewareHandlers(app, function(err) {
if (err) return done(err);
expect(steps).to.eql(['my-handler']);
done();
});
});
it('allows handlers to be wrapped as __appdynamicsProxyInfo__ on express stack',
function(done) {
const myHandler = namedHandler('my-handler');
const wrappedHandler = function(req, res, next) {
myHandler(req, res, next);
};
wrappedHandler['__appdynamicsProxyInfo__'] = {
orig: myHandler,
};
app.middleware('routes:before', wrappedHandler);
const found = app._findLayerByHandler(myHandler);
expect(found).to.be.an('object');
expect(found).have.property('phase', 'routes:before');
executeMiddlewareHandlers(app, function(err) {
@ -126,13 +148,13 @@ describe('app', function() {
it('allows handlers to be wrapped as a property on express stack',
function(done) {
var myHandler = namedHandler('my-handler');
var wrappedHandler = function(req, res, next) {
const myHandler = namedHandler('my-handler');
const wrappedHandler = function(req, res, next) {
myHandler(req, res, next);
};
wrappedHandler['__handler'] = myHandler;
app.middleware('routes:before', wrappedHandler);
var found = app._findLayerByHandler(myHandler);
const found = app._findLayerByHandler(myHandler);
expect(found).to.be.an('object');
expect(found).have.property('phase', 'routes:before');
executeMiddlewareHandlers(app, function(err) {
@ -145,7 +167,7 @@ describe('app', function() {
});
it('injects error from previous phases into the router', function(done) {
var expectedError = new Error('expected error');
const expectedError = new Error('expected error');
app.middleware('initial', function(req, res, next) {
steps.push('initial');
@ -171,7 +193,7 @@ describe('app', function() {
});
it('passes unhandled error to callback', function(done) {
var expectedError = new Error('expected error');
const expectedError = new Error('expected error');
app.middleware('initial', function(req, res, next) {
next(expectedError);
@ -185,8 +207,8 @@ describe('app', function() {
});
it('passes errors to error handlers in the same phase', function(done) {
var expectedError = new Error('this should be handled by middleware');
var handledError;
const expectedError = new Error('this should be handled by middleware');
let handledError;
app.middleware('initial', function(req, res, next) {
// continue in the next tick, this verifies that the next
@ -223,7 +245,7 @@ describe('app', function() {
expect(steps).to.eql(['/scope', '/scope/item']);
done();
}
},
);
});
@ -239,7 +261,7 @@ describe('app', function() {
expect(steps).to.eql(['/a', '/b']);
done();
}
},
);
});
@ -255,7 +277,7 @@ describe('app', function() {
expect(steps).to.eql(['/a', '/b', '/scope']);
done();
}
},
);
});
@ -276,7 +298,7 @@ describe('app', function() {
});
it('exposes express helpers on req and res objects', function(done) {
var req, res;
let req, res;
app.middleware('initial', function(rq, rs, next) {
req = rq;
@ -314,7 +336,7 @@ describe('app', function() {
});
it('sets req.baseUrl and req.originalUrl', function(done) {
var reqProps;
let reqProps;
app.middleware('initial', function(req, res, next) {
reqProps = {baseUrl: req.baseUrl, originalUrl: req.originalUrl};
@ -352,7 +374,7 @@ describe('app', function() {
// we need at least 9 elements to expose non-stability
// of the built-in sort function
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
numbers.forEach(function(n) {
app.middleware('routes', namedHandler(n));
});
@ -367,8 +389,8 @@ describe('app', function() {
});
it('correctly mounts express apps', function(done) {
var data, mountWasEmitted;
var subapp = express();
let data, mountWasEmitted;
const subapp = express();
subapp.use(function(req, res, next) {
data = {
mountpath: req.app.mountpath,
@ -395,10 +417,10 @@ describe('app', function() {
});
it('restores req & res on return from mounted express app', function(done) {
var expected = {};
var actual = {};
const expected = {};
const actual = {};
var subapp = express();
const subapp = express();
subapp.use(function verifyTestAssumptions(req, res, next) {
expect(req.__proto__).to.not.equal(expected.req);
expect(res.__proto__).to.not.equal(expected.res);
@ -446,8 +468,8 @@ describe('app', function() {
}
function getObjectAndPrototypeKeys(obj) {
var result = [];
for (var k in obj) {
const result = [];
for (const k in obj) {
result.push(k);
}
result.sort();
@ -457,11 +479,11 @@ describe('app', function() {
describe.onServer('.middlewareFromConfig', function() {
it('provides API for loading middleware from JSON config', function(done) {
var steps = [];
var expectedConfig = {key: 'value'};
const steps = [];
const expectedConfig = {key: 'value'};
var handlerFactory = function() {
var args = Array.prototype.slice.apply(arguments);
const handlerFactory = function() {
const args = Array.prototype.slice.apply(arguments);
return function(req, res, next) {
steps.push(args);
@ -528,7 +550,7 @@ describe('app', function() {
});
it('scopes middleware from config to a list of scopes', function(done) {
var steps = [];
const steps = [];
app.middlewareFromConfig(
function factory() {
return function(req, res, next) {
@ -540,7 +562,7 @@ describe('app', function() {
{
phase: 'initial',
paths: ['/scope', /^\/(a|b)/],
}
},
);
async.eachSeries(
@ -552,13 +574,13 @@ describe('app', function() {
expect(steps).to.eql(['/a', '/b', '/scope']);
done();
}
},
);
});
});
describe.onServer('.defineMiddlewarePhases(nameOrArray)', function() {
var app;
let app;
beforeEach(function() {
app = loopback();
});
@ -604,7 +626,7 @@ describe('app', function() {
});
function verifyMiddlewarePhases(names, done) {
var steps = [];
const steps = [];
names.forEach(function(it) {
app.middleware(it, function(req, res, next) {
steps.push(it);
@ -624,7 +646,7 @@ describe('app', function() {
});
describe('app.model(Model)', function() {
var app, db, MyTestModel;
let app, db, MyTestModel;
beforeEach(function() {
app = loopback();
app.set('remoting', {errorHandler: {debug: true, log: false}});
@ -633,7 +655,7 @@ describe('app', function() {
});
it('Expose a `Model` to remote clients', function() {
var Color = PersistedModel.extend('color', {name: String});
const Color = PersistedModel.extend('color', {name: String});
app.model(Color);
Color.attachTo(db);
@ -641,22 +663,22 @@ describe('app', function() {
});
it('uses singular name as app.remoteObjects() key', function() {
var Color = PersistedModel.extend('color', {name: String});
const Color = PersistedModel.extend('color', {name: String});
app.model(Color);
Color.attachTo(db);
expect(app.remoteObjects()).to.eql({color: Color});
});
it('uses singular name as shared class name', function() {
var Color = PersistedModel.extend('color', {name: String});
const Color = PersistedModel.extend('color', {name: String});
app.model(Color);
Color.attachTo(db);
var classes = app.remotes().classes().map(function(c) { return c.name; });
const classes = app.remotes().classes().map(function(c) { return c.name; });
expect(classes).to.contain('color');
});
it('registers existing models to app.models', function() {
var Color = db.createModel('color', {name: String});
const Color = db.createModel('color', {name: String});
app.model(Color);
expect(Color.app).to.be.equal(app);
expect(Color.shared).to.equal(true);
@ -665,9 +687,9 @@ describe('app', function() {
});
it('emits a `modelRemoted` event', function() {
var Color = PersistedModel.extend('color', {name: String});
const Color = PersistedModel.extend('color', {name: String});
Color.shared = true;
var remotedClass;
let remotedClass;
app.on('modelRemoted', function(sharedClass) {
remotedClass = sharedClass;
});
@ -677,9 +699,9 @@ describe('app', function() {
});
it('emits a `remoteMethodDisabled` event', function() {
var Color = PersistedModel.extend('color', {name: String});
const Color = PersistedModel.extend('color', {name: String});
Color.shared = true;
var remoteMethodDisabledClass, disabledRemoteMethod;
let remoteMethodDisabledClass, disabledRemoteMethod;
app.on('remoteMethodDisabled', function(sharedClass, methodName) {
remoteMethodDisabledClass = sharedClass;
disabledRemoteMethod = methodName;
@ -694,23 +716,23 @@ describe('app', function() {
it('emits a `remoteMethodAdded` event', function() {
app.dataSource('db', {connector: 'memory'});
var Book = app.registry.createModel(
const Book = app.registry.createModel(
'Book',
{name: 'string'},
{plural: 'books'}
{plural: 'books'},
);
app.model(Book, {dataSource: 'db'});
var Page = app.registry.createModel(
const Page = app.registry.createModel(
'Page',
{name: 'string'},
{plural: 'pages'}
{plural: 'pages'},
);
app.model(Page, {dataSource: 'db'});
Book.hasMany(Page);
var remoteMethodAddedClass;
let remoteMethodAddedClass;
app.on('remoteMethodAdded', function(sharedClass) {
remoteMethodAddedClass = sharedClass;
});
@ -737,14 +759,14 @@ describe('app', function() {
});
it('throws error if model typeof string is passed', function() {
var fn = function() { app.model('MyTestModel'); };
const fn = function() { app.model('MyTestModel'); };
expect(fn).to.throw(/app(\.model|\.registry)/);
});
});
describe('app.model(ModelCtor, config)', function() {
it('attaches the model to a datasource', function() {
var previousModel = loopback.registry.findModel('TestModel');
const previousModel = loopback.registry.findModel('TestModel');
app.dataSource('db', {connector: 'memory'});
if (previousModel) {
@ -752,7 +774,7 @@ describe('app', function() {
}
assert(!previousModel || !previousModel.dataSource);
var TestModel = app.registry.createModel('TestModel');
const TestModel = app.registry.createModel('TestModel');
app.model(TestModel, {dataSource: 'db'});
expect(app.models.TestModel.dataSource).to.equal(app.dataSources.db);
});
@ -821,10 +843,10 @@ describe('app', function() {
describe('app.models', function() {
it('is unique per app instance', function() {
app.dataSource('db', {connector: 'memory'});
var Color = app.registry.createModel('Color');
const Color = app.registry.createModel('Color');
app.model(Color, {dataSource: 'db'});
expect(app.models.Color).to.equal(Color);
var anotherApp = loopback();
const anotherApp = loopback();
expect(anotherApp.models.Color).to.equal(undefined);
});
});
@ -833,7 +855,7 @@ describe('app', function() {
it('is unique per app instance', function() {
app.dataSource('ds', {connector: 'memory'});
expect(app.datasources.ds).to.not.equal(undefined);
var anotherApp = loopback();
const anotherApp = loopback();
expect(anotherApp.datasources.ds).to.equal(undefined);
});
});
@ -864,11 +886,11 @@ describe('app', function() {
describe.onServer('listen()', function() {
it('starts http server', function(done) {
var app = loopback();
const app = loopback();
app.set('port', 0);
app.get('/', function(req, res) { res.status(200).send('OK'); });
var server = app.listen();
const server = app.listen();
expect(server).to.be.an.instanceOf(require('http').Server);
@ -878,7 +900,7 @@ describe('app', function() {
});
it('updates port on `listening` event', function(done) {
var app = loopback();
const app = loopback();
app.set('port', 0);
app.listen(function() {
@ -889,12 +911,12 @@ describe('app', function() {
});
it('updates `url` on `listening` event', function(done) {
var app = loopback();
const app = loopback();
app.set('port', 0);
app.set('host', undefined);
app.listen(function() {
var expectedUrl = 'http://localhost:' + app.get('port') + '/';
const expectedUrl = 'http://localhost:' + app.get('port') + '/';
expect(app.get('url'), 'url').to.equal(expectedUrl);
done();
@ -902,7 +924,7 @@ describe('app', function() {
});
it('forwards to http.Server.listen on more than one arg', function(done) {
var app = loopback();
const app = loopback();
app.set('port', 1);
app.listen(0, '127.0.0.1', function() {
expect(app.get('port'), 'port').to.not.equal(0).and.not.equal(1);
@ -913,7 +935,7 @@ describe('app', function() {
});
it('forwards to http.Server.listen when the single arg is not a function', function(done) {
var app = loopback();
const app = loopback();
app.set('port', 1);
app.listen(0).on('listening', function() {
expect(app.get('port'), 'port') .to.not.equal(0).and.not.equal(1);
@ -923,7 +945,7 @@ describe('app', function() {
});
it('uses app config when no parameter is supplied', function(done) {
var app = loopback();
const app = loopback();
// Http listens on all interfaces by default
// Custom host serves as an indicator whether
// the value was used by app.listen
@ -945,26 +967,26 @@ describe('app', function() {
});
it('auto-configures required models to provided dataSource', function() {
var AUTH_MODELS = ['User', 'ACL', 'AccessToken', 'Role', 'RoleMapping'];
var app = loopback({localRegistry: true, loadBuiltinModels: true});
const AUTH_MODELS = ['User', 'ACL', 'AccessToken', 'Role', 'RoleMapping'];
const app = loopback({localRegistry: true, loadBuiltinModels: true});
require('../lib/builtin-models')(app.registry);
var db = app.dataSource('db', {connector: 'memory'});
const db = app.dataSource('db', {connector: 'memory'});
app.enableAuth({dataSource: 'db'});
expect(Object.keys(app.models)).to.include.members(AUTH_MODELS);
AUTH_MODELS.forEach(function(m) {
var Model = app.models[m];
const Model = app.models[m];
expect(Model.dataSource, m + '.dataSource').to.equal(db);
expect(Model.shared, m + '.shared').to.equal(m === 'User');
});
});
it('detects already configured subclass of a required model', function() {
var app = loopback({localRegistry: true, loadBuiltinModels: true});
var db = app.dataSource('db', {connector: 'memory'});
var Customer = app.registry.createModel('Customer', {}, {base: 'User'});
const app = loopback({localRegistry: true, loadBuiltinModels: true});
const db = app.dataSource('db', {connector: 'memory'});
const Customer = app.registry.createModel('Customer', {}, {base: 'User'});
app.model(Customer, {dataSource: 'db'});
// Fix AccessToken's "belongsTo user" relation to use our new Customer model
@ -979,7 +1001,7 @@ describe('app', function() {
describe.onServer('app.get(\'/\', loopback.status())', function() {
it('should return the status of the application', function(done) {
var app = loopback();
const app = loopback();
app.get('/', loopback.status());
request(app)
.get('/')
@ -991,7 +1013,7 @@ describe('app', function() {
expect(res.body).to.have.property('started');
expect(res.body.uptime, 'uptime').to.be.gte(0);
var elapsed = Date.now() - Number(new Date(res.body.started));
const elapsed = Date.now() - Number(new Date(res.body.started));
// elapsed should be a small positive number...
expect(elapsed, 'elapsed').to.be.within(0, 300);
@ -1004,7 +1026,7 @@ describe('app', function() {
describe('app.connectors', function() {
it('is unique per app instance', function() {
app.connectors.foo = 'bar';
var anotherApp = loopback();
const anotherApp = loopback();
expect(anotherApp.connectors.foo).to.equal(undefined);
});
@ -1047,8 +1069,8 @@ describe('app', function() {
});
it('is unique per app instance', function() {
var app1 = loopback();
var app2 = loopback();
const app1 = loopback();
const app2 = loopback();
expect(app1.settings).to.not.equal(app2.settings);
@ -1058,20 +1080,20 @@ describe('app', function() {
});
it('exposes loopback as a property', function() {
var app = loopback();
const app = loopback();
expect(app.loopback).to.equal(loopback);
});
function setupUserModels(app, options, done) {
app.dataSource('db', {connector: 'memory'});
var UserAccount = app.registry.createModel(
const UserAccount = app.registry.createModel(
'UserAccount',
{name: 'string'},
options
options,
);
var UserRole = app.registry.createModel(
const UserRole = app.registry.createModel(
'UserRole',
{name: 'string'}
{name: 'string'},
);
app.model(UserAccount, {dataSource: 'db'});
app.model(UserRole, {dataSource: 'db'});
@ -1086,7 +1108,7 @@ describe('app', function() {
}
describe('Model-level normalizeHttpPath option', function() {
var app;
let app;
beforeEach(function() {
app = loopback();
});
@ -1122,7 +1144,7 @@ describe('app', function() {
});
});
describe('app-level normalizeHttpPath option', function() {
var app;
let app;
beforeEach(function() {
app = loopback();
});
@ -1157,7 +1179,7 @@ describe('app', function() {
});
describe('Model-level and app-level normalizeHttpPath options', function() {
var app;
let app;
beforeEach(function() {
app = loopback();
});
@ -1181,8 +1203,8 @@ describe('app', function() {
});
function executeMiddlewareHandlers(app, urlPath, callback) {
var handlerError = undefined;
var server = http.createServer(function(req, res) {
let handlerError = undefined;
const server = http.createServer(function(req, res) {
app.handle(req, res, function(err) {
if (err) {
handlerError = err;

View File

@ -1,20 +1,20 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var expect = require('./helpers/expect');
var sinon = require('sinon');
var loopback = require('../');
const expect = require('./helpers/expect');
const sinon = require('sinon');
const loopback = require('../');
describe('PersistedModel.createChangeStream()', function() {
describe('configured to source changes locally', function() {
before(function() {
var test = this;
var app = loopback({localRegistry: true});
var ds = app.dataSource('ds', {connector: 'memory'});
var Score = app.registry.createModel('Score');
const test = this;
const app = loopback({localRegistry: true});
const ds = app.dataSource('ds', {connector: 'memory'});
const Score = app.registry.createModel('Score');
this.Score = app.model(Score, {
dataSource: 'ds',
changeDataSource: false, // use only local observers
@ -24,7 +24,7 @@ describe('PersistedModel.createChangeStream()', function() {
afterEach(verifyObserversRemoval);
it('should detect create', function(done) {
var Score = this.Score;
const Score = this.Score;
Score.createChangeStream(function(err, changes) {
changes.on('data', function(change) {
@ -38,7 +38,7 @@ describe('PersistedModel.createChangeStream()', function() {
});
it('should detect update', function(done) {
var Score = this.Score;
const Score = this.Score;
Score.create({team: 'foo'}, function(err, newScore) {
Score.createChangeStream(function(err, changes) {
changes.on('data', function(change) {
@ -55,7 +55,7 @@ describe('PersistedModel.createChangeStream()', function() {
});
it('should detect delete', function(done) {
var Score = this.Score;
const Score = this.Score;
Score.create({team: 'foo'}, function(err, newScore) {
Score.createChangeStream(function(err, changes) {
changes.on('data', function(change) {
@ -103,9 +103,9 @@ describe('PersistedModel.createChangeStream()', function() {
});
it('should not emit changes after destroy', function(done) {
var Score = this.Score;
const Score = this.Score;
var spy = sinon.spy();
const spy = sinon.spy();
Score.createChangeStream(function(err, changes) {
changes.on('data', function() {
@ -123,7 +123,7 @@ describe('PersistedModel.createChangeStream()', function() {
});
function verifyObserversRemoval() {
var Score = this.Score;
const Score = this.Score;
expect(Score._observers['after save']).to.be.empty();
expect(Score._observers['after delete']).to.be.empty();
}
@ -132,10 +132,10 @@ describe('PersistedModel.createChangeStream()', function() {
// TODO(ritch) implement multi-server support
describe.skip('configured to source changes using pubsub', function() {
before(function() {
var test = this;
var app = loopback({localRegistry: true});
var db = app.dataSource('ds', {connector: 'memory'});
var ps = app.dataSource('ps', {
const test = this;
const app = loopback({localRegistry: true});
const db = app.dataSource('ds', {connector: 'memory'});
const ps = app.dataSource('ps', {
host: 'localhost',
port: '12345',
connector: 'pubsub',
@ -148,7 +148,7 @@ describe('PersistedModel.createChangeStream()', function() {
});
it('should detect a change', function(done) {
var Score = this.Score;
const Score = this.Score;
Score.createChangeStream(function(err, changes) {
changes.on('data', function(change) {

View File

@ -1,19 +1,19 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var async = require('async');
var expect = require('./helpers/expect');
var loopback = require('../');
const assert = require('assert');
const async = require('async');
const expect = require('./helpers/expect');
const loopback = require('../');
describe('Change', function() {
let Change, TestModel;
beforeEach(function() {
var memory = loopback.createDataSource({
const memory = loopback.createDataSource({
connector: loopback.Memory,
});
TestModel = loopback.PersistedModel.extend('ChangeTestModel',
@ -29,7 +29,7 @@ describe('Change', function() {
});
beforeEach(function(done) {
var test = this;
const test = this;
test.data = {
foo: 'bar',
};
@ -52,13 +52,13 @@ describe('Change', function() {
describe('change.id', function() {
it('should be a hash of the modelName and modelId', function() {
var change = new Change({
const change = new Change({
rev: 'abc',
modelName: 'foo',
modelId: 'bar',
});
var hash = Change.hash([change.modelName, change.modelId].join('-'));
const hash = Change.hash([change.modelName, change.modelId].join('-'));
assert.equal(change.id, hash);
});
@ -67,7 +67,7 @@ describe('Change', function() {
describe('Change.rectifyModelChanges(modelName, modelIds, callback)', function() {
describe('using an existing untracked model', function() {
beforeEach(function(done) {
var test = this;
const test = this;
Change.rectifyModelChanges(this.modelName, [this.modelId], function(err, trackedChanges) {
if (err) return done(err);
@ -76,7 +76,7 @@ describe('Change', function() {
});
it('should create an entry', function(done) {
var test = this;
const test = this;
Change.find(function(err, trackedChanges) {
assert.equal(trackedChanges[0].modelId, test.modelId.toString());
@ -97,7 +97,7 @@ describe('Change', function() {
describe('Change.rectifyModelChanges - promise variant', function() {
describe('using an existing untracked model', function() {
beforeEach(function(done) {
var test = this;
const test = this;
Change.rectifyModelChanges(this.modelName, [this.modelId])
.then(function(trackedChanges) {
done();
@ -106,7 +106,7 @@ describe('Change', function() {
});
it('should create an entry', function(done) {
var test = this;
const test = this;
Change.find()
.then(function(trackedChanges) {
assert.equal(trackedChanges[0].modelId, test.modelId.toString());
@ -131,7 +131,7 @@ describe('Change', function() {
describe('Change.findOrCreateChange(modelName, modelId, callback)', function() {
describe('when a change doesnt exist', function() {
beforeEach(function(done) {
var test = this;
const test = this;
Change.findOrCreateChange(this.modelName, this.modelId, function(err, result) {
if (err) return done(err);
@ -142,7 +142,7 @@ describe('Change', function() {
});
it('should create an entry', function(done) {
var test = this;
const test = this;
Change.findById(this.result.id, function(err, change) {
if (err) return done(err);
@ -155,7 +155,7 @@ describe('Change', function() {
describe('when a change doesnt exist - promise variant', function() {
beforeEach(function(done) {
var test = this;
const test = this;
Change.findOrCreateChange(this.modelName, this.modelId)
.then(function(result) {
test.result = result;
@ -166,7 +166,7 @@ describe('Change', function() {
});
it('should create an entry', function(done) {
var test = this;
const test = this;
Change.findById(this.result.id, function(err, change) {
if (err) return done(err);
@ -179,7 +179,7 @@ describe('Change', function() {
describe('when a change does exist', function() {
beforeEach(function(done) {
var test = this;
const test = this;
Change.create({
modelName: test.modelName,
modelId: test.modelId,
@ -191,7 +191,7 @@ describe('Change', function() {
});
beforeEach(function(done) {
var test = this;
const test = this;
Change.findOrCreateChange(this.modelName, this.modelId, function(err, result) {
if (err) return done(err);
@ -202,7 +202,7 @@ describe('Change', function() {
});
it('should find the entry', function(done) {
var test = this;
const test = this;
assert.equal(test.existingChange.id, test.result.id);
done();
@ -211,7 +211,7 @@ describe('Change', function() {
});
describe('change.rectify(callback)', function() {
var change;
let change;
beforeEach(function(done) {
Change.findOrCreate(
{
@ -222,12 +222,12 @@ describe('Change', function() {
change = ch;
done(err);
}
},
);
});
it('should create a new change with the correct revision', function(done) {
var test = this;
const test = this;
change.rectify(function(err, ch) {
assert.equal(ch.rev, test.revisionForModel);
@ -238,9 +238,9 @@ describe('Change', function() {
// This test is a low-level equivalent of the test in replication.test.js
// called "replicates multiple updates within the same CP"
it('should merge updates within the same checkpoint', function(done) {
var test = this;
var originalRev = this.revisionForModel;
var cp;
const test = this;
const originalRev = this.revisionForModel;
let cp;
async.series([
rectify,
@ -274,7 +274,7 @@ describe('Change', function() {
}
function update(next) {
var model = test.model;
const model = test.model;
model.name += 'updated';
model.save(function(err) {
@ -286,9 +286,9 @@ describe('Change', function() {
});
it('should not change checkpoint when rev is the same', function(done) {
var test = this;
var originalCheckpoint = change.checkpoint;
var originalRev = change.rev;
const test = this;
const originalCheckpoint = change.checkpoint;
const originalRev = change.rev;
TestModel.checkpoint(function(err, inst) {
if (err) return done(err);
@ -306,7 +306,7 @@ describe('Change', function() {
});
describe('change.rectify - promise variant', function() {
var change;
let change;
beforeEach(function(done) {
Change.findOrCreateChange(this.modelName, this.modelId)
.then(function(ch) {
@ -318,7 +318,7 @@ describe('Change', function() {
});
it('should create a new change with the correct revision', function(done) {
var test = this;
const test = this;
change.rectify()
.then(function(ch) {
assert.equal(ch.rev, test.revisionForModel);
@ -330,8 +330,8 @@ describe('Change', function() {
describe('change.currentRevision(callback)', function() {
it('should get the correct revision', function(done) {
var test = this;
var change = new Change({
const test = this;
const change = new Change({
modelName: this.modelName,
modelId: this.modelId,
});
@ -346,8 +346,8 @@ describe('Change', function() {
describe('change.currentRevision - promise variant', function() {
it('should get the correct revision', function(done) {
var test = this;
var change = new Change({
const test = this;
const change = new Change({
modelName: this.modelName,
modelId: this.modelId,
});
@ -365,8 +365,8 @@ describe('Change', function() {
describe('Change.hash(str)', function() {
// todo(ritch) test other hashing algorithms
it('should hash the given string', function() {
var str = 'foo';
var hash = Change.hash(str);
const str = 'foo';
const hash = Change.hash(str);
assert(hash !== str);
assert(typeof hash === 'string');
});
@ -374,54 +374,54 @@ describe('Change', function() {
describe('Change.revisionForInst(inst)', function() {
it('should return the same revision for the same data', function() {
var a = {
const a = {
b: {
b: ['c', 'd'],
c: ['d', 'e'],
},
};
var b = {
const b = {
b: {
c: ['d', 'e'],
b: ['c', 'd'],
},
};
var aRev = Change.revisionForInst(a);
var bRev = Change.revisionForInst(b);
const aRev = Change.revisionForInst(a);
const bRev = Change.revisionForInst(b);
assert.equal(aRev, bRev);
});
});
describe('change.type()', function() {
it('CREATE', function() {
var change = new Change({
const change = new Change({
rev: this.revisionForModel,
});
assert.equal(Change.CREATE, change.type());
});
it('UPDATE', function() {
var change = new Change({
const change = new Change({
rev: this.revisionForModel,
prev: this.revisionForModel,
});
assert.equal(Change.UPDATE, change.type());
});
it('DELETE', function() {
var change = new Change({
const change = new Change({
prev: this.revisionForModel,
});
assert.equal(Change.DELETE, change.type());
});
it('UNKNOWN', function() {
var change = new Change();
const change = new Change();
assert.equal(Change.UNKNOWN, change.type());
});
});
describe('change.getModelCtor()', function() {
it('should get the correct model class', function() {
var change = new Change({
const change = new Change({
modelName: this.modelName,
});
@ -431,11 +431,11 @@ describe('Change', function() {
describe('change.equals(otherChange)', function() {
it('should return true when the change is equal', function() {
var change = new Change({
const change = new Change({
rev: this.revisionForModel,
});
var otherChange = new Change({
const otherChange = new Change({
rev: this.revisionForModel,
});
@ -443,13 +443,13 @@ describe('Change', function() {
});
it('should return true when both changes are deletes', function() {
var REV = 'foo';
var change = new Change({
const REV = 'foo';
const change = new Change({
rev: null,
prev: REV,
});
var otherChange = new Change({
const otherChange = new Change({
rev: undefined,
prev: REV,
});
@ -463,11 +463,11 @@ describe('Change', function() {
describe('change.isBasedOn(otherChange)', function() {
it('should return true when the change is based on the other', function() {
var change = new Change({
const change = new Change({
prev: this.revisionForModel,
});
var otherChange = new Change({
const otherChange = new Change({
rev: this.revisionForModel,
});
@ -485,7 +485,7 @@ describe('Change', function() {
});
it('should return delta and conflict lists', function(done) {
var remoteChanges = [
const remoteChanges = [
// an update => should result in a delta
{rev: 'foo2', prev: 'foo', modelName: this.modelName, modelId: 9, checkpoint: 1},
// no change => should not result in a delta / conflict
@ -505,7 +505,7 @@ describe('Change', function() {
});
it('should return delta and conflict lists - promise variant', function(done) {
var remoteChanges = [
const remoteChanges = [
// an update => should result in a delta
{rev: 'foo2', prev: 'foo', modelName: this.modelName, modelId: 9, checkpoint: 1},
// no change => should not result in a delta / conflict
@ -525,7 +525,7 @@ describe('Change', function() {
});
it('should set "prev" to local revision in non-conflicting delta', function(done) {
var updateRecord = {
const updateRecord = {
rev: 'foo-new',
prev: 'foo',
modelName: this.modelName,
@ -537,7 +537,7 @@ describe('Change', function() {
expect(diff.conflicts, 'conflicts').to.have.length(0);
expect(diff.deltas, 'deltas').to.have.length(1);
var actual = diff.deltas[0].toObject();
const actual = diff.deltas[0].toObject();
delete actual.id;
expect(actual).to.eql({
checkpoint: 2,
@ -552,7 +552,7 @@ describe('Change', function() {
});
it('should set "prev" to local revision in remote-only delta', function(done) {
var updateRecord = {
const updateRecord = {
rev: 'foo-new',
prev: 'foo-prev',
modelName: this.modelName,
@ -566,7 +566,7 @@ describe('Change', function() {
expect(diff.conflicts, 'conflicts').to.have.length(0);
expect(diff.deltas, 'deltas').to.have.length(1);
var actual = diff.deltas[0].toObject();
const actual = diff.deltas[0].toObject();
delete actual.id;
expect(actual).to.eql({
checkpoint: 2,
@ -581,7 +581,7 @@ describe('Change', function() {
});
it('should set "prev" to null for a new instance', function(done) {
var updateRecord = {
const updateRecord = {
rev: 'new-rev',
prev: 'new-prev',
modelName: this.modelName,
@ -594,7 +594,7 @@ describe('Change', function() {
expect(diff.conflicts).to.have.length(0);
expect(diff.deltas).to.have.length(1);
var actual = diff.deltas[0].toObject();
const actual = diff.deltas[0].toObject();
delete actual.id;
expect(actual).to.eql({
checkpoint: 2,
@ -614,7 +614,7 @@ describe('Change with with custom properties', function() {
let Change, TestModel;
beforeEach(function() {
let memory = loopback.createDataSource({
const memory = loopback.createDataSource({
connector: loopback.Memory,
});
@ -630,7 +630,7 @@ describe('Change with with custom properties', function() {
this.modelName = TestModel.modelName;
TestModel.prototype.fillCustomChangeProperties = function(change, cb) {
var inst = this;
const inst = this;
if (inst && inst.tenantId) {
change.tenantId = inst.tenantId;

View File

@ -1,19 +1,19 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var async = require('async');
var loopback = require('../');
var expect = require('./helpers/expect');
const async = require('async');
const loopback = require('../');
const expect = require('./helpers/expect');
var Checkpoint = loopback.Checkpoint.extend('TestCheckpoint');
const Checkpoint = loopback.Checkpoint.extend('TestCheckpoint');
describe('Checkpoint', function() {
describe('bumpLastSeq() and current()', function() {
beforeEach(function() {
var memory = loopback.createDataSource({
const memory = loopback.createDataSource({
connector: loopback.Memory,
});
Checkpoint.attachTo(memory);

View File

@ -1,16 +1,16 @@
// Copyright IBM Corp. 2016,2018. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var expect = require('chai').expect;
var loopback = require('..');
var supertest = require('supertest');
const expect = require('chai').expect;
const loopback = require('..');
const supertest = require('supertest');
describe('OptionsFromRemotingContext', function() {
var app, request, accessToken, userId, Product, actualOptions;
let app, request, accessToken, userId, Product, actualOptions;
beforeEach(setupAppAndRequest);
beforeEach(resetActualOptions);
@ -133,7 +133,7 @@ describe('OptionsFromRemotingContext', function() {
// despite the fact that under the hood a method on "modelTo" is called.
context('hasManyThrough', function() {
var Category, ThroughModel;
let Category, ThroughModel;
beforeEach(givenCategoryHasManyProductsThroughAnotherModel);
beforeEach(givenCategoryAndProduct);
@ -215,7 +215,7 @@ describe('OptionsFromRemotingContext', function() {
Category = app.registry.createModel(
'Category',
{name: String},
{forceId: false, replaceOnPUT: true}
{forceId: false, replaceOnPUT: true},
);
app.model(Category, {dataSource: 'db'});
@ -242,7 +242,7 @@ describe('OptionsFromRemotingContext', function() {
});
context('hasOne', function() {
var Category;
let Category;
beforeEach(givenCategoryHasOneProduct);
beforeEach(givenCategoryId1);
@ -288,7 +288,7 @@ describe('OptionsFromRemotingContext', function() {
Category = app.registry.createModel(
'Category',
{name: String},
{forceId: false, replaceOnPUT: true}
{forceId: false, replaceOnPUT: true},
);
app.model(Category, {dataSource: 'db'});
@ -313,7 +313,7 @@ describe('OptionsFromRemotingContext', function() {
});
context('belongsTo', function() {
var Category;
let Category;
beforeEach(givenCategoryBelongsToProduct);
@ -333,7 +333,7 @@ describe('OptionsFromRemotingContext', function() {
Category = app.registry.createModel(
'Category',
{name: String},
{forceId: false, replaceOnPUT: true}
{forceId: false, replaceOnPUT: true},
);
app.model(Category, {dataSource: 'db'});
@ -364,7 +364,7 @@ describe('OptionsFromRemotingContext', function() {
Product = app.registry.createModel(
'Product',
{name: String},
{forceId: false, replaceOnPUT: true}
{forceId: false, replaceOnPUT: true},
);
Product.createOptionsFromRemotingContext = function(ctx) {
@ -382,7 +382,7 @@ describe('OptionsFromRemotingContext', function() {
}
function observeOptionsBeforeSave() {
var Model = arguments[0] || Product;
const Model = arguments[0] || Product;
Model.observe('before save', function(ctx, next) {
actualOptions = ctx.options;
next();
@ -390,7 +390,7 @@ describe('OptionsFromRemotingContext', function() {
}
function observeOptionsBeforeDelete() {
var Model = arguments[0] || Product;
const Model = arguments[0] || Product;
Model.observe('before delete', function(ctx, next) {
actualOptions = ctx.options;
next();
@ -398,7 +398,7 @@ describe('OptionsFromRemotingContext', function() {
}
function observeOptionsOnAccess() {
var Model = arguments[0] || Product;
const Model = arguments[0] || Product;
Model.observe('access', function(ctx, next) {
actualOptions = ctx.options;
next();

View File

@ -1,14 +1,14 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var loopback = require('../');
const assert = require('assert');
const loopback = require('../');
describe('DataSource', function() {
var memory;
let memory;
beforeEach(function() {
memory = loopback.createDataSource({
@ -20,7 +20,7 @@ describe('DataSource', function() {
describe('dataSource.createModel(name, properties, settings)', function() {
it('Define a model and attach it to a `DataSource`', function() {
var Color = memory.createModel('color', {name: String});
const Color = memory.createModel('color', {name: String});
assert.isFunc(Color, 'find');
assert.isFunc(Color, 'findById');
assert.isFunc(Color, 'findOne');
@ -45,31 +45,31 @@ describe('DataSource', function() {
});
it('should honor settings.base', function() {
var Base = memory.createModel('base');
var Color = memory.createModel('color', {name: String}, {base: Base});
const Base = memory.createModel('base');
const Color = memory.createModel('color', {name: String}, {base: Base});
assert(Color.prototype instanceof Base);
assert.equal(Color.base, Base);
});
it('should use loopback.PersistedModel as the base for DBs', function() {
var Color = memory.createModel('color', {name: String});
const Color = memory.createModel('color', {name: String});
assert(Color.prototype instanceof loopback.PersistedModel);
assert.equal(Color.base, loopback.PersistedModel);
});
it('should use loopback.Model as the base for non DBs', function() {
// Mock up a non-DB connector
var Connector = function() {
const Connector = function() {
};
Connector.prototype.getTypes = function() {
return ['rest'];
};
var ds = loopback.createDataSource({
const ds = loopback.createDataSource({
connector: new Connector(),
});
var Color = ds.createModel('color', {name: String});
const Color = ds.createModel('color', {name: String});
assert(Color.prototype instanceof Color.registry.getModel('Model'));
assert.equal(Color.base.modelName, 'PersistedModel');
});
@ -77,7 +77,7 @@ describe('DataSource', function() {
describe.skip('PersistedModel Methods', function() {
it('List the enabled and disabled methods', function() {
var TestModel = loopback.PersistedModel.extend('TestPersistedModel');
const TestModel = loopback.PersistedModel.extend('TestPersistedModel');
TestModel.attachTo(loopback.memory());
// assert the defaults
@ -109,9 +109,9 @@ describe('DataSource', function() {
existsAndShared('reload', false);
function existsAndShared(Model, name, isRemoteEnabled, isProto) {
var scope = isProto ? Model.prototype : Model;
var fn = scope[name];
var actuallyEnabled = Model.getRemoteMethod(name);
const scope = isProto ? Model.prototype : Model;
const fn = scope[name];
const actuallyEnabled = Model.getRemoteMethod(name);
assert(fn, name + ' should be defined!');
assert(actuallyEnabled === isRemoteEnabled,
name + ' ' + (isRemoteEnabled ? 'should' : 'should not') +
@ -121,7 +121,7 @@ describe('DataSource', function() {
});
});
var assertValidDataSource = function(dataSource) {
function assertValidDataSource(dataSource) {
// has methods
assert.isFunc(dataSource, 'createModel');
assert.isFunc(dataSource, 'discoverModelDefinitions');
@ -130,7 +130,7 @@ var assertValidDataSource = function(dataSource) {
assert.isFunc(dataSource, 'disableRemote');
assert.isFunc(dataSource, 'defineOperation');
assert.isFunc(dataSource, 'operations');
};
}
assert.isFunc = function(obj, name) {
assert(obj, 'cannot assert function ' + name + ' on object that doesnt exist');

View File

@ -1,19 +1,19 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var path = require('path');
var loopback = require('../../');
var models = require('../fixtures/e2e/models');
var TestModel = models.TestModel;
var assert = require('assert');
const path = require('path');
const loopback = require('../../');
const models = require('../fixtures/e2e/models');
const TestModel = models.TestModel;
const assert = require('assert');
describe('RemoteConnector', function() {
before(function() {
// setup the remote connector
var ds = loopback.createDataSource({
const ds = loopback.createDataSource({
url: 'http://127.0.0.1:3000/api',
connector: loopback.Remote,
});
@ -33,7 +33,7 @@ describe('RemoteConnector', function() {
});
it('should be able to call save', function(done) {
var m = new TestModel({
const m = new TestModel({
foo: 'bar',
});
m.save(function(err, data) {

View File

@ -1,32 +1,32 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var path = require('path');
var loopback = require('../../');
var models = require('../fixtures/e2e/models');
var TestModel = models.TestModel;
var LocalTestModel = TestModel.extend('LocalTestModel', {}, {
const path = require('path');
const loopback = require('../../');
const models = require('../fixtures/e2e/models');
const TestModel = models.TestModel;
const LocalTestModel = TestModel.extend('LocalTestModel', {}, {
trackChanges: true,
});
var assert = require('assert');
const assert = require('assert');
describe('Replication', function() {
before(function() {
// setup the remote connector
var ds = loopback.createDataSource({
const ds = loopback.createDataSource({
url: 'http://127.0.0.1:3000/api',
connector: loopback.Remote,
});
TestModel.attachTo(ds);
var memory = loopback.memory();
const memory = loopback.memory();
LocalTestModel.attachTo(memory);
});
it('should replicate local data to the remote', function(done) {
var RANDOM = Math.random();
const RANDOM = Math.random();
LocalTestModel.create({
n: RANDOM,

View File

@ -1,38 +1,38 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../');
var MyEmail;
var assert = require('assert');
var MailConnector = require('../lib/connectors/mail');
const loopback = require('../');
let MyEmail;
const assert = require('assert');
const MailConnector = require('../lib/connectors/mail');
describe('Email connector', function() {
it('should set up SMTP', function() {
var connector = new MailConnector({transports: [
const connector = new MailConnector({transports: [
{type: 'smtp', service: 'gmail'},
]});
assert(connector.transportForName('smtp'));
});
it('should set up DIRECT', function() {
var connector = new MailConnector({transports: [
const connector = new MailConnector({transports: [
{type: 'direct', name: 'localhost'},
]});
assert(connector.transportForName('direct'));
});
it('should set up STUB', function() {
var connector = new MailConnector({transports: [
const connector = new MailConnector({transports: [
{type: 'stub', service: 'gmail'},
]});
assert(connector.transportForName('stub'));
});
it('should set up a single transport for SMTP', function() {
var connector = new MailConnector({transport:
const connector = new MailConnector({transport:
{type: 'smtp', service: 'gmail'},
});
@ -40,7 +40,7 @@ describe('Email connector', function() {
});
it('should set up a aliased transport for SMTP', function() {
var connector = new MailConnector({transport:
const connector = new MailConnector({transport:
{type: 'smtp', service: 'ses-us-east-1', alias: 'ses-smtp'},
});
@ -51,7 +51,7 @@ describe('Email connector', function() {
describe('Email and SMTP', function() {
beforeEach(function() {
MyEmail = loopback.Email.extend('my-email');
var ds = loopback.createDataSource('email', {
const ds = loopback.createDataSource('email', {
connector: loopback.Mail,
transports: [{type: 'STUB'}],
});
@ -65,7 +65,7 @@ describe('Email and SMTP', function() {
describe('MyEmail', function() {
it('MyEmail.send(options, callback)', function(done) {
var options = {
const options = {
to: 'to@to.com',
from: 'from@from.com',
subject: 'subject',
@ -84,7 +84,7 @@ describe('Email and SMTP', function() {
});
it('myEmail.send(callback)', function(done) {
var message = new MyEmail({
const message = new MyEmail({
to: 'to@to.com',
from: 'from@from.com',
subject: 'subject',

View File

@ -1,14 +1,14 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../');
var app;
var assert = require('assert');
var request = require('supertest');
var expect = require('./helpers/expect');
const loopback = require('../');
let app;
const assert = require('assert');
const request = require('supertest');
const expect = require('./helpers/expect');
describe('loopback.errorHandler(options)', function() {
it('should throw a descriptive error', function() {

View File

@ -1,20 +1,20 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../../..');
var boot = require('loopback-boot');
var app = module.exports = loopback({
const loopback = require('../../../..');
const boot = require('loopback-boot');
const app = module.exports = loopback({
localRegistry: true,
loadBuiltinModels: true,
});
var errorHandler = require('strong-error-handler');
const errorHandler = require('strong-error-handler');
boot(app, __dirname);
var apiPath = '/api';
const apiPath = '/api';
app.use(loopback.token({model: app.models.accessToken}));
app.use(apiPath, loopback.rest());

View File

@ -1,11 +1,11 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../../../index');
var PersistedModel = loopback.PersistedModel;
const loopback = require('../../../../index');
const PersistedModel = loopback.PersistedModel;
exports.TestModel = PersistedModel.extend('TestModel', {}, {
trackChanges: true,

View File

@ -1,15 +1,15 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../../../index');
var app = module.exports = loopback({localRegistry: true});
var models = require('./models');
var TestModel = models.TestModel;
const loopback = require('../../../../index');
const app = module.exports = loopback({localRegistry: true});
const models = require('./models');
const TestModel = models.TestModel;
var apiPath = '/api';
const apiPath = '/api';
app.use(apiPath, loopback.rest());
TestModel.attachTo(loopback.memory());

View File

@ -1,12 +1,12 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot');
var loopback = require('../../../../../index');
const boot = require('loopback-boot');
const loopback = require('../../../../../index');
var app = module.exports = loopback();
const app = module.exports = loopback();
boot(app, __dirname);
app.use(loopback.rest());

View File

@ -1,12 +1,12 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot');
var loopback = require('../../../../../index');
const boot = require('loopback-boot');
const loopback = require('../../../../../index');
var app = module.exports = loopback();
const app = module.exports = loopback();
boot(app, __dirname);
app.use(loopback.rest());

View File

@ -1,12 +1,12 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot');
var loopback = require('../../../../../index');
const boot = require('loopback-boot');
const loopback = require('../../../../../index');
var app = module.exports = loopback();
const app = module.exports = loopback();
boot(app, __dirname);
app.use(loopback.rest());

View File

@ -1,12 +1,12 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot');
var loopback = require('../../../../../index');
const boot = require('loopback-boot');
const loopback = require('../../../../../index');
var app = module.exports = loopback();
const app = module.exports = loopback();
boot(app, __dirname);
app.use(loopback.rest());

View File

@ -1,12 +1,12 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot');
var loopback = require('../../../../../index');
const boot = require('loopback-boot');
const loopback = require('../../../../../index');
var app = module.exports = loopback();
const app = module.exports = loopback();
boot(app, __dirname);
app.use(loopback.rest());

View File

@ -1,12 +1,12 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot');
var loopback = require('../../../../../index');
const boot = require('loopback-boot');
const loopback = require('../../../../../index');
var app = module.exports = loopback();
const app = module.exports = loopback();
boot(app, __dirname);
app.use(loopback.rest());

View File

@ -1,12 +1,12 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot');
var loopback = require('../../../../../index');
const boot = require('loopback-boot');
const loopback = require('../../../../../index');
var app = module.exports = loopback();
const app = module.exports = loopback();
boot(app, __dirname);
app.use(loopback.rest());

View File

@ -1,12 +1,12 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot');
var loopback = require('../../../../../index');
const boot = require('loopback-boot');
const loopback = require('../../../../../index');
var app = module.exports = loopback();
const app = module.exports = loopback();
boot(app, __dirname);
app.use(loopback.rest());

View File

@ -1,12 +1,12 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot');
var loopback = require('../../../../../index');
const boot = require('loopback-boot');
const loopback = require('../../../../../index');
var app = module.exports = loopback();
const app = module.exports = loopback();
boot(app, __dirname);
app.use(loopback.rest());

View File

@ -1,16 +1,16 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../../../index');
var boot = require('loopback-boot');
var app = module.exports = loopback({localRegistry: true});
var errorHandler = require('strong-error-handler');
const loopback = require('../../../../index');
const boot = require('loopback-boot');
const app = module.exports = loopback({localRegistry: true});
const errorHandler = require('strong-error-handler');
boot(app, __dirname);
var apiPath = '/api';
const apiPath = '/api';
app.use(apiPath, loopback.rest());
app.use(loopback.urlNotFound());
app.use(errorHandler());

View File

@ -1,21 +1,21 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../../../index');
var boot = require('loopback-boot');
var app = module.exports = loopback({
const loopback = require('../../../../index');
const boot = require('loopback-boot');
const app = module.exports = loopback({
localRegistry: true,
loadBuiltinModels: true,
});
var errorHandler = require('strong-error-handler');
const errorHandler = require('strong-error-handler');
app.enableAuth();
boot(app, __dirname);
app.use(loopback.token({model: app.models.AccessToken}));
var apiPath = '/api';
const apiPath = '/api';
app.use(apiPath, loopback.rest());
app.use(loopback.urlNotFound());
app.use(errorHandler());

View File

@ -1,19 +1,19 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var loopback = require('../');
var GeoPoint = loopback.GeoPoint;
const assert = require('assert');
const loopback = require('../');
const GeoPoint = loopback.GeoPoint;
describe('GeoPoint', function() {
describe('geoPoint.distanceTo(geoPoint, options)', function() {
it('Get the distance to another `GeoPoint`', function() {
var here = new GeoPoint({lat: 10, lng: 10});
var there = new GeoPoint({lat: 5, lng: 5});
var distance = here.distanceTo(there, {type: 'meters'});
const here = new GeoPoint({lat: 10, lng: 10});
const there = new GeoPoint({lat: 5, lng: 5});
const distance = here.distanceTo(there, {type: 'meters'});
assert.equal(Math.floor(distance), 782777);
});
@ -21,9 +21,9 @@ describe('GeoPoint', function() {
describe('GeoPoint.distanceBetween(a, b, options)', function() {
it('Get the distance between two points', function() {
var here = new GeoPoint({lat: 10, lng: 10});
var there = new GeoPoint({lat: 5, lng: 5});
var distance = GeoPoint.distanceBetween(here, there, {type: 'feet'});
const here = new GeoPoint({lat: 10, lng: 10});
const there = new GeoPoint({lat: 5, lng: 5});
const distance = GeoPoint.distanceBetween(here, there, {type: 'feet'});
assert.equal(Math.floor(distance), 2568169);
});
@ -31,32 +31,32 @@ describe('GeoPoint', function() {
describe('GeoPoint()', function() {
it('Create from string', function() {
var point = new GeoPoint('1.234,5.678');
const point = new GeoPoint('1.234,5.678');
assert.equal(point.lat, 1.234);
assert.equal(point.lng, 5.678);
var point2 = new GeoPoint('1.222, 5.333');
const point2 = new GeoPoint('1.222, 5.333');
assert.equal(point2.lat, 1.222);
assert.equal(point2.lng, 5.333);
var point3 = new GeoPoint('1.333, 5.111');
const point3 = new GeoPoint('1.333, 5.111');
assert.equal(point3.lat, 1.333);
assert.equal(point3.lng, 5.111);
});
it('Serialize as string', function() {
var str = '1.234,5.678';
var point = new GeoPoint(str);
const str = '1.234,5.678';
const point = new GeoPoint(str);
assert.equal(point.toString(), str);
});
it('Create from array', function() {
var point = new GeoPoint([5.555, 6.777]);
const point = new GeoPoint([5.555, 6.777]);
assert.equal(point.lat, 5.555);
assert.equal(point.lng, 6.777);
});
it('Create as Model property', function() {
var Model = loopback.createModel('geo-model', {
const Model = loopback.createModel('geo-model', {
geo: {type: 'GeoPoint'},
});
var m = new Model({
const m = new Model({
geo: '1.222,3.444',
});

View File

@ -1,11 +1,11 @@
// Copyright IBM Corp. 2016,2018. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var chai = require('chai');
const chai = require('chai');
chai.use(require('dirty-chai'));
chai.use(require('sinon-chai'));

View File

@ -1,24 +1,24 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var _describe = {};
var _it = {};
var _beforeEach = {};
var helpers = {
const _describe = {};
const _it = {};
const _beforeEach = {};
const helpers = {
describe: _describe,
it: _it,
beforeEach: _beforeEach,
};
module.exports = helpers;
var assert = require('assert');
var request = require('supertest');
var chai = require('chai');
var expect = chai.expect;
var sinon = require('sinon');
const assert = require('assert');
const request = require('supertest');
const chai = require('chai');
const expect = chai.expect;
const sinon = require('sinon');
chai.use(require('sinon-chai'));
_beforeEach.withApp = function(app) {
@ -29,7 +29,7 @@ _beforeEach.withApp = function(app) {
beforeEach(function(done) {
this.app = app;
var _request = this.request = request(app);
const _request = this.request = request(app);
this.post = _request.post;
this.get = _request.get;
this.put = _request.put;
@ -45,14 +45,14 @@ _beforeEach.withApp = function(app) {
};
_beforeEach.withArgs = function() {
var args = Array.prototype.slice.call(arguments, 0);
const args = Array.prototype.slice.call(arguments, 0);
beforeEach(function() {
this.args = args;
});
};
_beforeEach.givenModel = function(modelName, attrs, optionalHandler) {
var modelKey = modelName;
let modelKey = modelName;
if (typeof attrs === 'function') {
optionalHandler = attrs;
@ -66,9 +66,9 @@ _beforeEach.givenModel = function(modelName, attrs, optionalHandler) {
attrs = attrs || {};
beforeEach(function(done) {
var test = this;
var app = this.app;
var model = app.models[modelName];
const test = this;
const app = this.app;
const model = app.models[modelName];
app.set('remoting', {errorHandler: {debug: true, log: false}});
assert(model, 'cannot get model of name ' + modelName + ' from app.models');
@ -76,7 +76,7 @@ _beforeEach.givenModel = function(modelName, attrs, optionalHandler) {
' without attached dataSource');
assert(
typeof model.create === 'function',
modelName + ' does not have a create method'
modelName + ' does not have a create method',
);
model.create(attrs, function(err, result) {
@ -108,7 +108,7 @@ _beforeEach.givenUser = function(attrs, optionalHandler) {
_beforeEach.givenLoggedInUser = function(credentials, optionalHandler) {
_beforeEach.givenUser(credentials, function(done) {
var test = this;
const test = this;
this.user.constructor.login(credentials, function(err, token) {
if (err) {
done(err);
@ -121,7 +121,7 @@ _beforeEach.givenLoggedInUser = function(credentials, optionalHandler) {
});
afterEach(function(done) {
var test = this;
const test = this;
this.loggedInAccessToken.destroy(function(err) {
if (err) return done(err);
@ -146,7 +146,7 @@ _describe.whenCalledRemotely = function(verb, url, data, cb) {
data = null;
}
var urlStr = url;
let urlStr = url;
if (typeof url === 'function') {
urlStr = '/<dynamic>';
}
@ -159,11 +159,11 @@ _describe.whenCalledRemotely = function(verb, url, data, cb) {
this.remotely = true;
this.verb = verb.toUpperCase();
this.url = this.url || url;
var methodForVerb = verb.toLowerCase();
let methodForVerb = verb.toLowerCase();
if (methodForVerb === 'delete') methodForVerb = 'del';
if (this.request === undefined) {
var msg = 'App is not specified. ' +
const msg = 'App is not specified. ' +
'Please use lt.beforeEach.withApp to specify the app.';
throw new Error(msg);
}
@ -175,13 +175,13 @@ _describe.whenCalledRemotely = function(verb, url, data, cb) {
this.http.set('authorization', this.loggedInAccessToken.id);
}
if (data) {
var payload = data;
let payload = data;
if (typeof data === 'function')
payload = data.call(this);
this.http.send(payload);
}
this.req = this.http.req;
var test = this;
const test = this;
this.http.end(function(err) {
test.req = test.http.req;
test.res = test.http.response;
@ -236,7 +236,7 @@ _it.shouldBeAllowed = function() {
_it.shouldBeDenied = function() {
it('should not be allowed', function() {
assert(this.res);
var expectedStatus = this.aclErrorStatus ||
const expectedStatus = this.aclErrorStatus ||
this.app && this.app.get('aclErrorStatus') ||
401;
expect(this.res.statusCode).to.equal(expectedStatus);

View File

@ -1,11 +1,11 @@
// Copyright IBM Corp. 2017,2018. All Rights Reserved.
// Copyright IBM Corp. 2017,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var env = process.env;
const env = process.env;
// delete any user-provided language settings
delete env.LC_ALL;

View File

@ -1,24 +1,24 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var loopback = require('../');
var request = require('supertest');
const assert = require('assert');
const loopback = require('../');
const request = require('supertest');
describe('hidden properties', function() {
beforeEach(function(done) {
var app = this.app = loopback();
var Product = this.Product = loopback.PersistedModel.extend(
const app = this.app = loopback();
const Product = this.Product = loopback.PersistedModel.extend(
'product',
{},
{hidden: ['secret']}
{hidden: ['secret']},
);
Product.attachTo(loopback.memory());
var Category = this.Category = loopback.PersistedModel.extend('category');
const Category = this.Category = loopback.PersistedModel.extend('category');
Category.attachTo(loopback.memory());
Category.hasMany(Product);
@ -37,7 +37,7 @@ describe('hidden properties', function() {
});
afterEach(function(done) {
var Product = this.Product;
const Product = this.Product;
this.Category.destroyAll(function() {
Product.destroyAll(done);
});
@ -51,7 +51,7 @@ describe('hidden properties', function() {
.end(function(err, res) {
if (err) return done(err);
var product = res.body[0];
const product = res.body[0];
assert.equal(product.secret, undefined);
done();
@ -59,7 +59,7 @@ describe('hidden properties', function() {
});
it('should hide a property of nested models', function(done) {
var app = this.app;
const app = this.app;
request(app)
.get('/categories?filter[include]=products')
.expect('Content-Type', /json/)
@ -67,8 +67,8 @@ describe('hidden properties', function() {
.end(function(err, res) {
if (err) return done(err);
var category = res.body[0];
var product = category.products[0];
const category = res.body[0];
const product = category.products[0];
assert.equal(product.secret, undefined);
done();

View File

@ -1,18 +1,18 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var expect = require('./helpers/expect');
var loopback = require('../');
var net = require('net');
const expect = require('./helpers/expect');
const loopback = require('../');
const net = require('net');
describe('loopback application', function() {
it('pauses request stream during authentication', function(done) {
// This test reproduces the issue reported in
// https://github.com/strongloop/loopback-storage-service/issues/7
var app = loopback();
const app = loopback();
setupAppWithStreamingMethod();
app.listen(0, function() {
@ -29,7 +29,7 @@ describe('loopback application', function() {
expect(res).to.match(/\nX$/);
done();
}
},
);
});
@ -37,7 +37,7 @@ describe('loopback application', function() {
app.dataSource('db', {
connector: loopback.Memory,
});
var db = app.datasources.db;
const db = app.datasources.db;
loopback.User.attachTo(db);
loopback.AccessToken.attachTo(db);
@ -45,10 +45,10 @@ describe('loopback application', function() {
loopback.ACL.attachTo(db);
loopback.User.hasMany(loopback.AccessToken, {as: 'accessTokens'});
var Streamer = app.registry.createModel('Streamer');
const Streamer = app.registry.createModel('Streamer');
app.model(Streamer, {dataSource: 'db'});
Streamer.read = function(req, res, cb) {
var body = new Buffer(0);
let body = new Buffer(0);
req.on('data', function(chunk) {
body += chunk;
});
@ -75,8 +75,8 @@ describe('loopback application', function() {
}
function sendHttpRequestInOnePacket(port, reqString, cb) {
var socket = net.createConnection(port);
var response = new Buffer(0);
const socket = net.createConnection(port);
let response = new Buffer(0);
socket.on('data', function(chunk) {
response += chunk;

View File

@ -1,14 +1,39 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
const isDocker = require('is-docker');
const which = require('which');
// Karma configuration
// http://karma-runner.github.io/0.12/config/configuration-file.html
'use strict';
module.exports = function(config) {
// see https://github.com/docker/for-linux/issues/496
const disableChromeSandbox = isDocker() && !process.env.TRAVIS;
if (disableChromeSandbox) {
console.log('!! Disabling Chrome sandbox to support un-privileged Docker !!');
}
const hasChromium =
which.sync('chromium-browser', {nothrow: true}) ||
which.sync('chromium', {nothrow: true});
config.set({
customLaunchers: {
ChromeDocker: {
// cis-jenkins build server does not provide Chrome, only Chromium
base: hasChromium ? 'ChromiumHeadless' : 'ChromeHeadless',
// We must disable the Chrome sandbox when running Chrome inside Docker
// (Chrome's sandbox needs more permissions than Docker allows by default)
// See https://github.com/docker/for-linux/issues/496
flags: disableChromeSandbox ? ['--no-sandbox'] : [],
},
},
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
@ -64,7 +89,6 @@ module.exports = function(config) {
'karma-browserify',
'karma-es6-shim',
'karma-mocha',
'karma-phantomjs-launcher',
'karma-chrome-launcher',
'karma-junit-reporter',
],
@ -104,27 +128,18 @@ module.exports = function(config) {
'superagent',
'supertest',
],
transform: [
['babelify', {
presets: [
['es2015', {
// Disable transform-es2015-modules-commonjs which adds
// "use strict" to all files, even those that don't work
// in strict mode
// (e.g. chai, loopback-datasource-juggler, etc.)
modules: false,
}],
],
// By default, browserify does not transform node_modules
// As a result, our dependencies like strong-remoting and juggler
// are kept in original ES6 form that does not work in PhantomJS
global: true,
// Prevent SyntaxError in strong-task-emitter:
// strong-task-emitter/lib/task.js (83:4):
// arguments is a reserved word in strict mode
ignore: /node_modules\/(strong-task-emitter)\//,
}],
],
packageFilter: function(pkg, dir) {
// async@3 (used e.g. by loopback-connector) is specifying custom
// browserify config, in particular it wants to apply transformation
// `babelify`. We don't have `babelify` installed because we are
// testing using latest Chrome and thus don't need any transpilation.
// Let's remove the browserify config from the package and force
// browserify to use our config instead.
if (pkg.name === 'async') {
delete pkg.browserify;
}
return pkg;
},
debug: true,
// noParse: ['jquery'],
watch: true,

View File

@ -1,18 +1,18 @@
// Copyright IBM Corp. 2016,2018. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var expect = require('./helpers/expect');
var http = require('http');
var loopback = require('..');
var supertest = require('supertest');
const expect = require('./helpers/expect');
const http = require('http');
const loopback = require('..');
const supertest = require('supertest');
var AN_OBJECT_VALUE = {name: 'an-object'};
const AN_OBJECT_VALUE = {name: 'an-object'};
describe('KeyValueModel', function() {
var request, app, CacheItem;
let request, app, CacheItem;
beforeEach(setupAppAndCacheItem);
describe('REST API', function() {
@ -156,7 +156,7 @@ describe('KeyValueModel', function() {
app.model(CacheItem, {dataSource: 'kv'});
}
var _server, _requestHandler; // eslint-disable-line one-var
let _server, _requestHandler; // eslint-disable-line one-var
function setupSharedHttpServer(done) {
_server = http.createServer(function(req, res) {
app(req, res);

View File

@ -1,20 +1,20 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var it = require('./util/it');
var describe = require('./util/describe');
var Domain = require('domain');
var EventEmitter = require('events').EventEmitter;
var loopback = require('../');
var expect = require('./helpers/expect');
var assert = require('assert');
const it = require('./util/it');
const describe = require('./util/describe');
const Domain = require('domain');
const EventEmitter = require('events').EventEmitter;
const loopback = require('../');
const expect = require('./helpers/expect');
const assert = require('assert');
describe('loopback', function() {
var nameCounter = 0;
var uniqueModelName;
let nameCounter = 0;
let uniqueModelName;
beforeEach(function() {
uniqueModelName = 'TestModel-' + (++nameCounter);
@ -27,7 +27,7 @@ describe('loopback', function() {
});
it.onServer('includes `faviconFile`', function() {
var file = loopback.faviconFile;
const file = loopback.faviconFile;
expect(file, 'faviconFile').to.not.equal(undefined);
expect(require('fs').existsSync(loopback.faviconFile), 'file exists')
.to.equal(true);
@ -38,7 +38,7 @@ describe('loopback', function() {
});
it.onServer('exports all expected properties', function() {
var EXPECTED = [
const EXPECTED = [
'ACL',
'AccessToken',
'Application',
@ -98,7 +98,7 @@ describe('loopback', function() {
'version',
];
var actual = Object.getOwnPropertyNames(loopback);
const actual = Object.getOwnPropertyNames(loopback);
actual.sort();
expect(actual).to.include.members(EXPECTED);
});
@ -106,17 +106,17 @@ describe('loopback', function() {
describe('loopback(options)', function() {
it('supports localRegistry:true', function() {
var app = loopback({localRegistry: true});
const app = loopback({localRegistry: true});
expect(app.registry).to.not.equal(loopback.registry);
});
it('does not load builtin models into the local registry', function() {
var app = loopback({localRegistry: true});
const app = loopback({localRegistry: true});
expect(app.registry.findModel('User')).to.equal(undefined);
});
it('supports loadBuiltinModels:true', function() {
var app = loopback({localRegistry: true, loadBuiltinModels: true});
const app = loopback({localRegistry: true, loadBuiltinModels: true});
expect(app.registry.findModel('User'))
.to.have.property('modelName', 'User');
});
@ -124,7 +124,7 @@ describe('loopback', function() {
describe('loopback.createDataSource(options)', function() {
it('Create a data source with a connector.', function() {
var dataSource = loopback.createDataSource({
const dataSource = loopback.createDataSource({
connector: loopback.Memory,
});
assert(dataSource.connector);
@ -133,24 +133,24 @@ describe('loopback', function() {
describe('data source created by loopback', function() {
it('should create model extending Model by default', function() {
var dataSource = loopback.createDataSource({
const dataSource = loopback.createDataSource({
connector: loopback.Memory,
});
var m1 = dataSource.createModel('m1', {});
const m1 = dataSource.createModel('m1', {});
assert(m1.prototype instanceof loopback.Model);
});
});
describe('model created by loopback', function() {
it('should extend from Model by default', function() {
var m1 = loopback.createModel('m1', {});
const m1 = loopback.createModel('m1', {});
assert(m1.prototype instanceof loopback.Model);
});
});
describe('loopback.remoteMethod(Model, fn, [options]);', function() {
it('Setup a remote method.', function() {
var Product = loopback.createModel('product', {price: Number});
const Product = loopback.createModel('product', {price: Number});
Product.stats = function(fn) {
// ...
@ -161,7 +161,7 @@ describe('loopback', function() {
{
returns: {arg: 'stats', type: 'array'},
http: {path: '/info', verb: 'get'},
}
},
);
assert.equal(Product.stats.returns.arg, 'stats');
@ -175,12 +175,12 @@ describe('loopback', function() {
describe('loopback.createModel(name, properties, options)', function() {
describe('options.base', function() {
it('should extend from options.base', function() {
var MyModel = loopback.createModel('MyModel', {}, {
const MyModel = loopback.createModel('MyModel', {}, {
foo: {
bar: 'bat',
},
});
var MyCustomModel = loopback.createModel('MyCustomModel', {}, {
const MyCustomModel = loopback.createModel('MyCustomModel', {}, {
base: 'MyModel',
foo: {
bat: 'baz',
@ -194,12 +194,12 @@ describe('loopback', function() {
describe('loopback.getModel and getModelByType', function() {
it('should be able to get model by name', function() {
var MyModel = loopback.createModel('MyModel', {}, {
const MyModel = loopback.createModel('MyModel', {}, {
foo: {
bar: 'bat',
},
});
var MyCustomModel = loopback.createModel('MyCustomModel', {}, {
const MyCustomModel = loopback.createModel('MyCustomModel', {}, {
base: 'MyModel',
foo: {
bat: 'baz',
@ -211,12 +211,12 @@ describe('loopback', function() {
assert(loopback.getModel(MyModel) === MyModel);
});
it('should be able to get model by type', function() {
var MyModel = loopback.createModel('MyModel', {}, {
const MyModel = loopback.createModel('MyModel', {}, {
foo: {
bar: 'bat',
},
});
var MyCustomModel = loopback.createModel('MyCustomModel', {}, {
const MyCustomModel = loopback.createModel('MyCustomModel', {}, {
base: 'MyModel',
foo: {
bat: 'baz',
@ -233,7 +233,7 @@ describe('loopback', function() {
});
it('configures remote methods', function() {
var TestModel = loopback.createModel(uniqueModelName, {}, {
const TestModel = loopback.createModel(uniqueModelName, {}, {
methods: {
staticMethod: {
isStatic: true,
@ -246,7 +246,7 @@ describe('loopback', function() {
},
});
var methodNames = TestModel.sharedClass.methods().map(function(m) {
const methodNames = TestModel.sharedClass.methods().map(function(m) {
return m.stringName.replace(/^[^.]+\./, ''); // drop the class name
});
@ -259,7 +259,7 @@ describe('loopback', function() {
describe('loopback.createModel(config)', function() {
it('creates the model', function() {
var model = loopback.createModel({
const model = loopback.createModel({
name: uniqueModelName,
});
@ -267,7 +267,7 @@ describe('loopback', function() {
});
it('interprets extra first-level keys as options', function() {
var model = loopback.createModel({
const model = loopback.createModel({
name: uniqueModelName,
base: 'User',
});
@ -276,7 +276,7 @@ describe('loopback', function() {
});
it('prefers config.options.key over config.key', function() {
var model = loopback.createModel({
const model = loopback.createModel({
name: uniqueModelName,
base: 'User',
options: {
@ -290,7 +290,7 @@ describe('loopback', function() {
describe('loopback.configureModel(ModelCtor, config)', function() {
it('adds new relations', function() {
var model = loopback.Model.extend(uniqueModelName);
const model = loopback.Model.extend(uniqueModelName);
loopback.configureModel(model, {
dataSource: null,
@ -306,7 +306,7 @@ describe('loopback', function() {
});
it('updates existing relations', function() {
var model = loopback.Model.extend(uniqueModelName, {}, {
const model = loopback.Model.extend(uniqueModelName, {}, {
relations: {
owner: {
type: 'belongsTo',
@ -331,8 +331,8 @@ describe('loopback', function() {
});
it('updates relations before attaching to a dataSource', function() {
var db = loopback.createDataSource({connector: loopback.Memory});
var model = loopback.Model.extend(uniqueModelName);
const db = loopback.createDataSource({connector: loopback.Memory});
const model = loopback.Model.extend(uniqueModelName);
// This test used to work because User model was already attached
// by other tests via `loopback.autoAttach()`
@ -352,13 +352,13 @@ describe('loopback', function() {
},
});
var owner = model.prototype.owner;
const owner = model.prototype.owner;
expect(owner, 'model.prototype.owner').to.be.a('function');
expect(owner._targetClass).to.equal('User');
});
it('adds new acls', function() {
var model = loopback.Model.extend(uniqueModelName, {}, {
const model = loopback.Model.extend(uniqueModelName, {}, {
acls: [
{
property: 'find',
@ -402,7 +402,7 @@ describe('loopback', function() {
});
it('updates existing acls', function() {
var model = loopback.Model.extend(uniqueModelName, {}, {
const model = loopback.Model.extend(uniqueModelName, {}, {
acls: [
{
property: 'find',
@ -439,12 +439,12 @@ describe('loopback', function() {
});
it('updates existing settings', function() {
var model = loopback.Model.extend(uniqueModelName, {}, {
const model = loopback.Model.extend(uniqueModelName, {}, {
ttl: 10,
emailVerificationRequired: false,
});
var baseName = model.settings.base.name;
const baseName = model.settings.base.name;
loopback.configureModel(model, {
dataSource: null,
@ -465,7 +465,7 @@ describe('loopback', function() {
});
it('configures remote methods', function() {
var TestModel = loopback.createModel(uniqueModelName);
const TestModel = loopback.createModel(uniqueModelName);
loopback.configureModel(TestModel, {
dataSource: null,
methods: {
@ -480,7 +480,7 @@ describe('loopback', function() {
},
});
var methodNames = TestModel.sharedClass.methods().map(function(m) {
const methodNames = TestModel.sharedClass.methods().map(function(m) {
return m.stringName.replace(/^[^.]+\./, ''); // drop the class name
});
@ -493,14 +493,14 @@ describe('loopback', function() {
describe('loopback object', function() {
it('inherits properties from express', function() {
var express = require('express');
for (var i in express) {
const express = require('express');
for (const i in express) {
expect(loopback).to.have.property(i, express[i]);
}
});
it('exports all built-in models', function() {
var expectedModelNames = [
const expectedModelNames = [
'Email',
'User',
'Application',
@ -530,7 +530,7 @@ describe('loopback', function() {
}
it('treats method names that don\'t start with "prototype." as "isStatic:true"', function() {
var TestModel = loopback.createModel(uniqueModelName);
const TestModel = loopback.createModel(uniqueModelName);
loopback.configureModel(TestModel, {
dataSource: null,
methods: {
@ -540,13 +540,13 @@ describe('loopback', function() {
},
});
var methodNames = getAllMethodNamesWithoutClassName(TestModel);
const methodNames = getAllMethodNamesWithoutClassName(TestModel);
expect(methodNames).to.include('staticMethod');
});
it('treats method names starting with "prototype." as "isStatic:false"', function() {
var TestModel = loopback.createModel(uniqueModelName);
const TestModel = loopback.createModel(uniqueModelName);
loopback.configureModel(TestModel, {
dataSource: null,
methods: {
@ -556,13 +556,15 @@ describe('loopback', function() {
},
});
var methodNames = getAllMethodNamesWithoutClassName(TestModel);
const methodNames = getAllMethodNamesWithoutClassName(TestModel);
expect(methodNames).to.include('prototype.instanceMethod');
});
it('throws an error when "isStatic:true" and method name starts with "prototype."', function() {
var TestModel = loopback.createModel(uniqueModelName);
// Skip this test in browsers because strong-globalize is not removing
// `{{` and `}}` control characters from the string.
it.onServer('throws when "isStatic:true" and method name starts with "prototype."', function() {
const TestModel = loopback.createModel(uniqueModelName);
expect(function() {
loopback.configureModel(TestModel, {
dataSource: null,
@ -573,12 +575,12 @@ describe('loopback', function() {
},
},
});
}).to.throw(Error, new Error('Remoting metadata for' + TestModel.modelName +
' "isStatic" does not match new method name-based style.'));
}).to.throw(Error, 'Remoting metadata for ' + TestModel.modelName +
'.prototype.instanceMethod "isStatic" does not match new method name-based style.');
});
it('use "isStatic:true" if method name does not start with "prototype."', function() {
var TestModel = loopback.createModel(uniqueModelName);
const TestModel = loopback.createModel(uniqueModelName);
loopback.configureModel(TestModel, {
dataSource: null,
methods: {
@ -589,13 +591,13 @@ describe('loopback', function() {
},
});
var methodNames = getAllMethodNamesWithoutClassName(TestModel);
const methodNames = getAllMethodNamesWithoutClassName(TestModel);
expect(methodNames).to.include('staticMethod');
});
it('use "isStatic:false" if method name starts with "prototype."', function() {
var TestModel = loopback.createModel(uniqueModelName);
const TestModel = loopback.createModel(uniqueModelName);
loopback.configureModel(TestModel, {
dataSource: null,
methods: {
@ -606,19 +608,19 @@ describe('loopback', function() {
},
});
var methodNames = getAllMethodNamesWithoutClassName(TestModel);
const methodNames = getAllMethodNamesWithoutClassName(TestModel);
expect(methodNames).to.include('prototype.instanceMethod');
});
});
describe('Remote method inheritance', function() {
var app;
let app;
beforeEach(setupLoopback);
it('inherits remote methods defined via createModel', function() {
var Base = app.registry.createModel('Base', {}, {
const Base = app.registry.createModel('Base', {}, {
methods: {
greet: {
http: {path: '/greet'},
@ -626,7 +628,7 @@ describe('loopback', function() {
},
});
var MyCustomModel = app.registry.createModel('MyCustomModel', {}, {
const MyCustomModel = app.registry.createModel('MyCustomModel', {}, {
base: 'Base',
methods: {
hello: {
@ -634,14 +636,14 @@ describe('loopback', function() {
},
},
});
var methodNames = getAllMethodNamesWithoutClassName(MyCustomModel);
const methodNames = getAllMethodNamesWithoutClassName(MyCustomModel);
expect(methodNames).to.include('greet');
expect(methodNames).to.include('hello');
});
it('same remote method with different metadata should override parent', function() {
var Base = app.registry.createModel('Base', {}, {
const Base = app.registry.createModel('Base', {}, {
methods: {
greet: {
http: {path: '/greet'},
@ -649,7 +651,7 @@ describe('loopback', function() {
},
});
var MyCustomModel = app.registry.createModel('MyCustomModel', {}, {
const MyCustomModel = app.registry.createModel('MyCustomModel', {}, {
base: 'Base',
methods: {
greet: {
@ -657,9 +659,9 @@ describe('loopback', function() {
},
},
});
var methodNames = getAllMethodNamesWithoutClassName(MyCustomModel);
var baseMethod = Base.sharedClass.findMethodByName('greet');
var customMethod = MyCustomModel.sharedClass.findMethodByName('greet');
const methodNames = getAllMethodNamesWithoutClassName(MyCustomModel);
const baseMethod = Base.sharedClass.findMethodByName('greet');
const customMethod = MyCustomModel.sharedClass.findMethodByName('greet');
// Base Method
expect(baseMethod.http).to.eql({path: '/greet'});
@ -674,7 +676,7 @@ describe('loopback', function() {
});
it('does not inherit remote methods defined via configureModel', function() {
var Base = app.registry.createModel('Base');
const Base = app.registry.createModel('Base');
app.registry.configureModel(Base, {
dataSource: null,
methods: {
@ -684,7 +686,7 @@ describe('loopback', function() {
},
});
var MyCustomModel = app.registry.createModel('MyCustomModel', {}, {
const MyCustomModel = app.registry.createModel('MyCustomModel', {}, {
base: 'Base',
methods: {
hello: {
@ -692,7 +694,7 @@ describe('loopback', function() {
},
},
});
var methodNames = getAllMethodNamesWithoutClassName(MyCustomModel);
const methodNames = getAllMethodNamesWithoutClassName(MyCustomModel);
expect(methodNames).to.not.include('greet');
expect(methodNames).to.include('hello');
@ -700,8 +702,8 @@ describe('loopback', function() {
it('does not inherit remote methods defined via configureModel after child model ' +
'was created', function() {
var Base = app.registry.createModel('Base');
var MyCustomModel = app.registry.createModel('MyCustomModel', {}, {
const Base = app.registry.createModel('Base');
const MyCustomModel = app.registry.createModel('MyCustomModel', {}, {
base: 'Base',
});
@ -722,8 +724,8 @@ describe('loopback', function() {
},
},
});
var baseMethodNames = getAllMethodNamesWithoutClassName(Base);
var methodNames = getAllMethodNamesWithoutClassName(MyCustomModel);
const baseMethodNames = getAllMethodNamesWithoutClassName(Base);
const methodNames = getAllMethodNamesWithoutClassName(MyCustomModel);
expect(baseMethodNames).to.include('greet');
expect(methodNames).to.not.include('greet');
@ -742,12 +744,12 @@ describe('loopback', function() {
});
describe('Hiding shared methods', function() {
var app;
let app;
beforeEach(setupLoopback);
it('hides remote methods using fixed method names', function() {
var TestModel = app.registry.createModel(uniqueModelName);
const TestModel = app.registry.createModel(uniqueModelName);
app.model(TestModel, {
dataSource: null,
methods: {
@ -765,7 +767,7 @@ describe('loopback', function() {
},
});
var publicMethods = getSharedMethods(TestModel);
const publicMethods = getSharedMethods(TestModel);
expect(publicMethods).not.to.include.members([
'staticMethod',
@ -773,7 +775,7 @@ describe('loopback', function() {
});
it('hides remote methods using a glob pattern', function() {
var TestModel = app.registry.createModel(uniqueModelName);
const TestModel = app.registry.createModel(uniqueModelName);
app.model(TestModel, {
dataSource: null,
methods: {
@ -795,7 +797,7 @@ describe('loopback', function() {
},
});
var publicMethods = getSharedMethods(TestModel);
const publicMethods = getSharedMethods(TestModel);
expect(publicMethods).to.include.members([
'staticMethod',
@ -806,7 +808,7 @@ describe('loopback', function() {
});
it('hides all remote methods using *', function() {
var TestModel = app.registry.createModel(uniqueModelName);
const TestModel = app.registry.createModel(uniqueModelName);
app.model(TestModel, {
dataSource: null,
methods: {
@ -828,7 +830,7 @@ describe('loopback', function() {
},
});
var publicMethods = getSharedMethods(TestModel);
const publicMethods = getSharedMethods(TestModel);
expect(publicMethods).to.be.empty();
});

View File

@ -1,17 +1,17 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var loopback = require('../');
const assert = require('assert');
const loopback = require('../');
describe('Memory Connector', function() {
it('Create a model using the memory connector', function(done) {
// use the built in memory function
// to create a memory data source
var memory = loopback.memory();
let memory = loopback.memory();
// or create it using the standard
// data source creation api
@ -21,12 +21,12 @@ describe('Memory Connector', function() {
// create a model using the
// memory data source
var properties = {
const properties = {
name: String,
price: Number,
};
var Product = memory.createModel('product', properties);
const Product = memory.createModel('product', properties);
Product.create([
{name: 'apple', price: 0.79},

View File

@ -1,15 +1,15 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require(('../'));
var assert = require('assert');
var Application = loopback.Application;
const loopback = require(('../'));
const assert = require('assert');
const Application = loopback.Application;
describe('Application', function() {
var registeredApp = null;
let registeredApp = null;
before(function attachToMemory() {
Application.attachTo(loopback.memory());
@ -18,7 +18,7 @@ describe('Application', function() {
it('honors `application.register` - callback variant', function(done) {
Application.register('rfeng', 'MyTestApp',
{description: 'My test application'}, function(err, result) {
var app = result;
const app = result;
assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyTestApp');
assert.equal(app.description, 'My test application');
@ -31,7 +31,7 @@ describe('Application', function() {
Application.register('rfeng', 'MyTestApp',
{description: 'My test application'})
.then(function(result) {
var app = result;
const app = result;
assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyTestApp');
assert.equal(app.description, 'My test application');
@ -47,7 +47,7 @@ describe('Application', function() {
Application.create({owner: 'rfeng',
name: 'MyApp1',
description: 'My first mobile application'}, function(err, result) {
var app = result;
const app = result;
assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyApp1');
assert.equal(app.description, 'My first mobile application');
@ -90,7 +90,7 @@ describe('Application', function() {
},
}},
function(err, result) {
var app = result;
const app = result;
assert.deepEqual(app.pushSettings.toObject(), {
apns: {
production: false,
@ -119,7 +119,7 @@ describe('Application', function() {
beforeEach(function(done) {
Application.register('rfeng', 'MyApp2',
{description: 'My second mobile application'}, function(err, result) {
var app = result;
const app = result;
assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyApp2');
assert.equal(app.description, 'My second mobile application');
@ -138,7 +138,7 @@ describe('Application', function() {
it('Reset keys', function(done) {
Application.resetKeys(registeredApp.id, function(err, result) {
var app = result;
const app = result;
assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyApp2');
assert.equal(app.description, 'My second mobile application');
@ -165,7 +165,7 @@ describe('Application', function() {
it('Reset keys - promise variant', function(done) {
Application.resetKeys(registeredApp.id)
.then(function(result) {
var app = result;
const app = result;
assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyApp2');
assert.equal(app.description, 'My second mobile application');
@ -194,7 +194,7 @@ describe('Application', function() {
it('Reset keys without create a new instance', function(done) {
Application.resetKeys(registeredApp.id, function(err, result) {
var app = result;
const app = result;
assert(app.id);
assert(app.id === registeredApp.id);
registeredApp = app;
@ -206,7 +206,7 @@ describe('Application', function() {
it('Reset keys without create a new instance - promise variant', function(done) {
Application.resetKeys(registeredApp.id)
.then(function(result) {
var app = result;
const app = result;
assert(app.id);
assert(app.id === registeredApp.id);
registeredApp = app;
@ -307,12 +307,12 @@ describe('Application', function() {
describe('Application subclass', function() {
it('should use subclass model name', function(done) {
var MyApp = Application.extend('MyApp');
var ds = loopback.createDataSource({connector: loopback.Memory});
const MyApp = Application.extend('MyApp');
const ds = loopback.createDataSource({connector: loopback.Memory});
MyApp.attachTo(ds);
MyApp.register('rfeng', 'MyApp123',
{description: 'My 123 mobile application'}, function(err, result) {
var app = result;
const app = result;
assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyApp123');
assert.equal(app.description, 'My 123 mobile application');

View File

@ -1,21 +1,21 @@
// Copyright IBM Corp. 2013,2018. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var async = require('async');
var describe = require('./util/describe');
var loopback = require('../');
var ACL = loopback.ACL;
var defineModelTestsWithDataSource = require('./util/model-tests');
var PersistedModel = loopback.PersistedModel;
var Promise = require('bluebird');
var TaskEmitter = require('strong-task-emitter');
var request = require('supertest');
const assert = require('assert');
const async = require('async');
const describe = require('./util/describe');
const loopback = require('../');
const ACL = loopback.ACL;
const defineModelTestsWithDataSource = require('./util/model-tests');
const PersistedModel = loopback.PersistedModel;
const Promise = require('bluebird');
const TaskEmitter = require('strong-task-emitter');
const request = require('supertest');
var expect = require('./helpers/expect');
const expect = require('./helpers/expect');
describe('Model / PersistedModel', function() {
defineModelTestsWithDataSource({
@ -26,7 +26,7 @@ describe('Model / PersistedModel', function() {
describe('Model.validatesUniquenessOf(property, options)', function() {
it('Ensure the value for `property` is unique', function(done) {
var User = PersistedModel.extend('ValidatedUser', {
const User = PersistedModel.extend('ValidatedUser', {
'first': String,
'last': String,
'age': Number,
@ -36,7 +36,7 @@ describe('Model / PersistedModel', function() {
'email': String,
});
var dataSource = loopback.createDataSource({
const dataSource = loopback.createDataSource({
connector: loopback.Memory,
});
@ -44,8 +44,8 @@ describe('Model / PersistedModel', function() {
User.validatesUniquenessOf('email', {message: 'email is not unique'});
var joe = new User({email: 'joe@joe.com'});
var joe2 = new User({email: 'joe@joe.com'});
const joe = new User({email: 'joe@joe.com'});
const joe2 = new User({email: 'joe@joe.com'});
joe.save(function() {
joe2.save(function(err) {
@ -60,8 +60,8 @@ describe('Model / PersistedModel', function() {
describe('Model.attachTo(dataSource)', function() {
it('Attach a model to a [DataSource](#data-source)', function() {
var MyModel = loopback.createModel('my-model', {name: String});
var dataSource = loopback.createDataSource({
const MyModel = loopback.createModel('my-model', {name: String});
const dataSource = loopback.createDataSource({
connector: loopback.Memory,
});
@ -76,7 +76,7 @@ describe('Model / PersistedModel', function() {
});
describe.onServer('Remote Methods', function() {
var User, Post, dataSource, app;
let User, Post, dataSource, app;
beforeEach(function() {
app = loopback({localRegistry: true, loadBuiltinModels: true});
@ -132,7 +132,7 @@ describe.onServer('Remote Methods', function() {
describe('Model.create(data, callback)', function() {
it('creates model', function(done) {
var anObject = {first: 'June'};
const anObject = {first: 'June'};
request(app)
.post('/users')
// sends an object
@ -149,7 +149,7 @@ describe.onServer('Remote Methods', function() {
// batch create must be tested with a remote request because there are
// coercion being done on strong-remoting side
it('creates array of models', function(done) {
var arrayOfObjects = [
const arrayOfObjects = [
{first: 'John'}, {first: 'Jane'},
];
request(app)
@ -161,8 +161,8 @@ describe.onServer('Remote Methods', function() {
.end(function(err, res) {
if (err) return done(err);
expect(res.body.length).to.eql(2);
expect(res.body).to.have.deep.property('[0].first', 'John');
expect(res.body).to.have.deep.property('[1].first', 'Jane');
expect(res.body).to.have.nested.property('[0].first', 'John');
expect(res.body).to.have.nested.property('[1].first', 'Jane');
done();
});
});
@ -170,7 +170,7 @@ describe.onServer('Remote Methods', function() {
it('creates related models', function(done) {
User.create({first: 'Bob'}, function(err, res) {
expect(res).to.have.property('id');
var aPost = {title: 'A story', content: 'Once upon a time'};
const aPost = {title: 'A story', content: 'Once upon a time'};
request(app)
.post('/users/' + res.id + '/posts')
.send(aPost)
@ -189,7 +189,7 @@ describe.onServer('Remote Methods', function() {
it('creates array of hasMany models', function(done) {
User.create({first: 'Bob'}, function(err, res) {
expect(res).to.have.property('id');
var twoPosts = [
const twoPosts = [
{title: 'One story', content: 'Content #1'},
{title: 'Two story', content: 'Content #2'},
];
@ -201,21 +201,21 @@ describe.onServer('Remote Methods', function() {
.end(function(err, result) {
if (err) return done(err);
expect(result.body.length).to.eql(2);
expect(result.body).to.have.deep.property('[0].title', 'One story');
expect(result.body).to.have.deep.property('[1].title', 'Two story');
expect(result.body).to.have.nested.property('[0].title', 'One story');
expect(result.body).to.have.nested.property('[1].title', 'Two story');
done();
});
});
});
it('rejects array of obj input for hasOne relation', function(done) {
var Friend = app.registry.createModel('friend', {name: String});
const Friend = app.registry.createModel('friend', {name: String});
app.model(Friend, {dataSource: 'db'});
User.hasOne(Friend);
User.create({first: 'Bob'}, function(err, res) {
expect(res).to.have.property('id');
var twoFriends = [
const twoFriends = [
{name: 'bob'},
{name: 'rob'},
];
@ -226,7 +226,7 @@ describe.onServer('Remote Methods', function() {
.expect(400)
.end(function(err, result) {
if (err) return done(err);
var resError = result.body.error;
const resError = result.body.error;
expect(resError.message).to.match(/value(.*?)not(.*?)object(\.?)/i);
done();
});
@ -258,14 +258,14 @@ describe.onServer('Remote Methods', function() {
describe('Model.upsertWithWhere(where, data, callback)', function() {
it('Updates when a Model instance is retreived from data source', function(done) {
var taskEmitter = new TaskEmitter();
const taskEmitter = new TaskEmitter();
taskEmitter
.task(User, 'create', {first: 'jill', second: 'pill'})
.task(User, 'create', {first: 'bob', second: 'sob'})
.on('done', function() {
User.upsertWithWhere({second: 'pill'}, {second: 'jones'}, function(err, user) {
if (err) return done(err);
var id = user.id;
const id = user.id;
User.findById(id, function(err, user) {
if (err) return done(err);
assert.equal(user.second, 'jones');
@ -276,13 +276,13 @@ describe.onServer('Remote Methods', function() {
});
it('Creates when no Model instance is retreived from data source', function(done) {
var taskEmitter = new TaskEmitter();
const taskEmitter = new TaskEmitter();
taskEmitter
.task(User, 'create', {first: 'simon', second: 'somers'})
.on('done', function() {
User.upsertWithWhere({first: 'somers'}, {first: 'Simon'}, function(err, user) {
if (err) return done(err);
var id = user.id;
const id = user.id;
User.findById(id, function(err, user) {
if (err) return done(err);
assert.equal(user.first, 'Simon');
@ -315,7 +315,7 @@ describe.onServer('Remote Methods', function() {
.end(function(err, res) {
if (err) return done(err);
var errorResponse = res.body.error;
const errorResponse = res.body.error;
assert(errorResponse);
assert.equal(errorResponse.code, 'MODEL_NOT_FOUND');
@ -332,7 +332,7 @@ describe.onServer('Remote Methods', function() {
.end(function(err, res) {
if (err) return done(err);
var userId = res.body.id;
const userId = res.body.id;
assert(userId);
request(app)
.get('/users/' + userId + '?filter[fields]=first')
@ -358,7 +358,7 @@ describe.onServer('Remote Methods', function() {
.end(function(err, res) {
if (err) return done(err);
var userId = res.body.id;
const userId = res.body.id;
assert(userId);
request(app)
.post('/users/' + userId + '/posts')
@ -368,7 +368,7 @@ describe.onServer('Remote Methods', function() {
.end(function(err, res) {
if (err) return done(err);
var post = res.body;
const post = res.body;
request(app)
.get('/users/' + userId + '?filter[include]=posts')
.expect('Content-Type', /json/)
@ -389,7 +389,7 @@ describe.onServer('Remote Methods', function() {
describe('Model.beforeRemote(name, fn)', function() {
it('Run a function before a remote method is called by a client', function(done) {
var hookCalled = false;
let hookCalled = false;
User.beforeRemote('create', function(ctx, user, next) {
hookCalled = true;
@ -413,7 +413,7 @@ describe.onServer('Remote Methods', function() {
});
it('Does not stop the hook chain after returning a promise', function(done) {
var hooksCalled = [];
const hooksCalled = [];
User.beforeRemote('create', function() {
hooksCalled.push('first');
@ -441,8 +441,8 @@ describe.onServer('Remote Methods', function() {
describe('Model.afterRemote(name, fn)', function() {
it('Run a function after a remote method is called by a client', function(done) {
var beforeCalled = false;
var afterCalled = false;
let beforeCalled = false;
let afterCalled = false;
User.beforeRemote('create', function(ctx, user, next) {
assert(!afterCalled);
@ -476,7 +476,7 @@ describe.onServer('Remote Methods', function() {
describe('Model.afterRemoteError(name, fn)', function() {
it('runs the function when method fails', function(done) {
var actualError = 'hook not called';
let actualError = 'hook not called';
User.afterRemoteError('login', function(ctx, next) {
actualError = ctx.error;
@ -498,7 +498,7 @@ describe.onServer('Remote Methods', function() {
describe('Remote Method invoking context', function() {
describe('ctx.req', function() {
it('The express ServerRequest object', function(done) {
var hookCalled = false;
let hookCalled = false;
User.beforeRemote('create', function(ctx, user, next) {
hookCalled = true;
@ -530,7 +530,7 @@ describe.onServer('Remote Methods', function() {
describe('ctx.res', function() {
it('The express ServerResponse object', function(done) {
var hookCalled = false;
let hookCalled = false;
User.beforeRemote('create', function(ctx, user, next) {
hookCalled = true;
@ -563,15 +563,15 @@ describe.onServer('Remote Methods', function() {
describe('Model.hasMany(Model)', function() {
it('Define a one to many relationship', function(done) {
var Book = dataSource.createModel('book', {title: String, author: String});
var Chapter = dataSource.createModel('chapter', {title: String});
const Book = dataSource.createModel('book', {title: String, author: String});
const Chapter = dataSource.createModel('chapter', {title: String});
// by referencing model
Book.hasMany(Chapter);
Book.create({title: 'Into the Wild', author: 'Jon Krakauer'}, function(err, book) {
// using 'chapters' scope for build:
var c = book.chapters.build({title: 'Chapter 1'});
const c = book.chapters.build({title: 'Chapter 1'});
book.chapters.create({title: 'Chapter 2'}, function() {
c.save(function() {
Chapter.count({bookId: book.id}, function(err, count) {
@ -591,7 +591,7 @@ describe.onServer('Remote Methods', function() {
describe('Model.properties', function() {
it('Normalized properties passed in originally by loopback.createModel()', function() {
var props = {
const props = {
s: String,
n: {type: 'Number'},
o: {type: 'String', min: 10, max: 100},
@ -599,11 +599,11 @@ describe.onServer('Remote Methods', function() {
g: loopback.GeoPoint,
};
var MyModel = loopback.createModel('foo', props);
const MyModel = loopback.createModel('foo', props);
Object.keys(MyModel.definition.properties).forEach(function(key) {
var p = MyModel.definition.properties[key];
var o = MyModel.definition.properties[key];
const p = MyModel.definition.properties[key];
const o = MyModel.definition.properties[key];
assert(p);
assert(o);
assert(typeof p.type === 'function');
@ -613,7 +613,7 @@ describe.onServer('Remote Methods', function() {
// should match the given property
assert(
p.type.name === o.name ||
p.type.name === o
p.type.name === o,
);
}
});
@ -622,7 +622,7 @@ describe.onServer('Remote Methods', function() {
describe('Model.extend()', function() {
it('Create a new model by extending an existing model', function() {
var User = loopback.PersistedModel.extend('test-user', {
const User = loopback.PersistedModel.extend('test-user', {
email: String,
});
@ -634,7 +634,7 @@ describe.onServer('Remote Methods', function() {
return 'foo';
};
var MyUser = User.extend('my-user', {
const MyUser = User.extend('my-user', {
a: String,
b: String,
});
@ -642,7 +642,7 @@ describe.onServer('Remote Methods', function() {
assert.equal(MyUser.prototype.bar, User.prototype.bar);
assert.equal(MyUser.foo, User.foo);
var user = new MyUser({
const user = new MyUser({
email: 'foo@bar.com',
a: 'foo',
b: 'bar',
@ -656,21 +656,21 @@ describe.onServer('Remote Methods', function() {
describe('Model.extend() events', function() {
it('create isolated emitters for subclasses', function() {
var User1 = loopback.createModel('User1', {
const User1 = loopback.createModel('User1', {
'first': String,
'last': String,
});
var User2 = loopback.createModel('User2', {
const User2 = loopback.createModel('User2', {
'name': String,
});
var user1Triggered = false;
let user1Triggered = false;
User1.once('x', function(event) {
user1Triggered = true;
});
var user2Triggered = false;
let user2Triggered = false;
User2.once('x', function(event) {
user2Triggered = true;
});
@ -703,10 +703,10 @@ describe.onServer('Remote Methods', function() {
function shouldReturn(methodName, expectedAccessType) {
describe(methodName, function() {
it('should return ' + expectedAccessType, function() {
var remoteMethod = {name: methodName};
const remoteMethod = {name: methodName};
assert.equal(
User._getAccessTypeForMethod(remoteMethod),
expectedAccessType
expectedAccessType,
);
});
});
@ -715,8 +715,8 @@ describe.onServer('Remote Methods', function() {
describe('Model.getChangeModel()', function() {
it('Get the Change Model', function() {
var UserChange = User.getChangeModel();
var change = new UserChange();
const UserChange = User.getChangeModel();
const change = new UserChange();
assert(change instanceof app.registry.getModel('Change'));
});
});
@ -733,12 +733,12 @@ describe.onServer('Remote Methods', function() {
describe('Model.checkpoint(callback)', function() {
it('Create a checkpoint', function(done) {
var Checkpoint = User.getChangeModel().getCheckpointModel();
var tasks = [
const Checkpoint = User.getChangeModel().getCheckpointModel();
const tasks = [
getCurrentCheckpoint,
checkpoint,
];
var result, current;
let result, current;
async.series(tasks, function(err) {
if (err) return done(err);
@ -766,11 +766,11 @@ describe.onServer('Remote Methods', function() {
describe('Model._getACLModel()', function() {
it('should return the subclass of ACL', function() {
var Model = require('../').Model;
var originalValue = Model._ACL();
var acl = ACL.extend('acl');
const Model = require('../').Model;
const originalValue = Model._ACL();
const acl = ACL.extend('acl');
Model._ACL(null); // Reset the ACL class for the base model
var model = Model._ACL();
const model = Model._ACL();
Model._ACL(originalValue); // Reset the value back
assert.equal(model, acl);
});
@ -778,21 +778,21 @@ describe.onServer('Remote Methods', function() {
describe('PersistedModel remote methods', function() {
it('includes all aliases', function() {
var app = loopback();
var model = PersistedModel.extend('PersistedModelForAliases');
const app = loopback();
const model = PersistedModel.extend('PersistedModelForAliases');
app.dataSource('db', {connector: 'memory'});
app.model(model, {dataSource: 'db'});
// this code is used by loopback-sdk-angular codegen
var metadata = app.handler('rest')
const metadata = app.handler('rest')
.adapter
.getClasses()
.filter(function(c) { return c.name === model.modelName; })[0];
var methodNames = [];
let methodNames = [];
metadata.methods.forEach(function(method) {
methodNames.push(method.name);
var aliases = method.sharedMethod.aliases;
let aliases = method.sharedMethod.aliases;
if (method.name.indexOf('prototype.') === 0) {
aliases = aliases.map(function(alias) {
return 'prototype.' + alias;
@ -826,13 +826,13 @@ describe.onServer('Remote Methods', function() {
});
it('emits a `remoteMethodDisabled` event', function() {
var app = loopback();
var model = PersistedModel.extend('TestModelForDisablingRemoteMethod');
const app = loopback();
const model = PersistedModel.extend('TestModelForDisablingRemoteMethod');
app.dataSource('db', {connector: 'memory'});
app.model(model, {dataSource: 'db'});
var callbackSpy = require('sinon').spy();
var TestModel = app.models.TestModelForDisablingRemoteMethod;
const callbackSpy = require('sinon').spy();
const TestModel = app.models.TestModelForDisablingRemoteMethod;
TestModel.on('remoteMethodDisabled', callbackSpy);
TestModel.disableRemoteMethod('findOne', true);
@ -840,13 +840,13 @@ describe.onServer('Remote Methods', function() {
});
it('emits a `remoteMethodDisabled` event from disableRemoteMethodByName', function() {
var app = loopback();
var model = PersistedModel.extend('TestModelForDisablingRemoteMethod');
const app = loopback();
const model = PersistedModel.extend('TestModelForDisablingRemoteMethod');
app.dataSource('db', {connector: 'memory'});
app.model(model, {dataSource: 'db'});
var callbackSpy = require('sinon').spy();
var TestModel = app.models.TestModelForDisablingRemoteMethod;
const callbackSpy = require('sinon').spy();
const TestModel = app.models.TestModelForDisablingRemoteMethod;
TestModel.on('remoteMethodDisabled', callbackSpy);
TestModel.disableRemoteMethodByName('findOne');
@ -854,17 +854,17 @@ describe.onServer('Remote Methods', function() {
});
it('emits a `remoteMethodAdded` event', function() {
var app = loopback();
const app = loopback();
app.dataSource('db', {connector: 'memory'});
var User = app.registry.getModel('User');
const User = app.registry.getModel('User');
app.model(User, {dataSource: 'db'});
var Token = app.registry.getModel('AccessToken');
const Token = app.registry.getModel('AccessToken');
app.model(Token, {dataSource: 'db'});
var callbackSpy = require('sinon').spy();
var TestModel = app.models.User;
const callbackSpy = require('sinon').spy();
const TestModel = app.models.User;
TestModel.on('remoteMethodAdded', callbackSpy);
TestModel.nestRemoting('accessTokens');
@ -873,13 +873,13 @@ describe.onServer('Remote Methods', function() {
});
it('emits a `remoteMethodAdded` event from remoteMethod', function() {
var app = loopback();
var model = PersistedModel.extend('TestModelForAddingRemoteMethod');
const app = loopback();
const model = PersistedModel.extend('TestModelForAddingRemoteMethod');
app.dataSource('db', {connector: 'memory'});
app.model(model, {dataSource: 'db'});
var callbackSpy = require('sinon').spy();
var TestModel = app.models.TestModelForAddingRemoteMethod;
const callbackSpy = require('sinon').spy();
const TestModel = app.models.TestModelForAddingRemoteMethod;
TestModel.on('remoteMethodAdded', callbackSpy);
TestModel.remoteMethod('getTest', {
accepts: {arg: 'options', type: 'object', http: 'optionsFromRequest'},
@ -891,7 +891,7 @@ describe.onServer('Remote Methods', function() {
});
describe('Model.getApp(cb)', function() {
var app, TestModel;
let app, TestModel;
beforeEach(function setup() {
app = loopback();
TestModel = loopback.createModel('TestModelForGetApp'); // unique name
@ -924,7 +924,7 @@ describe.onServer('Remote Methods', function() {
});
describe('Model.createOptionsFromRemotingContext', function() {
var app, TestModel, accessToken, actualOptions;
let app, TestModel, accessToken, actualOptions;
before(setupAppAndRequest);
before(createUserAndAccessToken);
@ -1055,8 +1055,8 @@ describe.onServer('Remote Methods', function() {
}
function createUserAndAccessToken() {
var CREDENTIALS = {email: 'context@example.com', password: 'pass'};
var User = app.registry.getModel('User');
const CREDENTIALS = {email: 'context@example.com', password: 'pass'};
const User = app.registry.getModel('User');
return User.create(CREDENTIALS)
.then(function(u) {
return User.login(CREDENTIALS);

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2016,2018. All Rights Reserved.
// Copyright IBM Corp. 2018,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,16 +1,16 @@
// Copyright IBM Corp. 2016,2018. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var expect = require('./helpers/expect');
var loopback = require('../');
var ctx = require('../lib/access-context');
var extend = require('util')._extend;
var AccessContext = ctx.AccessContext;
var Principal = ctx.Principal;
var Promise = require('bluebird');
const expect = require('./helpers/expect');
const loopback = require('../');
const ctx = require('../lib/access-context');
const extend = require('util')._extend;
const AccessContext = ctx.AccessContext;
const Principal = ctx.Principal;
const Promise = require('bluebird');
const waitForEvent = require('./helpers/wait-for-event');
const supertest = require('supertest');
const loggers = require('./helpers/error-loggers');
@ -19,8 +19,8 @@ const logServerErrorsOtherThan = loggers.logServerErrorsOtherThan;
describe('Multiple users with custom principalType', function() {
this.timeout(10000);
var commonCredentials = {email: 'foo@bar.com', password: 'bar'};
var app, OneUser, AnotherUser, AccessToken, Role,
const commonCredentials = {email: 'foo@bar.com', password: 'bar'};
let app, OneUser, AnotherUser, AccessToken, Role,
userFromOneModel, userFromAnotherModel, userRole, userOneBaseContext;
beforeEach(function setupAppAndModels() {
@ -30,7 +30,7 @@ describe('Multiple users with custom principalType', function() {
app.set('remoting', {rest: {handleErrors: false}});
app.dataSource('db', {connector: 'memory'});
var userModelOptions = {
const userModelOptions = {
base: 'User',
// forceId is set to false for the purpose of updating the same affected user within the
// `Email Update` test cases.
@ -101,7 +101,7 @@ describe('Multiple users with custom principalType', function() {
},
function onError(err) {
expect(err).to.have.property('code', 'LOGIN_FAILED');
}
},
);
});
});
@ -118,7 +118,7 @@ describe('Multiple users with custom principalType', function() {
describe('User.logout', function() {
it('logs out a user from user model 1 without logging out user from model 2',
function() {
var tokenOfOneUser;
let tokenOfOneUser;
return Promise.all([
OneUser.login(commonCredentials),
AnotherUser.login(commonCredentials),
@ -131,7 +131,7 @@ describe('Multiple users with custom principalType', function() {
return AccessToken.find({});
})
.then(function(allTokens) {
var data = allTokens.map(function(token) {
const data = allTokens.map(function(token) {
return {userId: token.userId, principalType: token.principalType};
});
expect(data).to.eql([
@ -144,7 +144,7 @@ describe('Multiple users with custom principalType', function() {
describe('Password Reset', function() {
describe('User.resetPassword(options)', function() {
var options = {
const options = {
email: 'foo@bar.com',
redirect: 'http://foobar.com/reset-password',
};
@ -172,7 +172,7 @@ describe('Multiple users with custom principalType', function() {
});
describe('AccessToken (session) invalidation when changing email', function() {
var anotherUserFromOneModel;
let anotherUserFromOneModel;
it('impact only the related user', function() {
return OneUser.create({email: 'original@example.com', password: 'bar'})
@ -192,7 +192,7 @@ describe('Multiple users with custom principalType', function() {
return AccessToken.find({'order': 'principalType ASC'});
})
.then(function(allTokens) {
var data = allTokens.map(function(token) {
const data = allTokens.map(function(token) {
return {userId: token.userId, principalType: token.principalType};
});
expect(data).to.eql([
@ -205,7 +205,7 @@ describe('Multiple users with custom principalType', function() {
});
describe('AccessContext', function() {
var ThirdUser, userFromThirdModel, accessContext;
let ThirdUser, userFromThirdModel, accessContext;
beforeEach(function() {
accessContext = new AccessContext({registry: OneUser.registry});
@ -221,7 +221,7 @@ describe('Multiple users with custom principalType', function() {
{type: Principal.SCOPE},
{type: OneUser.modelName, id: userFromOneModel.id},
]);
var user = accessContext.getUser();
const user = accessContext.getUser();
expect(user).to.eql({
id: userFromOneModel.id,
principalType: OneUser.modelName,
@ -237,7 +237,7 @@ describe('Multiple users with custom principalType', function() {
{type: 'invalidModelName'},
{type: OneUser.modelName, id: userFromOneModel.id},
]);
var user = accessContext.getUser();
const user = accessContext.getUser();
expect(user).to.eql({
id: userFromOneModel.id,
principalType: OneUser.modelName,
@ -251,7 +251,7 @@ describe('Multiple users with custom principalType', function() {
return ThirdUser.create(commonCredentials)
.then(function(userFromThirdModel) {
accessContext.addPrincipal(ThirdUser.modelName, userFromThirdModel.id);
var user = accessContext.getUser();
const user = accessContext.getUser();
expect(user).to.eql({
id: userFromThirdModel.id,
principalType: ThirdUser.modelName,
@ -272,7 +272,7 @@ describe('Multiple users with custom principalType', function() {
describe('Role model', function() {
this.timeout(10000);
var RoleMapping, ACL, user;
let RoleMapping, ACL, user;
beforeEach(function() {
ACL = app.registry.getModel('ACL');
@ -285,7 +285,7 @@ describe('Multiple users with custom principalType', function() {
describe('role.users()', function() {
it('returns users when using custom user principalType', function() {
return userRole.principals.create(
{principalType: OneUser.modelName, principalId: userFromOneModel.id}
{principalType: OneUser.modelName, principalId: userFromOneModel.id},
)
.then(function() {
return userRole.users({where: {principalType: OneUser.modelName}});
@ -298,7 +298,7 @@ describe('Multiple users with custom principalType', function() {
it('returns empty array when using invalid principalType', function() {
return userRole.principals.create(
{principalType: 'invalidModelName', principalId: userFromOneModel.id}
{principalType: 'invalidModelName', principalId: userFromOneModel.id},
)
.then(function() {
return userRole.users({where: {principalType: 'invalidModelName'}});
@ -312,7 +312,7 @@ describe('Multiple users with custom principalType', function() {
describe('principal.user()', function() {
it('returns the correct user instance', function() {
return userRole.principals.create(
{principalType: OneUser.modelName, principalId: userFromOneModel.id}
{principalType: OneUser.modelName, principalId: userFromOneModel.id},
).then(function(principal) {
return principal.user();
}).then(function(user) {
@ -322,7 +322,7 @@ describe('Multiple users with custom principalType', function() {
it('returns null when created with invalid principalType', function() {
return userRole.principals.create(
{principalType: 'invalidModelName', principalId: userFromOneModel.id}
{principalType: 'invalidModelName', principalId: userFromOneModel.id},
).then(function(principal) {
return principal.user();
}).then(function(user) {
@ -346,7 +346,7 @@ describe('Multiple users with custom principalType', function() {
it('supports getRoles()', function() {
return Role.getRoles(
userOneBaseContext
userOneBaseContext,
).then(function(roles) {
expect(roles).to.eql([
Role.AUTHENTICATED,
@ -374,7 +374,7 @@ describe('Multiple users with custom principalType', function() {
describe('$owner', function() {
it('supports legacy behavior with relations', function() {
var Album = app.registry.createModel('Album', {
const Album = app.registry.createModel('Album', {
name: String,
userId: Number,
}, {
@ -390,7 +390,7 @@ describe('Multiple users with custom principalType', function() {
return Album.create({name: 'album', userId: userFromOneModel.id})
.then(function(album) {
var validContext = {
const validContext = {
principalType: OneUser.modelName,
principalId: userFromOneModel.id,
model: Album,
@ -406,7 +406,7 @@ describe('Multiple users with custom principalType', function() {
// With multiple users config, we cannot resolve a user based just on
// his id, as many users from different models could have the same id.
it('legacy behavior resolves false without belongsTo relation', function() {
var Album = app.registry.createModel('Album', {
const Album = app.registry.createModel('Album', {
name: String,
userId: Number,
owner: Number,
@ -419,7 +419,7 @@ describe('Multiple users with custom principalType', function() {
owner: userFromOneModel.id,
})
.then(function(album) {
var authContext = {
const authContext = {
principalType: OneUser.modelName,
principalId: userFromOneModel.id,
model: Album,
@ -433,7 +433,7 @@ describe('Multiple users with custom principalType', function() {
});
it('legacy behavior resolves false if owner has incorrect principalType', function() {
var Album = app.registry.createModel('Album', {
const Album = app.registry.createModel('Album', {
name: String,
userId: Number,
}, {
@ -449,12 +449,12 @@ describe('Multiple users with custom principalType', function() {
return Album.create({name: 'album', userId: userFromOneModel.id})
.then(function(album) {
var invalidPrincipalTypes = [
const invalidPrincipalTypes = [
'invalidContextName',
'USER',
AnotherUser.modelName,
];
var invalidContexts = invalidPrincipalTypes.map(principalType => {
const invalidContexts = invalidPrincipalTypes.map(principalType => {
return {
principalType,
principalId: userFromOneModel.id,
@ -485,12 +485,12 @@ describe('Multiple users with custom principalType', function() {
function() {
// passing {ownerRelations: true} will enable the new $owner role resolver
// with any belongsTo relation allowing to resolve truthy
var Message = createModelWithOptions(
const Message = createModelWithOptions(
'ModelWithAllRelations',
{ownerRelations: true}
{ownerRelations: true},
);
var messages = [
const messages = [
{content: 'firstMessage', customerId: userFromOneModel.id},
{
content: 'secondMessage',
@ -552,7 +552,7 @@ describe('Multiple users with custom principalType', function() {
// helpers
function isOwnerForMessage(user, msg) {
var accessContext = {
const accessContext = {
principalType: user.constructor.modelName,
principalId: user.id,
model: msg.constructor,
@ -569,7 +569,7 @@ describe('Multiple users with custom principalType', function() {
}
function createModelWithOptions(name, options) {
var baseOptions = {
const baseOptions = {
relations: {
sender: {
type: 'belongsTo',
@ -584,10 +584,10 @@ describe('Multiple users with custom principalType', function() {
},
};
options = extend(baseOptions, options);
var Model = app.registry.createModel(
const Model = app.registry.createModel(
name,
{content: String, senderType: String},
options
options,
);
app.model(Model, {dataSource: 'db'});
return Model;
@ -616,7 +616,7 @@ describe('Multiple users with custom principalType', function() {
function onError(err) {
expect(err).to.have.property('statusCode', 400);
expect(err).to.have.property('code', 'INVALID_PRINCIPAL_TYPE');
}
},
);
});
@ -768,7 +768,7 @@ describe('Multiple users with custom principalType', function() {
// helpers
function createUserModel(app, name, options) {
var model = app.registry.createModel(Object.assign({name: name}, options));
const model = app.registry.createModel(Object.assign({name: name}, options));
app.model(model, {dataSource: 'db'});
model.setMaxListeners(0); // allow many User.afterRemote's to be called
return model;

View File

@ -1,19 +1,19 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var expect = require('./helpers/expect');
var loopback = require('../');
const assert = require('assert');
const expect = require('./helpers/expect');
const loopback = require('../');
describe('Registry', function() {
describe('createModel', function() {
it('should throw error upon extending non-exist base model', function() {
var app = loopback();
var props = {};
var opts = {base: 'nonexistent'};
const app = loopback();
const props = {};
const opts = {base: 'nonexistent'};
expect(function() { app.registry.createModel('aModel', props, opts); })
.to.throw(/model\s`aModel`(.*)unknown\smodel\s`nonexistent`/);
});
@ -21,26 +21,26 @@ describe('Registry', function() {
describe('one per app', function() {
it('should allow two apps to reuse the same model name', function(done) {
var appFoo = loopback();
var appBar = loopback();
var modelName = 'MyModel';
var subModelName = 'Sub' + modelName;
var settings = {base: 'PersistedModel'};
const appFoo = loopback();
const appBar = loopback();
const modelName = 'MyModel';
const subModelName = 'Sub' + modelName;
const settings = {base: 'PersistedModel'};
appFoo.set('perAppRegistries', true);
appBar.set('perAppRegistries', true);
var dsFoo = appFoo.dataSource('dsFoo', {connector: 'memory'});
var dsBar = appFoo.dataSource('dsBar', {connector: 'memory'});
const dsFoo = appFoo.dataSource('dsFoo', {connector: 'memory'});
const dsBar = appFoo.dataSource('dsBar', {connector: 'memory'});
var FooModel = appFoo.registry.createModel(modelName, {}, settings);
const FooModel = appFoo.registry.createModel(modelName, {}, settings);
appFoo.model(FooModel, {dataSource: dsFoo});
var FooSubModel = appFoo.registry.createModel(subModelName, {}, settings);
const FooSubModel = appFoo.registry.createModel(subModelName, {}, settings);
appFoo.model(FooSubModel, {dataSource: dsFoo});
var BarModel = appBar.registry.createModel(modelName, {}, settings);
const BarModel = appBar.registry.createModel(modelName, {}, settings);
appBar.model(BarModel, {dataSource: dsBar});
var BarSubModel = appBar.registry.createModel(subModelName, {}, settings);
const BarSubModel = appBar.registry.createModel(subModelName, {}, settings);
appBar.model(BarSubModel, {dataSource: dsBar});
FooModel.hasMany(FooSubModel);

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,21 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var loopback = require('../');
var defineModelTestsWithDataSource = require('./util/model-tests');
const assert = require('assert');
const loopback = require('../');
const defineModelTestsWithDataSource = require('./util/model-tests');
describe('RemoteConnector', function() {
this.timeout(10000);
var remoteApp, remote;
let remoteApp, remote;
defineModelTestsWithDataSource({
beforeEach: function(done) {
var test = this;
const test = this;
remoteApp = loopback();
remoteApp.set('remoting', {
errorHandler: {debug: true, log: false},
@ -40,7 +40,7 @@ describe('RemoteConnector', function() {
enableRemoteReplication: true,
onDefine: function(Model) {
var ServerModel = Model.extend('Server' + Model.modelName, {}, {
const ServerModel = Model.extend('Server' + Model.modelName, {}, {
plural: Model.pluralModelName,
// This is the model running on the server & attached to a real
// datasource, that's the place where to keep track of changes
@ -54,13 +54,13 @@ describe('RemoteConnector', function() {
});
beforeEach(function(done) {
var test = this;
const test = this;
remoteApp = this.remoteApp = loopback();
remoteApp.set('remoting', {
types: {warnWhenOverridingType: false},
});
remoteApp.use(loopback.rest());
var ServerModel = this.ServerModel = loopback.PersistedModel.extend('TestModel');
const ServerModel = this.ServerModel = loopback.PersistedModel.extend('TestModel');
remoteApp.model(ServerModel);
@ -76,11 +76,11 @@ describe('RemoteConnector', function() {
});
it('should support the save method', function(done) {
var calledServerCreate = false;
var RemoteModel = loopback.PersistedModel.extend('TestModel');
let calledServerCreate = false;
const RemoteModel = loopback.PersistedModel.extend('TestModel');
RemoteModel.attachTo(this.remote);
var ServerModel = this.ServerModel;
const ServerModel = this.ServerModel;
ServerModel.create = function(data, options, cb) {
calledServerCreate = true;
@ -90,7 +90,7 @@ describe('RemoteConnector', function() {
ServerModel.setupRemoting();
var m = new RemoteModel({foo: 'bar'});
const m = new RemoteModel({foo: 'bar'});
m.save(function(err, inst) {
if (err) return done(err);

View File

@ -1,20 +1,20 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var loopback = require('../');
var request = require('supertest');
const assert = require('assert');
const loopback = require('../');
const request = require('supertest');
describe('remoting coercion', function() {
it('should coerce arguments based on the type', function(done) {
var called = false;
var app = loopback();
let called = false;
const app = loopback();
app.use(loopback.rest());
var TestModel = app.registry.createModel('TestModel',
const TestModel = app.registry.createModel('TestModel',
{},
{base: 'Model'});
app.model(TestModel, {public: true});

View File

@ -1,16 +1,16 @@
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../');
var lt = require('./helpers/loopback-testing-helper');
var path = require('path');
var SIMPLE_APP = path.join(__dirname, 'fixtures', 'simple-integration-app');
var app = require(path.join(SIMPLE_APP, 'server/server.js'));
var assert = require('assert');
var expect = require('./helpers/expect');
const loopback = require('../');
const lt = require('./helpers/loopback-testing-helper');
const path = require('path');
const SIMPLE_APP = path.join(__dirname, 'fixtures', 'simple-integration-app');
const app = require(path.join(SIMPLE_APP, 'server/server.js'));
const assert = require('assert');
const expect = require('./helpers/expect');
describe('remoting - integration', function() {
lt.beforeEach.withApp(app);
@ -22,21 +22,21 @@ describe('remoting - integration', function() {
describe('app.remotes.options', function() {
it('should load remoting options', function() {
var remotes = app.remotes();
const remotes = app.remotes();
assert.deepEqual(remotes.options, {'json': {'limit': '1kb', 'strict': false},
'urlencoded': {'limit': '8kb', 'extended': true},
'errorHandler': {'debug': true, log: false}});
});
it('rest handler', function() {
var handler = app.handler('rest');
const handler = app.handler('rest');
assert(handler);
});
it('should accept request that has entity below 1kb', function(done) {
// Build an object that is smaller than 1kb
var name = '';
for (var i = 0; i < 256; i++) {
let name = '';
for (let i = 0; i < 256; i++) {
name += '11';
}
this.http = this.post('/api/stores');
@ -55,8 +55,8 @@ describe('remoting - integration', function() {
it('should reject request that has entity beyond 1kb', function(done) {
// Build an object that is larger than 1kb
var name = '';
for (var i = 0; i < 2048; i++) {
let name = '';
for (let i = 0; i < 2048; i++) {
name += '11111111111';
}
this.http = this.post('/api/stores');
@ -79,10 +79,10 @@ describe('remoting - integration', function() {
it('has expected remote methods with default model.settings.replaceOnPUT' +
'set to true (3.x)',
function() {
var storeClass = findClass('store');
var methods = getFormattedMethodsExcludingRelations(storeClass.methods);
const storeClass = findClass('store');
const methods = getFormattedMethodsExcludingRelations(storeClass.methods);
var expectedMethods = [
const expectedMethods = [
'create(data:object:store):store POST /stores',
'patchOrCreate(data:object:store):store PATCH /stores',
'replaceOrCreate(data:object:store):store PUT /stores',
@ -106,10 +106,10 @@ describe('remoting - integration', function() {
});
it('has expected remote methods for scopes', function() {
var storeClass = findClass('store');
var methods = getFormattedScopeMethods(storeClass.methods);
const storeClass = findClass('store');
const methods = getFormattedScopeMethods(storeClass.methods);
var expectedMethods = [
const expectedMethods = [
'__get__superStores(filter:object):store GET /stores/superStores',
'__create__superStores(data:object:store):store POST /stores/superStores',
'__delete__superStores() DELETE /stores/superStores',
@ -121,10 +121,10 @@ describe('remoting - integration', function() {
it('should have correct signatures for belongsTo methods',
function() {
var widgetClass = findClass('widget');
var methods = getFormattedPrototypeMethods(widgetClass.methods);
const widgetClass = findClass('widget');
const methods = getFormattedPrototypeMethods(widgetClass.methods);
var expectedMethods = [
const expectedMethods = [
'prototype.__get__store(refresh:boolean):store ' +
'GET /widgets/:id/store',
];
@ -133,10 +133,10 @@ describe('remoting - integration', function() {
it('should have correct signatures for hasMany methods',
function() {
var storeClass = findClass('store');
var methods = getFormattedPrototypeMethods(storeClass.methods);
const storeClass = findClass('store');
const methods = getFormattedPrototypeMethods(storeClass.methods);
var expectedMethods = [
const expectedMethods = [
'prototype.__findById__widgets(fk:any):widget ' +
'GET /stores/:id/widgets/:fk',
'prototype.__destroyById__widgets(fk:any) ' +
@ -157,10 +157,10 @@ describe('remoting - integration', function() {
it('should have correct signatures for hasMany-through methods',
function() { // jscs:disable validateIndentation
var physicianClass = findClass('physician');
var methods = getFormattedPrototypeMethods(physicianClass.methods);
const physicianClass = findClass('physician');
const methods = getFormattedPrototypeMethods(physicianClass.methods);
var expectedMethods = [
const expectedMethods = [
'prototype.__findById__patients(fk:any):patient ' +
'GET /physicians/:id/patients/:fk',
'prototype.__destroyById__patients(fk:any) ' +
@ -187,9 +187,9 @@ describe('remoting - integration', function() {
});
it('has upsertWithWhere remote method', function() {
var storeClass = findClass('store');
var methods = getFormattedMethodsExcludingRelations(storeClass.methods);
var expectedMethods = [
const storeClass = findClass('store');
const methods = getFormattedMethodsExcludingRelations(storeClass.methods);
const expectedMethods = [
'upsertWithWhere(where:object,data:object:store):store POST /stores/upsertWithWhere',
];
expect(methods).to.include.members(expectedMethods);
@ -198,21 +198,21 @@ describe('remoting - integration', function() {
describe('createOnlyInstance', function() {
it('sets createOnlyInstance to true if id is generated and forceId is not set to false',
function() {
var storeClass = findClass('store');
var createMethod = getCreateMethod(storeClass.methods);
const storeClass = findClass('store');
const createMethod = getCreateMethod(storeClass.methods);
assert(createMethod.accepts[0].createOnlyInstance === true);
});
it('sets createOnlyInstance to false if forceId is set to false in the model', function() {
var customerClass = findClass('customerforceidfalse');
var createMethod = getCreateMethod(customerClass.methods);
const customerClass = findClass('customerforceidfalse');
const createMethod = getCreateMethod(customerClass.methods);
assert(createMethod.accepts[0].createOnlyInstance === false);
});
it('sets createOnlyInstance based on target model for scoped or related methods',
function() {
var userClass = findClass('user');
var createMethod = userClass.methods.find(function(m) {
const userClass = findClass('user');
const createMethod = userClass.methods.find(function(m) {
return (m.name === 'prototype.__create__accessTokens');
});
assert(createMethod.accepts[0].createOnlyInstance === false);
@ -229,10 +229,10 @@ describe('With model.settings.replaceOnPUT false', function() {
it('should have expected remote methods',
function() {
var storeClass = findClass('storeWithReplaceOnPUTfalse');
var methods = getFormattedMethodsExcludingRelations(storeClass.methods);
const storeClass = findClass('storeWithReplaceOnPUTfalse');
const methods = getFormattedMethodsExcludingRelations(storeClass.methods);
var expectedMethods = [
const expectedMethods = [
'create(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating',
'patchOrCreate(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PUT /stores-updating',
'patchOrCreate(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PATCH /stores-updating',
@ -266,10 +266,10 @@ describe('With model.settings.replaceOnPUT true', function() {
it('should have expected remote methods',
function() {
var storeClass = findClass('storeWithReplaceOnPUTtrue');
var methods = getFormattedMethodsExcludingRelations(storeClass.methods);
const storeClass = findClass('storeWithReplaceOnPUTtrue');
const methods = getFormattedMethodsExcludingRelations(storeClass.methods);
var expectedMethods = [
const expectedMethods = [
'patchOrCreate(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PATCH /stores-replacing',
'replaceOrCreate(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue POST /stores-replacing/replaceOrCreate',
'replaceOrCreate(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PUT /stores-replacing',
@ -283,11 +283,11 @@ describe('With model.settings.replaceOnPUT true', function() {
});
function formatReturns(m) {
var returns = m.returns;
const returns = m.returns;
if (!returns || returns.length === 0) {
return '';
}
var type = returns[0].type;
let type = returns[0].type;
// handle anonymous type definitions, e.g
// { arg: 'info', type: { count: 'number' } }
@ -298,9 +298,9 @@ function formatReturns(m) {
}
function formatMethod(m) {
var arr = [];
var endpoints = m.getEndpoints();
for (var i = 0; i < endpoints.length; i++) {
const arr = [];
const endpoints = m.getEndpoints();
for (let i = 0; i < endpoints.length; i++) {
arr.push([
m.name,
'(',

View File

@ -1,28 +1,28 @@
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var async = require('async');
var debug = require('debug')('test');
var extend = require('util')._extend;
var loopback = require('../');
var expect = require('./helpers/expect');
var supertest = require('supertest');
const async = require('async');
const debug = require('debug')('test');
const extend = require('util')._extend;
const loopback = require('../');
const expect = require('./helpers/expect');
const supertest = require('supertest');
describe('Replication over REST', function() {
this.timeout(10000);
var ALICE = {id: 'a', username: 'alice', email: 'a@t.io', password: 'p'};
var PETER = {id: 'p', username: 'peter', email: 'p@t.io', password: 'p'};
var EMERY = {id: 'e', username: 'emery', email: 'e@t.io', password: 'p'};
const ALICE = {id: 'a', username: 'alice', email: 'a@t.io', password: 'p'};
const PETER = {id: 'p', username: 'peter', email: 'p@t.io', password: 'p'};
const EMERY = {id: 'e', username: 'emery', email: 'e@t.io', password: 'p'};
/* eslint-disable one-var */
var serverApp, serverUrl, ServerUser, ServerCar, serverCars;
var aliceId, peterId, aliceToken, peterToken, emeryToken, request;
var clientApp, LocalUser, LocalCar, RemoteUser, RemoteCar, clientCars;
var conflictedCarId;
let serverApp, serverUrl, ServerUser, ServerCar, serverCars;
let aliceId, peterId, aliceToken, peterToken, emeryToken, request;
let clientApp, LocalUser, LocalCar, RemoteUser, RemoteCar, clientCars;
let conflictedCarId;
/* eslint-enable one-var */
before(setupServer);
@ -177,7 +177,7 @@ describe('Replication over REST', function() {
});
describe('conflict resolution with model-level permissions', function() {
var LocalConflict, RemoteConflict;
let LocalConflict, RemoteConflict;
before(function setupConflictModels() {
LocalConflict = LocalCar.getChangeModel().Conflict;
@ -189,20 +189,20 @@ describe('Replication over REST', function() {
describe('as anonymous user', function() {
it('rejects resolve() on the client', function(done) {
// simulate replication Client->Server
var conflict = new LocalConflict(
const conflict = new LocalConflict(
conflictedCarId,
LocalCar,
RemoteCar
RemoteCar,
);
conflict.resolveUsingSource(expectHttpError(401, done));
});
it('rejects resolve() on the server', function(done) {
// simulate replication Server->Client
var conflict = new RemoteConflict(
const conflict = new RemoteConflict(
conflictedCarId,
RemoteCar,
LocalCar
LocalCar,
);
conflict.resolveUsingSource(expectHttpError(401, done));
});
@ -215,20 +215,20 @@ describe('Replication over REST', function() {
it('allows resolve() on the client', function(done) {
// simulate replication Client->Server
var conflict = new LocalConflict(
const conflict = new LocalConflict(
conflictedCarId,
LocalCar,
RemoteCar
RemoteCar,
);
conflict.resolveUsingSource(done);
});
it('rejects resolve() on the server', function(done) {
// simulate replication Server->Client
var conflict = new RemoteConflict(
const conflict = new RemoteConflict(
conflictedCarId,
RemoteCar,
LocalCar
LocalCar,
);
conflict.resolveUsingSource(expectHttpError(401, done));
});
@ -332,7 +332,7 @@ describe('Replication over REST', function() {
if (conflicts.length) return done(conflictError(conflicts));
LocalUser.find(function(err, users) {
var userNames = users.map(function(u) { return u.username; });
const userNames = users.map(function(u) { return u.username; });
expect(userNames).to.eql([ALICE.username]);
done();
@ -407,17 +407,17 @@ describe('Replication over REST', function() {
LocalUser.updateAll(
{id: aliceId},
{fullname: 'Alice Smith'},
done
done,
);
});
}
});
var USER_PROPS = {
const USER_PROPS = {
id: {type: 'string', id: true},
};
var USER_OPTS = {
const USER_OPTS = {
base: 'User',
plural: 'Users', // use the same REST path in all models
trackChanges: true,
@ -427,13 +427,13 @@ describe('Replication over REST', function() {
saltWorkFactor: 4,
};
var CAR_PROPS = {
const CAR_PROPS = {
id: {type: 'string', id: true, defaultFn: 'guid'},
model: {type: 'string', required: true},
maker: {type: 'string'},
};
var CAR_OPTS = {
const CAR_OPTS = {
base: 'PersistedModel',
plural: 'Cars', // use the same REST path in all models
trackChanges: true,
@ -477,7 +477,7 @@ describe('Replication over REST', function() {
// Setup a custom access-token model that is not shared
// with the client app
var ServerToken = serverApp.registry.createModel('ServerToken', {}, {
const ServerToken = serverApp.registry.createModel('ServerToken', {}, {
base: 'AccessToken',
relations: {
user: {
@ -531,7 +531,7 @@ describe('Replication over REST', function() {
// model. This causes the in-process replication to work differently
// than client-server replication.
// As a workaround, we manually setup unique Checkpoint for ClientModel.
var ClientCheckpoint = clientApp.registry.createModel({
const ClientCheckpoint = clientApp.registry.createModel({
name: 'ClientCheckpoint',
base: 'Checkpoint',
});
@ -545,7 +545,7 @@ describe('Replication over REST', function() {
LocalCar.Change.Checkpoint = ClientCheckpoint;
clientApp.model(LocalCar, {dataSource: 'db'});
var remoteOpts = createRemoteModelOpts(USER_OPTS);
let remoteOpts = createRemoteModelOpts(USER_OPTS);
RemoteUser = clientApp.registry.createModel('RemoteUser', USER_PROPS, remoteOpts);
clientApp.model(RemoteUser, {dataSource: 'remote'});
@ -611,7 +611,7 @@ describe('Replication over REST', function() {
serverCars = cars.map(carToString);
next();
}
},
);
},
], done);
@ -631,7 +631,7 @@ describe('Replication over REST', function() {
clientCars = cars.map(carToString);
next();
}
},
);
},
], done);
@ -690,7 +690,7 @@ describe('Replication over REST', function() {
}
function conflictError(conflicts) {
var err = new Error('Unexpected conflicts\n' +
const err = new Error('Unexpected conflicts\n' +
conflicts.map(JSON.stringify).join('\n'));
err.name = 'ConflictError';
}

Some files were not shown because too many files have changed in this diff Show More