Merge branch 'release/1.8.2' into production
This commit is contained in:
commit
8a924c3e73
69
README.md
69
README.md
|
@ -1,26 +1,71 @@
|
|||
# LoopBack
|
||||
LoopBack is a highly extensible, open source Node.js framework that enables you to:
|
||||
|
||||
For a quick introduction and overview, see http://loopback.io/.
|
||||
* Create dynamic end-to-end REST APIs with little or no coding
|
||||
* Easily access data from Oracle, MySQL, PostgreSQL, MS SQL Server, MongoDB, SOAP and other REST APIs
|
||||
* Incorporate model relationships and access controls for complex APIs
|
||||
* Run your application on-premises or in the cloud
|
||||
* Use built-in push, geolocation, and file services for mobile use cases
|
||||
* Easily create client apps using Android, iOS, and JavaScript SDKs
|
||||
|
||||
## Documentation
|
||||
LoopBack consists of:
|
||||
* A library of Node.js modules.
|
||||
* A command line tool, `slc`, for creating and working with LoopBack applications.
|
||||
* Client SDKs for native and web-based mobile clients.
|
||||
|
||||
[See the full documentation](http://docs.strongloop.com/display/DOC/LoopBack).
|
||||
For more details, see http://loopback.io/.
|
||||
|
||||
## API
|
||||
## LoopBack modules
|
||||
The LoopBack Node.js modules are illustrated below:
|
||||
|
||||
[Browse the API documentation](http://apidocs.strongloop.com/loopback).
|
||||
![LoopBack modules](http://content.screencast.com/users/RaymondFeng/folders/Jing/media/74fcdafa-7d4b-4b9e-9f1f-f303b2b6adc4/00000065.png)
|
||||
|
||||
## Mailing List
|
||||
* Frameworks
|
||||
* [loopback](https://github.com/strongloop/loopback)
|
||||
* [loopback-datasource-juggler](https://github.com/strongloop/loopback-datasource-juggler)
|
||||
* [strong-remoting](https://github.com/strongloop/strong-remoting)
|
||||
|
||||
Discuss features and ask questions on [LoopBack Forum](https://groups.google.com/forum/#!forum/loopbackjs).
|
||||
* Enterprise Connectors
|
||||
* [loopback-connector-mongodb](https://github.com/strongloop/loopback-connector-mongodb)
|
||||
* [loopback-connector-mysql](https://github.com/strongloop/loopback-connector-mysql)
|
||||
* [loopback-connector-oracle](https://github.com/strongloop/loopback-connector-oracle)
|
||||
* [loopback-connector-postgresql](https://github.com/strongloop/loopback-connector-postgresql)
|
||||
* [loopback-connector-rest](https://github.com/strongloop/loopback-connector-rest)
|
||||
* [loopback-connector-soap](https://github.com/strongloop/loopback-connector-soap)
|
||||
|
||||
## Issues
|
||||
* Mobile services
|
||||
* [loopback-push-notification](https://github.com/strongloop/loopback-push-notification)
|
||||
* [loopback-storage-service](https://github.com/strongloop/loopback-storage-service)
|
||||
|
||||
File any issues [here on GitHub](https://github.com/strongloop/loopback/issues).
|
||||
* Clients
|
||||
* [loopback-ios](https://github.com/strongloop/loopback-ios)
|
||||
* [loopback-remoting-ios](https://github.com/strongloop/loopback-remoting-ios)
|
||||
* [loopback-android](https://github.com/strongloop/loopback-android)
|
||||
* [loopback-remoting-android](https://github.com/strongloop/loopback-remoting-android)
|
||||
* [loopback-angular](https://github.com/strongloop/loopback-angular)
|
||||
|
||||
## Features
|
||||
* Tools
|
||||
* [loopback-explorer](https://github.com/strongloop/loopback-explorer)
|
||||
* [loopback-workspace](https://github.com/strongloop/loopback-workspace)
|
||||
* [strong-cli](https://github.com/strongloop/strong-cli)
|
||||
|
||||
Read about the [features of LoopBack](https://github.com/strongloop/loopback/wiki/Features).
|
||||
* Examples
|
||||
* [loopback-example-full-stack](https://github.com/strongloop/loopback-example-full-stack)
|
||||
* [loopback-example-office-supplies](https://github.com/strongloop/loopback-example-office-supplies)
|
||||
* [loopback-example-todo](https://github.com/strongloop/loopback-example-todo)
|
||||
* [loopback-example-access-control](https://github.com/strongloop/loopback-example-access-control)
|
||||
* [loopback-example-proxy](https://github.com/strongloop/loopback-example-proxy)
|
||||
* [strongloop-community/loopback-example-datagraph](https://github.com/strongloop-community/loopback-example-datagraph)
|
||||
* [strongloop-community/loopback-mysql-example](https://github.com/strongloop-community/loopback-mysql-example)
|
||||
* [strongloop-community/loopback-examples-ios](https://github.com/strongloop-community/loopback-examples-ios)
|
||||
* [strongloop-community/loopback-example-ssl](https://github.com/strongloop-community/loopback-example-ssl)
|
||||
|
||||
## Resources
|
||||
|
||||
* [Documentation](http://docs.strongloop.com/display/DOC/LoopBack).
|
||||
* [API documentation](http://apidocs.strongloop.com/loopback).
|
||||
* [LoopBack Google Group](https://groups.google.com/forum/#!forum/loopbackjs).
|
||||
* [GitHub issues](https://github.com/strongloop/loopback/issues).
|
||||
* Read more about the [LoopBack's features](https://github.com/strongloop/loopback/wiki/Features).
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
"lib/models/data-model.js",
|
||||
"lib/models/role.js",
|
||||
"lib/models/user.js",
|
||||
"docs/api-datasource.md",
|
||||
"docs/api-geopoint.md",
|
||||
"docs/api-model.md",
|
||||
"docs/api-model-remote.md"
|
||||
],
|
||||
|
|
|
@ -442,145 +442,6 @@ appearing in many groups, you could declare the models this way,
|
|||
user.groups.add(group, callback); // connect an existing group with the user
|
||||
user.groups.remove(group, callback); // remove the user from the group
|
||||
```
|
||||
|
||||
### Validations
|
||||
|
||||
#### Model.validatesFormatOf(property, options)
|
||||
|
||||
Require a model to include a property that matches the given format.
|
||||
|
||||
```js
|
||||
User.validatesFormat('name', {with: /\w+/});
|
||||
```
|
||||
|
||||
#### Model.validatesPresenceOf(properties...)
|
||||
|
||||
Require a model to include a property to be considered valid.
|
||||
|
||||
```js
|
||||
User.validatesPresenceOf('first', 'last', 'age');
|
||||
```
|
||||
|
||||
#### Model.validatesLengthOf(property, options)
|
||||
|
||||
Require a property length to be within a specified range.
|
||||
|
||||
```js
|
||||
User.validatesLengthOf('password', {min: 5, message: {min: 'Password is too short'}});
|
||||
```
|
||||
|
||||
#### Model.validatesInclusionOf(property, options)
|
||||
|
||||
Require a value for `property` to be in the specified array.
|
||||
|
||||
```js
|
||||
User.validatesInclusionOf('gender', {in: ['male', 'female']});
|
||||
```
|
||||
|
||||
#### Model.validatesExclusionOf(property, options)
|
||||
|
||||
Require a value for `property` to not exist in the specified array.
|
||||
|
||||
```js
|
||||
User.validatesExclusionOf('domain', {in: ['www', 'billing', 'admin']});
|
||||
```
|
||||
|
||||
#### Model.validatesNumericalityOf(property, options)
|
||||
|
||||
Require a value for `property` to be a specific type of `Number`.
|
||||
|
||||
```js
|
||||
User.validatesNumericalityOf('age', {int: true});
|
||||
```
|
||||
|
||||
#### Model.validatesUniquenessOf(property, options)
|
||||
|
||||
Ensure the value for `property` is unique in the collection of models.
|
||||
|
||||
```js
|
||||
User.validatesUniquenessOf('email', {message: 'email is not unique'});
|
||||
```
|
||||
|
||||
**Note:** not available for all [connectors](#connectors).
|
||||
|
||||
Currently supported in these connectors:
|
||||
|
||||
- [In Memory](#memory-connector)
|
||||
- [Oracle](http://github.com/strongloop/loopback-connector-oracle)
|
||||
- [MongoDB](http://github.com/strongloop/loopback-connector-mongodb)
|
||||
|
||||
#### myModel.isValid()
|
||||
|
||||
Validate the model instance.
|
||||
|
||||
```js
|
||||
user.isValid(function (valid) {
|
||||
if (!valid) {
|
||||
console.log(user.errors);
|
||||
// => hash of errors
|
||||
// => {
|
||||
// => username: [errmessage, errmessage, ...],
|
||||
// => email: ...
|
||||
// => }
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### loopback.ValidationError
|
||||
|
||||
`ValidationError` is raised when the application attempts to save an invalid
|
||||
model instance.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
{
|
||||
"name": "ValidationError",
|
||||
"status": 422,
|
||||
"message": "The Model instance is not valid. \
|
||||
See `details` property of the error object for more info.",
|
||||
"statusCode": 422,
|
||||
"details": {
|
||||
"context": "user",
|
||||
"codes": {
|
||||
"password": [
|
||||
"presence"
|
||||
],
|
||||
"email": [
|
||||
"uniqueness"
|
||||
]
|
||||
},
|
||||
"messages": {
|
||||
"password": [
|
||||
"can't be blank"
|
||||
],
|
||||
"email": [
|
||||
"Email already exists"
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
You might run into situations where you need to raise a validation error
|
||||
yourself, for example in a "before" hook or a custom model method.
|
||||
|
||||
```js
|
||||
MyModel.prototype.preflight = function(changes, callback) {
|
||||
// Update properties, do not save to db
|
||||
for (var key in changes) {
|
||||
model[key] = changes[key];
|
||||
}
|
||||
|
||||
if (model.isValid()) {
|
||||
return callback(null, { success: true });
|
||||
}
|
||||
|
||||
// This line shows how to create a ValidationError
|
||||
err = new ValidationError(model);
|
||||
callback(err);
|
||||
}
|
||||
```
|
||||
|
||||
### Shared methods
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ var client = loopback();
|
|||
var CartItem = require('./models').CartItem;
|
||||
var remote = loopback.createDataSource({
|
||||
connector: loopback.Remote,
|
||||
root: 'http://localhost:3000'
|
||||
url: 'http://localhost:3000'
|
||||
});
|
||||
|
||||
client.model(CartItem);
|
||||
|
|
|
@ -296,6 +296,9 @@ ACL.getStaticACLs = function getStaticACLs(model, property) {
|
|||
ACL.checkPermission = function checkPermission(principalType, principalId,
|
||||
model, property, accessType,
|
||||
callback) {
|
||||
if(principalId !== null && principalId !== undefined && (typeof principalId !== 'string') ) {
|
||||
principalId = principalId.toString();
|
||||
}
|
||||
property = property || ACL.ALL;
|
||||
var propertyQuery = (property === ACL.ALL) ? undefined : {inq: [property, ACL.ALL]};
|
||||
accessType = accessType || ACL.ALL;
|
||||
|
|
|
@ -66,7 +66,7 @@ function convertNullToNotFoundError(ctx, cb) {
|
|||
|
||||
var modelName = ctx.method.sharedClass.name;
|
||||
var id = ctx.getArgByName('id');
|
||||
var msg = 'Unkown "' + modelName + '" id "' + id + '".';
|
||||
var msg = 'Unknown "' + modelName + '" id "' + id + '".';
|
||||
var error = new Error(msg);
|
||||
error.statusCode = error.status = 404;
|
||||
cb(error);
|
||||
|
|
|
@ -373,8 +373,14 @@ Role.isInRole = function (role, context, callback) {
|
|||
async.some(context.principals, function (p, done) {
|
||||
var principalType = p.type || undefined;
|
||||
var principalId = p.id || undefined;
|
||||
var roleId = result.id.toString();
|
||||
|
||||
if(principalId !== null && principalId !== undefined && (typeof principalId !== 'string') ) {
|
||||
principalId = principalId.toString();
|
||||
}
|
||||
|
||||
if (principalType && principalId) {
|
||||
roleMappingModel.findOne({where: {roleId: result.id,
|
||||
roleMappingModel.findOne({where: {roleId: roleId,
|
||||
principalType: principalType, principalId: principalId}},
|
||||
function (err, result) {
|
||||
debug('Role mapping found: %j', result);
|
||||
|
|
|
@ -379,7 +379,7 @@ User.resetPassword = function(options, cb) {
|
|||
|
||||
options = options || {};
|
||||
if(typeof options.email === 'string') {
|
||||
UserModel.findOne({email: options.email}, function(err, user) {
|
||||
UserModel.findOne({ where: {email: options.email} }, function(err, user) {
|
||||
if(err) {
|
||||
cb(err);
|
||||
} else if(user) {
|
||||
|
@ -392,7 +392,8 @@ User.resetPassword = function(options, cb) {
|
|||
cb();
|
||||
UserModel.emit('resetPasswordRequest', {
|
||||
email: options.email,
|
||||
accessToken: accessToken
|
||||
accessToken: accessToken,
|
||||
user: user
|
||||
});
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"name": "loopback",
|
||||
"description": "LoopBack: Open Mobile Platform for Node.js",
|
||||
"homepage": "http://loopback.io",
|
||||
"keywords": [
|
||||
"StrongLoop",
|
||||
"LoopBack",
|
||||
|
@ -9,7 +10,7 @@
|
|||
"Platform",
|
||||
"mBaaS"
|
||||
],
|
||||
"version": "1.8.1",
|
||||
"version": "1.8.2",
|
||||
"scripts": {
|
||||
"test": "mocha -R spec"
|
||||
},
|
||||
|
@ -29,10 +30,10 @@
|
|||
"async": "~0.2.10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"loopback-datasource-juggler": "~1.3.11"
|
||||
"loopback-datasource-juggler": "^1.3.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"loopback-datasource-juggler": "~1.3.11",
|
||||
"loopback-datasource-juggler": "^1.3.11",
|
||||
"mocha": "~1.17.1",
|
||||
"strong-task-emitter": "0.0.x",
|
||||
"supertest": "~0.9.0",
|
||||
|
|
|
@ -3,8 +3,9 @@ describe('GeoPoint', 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});
|
||||
|
||||
assert.equal(here.distanceTo(there, {type: 'meters'}), 782777.923052584);
|
||||
var distance = here.distanceTo(there, {type: 'meters'});
|
||||
|
||||
assert.equal(Math.floor(distance), 782777);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -12,8 +13,9 @@ describe('GeoPoint', 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'});
|
||||
|
||||
assert.equal(GeoPoint.distanceBetween(here, there, {type: 'feet'}), 2568169.038886431);
|
||||
assert.equal(Math.floor(distance), 2568169);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue