Merge branch 'release/1.8.2' into production

This commit is contained in:
Miroslav Bajtoš 2014-05-16 20:11:08 +02:00
commit 8a924c3e73
10 changed files with 81 additions and 164 deletions

View File

@ -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

View File

@ -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"
],

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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
});
}
})

View File

@ -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",

View File

@ -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);
});
});