Compare commits

..
113 Commits
Author SHA1 Message Date
Natan Rolnik 7a3c9cd33a Changelog 2.3.4 (#3533) 2017-02-19 08:44:33 -05:00
Florent Vilmart 193e5a4278 Make sure we don't treat dot notation keys as topLevel atoms (#3531)
Fixing GeoPoints and Files in _GlobalConfig
2017-02-19 12:07:54 +02:00
Jeremy Louie 6ae0675010 Use flushdb instead of flushall in RedisCacheAdapter (#3523) 2017-02-18 19:36:43 -05:00
David Starke a520ea0243 Fix LiveQuery unsafe user (#3525)
* LiveQuery should not use unsafe user setting

* server should issue queries with the master key
2017-02-18 19:36:20 -05:00
Greenkeeper 58bdeeee2d chore(package): update pg-promise to version 5.5.7 (#3528)
https://greenkeeper.io/
2017-02-18 19:24:32 -05:00
Vitaly Tomilov fc7f9f76f5 removing inline sql. (#3529)
* removing inline sql.

* Update index.js

trying to fix indentation.

* Update index.js

commenting out console output for errors.

* Rename json-object-set-key.sql to json-object-set-keys.sql

* Update index.js

* Update add-unique.sql

correcting sql.

* Update add.sql

correcting sql.

* Update contains-all.sql

correcting sql.

* Update contains.sql

correcting sql.

* Update remove.sql

correcting sql.

* Update json-object-set-keys.sql

fixing sql reserved words.
2017-02-18 14:26:25 -05:00
Greenkeeper ef8d534679 chore(package): update babel-core to version 6.23.1 (#3512)
https://greenkeeper.io/
2017-02-17 10:18:12 -08:00
Greenkeeper 1c9852e53f chore(package): update babel-core to version 6.23.0 (#3509)
https://greenkeeper.io/
2017-02-17 10:16:43 -08:00
Greenkeeper 3f0de0c2ed chore(package): update babel-register to version 6.23.0 (#3510)
https://greenkeeper.io/
2017-02-17 10:14:27 -08:00
Greenkeeper eccdeccb59 chore(package): update babel-cli to version 6.23.0 (#3511)
https://greenkeeper.io/
2017-02-17 10:14:10 -08:00
Greenkeeper f16f8423db chore(package): update mongodb to version 2.2.24 (#3513)
https://greenkeeper.io/
2017-02-17 10:13:55 -08:00
Greenkeeper bd60a5c1d1 chore(package): update body-parser to version 1.16.1 (#3499)
https://greenkeeper.io/
2017-02-11 15:03:05 -08:00
Robin Naundorf 40b9f953ca Fix small display errors (#3500)
* Add missing '$' to declare variable
* Move \n to correct position
2017-02-11 12:24:09 -05:00
Héctor Ramos 15eafd4dcc Update ISSUE_TEMPLATE.md 2017-02-10 11:56:58 -08:00
Héctor Ramos 11cde12245 Merge pull request #3497 from acinader/allow-empty-client-key
Allow empty client key
2017-02-09 16:16:49 -08:00
Arthur Cinader 5861996cb0 explicitly check if auth keys are undefined
Simply checking if they are truthy causes a false negative
if the value is ''.
2017-02-09 15:20:10 -08:00
Arthur Cinader ca70ad0141 Add a unit test to fail when clientKey='' 2017-02-09 14:50:28 -08:00
Natan Rolnik 5a22df13a5 Changelog 2.3.3 (#3493) 2017-02-09 17:13:15 +02:00
Greenkeeper 5b7144176c chore(package): update ws to version 2.0.3 (#3488)
https://greenkeeper.io/
2017-02-08 10:43:00 -08:00
Arthur Cinader 4979503f63 Two tests that fail often. Give em a little more time. (#3453) 2017-02-08 10:06:42 -08:00
Greenkeeper e32a37c2ec chore(package): update bcryptjs to version 2.4.3 (#3485)
https://greenkeeper.io/
2017-02-08 09:09:29 -08:00
Florent Vilmart f7f17cdb23 Update package.json (#3480)
* Update package.json

* Update .travis.yml
2017-02-06 10:41:33 -07:00
nodechefMatt ecf422b2d9 Mongo object to Parse object date serialization - avoid re-serialization of iso of type Date (#3389)
* Mongo object to Parse object date serialization - avoid nested ios

* Mongo object to Parse object date serialization

* Remove file from previous commit
2017-02-04 08:32:35 -08:00
Greenkeeper 49dc8df1de chore(package): update babel-cli to version 6.22.2 (#3411)
https://greenkeeper.io/
2017-02-03 21:40:32 -08:00
Greenkeeper c3c5f06efd chore(package): update babel-register to version 6.22.0 (#3409)
https://greenkeeper.io/
2017-02-03 21:40:21 -08:00
Greenkeeper 2a454fec35 chore(package): update babel-preset-es2015 to version 6.22.0 (#3408)
https://greenkeeper.io/
2017-02-03 21:40:07 -08:00
Greenkeeper 01b4c4e0cb chore(package): update babel-plugin-transform-flow-strip-types to version 6.22.0 (#3406)
https://greenkeeper.io/
2017-02-03 21:39:18 -08:00
Greenkeeper 3714d68aaf chore(package): update babel-preset-stage-0 to version 6.22.0 (#3407)
https://greenkeeper.io/
2017-02-03 21:38:49 -08:00
Greenkeeper 77daa3ca18 chore(package): update ws to version 2.0.2 (#3475)
https://greenkeeper.io/
2017-02-03 21:37:24 -08:00
Greenkeeper 0b574f04a9 chore(package): update babel-core to version 6.22.1 (#3412)
https://greenkeeper.io/
2017-02-03 21:37:05 -08:00
Greenkeeper a89a30182e chore(package): update mongodb to version 2.2.22 (#3426)
https://greenkeeper.io/
2017-02-03 21:36:53 -08:00
Jack Wearden 96a9588a6e MongoDB $or Queries avoid SERVER-13732 bug (#3476)
MongoDB has an unfixed bug in all supported versions 2.6-3.4 which
results in suboptimal index usage for `$or` queries when the query has
implicit `$and`s at the query root.

When adding `_rperm` to `$or` queries, Parse accidentally creates
queries which hit this bug.

The fix in this commit applies the suggested workaround of putting the
`_rperm` property inside all `$or` subdocuments, moving it from the top
level and leaving `$or` as the only top-level operator.

MongoDB Bug Link: https://jira.mongodb.org/browse/SERVER-13732
2017-02-03 21:34:19 -08:00
Greenkeeper 66cdfaed4b chore(package): update ws to version 2.0.1 (#3465)
https://greenkeeper.io/
2017-02-02 14:05:05 -08:00
Greenkeeper 9262147a6f chore(package): update pg-promise to version 5.5.6 (#3461)
https://greenkeeper.io/
2017-02-02 12:00:07 -08:00
Greenkeeper 8b4e9ca637 chore(package): update multer to version 1.3.0 (#3434)
https://greenkeeper.io/
2017-02-02 11:52:20 -08:00
Greenkeeper 2160d10990 chore(package): update redis to version 2.6.5 (#3377)
https://greenkeeper.io/
2017-02-02 09:10:21 -08:00
Arthur Cinader e7f2995143 Adjust a test for change to logging. (#3452) 2017-01-30 13:28:52 -05:00
Arthur Cinader d5940b17b6 Add logging on failure to create file (#3424) 2017-01-30 12:36:30 -05:00
Arthur Cinader f864141663 Log Parse Errors so they are intelligible. (#3431)
The problem this pr is trying to solve:

When an error occurs on the server, a message should
be returned to the client, and a message should be logged.

Currently, on the server, the log is just [object, object]

This pr will stop calling the default express error handler
which causes two problems: 1. it writes to console instead of log file
2. the output is completely useless! :)

Instead, we'll log the error ourselves using the ParseServer's logger.

fixes: #661
2017-01-30 12:32:54 -05:00
Elliot Blackburn 711db9ccd2 Remove duplicate word from the README log section (#3450)
In the "Logging" section it originally read: "Parse Server, will, by default, will log:", I've removed the second "will" to make "Parse Server will, by default, log:".
2017-01-30 14:39:18 +02:00
Greenkeeper 6a6829ce80 chore(package): update express to version 4.14.1 (#3445)
https://greenkeeper.io/
2017-01-29 15:08:47 -05:00
Ricardo Matsui d67be492f5 Verify pushes are sent to the expected number of installations (#3418) 2017-01-28 11:10:21 -08:00
Greenkeeper ea45f69af6 chore(package): update winston-daily-rotate-file to version 1.4.4 (#3442)
https://greenkeeper.io/
2017-01-28 09:18:21 -08:00
Greenkeeper 43c3d8e2a2 chore(package): update winston to version 2.3.1 (#3414)
https://greenkeeper.io/
2017-01-23 10:29:40 -07:00
Greenkeeper d8a1a614e8 chore(package): update body-parser to version 1.16.0 (#3391)
https://greenkeeper.io/
2017-01-19 13:42:17 -08:00
Greenkeeper 553db0ada5 chore(package): update pg-promise to version 5.5.2 (#3379)
https://greenkeeper.io/
2017-01-19 11:01:03 -08:00
Greenkeeper 388a59d816 chore(package): update pg-promise to version 5.5.1 (#3362)
https://greenkeeper.io/
2017-01-19 11:00:34 -08:00
Greenkeeper de4c1ee418 Update mongodb to version 2.2.21 🚀 (#3368)
* chore(package): update mongodb to version 2.2.20

https://greenkeeper.io/

* Fix race when fetching schema frequently

* Bumps mongo to 2.2.21
2017-01-16 13:26:14 -08:00
Florent Vilmart cb15c0b616 Disallow failures for PG (#3372) 2017-01-16 13:24:45 -08:00
Greenkeeper 8dd864a033 chore(package): update parse-server-push-adapter to version 1.2.0 (#3386)
https://greenkeeper.io/
2017-01-16 11:27:19 -05:00
Florent Vilmart c26db2248f use uWS as optional dependency for ws server (#3231)
* use uWS as optional dependency for ws server

* Update ParseWebSocketServer.js
2017-01-14 07:43:31 -08:00
Greenkeeper b2a3479dbf chore(package): update winston-daily-rotate-file to version 1.4.3 (#3369)
https://greenkeeper.io/
2017-01-14 07:40:57 -08:00
Florent Vilmart deedf7b370 Push scalability (#3080)
* Update status through increment
* adds support for incrementing nested keys
* fix issue when having spaces in keys for ordering
* Refactors PushController to use worker
* Adds tests for custom push queue config
* Makes PushController adapter independant
* Better logging of _PushStatus in VERBOSE
2017-01-13 19:34:04 -05:00
Greenkeeper 5f849ca662 chore(package): update redis to version 2.6.4 (#3364)
https://greenkeeper.io/
2017-01-12 21:45:14 -05:00
Greenkeeper 0279b5e5f3 chore(package): update jasmine to version 2.5.3 (#3358)
https://greenkeeper.io/
2017-01-11 18:54:23 -08:00
Arthur Cinader 4cb6e7d209 Add lint rule space-infix-ops (#3237)
Disallows: 1+1.  Must be 1 + 1.
2017-01-11 12:31:40 -08:00
Greenkeeper 56bb505df2 chore(package): update jasmine-spec-reporter to version 3.1.0 (#3344)
https://greenkeeper.io/
2017-01-11 12:31:15 -08:00
Arthur Cinader ceb5a1b5f0 chore(package): update jasmine-spec-reporter to version 3.0.0 (#3333)
https://greenkeeper.io/

Fix parse-server to work with jasmine-spec-reporter-3.0.0
2017-01-11 11:53:24 -08:00
Natan Rolnik 0958b15297 Changelog 2.3.2 (#3343)
* Updates package.json: version to 2.3.2

* Updates Changelog for 2.3.2
2017-01-09 15:46:34 +02:00
Lenart Rudel 5d9dbea07b Add parseFrameURL for masking user-facing pages (#3267)
* Add parseFrameURL for masking user-facing pages.

Allow users to specify a different address which is used to mask parse
requests for verifying email and resetting password. This is how Parse.com
used to allow customers to gain control over page content, styling etc.

On the destination page javascript is used to check the link in the request
and embed the parse server page using IFRAME.

* Fix code indentation

* Rename method for building link and pass config to it.

* Add customPages options to README.md.

* Add tests for parseFrameURL email link building, and parseFrameURL option.

* Add parseFrameURL for masking user-facing pages.

Allow users to specify a different address which is used to mask parse
requests for verifying email and resetting password. This is how Parse.com
used to allow customers to gain control over page content, styling etc.

On the destination page javascript is used to check the link in the request
and embed the parse server page using IFRAME.

* Fix code indentation

* Rename method for building link and pass config to it.

* Add customPages options to README.md.

* Don't Object.assign to defaultConfiguration global
2017-01-08 10:56:57 -08:00
Bhaskar Reddy Yasa f331f6644c Add support for regex string for password policy validatorPattern setting (#3331) 2017-01-08 07:12:44 -08:00
David Starke df029b82eb LiveQuery should match subobjects with dot notation (#3322)
* LiveQuery should match subobjects with dot notation

* one additional test case
2017-01-06 17:06:25 -08:00
Arthur Cinader edba550cf6 winston-daily-roate-file-1.4.2 makes a change where timestamp is not on by default anymore. (#3335)
see: https://github.com/winstonjs/winston-daily-rotate-file/commit/aa28f522718778fe8210ced1090353ffc29c6f31

pretty incredible that they would release this as a patch release, but my fix is solid and defensive

chore(package): update winston-daily-rotate-file to version 1.4.2

https://greenkeeper.io/
2017-01-06 16:32:03 -08:00
Greenkeeper c7775eb0b9 chore(package): update cross-env to version 3.1.4 (#3308)
https://greenkeeper.io/
2017-01-06 14:50:09 -08:00
Greenkeeper 0b44820a7d chore(package): update winston-daily-rotate-file to version 1.4.1 (#3317)
https://greenkeeper.io/
2017-01-06 13:20:12 -08:00
Greenkeeper b7322064d8 chore(package): update pg-promise to version 5.5.0 (#3224)
https://greenkeeper.io/
2017-01-04 09:41:21 -05:00
jeacott1 ac3f5cd686 this function was extremely slow. (#3264)
this fix reduces the time to process 165k installations
from 282738.599ms (almost 5 minutes of total server lockup!)
to just 16.283ms!
2017-01-04 09:27:47 -05:00
Greenkeeper 9fd34fd25e chore(package): update bcryptjs to version 2.4.0 (#3225)
https://greenkeeper.io/
2017-01-03 16:42:59 -06:00
Greenkeeper 7ff3a3813d chore(package): update babel-core to version 6.21.0 (#3249)
https://greenkeeper.io/
2017-01-02 15:04:18 -06:00
Greenkeeper 754f5d0505 chore(package): update babel-plugin-transform-flow-strip-types to version 6.21.0 (#3250)
https://greenkeeper.io/
2017-01-02 14:40:30 -06:00
Greenkeeper 0e8c3c2457 chore(package): update multer to version 1.2.1 (#3276)
https://greenkeeper.io/
2017-01-02 14:09:24 -06:00
Greenkeeper 423a50133a chore(package): update lodash to version 4.17.4 (#3303)
https://greenkeeper.io/
2017-01-02 13:25:37 -06:00
Greenkeeper a3d416de4a chore(package): update bcrypt to version 1.0.2 (#3304)
https://greenkeeper.io/
2017-01-01 12:01:59 -06:00
Greenkeeper a2dfcc8da8 chore(package): update babel-core to version 6.20.0 (#3216)
https://greenkeeper.io/
2017-01-01 08:44:38 -06:00
Arthur Cinader f4734a65c0 fix trivial typo (#3238) 2016-12-14 14:28:23 -08:00
Florent Vilmart aa071e034e Changelog 2.3.1 (#3213)
* Update CHANGELOG.md

* Update package.json
2016-12-08 14:30:59 -05:00
Florent Vilmart 4f46eceacf Fixes issue affecting the auth providers (#3211)
* Reproduces error for issue 3208

* Make sure we don't override a default adapter with the options when validation function are not provided
2016-12-08 08:54:06 -08:00
Florent Vilmart 81ebbb8954 Update README.md 2016-12-08 10:16:31 -05:00
Greenkeeper e82395e268 chore(package): update bcrypt to version 1.0.1 (#3207)
https://greenkeeper.io/
2016-12-08 09:55:35 -05:00
Florent Vilmart 0159360a5d Fixes CI dist (#3206) 2016-12-07 19:57:13 -08:00
Florent Vilmart aab10bea79 Changelog 2.3.0 (#3205)
* 2.3.0 changelog

* bumps package

* Update CHANGELOG.md

* Update CHANGELOG.md

* Update CHANGELOG.md
2016-12-07 20:48:54 -05:00
Florent Vilmart 752f0e9143 Fixes #3195 (#3201)
* Adds error reproduction

* Fix transform in order to accept nested array results in $in/$nin

The error originated by the nesting of 2 array in $in [["..."]], using _.flatMap with those will guarantee at the lower level
that the query is properly resolved

* nits

* _.flatMap the $in/$nin values
2016-12-07 20:03:40 -05:00
Florent Vilmart 025e7a3218 Adds depreciation notes for Parse.Cloud.useMasterKey(), (#3204)
Adds depreciation notes for Parse.Cloud.useMasterKey()
2016-12-07 18:35:22 -05:00
Arthur Cinader ca286b7108 Enable prefer-const lint rule (#3202) 2016-12-07 18:17:05 -05:00
Florent Vilmart a6c988176e Adds tests that shows issue #3194 is ok (#3200) 2016-12-07 14:18:52 -08:00
corban baxter e069b20ef9 adding simple test for adding and removing users on a role. (#3198) 2016-12-07 16:15:01 -05:00
Arthur Cinader ae30ec647b let's see if i can force latest to rebuild... (#3196) 2016-12-07 08:57:01 -08:00
Greenkeeper fc53fa9c32 chore(package): update parse-server-s3-adapter to version 1.0.6 (#3192)
https://greenkeeper.io/
2016-12-06 16:56:26 -08:00
Florent Vilmart c1dcaf1271 Auth Adapters refactoring (#3177)
* Moves all authentication providers to Adapter/Auth

* refactors specs

* Deprecates oauth option in favor of auth option

- Deprecates facebookAppIds option (in favor of auth.facebook.appIds)
- Adds warnings about the deprecated options

* nits
2016-12-06 14:09:43 -08:00
Florent Vilmart a9067260fc adds ability to pass custom installationId to create sessions in cloud code (#3156) 2016-12-06 16:46:09 -05:00
Florent Vilmart 2e569ca7dd Fixes SchemaController data for Volatile Classes (#3171)
* Reproduction for the issue

* Ensures Volatile classes and other schema share the same structure
2016-12-06 16:42:54 -05:00
Arthur Cinader 8111c3338e turn on max empty line rule with default of max: 2. (#3176)
Run with fix.
2016-12-06 13:35:23 -08:00
Florent Vilmart fb36dfa26f Fix #3185 (#3186)
* Adds tests that reproduce the issue

* Use values from keys to force include when needed
2016-12-06 16:28:55 -05:00
Andrew Lane 998b271994 HyperDev changed its name to Gomix, so reflect that in the README (#3191) 2016-12-06 10:44:37 -08:00
Florent Vilmart a7821f6e57 Removes NodeChef (#3188)
NodeChef explicitly runs a private fork of parse-server, we should not support this.

Explicitely, Scheduled Push and Cloud Code browser are most requested features, that they didn't provide back to the community.
2016-12-06 10:39:21 -05:00
Greenkeeper ddb6f7bc57 chore(package): update bcrypt to version 1.0.0 (#3178)
https://greenkeeper.io/
2016-12-05 19:08:46 -08:00
Kulshekhar Kabra 8124bf4600 Add a CLI option to specify the host (#3180) 2016-12-05 08:50:46 -05:00
Kulshekhar Kabra df74a1f8ae Use trusty in travis (#3170)
* Use trusty in travis

* Install postgresql-9.5-postgis-2.3 in travis
2016-12-03 18:43:30 -05:00
Florent Vilmart e0704b440c Adds class level permission requiring authenticated user (#893)
* Adds class level permission requiring authenticated user

* Updates to latest schema permissions syntax

* fix flaky test

* Exclude PG

* Rebased and nitted

* lints
2016-12-02 19:47:33 -05:00
Arthur Cinader 01b05b060f Strip personally identifiable information from user table for unauthorized users.
- add a config option to explicitly enumerate pii fields beyond email
- in query controller, strip pii of user table results before sending out the door.
2016-12-02 19:39:09 -05:00
Arthur Cinader a270632570 More lint tweaking (#3164)
1. Add no space in paren rule
2. fix spec/eslintrc.json so it allow for inheriting from root rc.

Because the spce rc specified reccomended, it "turned off" all of the
rule tweaks in the root.  This fixes that.
2016-12-02 19:11:54 -05:00
Florent Vilmart b9afccd338 Makes sudo: false (#3166)
* Makes sudo: false

* ignore error when configuring postgis

* Use precise instead of trusty
2016-12-02 17:53:32 -05:00
Arthur Cinader 37daafc7b0 Add strip whitespace and trailing eol to spec too. (#3159) 2016-12-01 21:45:49 -05:00
Arthur Cinader 8359284329 Fix some random minor typos. (#3157) 2016-12-01 20:34:39 -05:00
Greenkeeper 2b0c39caaa chore(package): update pg-promise to version 5.4.5 (#3140)
https://greenkeeper.io/
2016-12-01 17:59:10 -05:00
Arthur Cinader 11f7712651 Add no trailing whitespace and force eol at end of file. (#3154) 2016-12-01 13:24:46 -05:00
Arthur Cinader 7292fa7f11 Allow select (keys) to be altered in triggers (#3146)
Inspect the keys when a query is returned from a trigger and respect the new
value.
2016-12-01 10:04:47 -05:00
Arthur Cinader 4d17bed374 lint before test. (#3147)
Also turn on lint cacheing to make this change painless ;)
add lint cache to gitignore...
2016-11-30 17:58:59 -05:00
Steven Shipton 143bd11638 Change arg check from truthy to defined (#3143)
Show log on master when using cluster
2016-11-30 08:48:49 -05:00
Bhaskar Reddy Yasa bd1689190f Adds password history support to passwordPolicy (#3102)
* password history support in passwordPolicy

* Refactor RestWrite.transformUser

* fix eslint issues
2016-11-29 09:01:52 -08:00
Greenkeeper 08bac9f790 chore(package): update pg-promise to version 5.4.4 (#3121)
https://greenkeeper.io/
2016-11-29 12:01:49 -05:00
Greenkeeper f2df0303b2 chore(package): update winston-daily-rotate-file to version 1.4.0 (#3132)
https://greenkeeper.io/
2016-11-29 10:53:24 -05:00
Steven Shipton fbb2b086af ensure batch routing paths are posix (#3138) 2016-11-29 09:52:17 -05:00
171 changed files with 4778 additions and 2323 deletions
+7 -1
View File
@@ -15,6 +15,12 @@
},
"rules": {
"indent": ["error", 2],
"linebreak-style": ["error", "unix"]
"linebreak-style": ["error", "unix"],
"no-trailing-spaces": 2,
"eol-last": 2,
"space-in-parens": ["error", "never"],
"no-multiple-empty-lines": 1,
"prefer-const": "error",
"space-infix-ops": "error"
}
}
+9 -33
View File
@@ -1,50 +1,28 @@
Please read the following instructions carefully.
We use GitHub Issues for bugs.
Check out https://github.com/ParsePlatform/parse-server/issues/1271 for an ideal bug report.
The closer your issue report is to that one, the more likely we are to be able to help, and the more likely we will be to fix the issue quickly!
If you have a non-bug question, ask on Stack Overflow or Server Fault:
- https://stackoverflow.com/questions/tagged/parse.com
- https://serverfault.com/tags/parse
Many members of the community use Stack Overflow and Server Fault to ask questions.
Read through the existing questions or ask your own!
- Stack Overflow: http://stackoverflow.com/questions/tagged/parse.com
- Server Fault: https://serverfault.com/tags/parse
You may also search through existing issues before opening a new one: https://github.com/ParsePlatform/Parse-Server/issues?utf8=%E2%9C%93&q=is%3Aissue
For database migration help, please file a bug report at https://parse.com/help#report
Make sure these boxes are checked before submitting your issue -- thanks for reporting issues back to Parse Server!
- [ ] You've met the prerequisites: https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#prerequisites.
- [ ] You're running the latest version of Parse Server: https://github.com/ParsePlatform/parse-server/releases
- [ ] You've searched through existing issues: https://github.com/ParsePlatform/Parse-Server/issues?utf8=%E2%9C%93&q=is%3Aissue Chances are that your issue has been reported or resolved before.
- [ ] You have filled out every section below. Issues without sufficient information are more likely to be closed.
--
--- Please use this template. If you don't use this template, your issue may be closed without comment. ---
### Issue Description
[DELETE EVERYTHING ABOVE THIS LINE BEFORE SUBMITTING YOUR ISSUE]
Describe your issue in as much detail as possible.
[FILL THIS OUT]
### Steps to reproduce
Please include a detailed list of steps that reproduce the issue. Include curl commands when applicable.
1. [FILL THIS OUT]
2. [FILL THIS OUT]
3. [FILL THIS OUT]
#### Expected Results
[FILL THIS OUT]
What you expected to happen.
#### Actual Outcome
[FILL THIS OUT]
What is happening instead.
### Environment Setup
@@ -62,6 +40,4 @@ Please include a detailed list of steps that reproduce the issue. Include curl c
### Logs/Trace
You can turn on additional logging by configuring VERBOSE=1 in your environment.
[FILL THIS OUT]
Include all relevant logs. You can turn on additional logging by configuring VERBOSE=1 in your environment.
+1
View File
@@ -44,6 +44,7 @@ lib/
# cache folder
.cache
.eslintcache
# Mac DS_Store files
.DS_Store
+14 -15
View File
@@ -1,8 +1,7 @@
language: node_js
dist: trusty
sudo: required
node_js:
- '4.5'
- '4.6'
- '6.1'
services:
- postgresql
@@ -10,12 +9,13 @@ services:
- docker
addons:
postgresql: '9.5'
apt_packages:
- postgresql-9.5-postgis-2.3
before_script:
- ls -al "$HOME/.mongodb/versions"
- psql -c 'create database parse_server_postgres_adapter_test_database;' -U postgres
- psql -c 'CREATE EXTENSION postgis;' -U postgres -d parse_server_postgres_adapter_test_database
- psql -c 'CREATE EXTENSION postgis_topology;' -U postgres -d parse_server_postgres_adapter_test_database
- npm run lint
env:
global:
- COVERAGE_OPTION='./node_modules/.bin/istanbul cover'
@@ -26,8 +26,6 @@ env:
- PARSE_SERVER_TEST_CACHE=redis
matrix:
fast_finish: true
allow_failures:
- env: PARSE_SERVER_TEST_DB=postgres
branches:
only:
- master
@@ -45,6 +43,17 @@ after_success:
- export $(cat resources/.to_export_back)
deploy:
- provider: npm
skip_cleanup: true
email:
secure: T3LwSJFcu632SDfCoavcKL39NktWLEOOFzonAjeHAglmMyDp9hvU8xHwQ4JJy2CRA03c+ezAe2gH3Va+jfxvh1JtFUan+p88vaCHHKuNwPSp4WZBPt1ZTDmG+ACG6j+ZWHK+eP7hLvtlCi/M9/v4/bVojpm7v01LLiM+MRhnE9E7eLemQC4zb6RVtf2oGQ3mX51kMeya218kEm5bsQPpRJElI9jwletFa8qYK5AFgaCHpll059RRHQTTE9MTNcN58P/Kf6Qb3KGpKNoaHTXoOD4U6LcXLWvdHONVB6AzGefxg2b/dvtaO4nd5lDooMBR3u9kWpopXkyAuf+fO/8je9JTxO6CDUtDjHRcR2mCEXWX6rculIAbNXOv1ccRYCTQ8aFtYnFlMSb1+QIAdyT6HHmeT5ktk3+XJRuEv0PJJvqHTo+j7tPngjiv5sPNutgGFlOFO90omTbzEkIT/D/LsgXbWm2QKYWejbLiuSINg+FiFiZN90doCf4aCpm2y1Q/9GzvK+eXcpqzPCGxOykE7EuPZK3+S/ZU2oaWL2uSpbKPtC0qxebrneR307aVEa7C85HCkTMMBzE4tjUr8h5HhLqtWvqmDcnBo3PfQhf9cEO6jQLd3qhEVJmcwKz/yOCfgPXlCbRqiKk7j94perpNCIalXtMI9ySYjJNjHsB4600=
api_key:
secure: WLjhHVAdUkDy6UdNWveTpZqphw9olN0alCpyPpU0cJjlN/hk7YxPP+YHOSVnMZaRZoHM0LL11jPKLf970nymBfvJHDWxKk71c/5xyTX8pBtSxmGmGy23a5g2VrHVMd2JxsI7NEAH500tlFz+01t4E3Steo0NpAkHR3Q51kj01gQy8IumsksfhRc9uvjZ7zjm99Yk4L+cxyei79v4esfpx7Bgm0HTfAAAG/19F+r0hvvFiV517SREDU/YtcX/rIjVepEy1uiLKEohnmYtVIRSA3Hjh6VlHVhdj2WDd/dYrxi/Ioysq2zOM9pZVLamO9asB1e6JrTEipWE9jSZXxsbnfFzuNLxcOjKv1wd3OzQKF/7pGKGiWRTv5Xm19D/FrXoE/ULs6bHcC/Ke8Gs2RxPlOCdvAFehCkyf5P4HOPCQdR7o8Yiuvt+5JWKBflElNbSd4nWgwUOo3Yv8vC4Vj53fwmM+Uqfu3IgYFWktYxCm4RWIKMfB/gtmjcF6QYFfjvEMwAvRfBV81kuynCsnubXWzQeBE/b3JOhBfpGciKCjKfy+tS6bZfFjCtQV98hMMiCPre8Y7PahHDYc65wU9Ake+ZE+dDaSbeV3DZ5JeifLJHzKW2J2dWeRANkOaiSwO9VBC9/rht5ulK5qQ1pB2+sKDToAaiKy6RMlB/HgIoYqsU=
on:
tags: true
all_branches: true
condition: "$BUILD_LEADER$BUILD_AGGREGATE_STATUS = YESothers_succeeded"
repo: ParsePlatform/parse-server
- provider: script
skip_cleanup: true
script: ./resources/npm-git.sh
@@ -58,13 +67,3 @@ deploy:
tags: true
all_branches: true
condition: "$BUILD_LEADER$BUILD_AGGREGATE_STATUS = YESothers_succeeded"
- provider: npm
email:
secure: T3LwSJFcu632SDfCoavcKL39NktWLEOOFzonAjeHAglmMyDp9hvU8xHwQ4JJy2CRA03c+ezAe2gH3Va+jfxvh1JtFUan+p88vaCHHKuNwPSp4WZBPt1ZTDmG+ACG6j+ZWHK+eP7hLvtlCi/M9/v4/bVojpm7v01LLiM+MRhnE9E7eLemQC4zb6RVtf2oGQ3mX51kMeya218kEm5bsQPpRJElI9jwletFa8qYK5AFgaCHpll059RRHQTTE9MTNcN58P/Kf6Qb3KGpKNoaHTXoOD4U6LcXLWvdHONVB6AzGefxg2b/dvtaO4nd5lDooMBR3u9kWpopXkyAuf+fO/8je9JTxO6CDUtDjHRcR2mCEXWX6rculIAbNXOv1ccRYCTQ8aFtYnFlMSb1+QIAdyT6HHmeT5ktk3+XJRuEv0PJJvqHTo+j7tPngjiv5sPNutgGFlOFO90omTbzEkIT/D/LsgXbWm2QKYWejbLiuSINg+FiFiZN90doCf4aCpm2y1Q/9GzvK+eXcpqzPCGxOykE7EuPZK3+S/ZU2oaWL2uSpbKPtC0qxebrneR307aVEa7C85HCkTMMBzE4tjUr8h5HhLqtWvqmDcnBo3PfQhf9cEO6jQLd3qhEVJmcwKz/yOCfgPXlCbRqiKk7j94perpNCIalXtMI9ySYjJNjHsB4600=
api_key:
secure: WLjhHVAdUkDy6UdNWveTpZqphw9olN0alCpyPpU0cJjlN/hk7YxPP+YHOSVnMZaRZoHM0LL11jPKLf970nymBfvJHDWxKk71c/5xyTX8pBtSxmGmGy23a5g2VrHVMd2JxsI7NEAH500tlFz+01t4E3Steo0NpAkHR3Q51kj01gQy8IumsksfhRc9uvjZ7zjm99Yk4L+cxyei79v4esfpx7Bgm0HTfAAAG/19F+r0hvvFiV517SREDU/YtcX/rIjVepEy1uiLKEohnmYtVIRSA3Hjh6VlHVhdj2WDd/dYrxi/Ioysq2zOM9pZVLamO9asB1e6JrTEipWE9jSZXxsbnfFzuNLxcOjKv1wd3OzQKF/7pGKGiWRTv5Xm19D/FrXoE/ULs6bHcC/Ke8Gs2RxPlOCdvAFehCkyf5P4HOPCQdR7o8Yiuvt+5JWKBflElNbSd4nWgwUOo3Yv8vC4Vj53fwmM+Uqfu3IgYFWktYxCm4RWIKMfB/gtmjcF6QYFfjvEMwAvRfBV81kuynCsnubXWzQeBE/b3JOhBfpGciKCjKfy+tS6bZfFjCtQV98hMMiCPre8Y7PahHDYc65wU9Ake+ZE+dDaSbeV3DZ5JeifLJHzKW2J2dWeRANkOaiSwO9VBC9/rht5ulK5qQ1pB2+sKDToAaiKy6RMlB/HgIoYqsU=
on:
tags: true
all_branches: true
condition: "$MONGODB_VERSION = '3.0.8'"
repo: ParsePlatform/parse-server
+81 -2
View File
@@ -1,5 +1,84 @@
## Parse Server Changelog
### 2.3.4
[Full Changelog](https://github.com/ParsePlatform/parse-server/compare/2.3.3...2.3.4)
#### Bug Fixes
* Allow empty client key
(#3497), thanks to [Arthur Cinader](https://github.com/acinader)
* Fix LiveQuery unsafe user
(#3525), thanks to [David Starke](https://github.com/dstarke)
* Use `flushdb` instead of `flushall` in RedisCacheAdapter
(#3523), thanks to [Jeremy Louie](https://github.com/JeremyPlease)
* Fix saving GeoPoints and Files in `_GlobalConfig` (Make sure we don't treat
dot notation keys as topLevel atoms)
(#3531), thanks to [Florent Vilmart](https://github.com/flovilmart)
### 2.3.3
[Full Changelog](https://github.com/ParsePlatform/parse-server/compare/2.3.2...2.3.3)
#### Breaking Changes
* **Minimum Node engine bumped to 4.6** (#3480), thanks to [Florent Vilmart](https://github.com/flovilmart)
#### Bug Fixes
* Add logging on failure to create file (#3424), thanks to [Arthur Cinader](https://github.com/acinader)
* Log Parse Errors so they are intelligible (#3431), thanks to [Arthur Cinader](https://github.com/acinader)
* MongoDB $or Queries avoid SERVER-13732 bug (#3476), thanks to [Jack Wearden](https://github.com/NotBobTheBuilder)
* Mongo object to Parse object date serialization - avoid re-serialization of iso of type Date (#3389), thanks to [nodechefMatt](https://github.com/nodechefMatt)
#### Improvements
* Ground preparations for push scalability (#3080), thanks to [Florent Vilmart](https://github.com/flovilmart)
* Use uWS as optional dependency for ws server (#3231), thanks to [Florent Vilmart](https://github.com/flovilmart)
### 2.3.2
[Full Changelog](https://github.com/ParsePlatform/parse-server/compare/2.3.1...2.3.2)
#### New features
* Add parseFrameURL for masking user-facing pages (#3267), thanks to [Lenart Rudel](https://github.com/lenart)
#### Bug fixes
* Fix Parse-Server to work with winston-daily-rotate-1.4.2 (#3335), thanks to [Arthur Cinader](https://github.com/acinader)
#### Improvements
* Add support for regex string for password policy validatorPattern setting (#3331), thanks to [Bhaskar Reddy Yasa](https://github.com/bhaskaryasa)
* LiveQuery should match subobjects with dot notation (#3322), thanks to [David Starke](https://github.com/dstarke)
* Reduce time to process high number of installations for push (#3264), thanks to [jeacott1](https://github.com/jeacott1)
* Fix trivial typo in error message (#3238), thanks to [Arthur Cinader](https://github.com/acinader)
### 2.3.1
[Full Changelog](https://github.com/ParsePlatform/parse-server/compare/2.3.0...2.3.1)
A major issue was introduced when refactoring the authentication modules.
This release addresses only that issue.
### 2.3.0
[Full Changelog](https://github.com/ParsePlatform/parse-server/compare/2.2.25...2.3.0)
#### Breaking changes
* Parse.Cloud.useMasterKey() is a no-op, please refer to (Cloud Code migration guide)[https://github.com/ParsePlatform/parse-server/wiki/Compatibility-with-Hosted-Parse#cloud-code]
* Authentication helpers are now proper adapters, deprecates oauth option in favor of auth.
* DEPRECATES: facebookAppIds, use `auth: { facebook: { appIds: ["AAAAAAAAA" ] } }`
* `email` field is not returned anymore for `Parse.User` queries. (Provided only on the user itself if provided).
#### New Features
* Adds ability to restrict access through Class Level Permissions to only authenticated users [see docs](http://parseplatform.github.io/docs/ios/guide/#requires-authentication-permission-requires-parse-server---230)
* Adds ability to strip sensitive data from `_User` responses, strips emails by default, thanks to [Arthur Cinader](https://github.com/acinader)
* Adds password history support for password policies, thanks to [Bhaskar Reddy Yasa](https://github.com/bhaskaryasa)
#### Improvements
* Bump parse-server-s3-adapter to 1.0.6, thanks to [Arthur Cinader](https://github.com/acinader)
* Using PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS let you create user sessions when passing {installationId: "xxx-xxx"} on signup in cloud code, thanks to [Florent Vilmart](https://github.com/flovilmart)
* Add CLI option to pass `host` parameter when creating parse-server from CLI, thanks to [Kulshekhar Kabra](https://github.com/kulshekhar)
#### Bug fixes
* Ensure batch routes are only using posix paths, thanks to [Steven Shipton](https://github.com/steven-supersolid)
* Ensure falsy options from CLI are properly taken into account, thanks to [Steven Shipton](https://github.com/steven-supersolid)
* Fixes issues affecting calls to `matchesKeyInQuery` with pointers.
* Ensure that `select` keys can be changed in triggers (beforeFind...), thanks to [Arthur Cinader](https://github.com/acinader)
#### Housekeeping
* Enables and enforces linting with eslint, thanks to [Arthur Cinader](https://github.com/acinader)
### 2.2.25
Postgres support requires v9.5
@@ -36,7 +115,7 @@ Postgres support requires v9.5
* Better Postgres support, thanks to [Kulshekhar Kabra](https://github.com/kulshekhar)
* Logs the function name when failing (#2963), thanks to [Michael Helvey](https://github.com/michaelhelvey)
* CLI: forces closing the connections with SIGINT/SIGTERM (#2964), thanks to [Kulshekhar Kabra](https://github.com/kulshekhar)
* Reduce the number of calls to the _SCHEMA table (#2912), thanks to [Steven Shipton](https://github.com/steven-supersolid)
* Reduce the number of calls to the `_SCHEMA` table (#2912), thanks to [Steven Shipton](https://github.com/steven-supersolid)
* LiveQuery: Support for Role ACL's, thanks to [Aaron Blondeau](https://github.com/aaron-blondeau-dose)
#### Bug Fixes
@@ -83,7 +162,7 @@ Postgres support requires v9.5
### 2.2.20
* New: Adds CloudCode handler for `beforeFind`, thanks to [Florent Vilmart](https://github.com/flovilmart)
* New: RedisCacheAdapter for syncing schema, role and user caches across servers, thanks to [Florent Vilmart](https://github.com/flovilmart)
* New: RedisCacheAdapter for syncing schema, role and user caches across servers, thanks to [Florent Vilmart](https://github.com/flovilmart)
* New: Latest master build available at `ParsePlatform/parse-server#latest`, thanks to [Florent Vilmart](https://github.com/flovilmart)
* Fix: Better support for upgradeToRevocableSession with missing session token, thanks to [Florent Vilmart](https://github.com/flovilmart)
* Fix: Removes babel-polyfill runtime dependency, thanks to [Florent Vilmart](https://github.com/flovilmart)
+6 -5
View File
@@ -122,10 +122,9 @@ We have provided a basic [Node.js application](https://github.com/ParsePlatform/
* [Microsoft Azure](https://azure.microsoft.com/en-us/blog/azure-welcomes-parse-developers/)
* [SashiDo](https://blog.sashido.io/tag/migration/)
* [Digital Ocean](https://www.digitalocean.com/community/tutorials/how-to-run-parse-server-on-ubuntu-14-04)
* [NodeChef](https://nodechef.com/blog/post/6/migrate-from-parse-to-nodechef%E2%80%99s-managed-parse-server)
* [Pivotal Web Services](https://github.com/cf-platform-eng/pws-parse-server)
* [Back4app](http://blog.back4app.com/2016/03/01/quick-wizard-migration/)
* [HyperDev](https://hyperdev.com/blog/use-parse-server-apps-backend-hyperdev/)
* [Gomix](https://gomix.com/#!/project/parse-server)
### Parse Server + Express
@@ -157,7 +156,7 @@ For a full list of available options, run `parse-server --help`.
## Logging
Parse Server will, by default, will log:
Parse Server will, by default, log:
* to the console
* daily rotating files as new line delimited JSON
@@ -207,7 +206,7 @@ The client keys used with Parse are no longer necessary with Parse Server. If yo
* `fileKey` - For migrated apps, this is necessary to provide access to files already hosted on Parse.
* `allowClientClassCreation` - Set to false to disable client class creation. Defaults to true.
* `enableAnonymousUsers` - Set to false to disable anonymous users. Defaults to true.
* `oauth` - Used to configure support for [3rd party authentication](https://github.com/ParsePlatform/parse-server/wiki/OAuth).
* `auth` - Used to configure support for [3rd party authentication](https://github.com/ParsePlatform/parse-server/wiki/OAuth--and-Custom-Authentication).
* `facebookAppIds` - An array of valid Facebook application IDs that users may authenticate with.
* `mountPath` - Mount path for the server. Defaults to `/parse`.
* `filesAdapter` - The default behavior (GridStore) can be changed by creating an adapter class (see [`FilesAdapter.js`](https://github.com/ParsePlatform/parse-server/blob/master/src/Adapters/Files/FilesAdapter.js)).
@@ -217,6 +216,7 @@ The client keys used with Parse are no longer necessary with Parse Server. If yo
* `revokeSessionOnPasswordReset` - When a user changes their password, either through the reset password email or while logged in, all sessions are revoked if this is true. Set to false if you don't want to revoke sessions.
* `accountLockout` - Lock account when a malicious user is attempting to determine an account password by trial and error.
* `passwordPolicy` - Optional password policy rules to enforce.
* `customPages` - A hash with urls to override email verification links, password reset links and specify frame url for masking user-facing pages. Available keys: `parseFrameURL`, `invalidLink`, `choosePassword`, `passwordResetSuccess`, `verifyEmailSuccess`.
##### Logging
@@ -282,12 +282,13 @@ var server = ParseServer({
passwordPolicy: {
// Two optional settings to enforce strong passwords. Either one or both can be specified.
// If both are specified, both checks must pass to accept the password
// 1. a RegExp representing the pattern to enforce
// 1. a RegExp object or a regex string representing the pattern to enforce
validatorPattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})/, // enforce password with at least 8 char with at least 1 lower case, 1 upper case and 1 digit
// 2. a callback function to be invoked to validate the password
validatorCallback: (password) => { return validatePassword(password) },
doNotAllowUsername: true, // optional setting to disallow username in passwords
maxPasswordAge: 90, // optional setting in days for password expiry. Login fails if user does not reset the password within this period after signup/last reset.
maxPasswordHistory: 5, // optional setting to prevent reuse of previous n passwords. Maximum value that can be specified is 20. Not specifying it or specifying 0 will not enforce history.
//optional setting to set a validity duration for password reset links (in seconds)
resetTokenValidityDuration: 24*60*60, // expire after 24 hours
}
+2 -2
View File
@@ -95,10 +95,10 @@ confirm 'Y' 'Do you want to continue? (Y/n): '
check_node
check_npm
printf "Setting up parse-server in %s" "${INSTALL_DIR}\n"
printf "Setting up parse-server in %s\n" "${INSTALL_DIR}"
if [ -d "${INSTALL_DIR}" ]; then
echo "{CHECK} ${INSTALL_DIR} exists"
echo "${CHECK} ${INSTALL_DIR} exists"
else
mkdir -p "${INSTALL_DIR}"
echo "${CHECK} Created ${INSTALL_DIR}"
+31 -28
View File
@@ -1,6 +1,6 @@
{
"name": "parse-server",
"version": "2.2.25",
"version": "2.3.4",
"description": "An express module providing a Parse-compatible API server",
"main": "lib/index.js",
"repository": {
@@ -18,71 +18,74 @@
],
"license": "BSD-3-Clause",
"dependencies": {
"bcryptjs": "2.3.0",
"body-parser": "1.15.2",
"bcryptjs": "2.4.3",
"body-parser": "1.16.1",
"commander": "2.9.0",
"deepcopy": "0.6.3",
"express": "4.14.0",
"express": "4.14.1",
"intersect": "1.0.1",
"lodash": "4.17.2",
"lodash": "4.17.4",
"lru-cache": "4.0.2",
"mime": "1.3.4",
"mongodb": "2.2.10",
"multer": "1.2.0",
"mongodb": "2.2.24",
"multer": "1.3.0",
"parse": "1.9.2",
"parse-server-fs-adapter": "1.0.1",
"parse-server-push-adapter": "1.1.0",
"parse-server-s3-adapter": "1.0.5",
"parse-server-push-adapter": "1.2.0",
"parse-server-s3-adapter": "1.0.6",
"parse-server-simple-mailgun-adapter": "1.0.0",
"pg-promise": "5.4.3",
"redis": "2.6.3",
"pg-promise": "5.5.7",
"redis": "2.6.5",
"request": "2.79.0",
"semver": "5.2.0",
"tv4": "1.2.7",
"winston": "2.3.0",
"winston-daily-rotate-file": "1.3.1",
"ws": "1.1.1"
"winston": "2.3.1",
"winston-daily-rotate-file": "1.4.4",
"ws": "2.0.3"
},
"devDependencies": {
"babel-cli": "6.18.0",
"babel-core": "6.18.2",
"babel-cli": "6.23.0",
"babel-core": "6.23.1",
"babel-eslint": "^7.1.1",
"babel-plugin-syntax-flow": "6.13.0",
"babel-plugin-transform-flow-strip-types": "6.18.0",
"babel-preset-es2015": "6.14.0",
"babel-preset-stage-0": "6.5.0",
"babel-register": "6.18.0",
"babel-plugin-transform-flow-strip-types": "6.22.0",
"babel-preset-es2015": "6.22.0",
"babel-preset-stage-0": "6.22.0",
"babel-register": "6.23.0",
"bcrypt-nodejs": "0.0.3",
"cross-env": "3.1.3",
"cross-env": "3.1.4",
"deep-diff": "0.3.4",
"eslint": "^3.10.2",
"eslint-plugin-flowtype": "^2.25.0",
"gaze": "1.1.1",
"istanbul": "1.0.0-alpha.1",
"jasmine": "2.5.2",
"jasmine-spec-reporter": "^2.7.0",
"jasmine": "2.5.3",
"jasmine-spec-reporter": "^3.1.0",
"mongodb-runner": "3.4.0",
"nodemon": "1.11.0",
"request-promise": "4.1.1"
},
"scripts": {
"dev": "npm run build && node bin/dev",
"lint": "eslint ./",
"lint": "eslint --cache ./",
"build": "babel src/ -d lib/",
"pretest": "npm run lint",
"test": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=3.2.6} MONGODB_STORAGE_ENGINE=mmapv1 NODE_ENV=test TESTING=1 $COVERAGE_OPTION jasmine",
"test:win": "npm run pretest && cross-env NODE_ENV=test TESTING=1 node ./node_modules/jasmine/bin/jasmine.js && npm run posttest",
"test:win": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=3.2.6} MONGODB_STORAGE_ENGINE=mmapv1 NODE_ENV=test TESTING=1 jasmine",
"coverage": "cross-env COVERAGE_OPTION='./node_modules/.bin/istanbul cover' npm test",
"coverage:win": "npm run pretest && cross-env NODE_ENV=test TESTING=1 node ./node_modules/babel-istanbul/lib/cli.js cover ./node_modules/jasmine/bin/jasmine.js && npm run posttest",
"coverage:win": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=3.2.6} MONGODB_STORAGE_ENGINE=mmapv1 NODE_ENV=test TESTING=1 node ./node_modules/istanbul/lib/cli.js cover ./node_modules/jasmine/bin/jasmine.js",
"start": "node ./bin/parse-server",
"prepublish": "npm run build"
},
"engines": {
"node": ">=4.5"
"node": ">=4.6"
},
"bin": {
"parse-server": "./bin/parse-server"
},
"optionalDependencies": {
"bcrypt": "0.8.7"
"bcrypt": "1.0.2",
"uws": "^0.12.0"
}
}
Regular → Executable
View File
+2 -6
View File
@@ -1,8 +1,5 @@
{
"extends": "eslint:recommended",
"env": {
"node": true,
"es6": true,
"jasmine": true
},
"globals": {
@@ -29,7 +26,6 @@
"arrayContains": true
},
"rules": {
"no-console": [0],
"indent": ["error", 2]
"no-console": [0]
}
}
}
+2 -2
View File
@@ -263,7 +263,7 @@ describe("Account Lockout Policy: ", () => {
return isAccountLockoutError('username3', 'wrong password', 0.05, 1);
})
.then(() => {
// account should still be locked even after 2 seconds.
// account should still be locked even after 2 seconds.
return isAccountLockoutError('username3', 'wrong password', 0.05, 2000);
})
.then(() => {
@@ -297,7 +297,7 @@ describe("Account Lockout Policy: ", () => {
return loginWithWrongCredentialsShouldFail('username4', 'wrong password');
})
.then(() => {
// allow locked user to login after 3 seconds with a valid userid and password
// allow locked user to login after 3 seconds with a valid userid and password
return new Promise((resolve, reject) => {
setTimeout(() => {
Parse.User.logIn('username4', 'correct password')
+7 -7
View File
@@ -1,11 +1,11 @@
const analyticsAdapter = {
appOpened: function() {},
appOpened: function() {},
trackEvent: function() {}
}
describe('AnalyticsController', () => {
it('should track a simple event', (done) => {
spyOn(analyticsAdapter, 'trackEvent').and.callThrough();
reconfigureServer({
analyticsAdapter
@@ -17,7 +17,7 @@ describe('AnalyticsController', () => {
}).then(() => {
expect(analyticsAdapter.trackEvent).toHaveBeenCalled();
var lastCall = analyticsAdapter.trackEvent.calls.first();
let args = lastCall.args;
const args = lastCall.args;
expect(args[0]).toEqual('MyEvent');
expect(args[1]).toEqual({
dimensions: {
@@ -31,9 +31,9 @@ describe('AnalyticsController', () => {
done();
})
});
it('should track a app opened event', (done) => {
spyOn(analyticsAdapter, 'appOpened').and.callThrough();
reconfigureServer({
analyticsAdapter
@@ -45,7 +45,7 @@ describe('AnalyticsController', () => {
}).then(() => {
expect(analyticsAdapter.appOpened).toHaveBeenCalled();
var lastCall = analyticsAdapter.appOpened.calls.first();
let args = lastCall.args;
const args = lastCall.args;
expect(args[0]).toEqual({
dimensions: {
key: 'value',
@@ -58,4 +58,4 @@ describe('AnalyticsController', () => {
done();
})
})
})
})
@@ -1,145 +1,13 @@
var OAuth = require("../src/authDataManager/OAuth1Client");
var request = require('request');
var Config = require("../src/Config");
var defaultColumns = require('../src/Controllers/SchemaController').defaultColumns;
var authenticationLoader = require('../src/Adapters/Auth');
var path = require('path');
describe('OAuth', function() {
it("Nonce should have right length", (done) => {
jequal(OAuth.nonce().length, 30);
done();
});
it("Should properly build parameter string", (done) => {
var string = OAuth.buildParameterString({c:1, a:2, b:3})
jequal(string, "a=2&b=3&c=1");
done();
});
it("Should properly build empty parameter string", (done) => {
var string = OAuth.buildParameterString()
jequal(string, "");
done();
});
it("Should properly build signature string", (done) => {
var string = OAuth.buildSignatureString("get", "http://dummy.com", "");
jequal(string, "GET&http%3A%2F%2Fdummy.com&");
done();
});
it("Should properly generate request signature", (done) => {
var request = {
host: "dummy.com",
path: "path"
};
var oauth_params = {
oauth_timestamp: 123450000,
oauth_nonce: "AAAAAAAAAAAAAAAAA",
oauth_consumer_key: "hello",
oauth_token: "token"
};
var consumer_secret = "world";
var auth_token_secret = "secret";
request = OAuth.signRequest(request, oauth_params, consumer_secret, auth_token_secret);
jequal(request.headers['Authorization'], 'OAuth oauth_consumer_key="hello", oauth_nonce="AAAAAAAAAAAAAAAAA", oauth_signature="8K95bpQcDi9Nd2GkhumTVcw4%2BXw%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="123450000", oauth_token="token", oauth_version="1.0"');
done();
});
it("Should properly build request", (done) => {
var options = {
host: "dummy.com",
consumer_key: "hello",
consumer_secret: "world",
auth_token: "token",
auth_token_secret: "secret",
// Custom oauth params for tests
oauth_params: {
oauth_timestamp: 123450000,
oauth_nonce: "AAAAAAAAAAAAAAAAA"
}
};
var path = "path";
var method = "get";
var oauthClient = new OAuth(options);
var req = oauthClient.buildRequest(method, path, {"query": "param"});
jequal(req.host, options.host);
jequal(req.path, "/"+path+"?query=param");
jequal(req.method, "GET");
jequal(req.headers['Content-Type'], 'application/x-www-form-urlencoded');
jequal(req.headers['Authorization'], 'OAuth oauth_consumer_key="hello", oauth_nonce="AAAAAAAAAAAAAAAAA", oauth_signature="wNkyEkDE%2F0JZ2idmqyrgHdvC0rs%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="123450000", oauth_token="token", oauth_version="1.0"')
done();
});
function validateCannotAuthenticateError(data, done) {
jequal(typeof data, "object");
jequal(typeof data.errors, "object");
var errors = data.errors;
jequal(typeof errors[0], "object");
// Cannot authenticate error
jequal(errors[0].code, 32);
done();
}
it("Should fail a GET request", (done) => {
var options = {
host: "api.twitter.com",
consumer_key: "XXXXXXXXXXXXXXXXXXXXXXXXX",
consumer_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
};
var path = "/1.1/help/configuration.json";
var params = {"lang": "en"};
var oauthClient = new OAuth(options);
oauthClient.get(path, params).then(function(data){
validateCannotAuthenticateError(data, done);
})
});
it("Should fail a POST request", (done) => {
var options = {
host: "api.twitter.com",
consumer_key: "XXXXXXXXXXXXXXXXXXXXXXXXX",
consumer_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
};
var body = {
lang: "en"
};
var path = "/1.1/account/settings.json";
var oauthClient = new OAuth(options);
oauthClient.post(path, null, body).then(function(data){
validateCannotAuthenticateError(data, done);
})
});
it("Should fail a request", (done) => {
var options = {
host: "localhost",
consumer_key: "XXXXXXXXXXXXXXXXXXXXXXXXX",
consumer_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
};
var body = {
lang: "en"
};
var path = "/";
var oauthClient = new OAuth(options);
oauthClient.post(path, null, body).then(function(){
jequal(false, true);
done();
}).catch(function(){
jequal(true, true);
done();
})
});
describe('AuthenticationProviers', function() {
["facebook", "github", "instagram", "google", "linkedin", "meetup", "twitter", "janrainengage", "janraincapture", "vkontakte"].map(function(providerName){
it("Should validate structure of "+providerName, (done) => {
var provider = require("../src/authDataManager/"+providerName);
it("Should validate structure of " + providerName, (done) => {
var provider = require("../src/Adapters/Auth/" + providerName);
jequal(typeof provider.validateAuthData, "function");
jequal(typeof provider.validateAppId, "function");
jequal(provider.validateAuthData({}, {}).constructor, Promise.prototype.constructor);
@@ -325,5 +193,123 @@ describe('OAuth', function() {
});
});
function validateValidator(validator) {
expect(typeof validator).toBe('function');
}
})
function validateAuthenticationHandler(authenticatonHandler) {
expect(authenticatonHandler).not.toBeUndefined();
expect(typeof authenticatonHandler.getValidatorForProvider).toBe('function');
expect(typeof authenticatonHandler.getValidatorForProvider).toBe('function');
}
function validateAuthenticationAdapter(authAdapter) {
expect(authAdapter).not.toBeUndefined();
if (!authAdapter) { return; }
expect(typeof authAdapter.validateAuthData).toBe('function');
expect(typeof authAdapter.validateAppId).toBe('function');
}
it('properly loads custom adapter', (done) => {
var validAuthData = {
id: 'hello',
token: 'world'
}
const adapter = {
validateAppId: function() {
return Promise.resolve();
},
validateAuthData: function(authData) {
if (authData.id == validAuthData.id && authData.token == validAuthData.token) {
return Promise.resolve();
}
return Promise.reject();
}
};
const authDataSpy = spyOn(adapter, 'validateAuthData').and.callThrough();
const appIdSpy = spyOn(adapter, 'validateAppId').and.callThrough();
const authenticationHandler = authenticationLoader({
customAuthentication: adapter
});
validateAuthenticationHandler(authenticationHandler);
const validator = authenticationHandler.getValidatorForProvider('customAuthentication');
validateValidator(validator);
validator(validAuthData).then(() => {
expect(authDataSpy).toHaveBeenCalled();
// AppIds are not provided in the adapter, should not be called
expect(appIdSpy).not.toHaveBeenCalled();
done();
}, (err) => {
jfail(err);
done();
})
});
it('properly loads custom adapter module object', (done) => {
const authenticationHandler = authenticationLoader({
customAuthentication: path.resolve('./spec/support/CustomAuth.js')
});
validateAuthenticationHandler(authenticationHandler);
const validator = authenticationHandler.getValidatorForProvider('customAuthentication');
validateValidator(validator);
validator({
token: 'my-token'
}).then(() => {
done();
}, (err) => {
jfail(err);
done();
})
});
it('properly loads custom adapter module object', (done) => {
const authenticationHandler = authenticationLoader({
customAuthentication: { module: path.resolve('./spec/support/CustomAuthFunction.js'), options: { token: 'valid-token' }}
});
validateAuthenticationHandler(authenticationHandler);
const validator = authenticationHandler.getValidatorForProvider('customAuthentication');
validateValidator(validator);
validator({
token: 'valid-token'
}).then(() => {
done();
}, (err) => {
jfail(err);
done();
})
});
it('properly loads a default adapter with options', () => {
const options = {
facebook: {
appIds: ['a', 'b']
}
};
const { adapter, appIds, providerOptions } = authenticationLoader.loadAuthAdapter('facebook', options);
validateAuthenticationAdapter(adapter);
expect(appIds).toEqual(['a', 'b']);
expect(providerOptions).toEqual(options.facebook);
});
it('properly loads a custom adapter with options', () => {
const options = {
custom: {
validateAppId: () => {},
validateAuthData: () => {},
appIds: ['a', 'b']
}
};
const { adapter, appIds, providerOptions } = authenticationLoader.loadAuthAdapter('custom', options);
validateAuthenticationAdapter(adapter);
expect(appIds).toEqual(['a', 'b']);
expect(providerOptions).toEqual(options.custom);
});
});
+9 -8
View File
@@ -63,15 +63,16 @@ describe('commander additions', () => {
it('should load properly use args over env', (done) => {
commander.loadDefinitions(testDefinitions);
commander.parse(['node','./CLI.spec.js','--arg0', 'arg0Value', '--arg4', 'anotherArg4'], {
commander.parse(['node','./CLI.spec.js','--arg0', 'arg0Value', '--arg4', ''], {
'PROGRAM_ARG_0': 'arg0ENVValue',
'PROGRAM_ARG_1': 'arg1ENVValue',
'PROGRAM_ARG_2': '4',
'PROGRAM_ARG_4': 'arg4ENVValue'
});
expect(commander.arg0).toEqual('arg0Value');
expect(commander.arg1).toEqual('arg1ENVValue');
expect(commander.arg2).toEqual(4);
expect(commander.arg4).toEqual('anotherArg4');
expect(commander.arg4).toEqual('');
done();
});
@@ -93,7 +94,7 @@ describe('commander additions', () => {
'PROGRAM_ARG_0': 'arg0ENVValue',
'PROGRAM_ARG_1': 'arg1ENVValue',
});
let options = commander.getOptions();
const options = commander.getOptions();
expect(options.arg2).toBe(8888);
expect(options.arg3).toBe('hello'); //config value
expect(options.arg4).toBe('/1');
@@ -122,7 +123,7 @@ describe('commander additions', () => {
it('should load config from apps', (done) => {
commander.loadDefinitions(testDefinitions);
commander.parse(['node', './CLI.spec.js', './spec/configs/CLIConfigApps.json']);
let options = commander.getOptions();
const options = commander.getOptions();
expect(options.arg1).toBe('my_app');
expect(options.arg2).toBe(8888);
expect(options.arg3).toBe('hello'); //config value
@@ -141,8 +142,8 @@ describe('commander additions', () => {
describe('definitions', () => {
it('should have valid types', () => {
for (let key in definitions) {
let definition = definitions[key];
for (const key in definitions) {
const definition = definitions[key];
expect(typeof definition).toBe('object');
if (typeof definition.env !== 'undefined') {
expect(typeof definition.env).toBe('string');
@@ -160,8 +161,8 @@ describe('definitions', () => {
describe('LiveQuery definitions', () => {
it('should have valid types', () => {
for (let key in liveQueryDefinitions) {
let definition = liveQueryDefinitions[key];
for (const key in liveQueryDefinitions) {
const definition = liveQueryDefinitions[key];
expect(typeof definition).toBe('object');
if (typeof definition.env !== 'undefined') {
expect(typeof definition.env).toBe('string');
+4 -4
View File
@@ -2,7 +2,7 @@ var ClientSDK = require('../src/ClientSDK');
describe('ClientSDK', () => {
it('should properly parse the SDK versions', () => {
let clientSDKFromVersion = ClientSDK.fromString;
const clientSDKFromVersion = ClientSDK.fromString;
expect(clientSDKFromVersion('i1.1.1')).toEqual({
sdk: 'i',
version: '1.1.1'
@@ -20,12 +20,12 @@ describe('ClientSDK', () => {
version: '1.9.0'
});
});
it('should properly sastisfy', () => {
expect(ClientSDK.compatible({
js: '>=1.9.0'
})("js1.9.0")).toBe(true);
expect(ClientSDK.compatible({
js: '>=1.9.0'
})("js2.0.0")).toBe(true);
@@ -38,4 +38,4 @@ describe('ClientSDK', () => {
js: '>=1.9.0'
})(undefined)).toBe(true);
})
})
})
+102 -67
View File
@@ -180,10 +180,10 @@ describe('Cloud Code', () => {
it('test afterSave ran on created object and returned a promise', function(done) {
Parse.Cloud.afterSave('AfterSaveTest2', function(req) {
let obj = req.object;
const obj = req.object;
if(!obj.existed())
{
let promise = new Parse.Promise();
const promise = new Parse.Promise();
setTimeout(function(){
obj.set('proof', obj.id);
obj.save().then(function(){
@@ -195,13 +195,13 @@ describe('Cloud Code', () => {
}
});
let obj = new Parse.Object('AfterSaveTest2');
const obj = new Parse.Object('AfterSaveTest2');
obj.save().then(function(){
let query = new Parse.Query('AfterSaveTest2');
const query = new Parse.Query('AfterSaveTest2');
query.equalTo('proof', obj.id);
query.find().then(function(results) {
expect(results.length).toEqual(1);
let savedObject = results[0];
const savedObject = results[0];
expect(savedObject.get('proof')).toEqual(obj.id);
done();
},
@@ -215,10 +215,10 @@ describe('Cloud Code', () => {
// TODO: Fails on CI randomly as racing
xit('test afterSave ignoring promise, object not found', function(done) {
Parse.Cloud.afterSave('AfterSaveTest2', function(req) {
let obj = req.object;
const obj = req.object;
if(!obj.existed())
{
let promise = new Parse.Promise();
const promise = new Parse.Promise();
setTimeout(function(){
obj.set('proof', obj.id);
obj.save().then(function(){
@@ -230,12 +230,12 @@ describe('Cloud Code', () => {
}
});
let obj = new Parse.Object('AfterSaveTest2');
const obj = new Parse.Object('AfterSaveTest2');
obj.save().then(function(){
done();
})
let query = new Parse.Query('AfterSaveTest2');
const query = new Parse.Query('AfterSaveTest2');
query.equalTo('proof', obj.id);
query.find().then(function(results) {
expect(results.length).toEqual(0);
@@ -247,7 +247,7 @@ describe('Cloud Code', () => {
it('test afterSave rejecting promise', function(done) {
Parse.Cloud.afterSave('AfterSaveTest2', function() {
let promise = new Parse.Promise();
const promise = new Parse.Promise();
setTimeout(function(){
promise.reject("THIS SHOULD BE IGNORED");
}, 1000);
@@ -255,7 +255,7 @@ describe('Cloud Code', () => {
return promise;
});
let obj = new Parse.Object('AfterSaveTest2');
const obj = new Parse.Object('AfterSaveTest2');
obj.save().then(function(){
done();
}, function(error){
@@ -266,10 +266,10 @@ describe('Cloud Code', () => {
it('test afterDelete returning promise, object is deleted when destroy resolves', function(done) {
Parse.Cloud.afterDelete('AfterDeleteTest2', function(req) {
let promise = new Parse.Promise();
const promise = new Parse.Promise();
setTimeout(function(){
let obj = new Parse.Object('AfterDeleteTestProof');
const obj = new Parse.Object('AfterDeleteTestProof');
obj.set('proof', req.object.id);
obj.save().then(function(){
promise.resolve();
@@ -280,19 +280,19 @@ describe('Cloud Code', () => {
return promise;
});
let errorHandler = function(error) {
const errorHandler = function(error) {
fail(error);
done();
}
let obj = new Parse.Object('AfterDeleteTest2');
const obj = new Parse.Object('AfterDeleteTest2');
obj.save().then(function(){
obj.destroy().then(function(){
let query = new Parse.Query('AfterDeleteTestProof');
const query = new Parse.Query('AfterDeleteTestProof');
query.equalTo('proof', obj.id);
query.find().then(function(results) {
expect(results.length).toEqual(1);
let deletedObject = results[0];
const deletedObject = results[0];
expect(deletedObject.get('proof')).toEqual(obj.id);
done();
}, errorHandler);
@@ -302,10 +302,10 @@ describe('Cloud Code', () => {
it('test afterDelete ignoring promise, object is not yet deleted', function(done) {
Parse.Cloud.afterDelete('AfterDeleteTest2', function(req) {
let promise = new Parse.Promise();
const promise = new Parse.Promise();
setTimeout(function(){
let obj = new Parse.Object('AfterDeleteTestProof');
const obj = new Parse.Object('AfterDeleteTestProof');
obj.set('proof', req.object.id);
obj.save().then(function(){
promise.resolve();
@@ -316,18 +316,18 @@ describe('Cloud Code', () => {
return promise;
});
let errorHandler = function(error) {
const errorHandler = function(error) {
fail(error);
done();
}
let obj = new Parse.Object('AfterDeleteTest2');
const obj = new Parse.Object('AfterDeleteTest2');
obj.save().then(function(){
obj.destroy().then(function(){
done();
})
let query = new Parse.Query('AfterDeleteTestProof');
const query = new Parse.Query('AfterDeleteTestProof');
query.equalTo('proof', obj.id);
query.find().then(function(results) {
expect(results.length).toEqual(0);
@@ -509,7 +509,7 @@ describe('Cloud Code', () => {
return res.success({});
});
let params = {
const params = {
'date': {
'__type': 'Date',
'iso': '2016-05-22T09:00:00.000Z'
@@ -616,7 +616,7 @@ describe('Cloud Code', () => {
res.success();
});
let obj = new Parse.Object('GameScore');
const obj = new Parse.Object('GameScore');
obj.set('foo', 'bar');
obj.set('fooAgain', 'barAgain');
obj.save().then(() => {
@@ -703,7 +703,7 @@ describe('Cloud Code', () => {
request.object.set('foo', 'baz');
response.success();
});
let obj = new Parse.Object('ChangingObject');
const obj = new Parse.Object('ChangingObject');
obj.save({ foo: 'bar' }).then((objAgain) => {
expect(objAgain.get('foo')).toEqual('baz');
done();
@@ -712,7 +712,7 @@ describe('Cloud Code', () => {
done();
});
});
it('beforeSave change propagates through the afterSave #1931', (done) => {
Parse.Cloud.beforeSave('ChangingObject', function(request, response) {
request.object.unset('file');
@@ -726,9 +726,9 @@ describe('Cloud Code', () => {
expect(request.object.get('file')).toBeUndefined();
return Promise.resolve();
});
let file = new Parse.File("yolo.txt", [1,2,3], "text/plain");
const file = new Parse.File("yolo.txt", [1,2,3], "text/plain");
file.save().then(() => {
let obj = new Parse.Object('ChangingObject');
const obj = new Parse.Object('ChangingObject');
return obj.save({ file, date: new Date() })
}).then(() => {
done();
@@ -995,7 +995,7 @@ describe('Cloud Code', () => {
});
let object;
let testObject = new TestObject({key: 'value'});
const testObject = new TestObject({key: 'value'});
testObject.save().then(() => {
object = new BeforeSaveObject();
return object.save().then(() => {
@@ -1026,7 +1026,7 @@ describe('Cloud Code', () => {
}, res.error);
});
let object = new BeforeSaveObject();
const object = new BeforeSaveObject();
object.save().then((objectAgain) => {
// Originally it would throw as it would be a non-relation
expect(() => { objectAgain.relation('testsRelation') }).not.toThrow();
@@ -1044,7 +1044,7 @@ describe('Cloud Code', () => {
res.success();
});
}).not.toThrow();
rp.post({
url: 'http://localhost:8378/1/jobs/myJob',
headers: {
@@ -1065,7 +1065,7 @@ describe('Cloud Code', () => {
res.success();
});
}).not.toThrow();
rp.post({
url: 'http://localhost:8378/1/jobs/myJob',
headers: {
@@ -1094,7 +1094,7 @@ describe('Cloud Code', () => {
done();
});
}).not.toThrow();
rp.post({
url: 'http://localhost:8378/1/jobs/myJob',
headers: {
@@ -1121,7 +1121,7 @@ describe('Cloud Code', () => {
done();
});
}).not.toThrow();
rp.post({
url: `http://${Parse.applicationId}:${Parse.masterKey}@localhost:8378/1/jobs/myJob`,
}).then(() => {
@@ -1152,7 +1152,7 @@ describe('Cloud Code', () => {
done();
});
});
rp.post({
url: 'http://localhost:8378/1/jobs/myJob',
headers: {
@@ -1179,7 +1179,7 @@ describe('Cloud Code', () => {
done();
});
});
rp.post({
url: 'http://localhost:8378/1/jobs/myJob',
headers: {
@@ -1194,7 +1194,7 @@ describe('Cloud Code', () => {
});
function getJobStatus(jobId) {
let q = new Parse.Query('_JobStatus');
const q = new Parse.Query('_JobStatus');
return q.get(jobId, {useMasterKey: true});
}
});
@@ -1203,9 +1203,9 @@ describe('Cloud Code', () => {
describe('beforeFind hooks', () => {
it('should add beforeFind trigger', (done) => {
Parse.Cloud.beforeFind('MyObject', (req) => {
let q = req.query;
const q = req.query;
expect(q instanceof Parse.Query).toBe(true);
let jsonQuery = q.toJSON();
const jsonQuery = q.toJSON();
expect(jsonQuery.where.key).toEqual('value');
expect(jsonQuery.where.some).toEqual({'$gt': 10});
expect(jsonQuery.include).toEqual('otherKey,otherValue');
@@ -1213,7 +1213,7 @@ describe('beforeFind hooks', () => {
expect(jsonQuery.skip).toBe(undefined);
});
let query = new Parse.Query('MyObject');
const query = new Parse.Query('MyObject');
query.equalTo('key', 'value');
query.greaterThan('some', 10);
query.include('otherKey');
@@ -1225,21 +1225,21 @@ describe('beforeFind hooks', () => {
it('should use modify', (done) => {
Parse.Cloud.beforeFind('MyObject', (req) => {
let q = req.query;
const q = req.query;
q.equalTo('forced', true);
});
let obj0 = new Parse.Object('MyObject');
const obj0 = new Parse.Object('MyObject');
obj0.set('forced', false);
let obj1 = new Parse.Object('MyObject');
const obj1 = new Parse.Object('MyObject');
obj1.set('forced', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
let query = new Parse.Query('MyObject');
const query = new Parse.Query('MyObject');
query.equalTo('forced', false);
query.find().then((results) => {
expect(results.length).toBe(1);
let firstResult = results[0];
const firstResult = results[0];
expect(firstResult.get('forced')).toBe(true);
done();
});
@@ -1248,19 +1248,19 @@ describe('beforeFind hooks', () => {
it('should use the modified the query', (done) => {
Parse.Cloud.beforeFind('MyObject', (req) => {
let q = req.query;
let otherQuery = new Parse.Query('MyObject');
const q = req.query;
const otherQuery = new Parse.Query('MyObject');
otherQuery.equalTo('forced', true);
return Parse.Query.or(q, otherQuery);
});
let obj0 = new Parse.Object('MyObject');
const obj0 = new Parse.Object('MyObject');
obj0.set('forced', false);
let obj1 = new Parse.Object('MyObject');
const obj1 = new Parse.Object('MyObject');
obj1.set('forced', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
let query = new Parse.Query('MyObject');
const query = new Parse.Query('MyObject');
query.equalTo('forced', false);
query.find().then((results) => {
expect(results.length).toBe(2);
@@ -1274,7 +1274,7 @@ describe('beforeFind hooks', () => {
return Promise.reject('Do not run that query');
});
let query = new Parse.Query('MyObject');
const query = new Parse.Query('MyObject');
query.find().then(() => {
fail('should not succeed');
done();
@@ -1287,7 +1287,7 @@ describe('beforeFind hooks', () => {
it('should handle empty where', (done) => {
Parse.Cloud.beforeFind('MyObject', (req) => {
let otherQuery = new Parse.Query('MyObject');
const otherQuery = new Parse.Query('MyObject');
otherQuery.equalTo('some', true);
return Parse.Query.or(req.query, otherQuery);
});
@@ -1315,10 +1315,10 @@ describe('afterFind hooks', () => {
}
res.success(req.objects);
});
let obj = new Parse.Object('MyObject');
const obj = new Parse.Object('MyObject');
obj.set('secretField', 'SSID');
obj.save().then(function() {
let query = new Parse.Query('MyObject');
const query = new Parse.Query('MyObject');
query.get(obj.id).then(function(result) {
expect(result.get('secretField')).toEqual('###');
done();
@@ -1339,10 +1339,10 @@ describe('afterFind hooks', () => {
}
res.success(req.objects);
});
let obj = new Parse.Object('MyObject');
const obj = new Parse.Object('MyObject');
obj.set('secretField', 'SSID');
obj.save().then(function() {
let query = new Parse.Query('MyObject');
const query = new Parse.Query('MyObject');
query.equalTo('objectId',obj.id);
query.find().then(function(results) {
expect(results[0].get('secretField')).toEqual('###');
@@ -1359,20 +1359,20 @@ describe('afterFind hooks', () => {
it('should filter out results',(done) => {
Parse.Cloud.afterFind('MyObject', (req, res) => {
let filteredResults = [];
const filteredResults = [];
for(let i = 0 ; i < req.objects.length ; i++){
if(req.objects[i].get("secretField")==="SSID1") {
if(req.objects[i].get("secretField") === "SSID1") {
filteredResults.push(req.objects[i]);
}
}
res.success(filteredResults);
});
let obj0 = new Parse.Object('MyObject');
const obj0 = new Parse.Object('MyObject');
obj0.set('secretField', 'SSID1');
let obj1 = new Parse.Object('MyObject');
const obj1 = new Parse.Object('MyObject');
obj1.set('secretField', 'SSID2');
Parse.Object.saveAll([obj0, obj1]).then(function() {
let query = new Parse.Query('MyObject');
const query = new Parse.Query('MyObject');
query.find().then(function(results) {
expect(results[0].get('secretField')).toEqual('SSID1');
expect(results.length).toEqual(1);
@@ -1391,10 +1391,10 @@ describe('afterFind hooks', () => {
Parse.Cloud.afterFind('MyObject', (req, res) => {
res.error(Parse.Error.SCRIPT_FAILED, "It should fail");
});
let obj = new Parse.Object('MyObject');
const obj = new Parse.Object('MyObject');
obj.set('secretField', 'SSID');
obj.save().then(function() {
let query = new Parse.Query('MyObject');
const query = new Parse.Query('MyObject');
query.equalTo('objectId',obj.id);
query.find().then(function() {
fail("AfterFind should handle response failure correctly");
@@ -1409,7 +1409,7 @@ describe('afterFind hooks', () => {
it('should also work with promise',(done) => {
Parse.Cloud.afterFind('MyObject', (req) => {
let promise = new Parse.Promise();
const promise = new Parse.Promise();
setTimeout(function(){
for(let i = 0 ; i < req.objects.length ; i++){
req.objects[i].set("secretField","###");
@@ -1418,10 +1418,10 @@ describe('afterFind hooks', () => {
}, 1000);
return promise;
});
let obj = new Parse.Object('MyObject');
const obj = new Parse.Object('MyObject');
obj.set('secretField', 'SSID');
obj.save().then(function() {
let query = new Parse.Query('MyObject');
const query = new Parse.Query('MyObject');
query.equalTo('objectId',obj.id);
query.find().then(function(results) {
expect(results[0].get('secretField')).toEqual('###');
@@ -1434,5 +1434,40 @@ describe('afterFind hooks', () => {
});
});
});
it('should alter select', (done) => {
Parse.Cloud.beforeFind('MyObject', (req) => {
req.query.select('white');
return req.query;
});
const obj0 = new Parse.Object('MyObject')
.set('white', true)
.set('black', true);
obj0.save()
.then(() => {
new Parse.Query('MyObject')
.first()
.then(result => {
expect(result.get('white')).toBe(true);
expect(result.get('black')).toBe(undefined);
done();
});
});
});
it('should not alter select', (done) => {
const obj0 = new Parse.Object('MyObject')
.set('white', true)
.set('black', true);
obj0.save()
.then(() => {
new Parse.Query('MyObject')
.first()
.then(result => {
expect(result.get('white')).toBe(true);
expect(result.get('black')).toBe(true);
done();
});
});
});
});
+12 -11
View File
@@ -37,10 +37,10 @@ describe("Cloud Code Logger", () => {
return logController.getLogs({ from: Date.now() - 500, size: 1000 });
}).then((res) => {
expect(res.length).not.toBe(0);
let lastLogs = res.slice(0, 3);
let cloudFunctionMessage = lastLogs[0];
let errorMessage = lastLogs[1];
let infoMessage = lastLogs[2];
const lastLogs = res.slice(0, 3);
const cloudFunctionMessage = lastLogs[0];
const errorMessage = lastLogs[1];
const infoMessage = lastLogs[2];
expect(cloudFunctionMessage.level).toBe('info');
expect(cloudFunctionMessage.params).toEqual({});
expect(cloudFunctionMessage.message).toMatch(/Ran cloud function loggerTest for user [^ ]* with:\n {2}Input: {}\n {2}Result: {}/);
@@ -82,15 +82,15 @@ describe("Cloud Code Logger", () => {
res.success({});
});
let obj = new Parse.Object('MyObject');
const obj = new Parse.Object('MyObject');
obj.save().then(() => {
return logController.getLogs({ from: Date.now() - 500, size: 1000 })
}).then((res) => {
expect(res.length).not.toBe(0);
let lastLogs = res.slice(0, 3);
let cloudTriggerMessage = lastLogs[0];
let errorMessage = lastLogs[1];
let infoMessage = lastLogs[2];
const lastLogs = res.slice(0, 3);
const cloudTriggerMessage = lastLogs[0];
const errorMessage = lastLogs[1];
const infoMessage = lastLogs[2];
expect(cloudTriggerMessage.level).toBe('info');
expect(cloudTriggerMessage.triggerType).toEqual('beforeSave');
expect(cloudTriggerMessage.message).toMatch(/beforeSave triggered for MyObject for user [^ ]*\n {2}Input: {}\n {2}Result: {}/);
@@ -156,8 +156,9 @@ describe("Cloud Code Logger", () => {
.save()
.then(
() => done.fail('this is not supposed to succeed'),
() => logController.getLogs({ from: Date.now() - 500, size: 1000 })
() => new Promise(resolve => setTimeout(resolve, 100))
)
.then(() => logController.getLogs({ from: Date.now() - 500, size: 1000 }))
.then(logs => {
const log = logs[1]; // 0 is the 'uh oh!' from rejection...
expect(log.level).toEqual('error');
@@ -194,7 +195,7 @@ describe("Cloud Code Logger", () => {
Parse.Cloud.run('aFunction', { foo: 'bar' })
.then(null, () => logController.getLogs({ from: Date.now() - 500, size: 1000 }))
.then(logs => {
const log = logs[1];
const log = logs[2];
expect(log.level).toEqual('error');
expect(log.message).toMatch(
/Failed running cloud function aFunction for user [^ ]* with:\n {2}Input: {"foo":"bar"}\n {2}Error: {"code":141,"message":"it failed!"}/);
+9 -9
View File
@@ -241,12 +241,12 @@ describe("Email Verification Token Expiration: ", () => {
return user.signUp();
})
.then(() => {
let config = new Config('test');
const config = new Config('test');
return config.database.find('_User', {username: 'sets_email_verify_token_expires_at'});
})
.then(results => {
expect(results.length).toBe(1);
let user = results[0];
const user = results[0];
expect(typeof user).toBe('object');
expect(user.emailVerified).toEqual(false);
expect(typeof user._email_verify_token).toBe('string');
@@ -288,7 +288,7 @@ describe("Email Verification Token Expiration: ", () => {
followRedirect: false,
}, (error, response) => {
expect(response.statusCode).toEqual(302);
let config = new Config('test');
const config = new Config('test');
return config.database.find('_User', {username: 'unsets_email_verify_token_expires_at'}).then((results) => {
expect(results.length).toBe(1);
return results[0];
@@ -420,18 +420,18 @@ describe("Email Verification Token Expiration: ", () => {
it('setting the email on the user should set a new email verification token and new expiration date for the token when expire email verify token flag is set', done => {
let user = new Parse.User();
const user = new Parse.User();
let userBeforeEmailReset;
let sendEmailOptions;
let emailAdapter = {
const emailAdapter = {
sendVerificationEmail: options => {
sendEmailOptions = options;
},
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => {}
};
let serverConfig = {
const serverConfig = {
appName: 'emailVerifyToken',
verifyUserEmails: true,
emailAdapter: emailAdapter,
@@ -447,7 +447,7 @@ describe("Email Verification Token Expiration: ", () => {
return user.signUp();
})
.then(() => {
let config = new Config('test');
const config = new Config('test');
return config.database.find('_User', {username: 'newEmailVerifyTokenOnEmailReset'}).then((results) => {
return results[0];
});
@@ -460,11 +460,11 @@ describe("Email Verification Token Expiration: ", () => {
user.set('email', 'user@parse.com');
return new Promise((resolve) => {
// wait for half a sec to get a new expiration time
setTimeout( () => resolve(user.save()), 500 );
setTimeout(() => resolve(user.save()), 500);
});
})
.then(() => {
let config = new Config('test');
const config = new Config('test');
return config.database.find('_User', {username: 'newEmailVerifyTokenOnEmailReset'}).then((results) => {
return results[0];
});
+39 -4
View File
@@ -1,7 +1,17 @@
var GridStoreAdapter = require("../src/Adapters/Files/GridStoreAdapter").GridStoreAdapter;
var Config = require("../src/Config");
var FilesController = require('../src/Controllers/FilesController').default;
const LoggerController = require('../src/Controllers/LoggerController').LoggerController;
const WinstonLoggerAdapter = require('../src/Adapters/Logger/WinstonLoggerAdapter').WinstonLoggerAdapter;
const GridStoreAdapter = require("../src/Adapters/Files/GridStoreAdapter").GridStoreAdapter;
const Config = require("../src/Config");
const FilesController = require('../src/Controllers/FilesController').default;
const mockAdapter = {
createFile: () => {
return Parse.Promise.reject(new Error('it failed'));
},
deleteFile: () => { },
getFileData: () => { },
getFileLocation: () => 'xyz'
}
// Small additional tests to improve overall coverage
describe("FilesController",() =>{
@@ -26,5 +36,30 @@ describe("FilesController",() =>{
expect(anObject.aFile.url).toEqual("http://an.url");
done();
})
});
it('should create a server log on failure', done => {
const logController = new LoggerController(new WinstonLoggerAdapter());
reconfigureServer({ filesAdapter: mockAdapter })
.then(() => new Promise(resolve => setTimeout(resolve, 1000)))
.then(() => new Parse.File("yolo.txt", [1,2,3], "text/plain").save())
.then(
() => done.fail('should not succeed'),
() => setImmediate(() => Parse.Promise.as('done'))
)
.then(() => logController.getLogs({ from: Date.now() - 500, size: 1000 }))
.then((logs) => {
// we get two logs here: 1. the source of the failure to save the file
// and 2 the message that will be sent back to the client.
const log1 = logs.pop();
expect(log1.level).toBe('error');
expect(log1.message).toBe('it failed');
const log2 = logs.pop();
expect(log2.level).toBe('error');
expect(log2.code).toBe(130);
expect(log2.message).toBe('Could not store file.');
done();
});
});
});
+36 -36
View File
@@ -6,7 +6,7 @@ var httpRequest = require("../src/cloud-code/httpRequest"),
express = require("express");
var port = 13371;
var httpRequestServer = "http://localhost:"+port;
var httpRequestServer = "http://localhost:" + port;
var app = express();
app.use(bodyParser.json({ 'type': '*/*' }));
@@ -39,7 +39,7 @@ app.listen(13371);
describe("httpRequest", () => {
it("should do /hello", (done) => {
httpRequest({
url: httpRequestServer+"/hello"
url: httpRequestServer + "/hello"
}).then(function(httpResponse){
expect(httpResponse.status).toBe(200);
expect(httpResponse.buffer).toEqual(new Buffer('{"response":"OK"}'));
@@ -55,7 +55,7 @@ describe("httpRequest", () => {
it("should do /hello with callback and promises", (done) => {
var calls = 0;
httpRequest({
url: httpRequestServer+"/hello",
url: httpRequestServer + "/hello",
success: function() { calls++; },
error: function() { calls++; }
}).then(function(httpResponse){
@@ -74,7 +74,7 @@ describe("httpRequest", () => {
it("should do not follow redirects by default", (done) => {
httpRequest({
url: httpRequestServer+"/301"
url: httpRequestServer + "/301"
}).then(function(httpResponse){
expect(httpResponse.status).toBe(301);
done();
@@ -87,7 +87,7 @@ describe("httpRequest", () => {
it("should follow redirects when set", (done) => {
httpRequest({
url: httpRequestServer+"/301",
url: httpRequestServer + "/301",
followRedirects: true
}).then(function(httpResponse){
expect(httpResponse.status).toBe(200);
@@ -104,7 +104,7 @@ describe("httpRequest", () => {
it("should fail on 404", (done) => {
var calls = 0;
httpRequest({
url: httpRequestServer+"/404",
url: httpRequestServer + "/404",
success: function() {
calls++;
fail("should not succeed");
@@ -124,7 +124,7 @@ describe("httpRequest", () => {
it("should fail on 404", (done) => {
httpRequest({
url: httpRequestServer+"/404",
url: httpRequestServer + "/404",
}).then(function(){
fail("should not succeed");
done();
@@ -141,7 +141,7 @@ describe("httpRequest", () => {
var calls = 0;
httpRequest({
method: "POST",
url: httpRequestServer+"/echo",
url: httpRequestServer + "/echo",
body: {
foo: "bar"
},
@@ -162,10 +162,10 @@ describe("httpRequest", () => {
});
it("should encode a query string body by default", (done) => {
let options = {
const options = {
body: {"foo": "bar"},
}
let result = httpRequest.encodeBody(options);
const result = httpRequest.encodeBody(options);
expect(result.body).toEqual('foo=bar');
expect(result.headers['Content-Type']).toEqual('application/x-www-form-urlencoded');
done();
@@ -173,30 +173,30 @@ describe("httpRequest", () => {
})
it("should encode a JSON body", (done) => {
let options = {
const options = {
body: {"foo": "bar"},
headers: {'Content-Type': 'application/json'}
}
let result = httpRequest.encodeBody(options);
const result = httpRequest.encodeBody(options);
expect(result.body).toEqual('{"foo":"bar"}');
done();
})
it("should encode a www-form body", (done) => {
let options = {
const options = {
body: {"foo": "bar", "bar": "baz"},
headers: {'cOntent-tYpe': 'application/x-www-form-urlencoded'}
}
let result = httpRequest.encodeBody(options);
const result = httpRequest.encodeBody(options);
expect(result.body).toEqual("foo=bar&bar=baz");
done();
});
it("should not encode a wrong content type", (done) => {
let options = {
const options = {
body:{"foo": "bar", "bar": "baz"},
headers: {'cOntent-tYpe': 'mime/jpeg'}
}
let result = httpRequest.encodeBody(options);
const result = httpRequest.encodeBody(options);
expect(result.body).toEqual({"foo": "bar", "bar": "baz"});
done();
});
@@ -218,7 +218,7 @@ describe("httpRequest", () => {
it("should params object to query string", (done) => {
httpRequest({
url: httpRequestServer+"/qs",
url: httpRequestServer + "/qs",
params: {
foo: "bar"
}
@@ -234,7 +234,7 @@ describe("httpRequest", () => {
it("should params string to query string", (done) => {
httpRequest({
url: httpRequestServer+"/qs",
url: httpRequestServer + "/qs",
params: "foo=bar&foo2=bar2"
}).then(function(httpResponse){
expect(httpResponse.status).toBe(200);
@@ -247,7 +247,7 @@ describe("httpRequest", () => {
});
it('should not crash with undefined body', () => {
let httpResponse = new HTTPResponse({});
const httpResponse = new HTTPResponse({});
expect(httpResponse.body).toBeUndefined();
expect(httpResponse.data).toBeUndefined();
expect(httpResponse.text).toBeUndefined();
@@ -255,24 +255,24 @@ describe("httpRequest", () => {
});
it('serialized httpResponse correctly with body string', () => {
let httpResponse = new HTTPResponse({}, 'hello');
const httpResponse = new HTTPResponse({}, 'hello');
expect(httpResponse.text).toBe('hello');
expect(httpResponse.data).toBe(undefined);
expect(httpResponse.body).toBe('hello');
let serialized = JSON.stringify(httpResponse);
let result = JSON.parse(serialized);
const serialized = JSON.stringify(httpResponse);
const result = JSON.parse(serialized);
expect(result.text).toBe('hello');
expect(result.data).toBe(undefined);
expect(result.body).toBe(undefined);
});
it('serialized httpResponse correctly with body object', () => {
let httpResponse = new HTTPResponse({}, {foo: "bar"});
const httpResponse = new HTTPResponse({}, {foo: "bar"});
Parse._encode(httpResponse);
let serialized = JSON.stringify(httpResponse);
let result = JSON.parse(serialized);
const serialized = JSON.stringify(httpResponse);
const result = JSON.parse(serialized);
expect(httpResponse.text).toEqual('{"foo":"bar"}');
expect(httpResponse.data).toEqual({foo: 'bar'});
expect(httpResponse.body).toEqual({foo: 'bar'});
@@ -283,29 +283,29 @@ describe("httpRequest", () => {
});
it('serialized httpResponse correctly with body buffer string', () => {
let httpResponse = new HTTPResponse({}, new Buffer('hello'));
const httpResponse = new HTTPResponse({}, new Buffer('hello'));
expect(httpResponse.text).toBe('hello');
expect(httpResponse.data).toBe(undefined);
let serialized = JSON.stringify(httpResponse);
let result = JSON.parse(serialized);
const serialized = JSON.stringify(httpResponse);
const result = JSON.parse(serialized);
expect(result.text).toBe('hello');
expect(result.data).toBe(undefined);
});
it('serialized httpResponse correctly with body buffer JSON Object', () => {
let json = '{"foo":"bar"}';
let httpResponse = new HTTPResponse({}, new Buffer(json));
let serialized = JSON.stringify(httpResponse);
let result = JSON.parse(serialized);
const json = '{"foo":"bar"}';
const httpResponse = new HTTPResponse({}, new Buffer(json));
const serialized = JSON.stringify(httpResponse);
const result = JSON.parse(serialized);
expect(result.text).toEqual('{"foo":"bar"}');
expect(result.data).toEqual({foo: 'bar'});
});
it('serialized httpResponse with Parse._encode should be allright', () => {
let json = '{"foo":"bar"}';
let httpResponse = new HTTPResponse({}, new Buffer(json));
let encoded = Parse._encode(httpResponse);
const json = '{"foo":"bar"}';
const httpResponse = new HTTPResponse({}, new Buffer(json));
const encoded = Parse._encode(httpResponse);
let foundData, foundText, foundBody = false;
for(var key in encoded) {
if (key == 'data') {
+5 -5
View File
@@ -23,8 +23,8 @@ describe('Logger', () => {
it('should have files transports', (done) => {
reconfigureServer().then(() => {
let transports = logging.logger.transports;
let transportKeys = Object.keys(transports);
const transports = logging.logger.transports;
const transportKeys = Object.keys(transports);
expect(transportKeys.length).toBe(3);
done();
});
@@ -34,8 +34,8 @@ describe('Logger', () => {
reconfigureServer({
logsFolder: null
}).then(() => {
let transports = logging.logger.transports;
let transportKeys = Object.keys(transports);
const transports = logging.logger.transports;
const transportKeys = Object.keys(transports);
expect(transportKeys.length).toBe(1);
done();
});
@@ -52,7 +52,7 @@ describe('Logger', () => {
logging.logger.info('hi', {key: 'value'});
expect(process.stdout.write).toHaveBeenCalled();
var firstLog = process.stdout.write.calls.first().args[0];
expect(firstLog).toEqual(JSON.stringify({key: 'value', level: 'info', message: 'hi' })+'\n');
expect(firstLog).toEqual(JSON.stringify({key: 'value', level: 'info', message: 'hi' }) + '\n');
return reconfigureServer({
jsonLogs: false
});
+14 -1
View File
@@ -79,6 +79,19 @@ describe('middlewares', () => {
});
});
it('should succeed when client key supplied but empty', (done) => {
AppCache.put(fakeReq.body._ApplicationId, {
clientKey: '',
masterKey: 'masterKey',
restAPIKey: 'restAPIKey'
});
fakeReq.headers['x-parse-client-key'] = '';
middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
expect(fakeRes.status).not.toHaveBeenCalled();
done();
});
});
it('should succeed when no keys are configured and none supplied', (done) => {
AppCache.put(fakeReq.body._ApplicationId, {
masterKey: 'masterKey'
@@ -120,4 +133,4 @@ describe('middlewares', () => {
});
});
});
});
});
+1 -1
View File
@@ -2,7 +2,7 @@ module.exports = options => {
if (!options) {
throw "Options were not provided"
}
let adapter = {
const adapter = {
sendVerificationEmail: () => Promise.resolve(),
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => Promise.resolve()
+25 -25
View File
@@ -48,7 +48,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
});
it('stores objectId in _id', done => {
let adapter = new MongoStorageAdapter({ uri: databaseURI });
const adapter = new MongoStorageAdapter({ uri: databaseURI });
adapter.createObject('Foo', { fields: {} }, { objectId: 'abcde' })
.then(() => adapter._rawFind('Foo', {}))
.then(results => {
@@ -62,7 +62,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
it('find succeeds when query is within maxTimeMS', (done) => {
const maxTimeMS = 250;
let adapter = new MongoStorageAdapter({
const adapter = new MongoStorageAdapter({
uri: databaseURI,
mongoOptions: { maxTimeMS },
});
@@ -78,7 +78,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
it('find fails when query exceeds maxTimeMS', (done) => {
const maxTimeMS = 250;
let adapter = new MongoStorageAdapter({
const adapter = new MongoStorageAdapter({
uri: databaseURI,
mongoOptions: { maxTimeMS },
});
@@ -98,7 +98,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
});
it('stores pointers with a _p_ prefix', (done) => {
let obj = {
const obj = {
objectId: 'bar',
aPointer: {
__type: 'Pointer',
@@ -106,7 +106,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
objectId: 'qwerty'
}
};
let adapter = new MongoStorageAdapter({ uri: databaseURI });
const adapter = new MongoStorageAdapter({ uri: databaseURI });
adapter.createObject('APointerDarkly', { fields: {
objectId: { type: 'String' },
aPointer: { type: 'Pointer', targetClass: 'JustThePointer' },
@@ -114,7 +114,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
.then(() => adapter._rawFind('APointerDarkly', {}))
.then(results => {
expect(results.length).toEqual(1);
let output = results[0];
const output = results[0];
expect(typeof output._id).toEqual('string');
expect(typeof output._p_aPointer).toEqual('string');
expect(output._p_aPointer).toEqual('JustThePointer$qwerty');
@@ -124,24 +124,24 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
});
it('handles object and subdocument', done => {
let adapter = new MongoStorageAdapter({ uri: databaseURI });
let schema = { fields : { subdoc: { type: 'Object' } } };
let obj = { subdoc: {foo: 'bar', wu: 'tan'} };
const adapter = new MongoStorageAdapter({ uri: databaseURI });
const schema = { fields : { subdoc: { type: 'Object' } } };
const obj = { subdoc: {foo: 'bar', wu: 'tan'} };
adapter.createObject('MyClass', schema, obj)
.then(() => adapter._rawFind('MyClass', {}))
.then(results => {
expect(results.length).toEqual(1);
let mob = results[0];
const mob = results[0];
expect(typeof mob.subdoc).toBe('object');
expect(mob.subdoc.foo).toBe('bar');
expect(mob.subdoc.wu).toBe('tan');
let obj = { 'subdoc.wu': 'clan' };
const obj = { 'subdoc.wu': 'clan' };
return adapter.findOneAndUpdate('MyClass', schema, {}, obj);
})
.then(() => adapter._rawFind('MyClass', {}))
.then(results => {
expect(results.length).toEqual(1);
let mob = results[0];
const mob = results[0];
expect(typeof mob.subdoc).toBe('object');
expect(mob.subdoc.foo).toBe('bar');
expect(mob.subdoc.wu).toBe('clan');
@@ -150,8 +150,8 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
});
it('handles creating an array, object, date', (done) => {
let adapter = new MongoStorageAdapter({ uri: databaseURI });
let obj = {
const adapter = new MongoStorageAdapter({ uri: databaseURI });
const obj = {
array: [1, 2, 3],
object: {foo: 'bar'},
date: {
@@ -159,7 +159,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
iso: '2016-05-26T20:55:01.154Z',
},
};
let schema = { fields: {
const schema = { fields: {
array: { type: 'Array' },
object: { type: 'Object' },
date: { type: 'Date' },
@@ -168,7 +168,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
.then(() => adapter._rawFind('MyClass', {}))
.then(results => {
expect(results.length).toEqual(1);
let mob = results[0];
const mob = results[0];
expect(mob.array instanceof Array).toBe(true);
expect(typeof mob.object).toBe('object');
expect(mob.date instanceof Date).toBe(true);
@@ -176,7 +176,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
})
.then(results => {
expect(results.length).toEqual(1);
let mob = results[0];
const mob = results[0];
expect(mob.array instanceof Array).toBe(true);
expect(typeof mob.object).toBe('object');
expect(mob.date.__type).toBe('Date');
@@ -191,20 +191,20 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
});
it("handles updating a single object with array, object date", (done) => {
let adapter = new MongoStorageAdapter({ uri: databaseURI });
let schema = { fields: {
const adapter = new MongoStorageAdapter({ uri: databaseURI });
const schema = { fields: {
array: { type: 'Array' },
object: { type: 'Object' },
date: { type: 'Date' },
} };
adapter.createObject('MyClass', schema, {})
.then(() => adapter._rawFind('MyClass', {}))
.then(results => {
expect(results.length).toEqual(1);
let update = {
const update = {
array: [1, 2, 3],
object: {foo: 'bar'},
date: {
@@ -212,11 +212,11 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
iso: '2016-05-26T20:55:01.154Z',
},
};
let query = {};
const query = {};
return adapter.findOneAndUpdate('MyClass', schema, query, update)
})
.then(results => {
let mob = results;
const mob = results;
expect(mob.array instanceof Array).toBe(true);
expect(typeof mob.object).toBe('object');
expect(mob.date.__type).toBe('Date');
@@ -225,7 +225,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
})
.then(results => {
expect(results.length).toEqual(1);
let mob = results[0];
const mob = results[0];
expect(mob.array instanceof Array).toBe(true);
expect(typeof mob.object).toBe('object');
expect(mob.date instanceof Date).toBe(true);
+33 -7
View File
@@ -1,9 +1,9 @@
// These tests are unit tests designed to only test transform.js.
"use strict";
let transform = require('../src/Adapters/Storage/Mongo/MongoTransform');
let dd = require('deep-diff');
let mongodb = require('mongodb');
const transform = require('../src/Adapters/Storage/Mongo/MongoTransform');
const dd = require('deep-diff');
const mongodb = require('mongodb');
describe('parseObjectToMongoObjectForCreate', () => {
it('a basic number', (done) => {
@@ -179,7 +179,7 @@ describe('parseObjectToMongoObjectForCreate', () => {
});
it('untransforms objects containing nested special keys', done => {
let input = {array: [{
const input = {array: [{
_id: "Test ID",
_hashed_password: "I Don't know why you would name a key this, but if you do it should work",
_tombstone: {
@@ -190,7 +190,7 @@ describe('parseObjectToMongoObjectForCreate', () => {
},
regularKey: "some data",
}]}
let output = transform.mongoObjectToParseObject(null, input, {
const output = transform.mongoObjectToParseObject(null, input, {
fields: { array: { type: 'Array' }},
});
expect(dd(output, input)).toEqual(undefined);
@@ -242,7 +242,7 @@ describe('parseObjectToMongoObjectForCreate', () => {
};
var output = transform.parseObjectToMongoObjectForCreate(null, input, {
fields: {
aRelation: { __type: 'Relation', className: 'Stuff' },
aRelation: { __type: 'Relation', className: 'Stuff' },
},
});
expect(output).toEqual({});
@@ -293,6 +293,32 @@ describe('parseObjectToMongoObjectForCreate', () => {
expect(output.double).toBe(Number.MAX_VALUE);
done();
});
it('Date object where iso attribute is of type Date', (done) => {
var input = {
ts : { __type: 'Date', iso: new Date('2017-01-18T00:00:00.000Z') }
}
var output = transform.mongoObjectToParseObject(null, input, {
fields : {
ts : { type : 'Date' }
}
});
expect(output.ts.iso).toEqual('2017-01-18T00:00:00.000Z');
done();
});
it('Date object where iso attribute is of type String', (done) => {
var input = {
ts : { __type: 'Date', iso: '2017-01-18T00:00:00.000Z' }
}
var output = transform.mongoObjectToParseObject(null, input, {
fields : {
ts : { type : 'Date' }
}
});
expect(output.ts.iso).toEqual('2017-01-18T00:00:00.000Z');
done();
});
});
describe('transformUpdate', () => {
@@ -302,7 +328,7 @@ describe('transformUpdate', () => {
};
var output = transform.transformUpdate(null, input, {
fields: {
aRelation: { __type: 'Relation', className: 'Stuff' },
aRelation: { __type: 'Relation', className: 'Stuff' },
},
});
expect(output).toEqual({});
+136
View File
@@ -0,0 +1,136 @@
var OAuth = require("../src/Adapters/Auth/OAuth1Client");
describe('OAuth', function() {
it("Nonce should have right length", (done) => {
jequal(OAuth.nonce().length, 30);
done();
});
it("Should properly build parameter string", (done) => {
var string = OAuth.buildParameterString({c:1, a:2, b:3})
jequal(string, "a=2&b=3&c=1");
done();
});
it("Should properly build empty parameter string", (done) => {
var string = OAuth.buildParameterString()
jequal(string, "");
done();
});
it("Should properly build signature string", (done) => {
var string = OAuth.buildSignatureString("get", "http://dummy.com", "");
jequal(string, "GET&http%3A%2F%2Fdummy.com&");
done();
});
it("Should properly generate request signature", (done) => {
var request = {
host: "dummy.com",
path: "path"
};
var oauth_params = {
oauth_timestamp: 123450000,
oauth_nonce: "AAAAAAAAAAAAAAAAA",
oauth_consumer_key: "hello",
oauth_token: "token"
};
var consumer_secret = "world";
var auth_token_secret = "secret";
request = OAuth.signRequest(request, oauth_params, consumer_secret, auth_token_secret);
jequal(request.headers['Authorization'], 'OAuth oauth_consumer_key="hello", oauth_nonce="AAAAAAAAAAAAAAAAA", oauth_signature="8K95bpQcDi9Nd2GkhumTVcw4%2BXw%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="123450000", oauth_token="token", oauth_version="1.0"');
done();
});
it("Should properly build request", (done) => {
var options = {
host: "dummy.com",
consumer_key: "hello",
consumer_secret: "world",
auth_token: "token",
auth_token_secret: "secret",
// Custom oauth params for tests
oauth_params: {
oauth_timestamp: 123450000,
oauth_nonce: "AAAAAAAAAAAAAAAAA"
}
};
var path = "path";
var method = "get";
var oauthClient = new OAuth(options);
var req = oauthClient.buildRequest(method, path, {"query": "param"});
jequal(req.host, options.host);
jequal(req.path, "/" + path + "?query=param");
jequal(req.method, "GET");
jequal(req.headers['Content-Type'], 'application/x-www-form-urlencoded');
jequal(req.headers['Authorization'], 'OAuth oauth_consumer_key="hello", oauth_nonce="AAAAAAAAAAAAAAAAA", oauth_signature="wNkyEkDE%2F0JZ2idmqyrgHdvC0rs%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="123450000", oauth_token="token", oauth_version="1.0"')
done();
});
function validateCannotAuthenticateError(data, done) {
jequal(typeof data, "object");
jequal(typeof data.errors, "object");
var errors = data.errors;
jequal(typeof errors[0], "object");
// Cannot authenticate error
jequal(errors[0].code, 32);
done();
}
it("Should fail a GET request", (done) => {
var options = {
host: "api.twitter.com",
consumer_key: "XXXXXXXXXXXXXXXXXXXXXXXXX",
consumer_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
};
var path = "/1.1/help/configuration.json";
var params = {"lang": "en"};
var oauthClient = new OAuth(options);
oauthClient.get(path, params).then(function(data){
validateCannotAuthenticateError(data, done);
})
});
it("Should fail a POST request", (done) => {
var options = {
host: "api.twitter.com",
consumer_key: "XXXXXXXXXXXXXXXXXXXXXXXXX",
consumer_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
};
var body = {
lang: "en"
};
var path = "/1.1/account/settings.json";
var oauthClient = new OAuth(options);
oauthClient.post(path, null, body).then(function(data){
validateCannotAuthenticateError(data, done);
})
});
it("Should fail a request", (done) => {
var options = {
host: "localhost",
consumer_key: "XXXXXXXXXXXXXXXXXXXXXXXXX",
consumer_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
};
var body = {
lang: "en"
};
var path = "/";
var oauthClient = new OAuth(options);
oauthClient.post(path, null, body).then(function(){
jequal(false, true);
done();
}).catch(function(){
jequal(true, true);
done();
})
});
});
+36 -11
View File
@@ -1,23 +1,33 @@
'use strict';
let request = require('request');
const request = require('request');
const delayPromise = (delay) => {
return new Promise((resolve) => {
setTimeout(resolve, delay);
});
}
describe('Parse.Push', () => {
var setup = function() {
var sendToInstallationSpy = jasmine.createSpy();
var pushAdapter = {
send: function(body, installations) {
var badge = body.data.badge;
let promises = installations.map((installation) => {
const promises = installations.map((installation) => {
sendToInstallationSpy(installation);
if (installation.deviceType == "ios") {
expect(installation.badge).toEqual(badge);
expect(installation.originalBadge+1).toEqual(installation.badge);
expect(installation.originalBadge + 1).toEqual(installation.badge);
} else {
expect(installation.badge).toBeUndefined();
}
return Promise.resolve({
err: null,
deviceType: installation.deviceType,
result: true
device: installation,
transmitted: true
})
});
return Promise.all(promises);
@@ -39,21 +49,29 @@ describe('Parse.Push', () => {
var installations = [];
while(installations.length != 10) {
var installation = new Parse.Object("_Installation");
installation.set("installationId", "installation_"+installations.length);
installation.set("deviceToken","device_token_"+installations.length)
installation.set("installationId", "installation_" + installations.length);
installation.set("deviceToken","device_token_" + installations.length)
installation.set("badge", installations.length);
installation.set("originalBadge", installations.length);
installation.set("deviceType", "ios");
installations.push(installation);
}
return Parse.Object.saveAll(installations);
}).catch((err) => {
})
.then(() => {
return {
sendToInstallationSpy,
};
})
.catch((err) => {
console.error(err);
throw err;
})
}
it('should properly send push', (done) => {
return setup().then(() => {
return setup().then(({ sendToInstallationSpy }) => {
return Parse.Push.send({
where: {
deviceType: 'ios'
@@ -63,8 +81,13 @@ describe('Parse.Push', () => {
alert: 'Hello world!'
}
}, {useMasterKey: true})
})
.then(() => {
.then(() => {
return delayPromise(500);
})
.then(() => {
expect(sendToInstallationSpy.calls.count()).toEqual(10);
})
}).then(() => {
done();
}).catch((err) => {
jfail(err);
@@ -83,6 +106,8 @@ describe('Parse.Push', () => {
alert: 'Hello world!'
}
}, {useMasterKey: true})
}).then(() => {
return delayPromise(500);
}).then(() => {
done();
}).catch((err) => {
+34
View File
@@ -733,6 +733,40 @@ describe('Parse.ACL', () => {
});
});
it("acl making an object privately writable (#3194)", (done) => {
// Create an object owned by Alice.
var object;
var user2;
var user = new Parse.User();
user.set("username", "alice");
user.set("password", "wonderland");
user.signUp().then(() => {
object = new TestObject();
var acl = new Parse.ACL(user);
acl.setPublicWriteAccess(false);
acl.setPublicReadAccess(true);
object.setACL(acl);
return object.save().then(() => {
return Parse.User.logOut();
})
}).then(() => {
user2 = new Parse.User();
user2.set("username", "bob");
user2.set("password", "burger");
return user2.signUp();
}).then(() => {
console.log(user2.getSessionToken());
return object.destroy({sessionToken: user2.getSessionToken() });
}).then((res) => {
console.log(res);
fail('should not be able to destroy the object');
done();
}, (err) => {
console.error(err);
done();
});
});
it("acl sharing with another user and get", (done) => {
// Sign in as Bob.
Parse.User.signUp("bob", "pass", null, {
+92 -92
View File
@@ -5,7 +5,7 @@
var request = require('request');
const rp = require('request-promise');
const Parse = require("parse/node");
let Config = require('../src/Config');
const Config = require('../src/Config');
const SchemaController = require('../src/Controllers/SchemaController');
var TestUtils = require('../src/TestUtils');
@@ -23,7 +23,7 @@ describe_only_db('mongo')('miscellaneous', () => {
obj.set('foo', 'bar');
return obj.save();
}).then(() => {
let config = new Config(appId);
const config = new Config(appId);
return config.database.adapter.find('TestObject', { fields: {} }, {}, {});
}).then((results) => {
expect(results.length).toEqual(1);
@@ -83,7 +83,7 @@ describe('miscellaneous', function() {
it('fail to create a duplicate username', done => {
let numCreated = 0;
let numFailed = 0;
let p1 = createTestUser();
const p1 = createTestUser();
p1.then(() => {
numCreated++;
expect(numCreated).toEqual(1);
@@ -93,7 +93,7 @@ describe('miscellaneous', function() {
expect(numFailed).toEqual(1);
expect(error.code).toEqual(Parse.Error.USERNAME_TAKEN);
});
let p2 = createTestUser();
const p2 = createTestUser();
p2.then(() => {
numCreated++;
expect(numCreated).toEqual(1);
@@ -114,11 +114,11 @@ describe('miscellaneous', function() {
it('ensure that email is uniquely indexed', done => {
let numFailed = 0;
let numCreated = 0;
let user1 = new Parse.User();
const user1 = new Parse.User();
user1.setPassword('asdf');
user1.setUsername('u1');
user1.setEmail('dupe@dupe.dupe');
let p1 = user1.signUp();
const p1 = user1.signUp();
p1.then(() => {
numCreated++;
expect(numCreated).toEqual(1);
@@ -128,11 +128,11 @@ describe('miscellaneous', function() {
expect(error.code).toEqual(Parse.Error.EMAIL_TAKEN);
});
let user2 = new Parse.User();
const user2 = new Parse.User();
user2.setPassword('asdf');
user2.setUsername('u2');
user2.setEmail('dupe@dupe.dupe');
let p2 = user2.signUp();
const p2 = user2.signUp();
p2.then(() => {
numCreated++;
expect(numCreated).toEqual(1);
@@ -151,7 +151,7 @@ describe('miscellaneous', function() {
});
it('ensure that if people already have duplicate users, they can still sign up new users', done => {
let config = new Config('test');
const config = new Config('test');
// Remove existing data to clear out unique index
TestUtils.destroyAllDataPermanently()
.then(() => config.database.adapter.createClass('_User', userSchema))
@@ -161,13 +161,13 @@ describe('miscellaneous', function() {
.then(reconfigureServer)
.catch(error => {
expect(error.code).toEqual(Parse.Error.DUPLICATE_VALUE);
let user = new Parse.User();
const user = new Parse.User();
user.setPassword('asdf');
user.setUsername('zxcv');
return user.signUp().catch(fail);
})
.then(() => {
let user = new Parse.User();
const user = new Parse.User();
user.setPassword('asdf');
user.setUsername('u');
return user.signUp()
@@ -183,7 +183,7 @@ describe('miscellaneous', function() {
});
it('ensure that if people already have duplicate emails, they can still sign up new users', done => {
let config = new Config('test');
const config = new Config('test');
// Remove existing data to clear out unique index
TestUtils.destroyAllDataPermanently()
.then(() => config.database.adapter.createClass('_User', userSchema))
@@ -191,14 +191,14 @@ describe('miscellaneous', function() {
.then(() => config.database.adapter.createObject('_User', userSchema, { objectId: 'y', email: 'a@b.c' }))
.then(reconfigureServer)
.catch(() => {
let user = new Parse.User();
const user = new Parse.User();
user.setPassword('asdf');
user.setUsername('qqq');
user.setEmail('unique@unique.unique');
return user.signUp().catch(fail);
})
.then(() => {
let user = new Parse.User();
const user = new Parse.User();
user.setPassword('asdf');
user.setUsername('www');
user.setEmail('a@b.c');
@@ -211,11 +211,11 @@ describe('miscellaneous', function() {
});
it('ensure that if you try to sign up a user with a unique username and email, but duplicates in some other field that has a uniqueness constraint, you get a regular duplicate value error', done => {
let config = new Config('test');
const config = new Config('test');
config.database.adapter.addFieldIfNotExists('_User', 'randomField', { type: 'String' })
.then(() => config.database.adapter.ensureUniqueness('_User', userSchema, ['randomField']))
.then(() => {
let user = new Parse.User();
const user = new Parse.User();
user.setPassword('asdf');
user.setUsername('1');
user.setEmail('1@b.c');
@@ -223,7 +223,7 @@ describe('miscellaneous', function() {
return user.signUp()
})
.then(() => {
let user = new Parse.User();
const user = new Parse.User();
user.setPassword('asdf');
user.setUsername('2');
user.setEmail('2@b.c');
@@ -374,7 +374,7 @@ describe('miscellaneous', function() {
let triggerTime = 0;
// Register a mock beforeSave hook
Parse.Cloud.beforeSave('GameScore', (req, res) => {
let object = req.object;
const object = req.object;
expect(object instanceof Parse.Object).toBeTruthy();
expect(object.get('fooAgain')).toEqual('barAgain');
if (triggerTime == 0) {
@@ -397,7 +397,7 @@ describe('miscellaneous', function() {
res.success();
});
let obj = new Parse.Object('GameScore');
const obj = new Parse.Object('GameScore');
obj.set('foo', 'bar');
obj.set('fooAgain', 'barAgain');
obj.save().then(() => {
@@ -417,13 +417,13 @@ describe('miscellaneous', function() {
let triggerTime = 0;
// Register a mock beforeSave hook
Parse.Cloud.beforeSave('GameScore', (req, res) => {
let object = req.object;
const object = req.object;
object.set('foo', 'bar');
triggerTime++;
res.success(object);
});
let obj = new Parse.Object('GameScore');
const obj = new Parse.Object('GameScore');
obj.set('foo', 'baz');
obj.save().then(() => {
expect(triggerTime).toBe(1);
@@ -439,10 +439,10 @@ describe('miscellaneous', function() {
let triggerTime = 0;
// Register a mock beforeSave hook
Parse.Cloud.beforeSave('GameScore', (req, res) => {
let object = req.object;
const object = req.object;
expect(object instanceof Parse.Object).toBeTruthy();
expect(object.get('fooAgain')).toEqual('barAgain');
let originalObject = req.original;
const originalObject = req.original;
if (triggerTime == 0) {
// No id/createdAt/updatedAt
expect(object.id).toBeUndefined();
@@ -472,7 +472,7 @@ describe('miscellaneous', function() {
res.success();
});
let obj = new Parse.Object('GameScore');
const obj = new Parse.Object('GameScore');
obj.set('foo', 'bar');
obj.set('fooAgain', 'barAgain');
obj.save().then(() => {
@@ -490,13 +490,13 @@ describe('miscellaneous', function() {
});
it('pointer mutation properly saves object', done => {
let className = 'GameScore';
const className = 'GameScore';
Parse.Cloud.beforeSave(className, (req, res) => {
let object = req.object;
const object = req.object;
expect(object instanceof Parse.Object).toBeTruthy();
let child = object.get('child');
const child = object.get('child');
expect(child instanceof Parse.Object).toBeTruthy();
child.set('a', 'b');
child.save().then(() => {
@@ -504,20 +504,20 @@ describe('miscellaneous', function() {
});
});
let obj = new Parse.Object(className);
const obj = new Parse.Object(className);
obj.set('foo', 'bar');
let child = new Parse.Object('Child');
const child = new Parse.Object('Child');
child.save().then(() => {
obj.set('child', child);
return obj.save();
}).then(() => {
let query = new Parse.Query(className);
const query = new Parse.Query(className);
query.include('child');
return query.get(obj.id).then(objAgain => {
expect(objAgain.get('foo')).toEqual('bar');
let childAgain = objAgain.get('child');
const childAgain = objAgain.get('child');
expect(childAgain instanceof Parse.Object).toBeTruthy();
expect(childAgain.get('a')).toEqual('b');
@@ -703,9 +703,9 @@ describe('miscellaneous', function() {
var triggerTime = 0;
// Register a mock beforeSave hook
Parse.Cloud.afterSave('GameScore', function(req, res) {
let object = req.object;
const object = req.object;
expect(object instanceof Parse.Object).toBeTruthy();
let originalObject = req.original;
const originalObject = req.original;
if (triggerTime == 0) {
// Create
expect(object.get('yolo')).toEqual(1);
@@ -740,13 +740,13 @@ describe('miscellaneous', function() {
let triggerTime = 0;
// Register a mock beforeSave hook
Parse.Cloud.beforeSave('GameScore', function(req, res) {
let object = req.object;
const object = req.object;
if (triggerTime == 0) {
let acl = object.getACL();
const acl = object.getACL();
expect(acl.getPublicReadAccess()).toBeTruthy();
expect(acl.getPublicWriteAccess()).toBeTruthy();
} else if (triggerTime == 1) {
let acl = object.getACL();
const acl = object.getACL();
expect(acl.getPublicReadAccess()).toBeFalsy();
expect(acl.getPublicWriteAccess()).toBeTruthy();
} else {
@@ -756,8 +756,8 @@ describe('miscellaneous', function() {
res.success();
});
let obj = new Parse.Object('GameScore');
let acl = new Parse.ACL();
const obj = new Parse.Object('GameScore');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(true);
obj.setACL(acl);
@@ -779,13 +779,13 @@ describe('miscellaneous', function() {
let triggerTime = 0;
// Register a mock beforeSave hook
Parse.Cloud.afterSave('GameScore', function(req, res) {
let object = req.object;
const object = req.object;
if (triggerTime == 0) {
let acl = object.getACL();
const acl = object.getACL();
expect(acl.getPublicReadAccess()).toBeTruthy();
expect(acl.getPublicWriteAccess()).toBeTruthy();
} else if (triggerTime == 1) {
let acl = object.getACL();
const acl = object.getACL();
expect(acl.getPublicReadAccess()).toBeFalsy();
expect(acl.getPublicWriteAccess()).toBeTruthy();
} else {
@@ -795,8 +795,8 @@ describe('miscellaneous', function() {
res.success();
});
let obj = new Parse.Object('GameScore');
let acl = new Parse.ACL();
const obj = new Parse.Object('GameScore');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(true);
obj.setACL(acl);
@@ -815,8 +815,8 @@ describe('miscellaneous', function() {
});
it('should return the updated fields on PUT', done => {
let obj = new Parse.Object('GameScore');
obj.save({a:'hello', c: 1, d: ['1'], e:['1'], f:['1','2']}).then(( ) => {
const obj = new Parse.Object('GameScore');
obj.save({a:'hello', c: 1, d: ['1'], e:['1'], f:['1','2']}).then(() => {
var headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test',
@@ -825,7 +825,7 @@ describe('miscellaneous', function() {
};
request.put({
headers: headers,
url: 'http://localhost:8378/1/classes/GameScore/'+obj.id,
url: 'http://localhost:8378/1/classes/GameScore/' + obj.id,
body: JSON.stringify({
a: 'b',
c: {"__op":"Increment","amount":2},
@@ -1037,7 +1037,7 @@ describe('miscellaneous', function() {
});
it('can handle date params in cloud functions (#2214)', done => {
let date = new Date();
const date = new Date();
Parse.Cloud.define('dateFunc', (request, response) => {
expect(request.params.date.__type).toEqual('Date');
expect(request.params.date.iso).toEqual(date.toISOString());
@@ -1133,27 +1133,27 @@ describe('miscellaneous', function() {
});
it('dedupes an installation properly and returns updatedAt', (done) => {
let headers = {
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest'
};
let data = {
const data = {
'installationId': 'lkjsahdfkjhsdfkjhsdfkjhsdf',
'deviceType': 'embedded'
};
let requestOptions = {
const requestOptions = {
headers: headers,
url: 'http://localhost:8378/1/installations',
body: JSON.stringify(data)
};
request.post(requestOptions, (error, response, body) => {
expect(error).toBe(null);
let b = JSON.parse(body);
const b = JSON.parse(body);
expect(typeof b.objectId).toEqual('string');
request.post(requestOptions, (error, response, body) => {
expect(error).toBe(null);
let b = JSON.parse(body);
const b = JSON.parse(body);
expect(typeof b.updatedAt).toEqual('string');
done();
});
@@ -1161,17 +1161,17 @@ describe('miscellaneous', function() {
});
it('android login providing empty authData block works', (done) => {
let headers = {
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest'
};
let data = {
const data = {
username: 'pulse1989',
password: 'password1234',
authData: {}
};
let requestOptions = {
const requestOptions = {
headers: headers,
url: 'http://localhost:8378/1/users',
body: JSON.stringify(data)
@@ -1181,7 +1181,7 @@ describe('miscellaneous', function() {
requestOptions.url = 'http://localhost:8378/1/login';
request.get(requestOptions, (error, response, body) => {
expect(error).toBe(null);
let b = JSON.parse(body);
const b = JSON.parse(body);
expect(typeof b['sessionToken']).toEqual('string');
done();
});
@@ -1189,25 +1189,25 @@ describe('miscellaneous', function() {
});
it('gets relation fields', (done) => {
let object = new Parse.Object('AnObject');
let relatedObject = new Parse.Object('RelatedObject');
const object = new Parse.Object('AnObject');
const relatedObject = new Parse.Object('RelatedObject');
Parse.Object.saveAll([object, relatedObject]).then(() => {
object.relation('related').add(relatedObject);
return object.save();
}).then(() => {
let headers = {
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest'
};
let requestOptions = {
const requestOptions = {
headers: headers,
url: 'http://localhost:8378/1/classes/AnObject',
json: true
};
request.get(requestOptions, (err, res, body) => {
expect(body.results.length).toBe(1);
let result = body.results[0];
const result = body.results[0];
expect(result.related).toEqual({
__type: "Relation",
className: 'RelatedObject'
@@ -1221,27 +1221,27 @@ describe('miscellaneous', function() {
});
it('properly returns incremented values (#1554)', (done) => {
let headers = {
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest'
};
let requestOptions = {
const requestOptions = {
headers: headers,
url: 'http://localhost:8378/1/classes/AnObject',
json: true
};
let object = new Parse.Object('AnObject');
const object = new Parse.Object('AnObject');
function runIncrement(amount) {
let options = Object.assign({}, requestOptions, {
const options = Object.assign({}, requestOptions, {
body: {
"key": {
__op: 'Increment',
amount: amount
}
},
url: 'http://localhost:8378/1/classes/AnObject/'+object.id
url: 'http://localhost:8378/1/classes/AnObject/' + object.id
})
return new Promise((resolve, reject) => {
request.put(options, (err, res, body) => {
@@ -1266,7 +1266,7 @@ describe('miscellaneous', function() {
})
it('ignores _RevocableSession "header" send by JS SDK', (done) => {
let object = new Parse.Object('AnObject');
const object = new Parse.Object('AnObject');
object.set('a', 'b');
object.save().then(() => {
request.post({
@@ -1285,7 +1285,7 @@ describe('miscellaneous', function() {
expect(body.error).toBeUndefined();
expect(body.results).not.toBeUndefined();
expect(body.results.length).toBe(1);
let result = body.results[0];
const result = body.results[0];
expect(result.a).toBe('b');
done();
})
@@ -1293,7 +1293,7 @@ describe('miscellaneous', function() {
});
it('doesnt convert interior keys of objects that use special names', done => {
let obj = new Parse.Object('Obj');
const obj = new Parse.Object('Obj');
obj.set('val', { createdAt: 'a', updatedAt: 1 });
obj.save()
.then(obj => new Parse.Query('Obj').get(obj.id))
@@ -1361,10 +1361,10 @@ describe('miscellaneous', function() {
});
it('does not change inner objects if the key has the same name as a geopoint field on the class, and the value is an array of length 2, or if the key has the same name as a file field on the class, and the value is a string', done => {
let file = new Parse.File('myfile.txt', { base64: 'eAo=' });
const file = new Parse.File('myfile.txt', { base64: 'eAo=' });
file.save()
.then(f => {
let obj = new Parse.Object('O');
const obj = new Parse.Object('O');
obj.set('fileField', f);
obj.set('geoField', new Parse.GeoPoint(0, 0));
obj.set('innerObj', {
@@ -1387,17 +1387,17 @@ describe('miscellaneous', function() {
});
it('purge all objects in class', (done) => {
let object = new Parse.Object('TestObject');
const object = new Parse.Object('TestObject');
object.set('foo', 'bar');
let object2 = new Parse.Object('TestObject');
const object2 = new Parse.Object('TestObject');
object2.set('alice', 'wonderland');
Parse.Object.saveAll([object, object2])
.then(() => {
let query = new Parse.Query(TestObject);
const query = new Parse.Query(TestObject);
return query.count()
}).then((count) => {
expect(count).toBe(2);
let headers = {
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test',
'X-Parse-Master-Key': 'test'
@@ -1408,7 +1408,7 @@ describe('miscellaneous', function() {
json: true
}, (err) => {
expect(err).toBe(null);
let query = new Parse.Query(TestObject);
const query = new Parse.Query(TestObject);
return query.count().then((count) => {
expect(count).toBe(0);
done();
@@ -1418,7 +1418,7 @@ describe('miscellaneous', function() {
});
it('fail on purge all objects in class without master key', (done) => {
let headers = {
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest'
@@ -1437,7 +1437,7 @@ describe('miscellaneous', function() {
});
it('purge all objects in _Role also purge cache', (done) => {
let headers = {
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test',
'X-Parse-Master-Key': 'test'
@@ -1445,26 +1445,26 @@ describe('miscellaneous', function() {
var user, object;
createTestUser().then((x) => {
user = x;
let acl = new Parse.ACL();
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(false);
let role = new Parse.Object('_Role');
const role = new Parse.Object('_Role');
role.set('name', 'TestRole');
role.setACL(acl);
let users = role.relation('users');
const users = role.relation('users');
users.add(user);
return role.save({}, { useMasterKey: true });
}).then(() => {
let query = new Parse.Query('_Role');
const query = new Parse.Query('_Role');
return query.find({ useMasterKey: true });
}).then((x) => {
expect(x.length).toEqual(1);
let relation = x[0].relation('users').query();
const relation = x[0].relation('users').query();
return relation.first({ useMasterKey: true });
}).then((x) => {
expect(x.id).toEqual(user.id);
object = new Parse.Object('TestObject');
let acl = new Parse.ACL();
const acl = new Parse.ACL();
acl.setPublicReadAccess(false);
acl.setPublicWriteAccess(false);
acl.setRoleReadAccess('TestRole', true);
@@ -1472,7 +1472,7 @@ describe('miscellaneous', function() {
object.setACL(acl);
return object.save();
}).then(() => {
let query = new Parse.Query('TestObject');
const query = new Parse.Query('TestObject');
return query.find({ sessionToken: user.getSessionToken() });
}).then((x) => {
expect(x.length).toEqual(1);
@@ -1483,7 +1483,7 @@ describe('miscellaneous', function() {
json: true
});
}).then(() => {
let query = new Parse.Query('TestObject');
const query = new Parse.Query('TestObject');
return query.get(object.id, { sessionToken: user.getSessionToken() });
}).then(() => {
fail('Should not succeed');
@@ -1502,7 +1502,7 @@ describe('miscellaneous', function() {
response.success();
});
let object = new Parse.Object('MyObject');
const object = new Parse.Object('MyObject');
object.set('key', 'value');
object.save().then(() => {
return object.save({'secret': 'should not update schema'});
@@ -1520,7 +1520,7 @@ describe('miscellaneous', function() {
json: true
});
}).then((res) => {
let fields = res.fields;
const fields = res.fields;
expect(fields.secret).toBeUndefined();
done();
}, (err) => {
@@ -1532,7 +1532,7 @@ describe('miscellaneous', function() {
describe_only_db('mongo')('legacy _acl', () => {
it('should have _acl when locking down (regression for #2465)', (done) => {
let headers = {
const headers = {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest'
}
@@ -1546,13 +1546,13 @@ describe_only_db('mongo')('legacy _acl', () => {
},
json: true
}).then(() => {
let config = new Config('test');
let adapter = config.database.adapter;
const config = new Config('test');
const adapter = config.database.adapter;
return adapter._adaptiveCollection("Report")
.then(collection => collection.find({}))
}).then((results) => {
expect(results.length).toBe(1);
let result = results[0];
const result = results[0];
expect(result.name).toEqual('My Report');
expect(result._wperm).toEqual([]);
expect(result._rperm).toEqual([]);
+2 -2
View File
@@ -563,7 +563,7 @@ describe('Parse.File testing', () => {
var query = new Parse.Query('FileTest');
return query.first();
}).then(result => {
let fileAgain = result.get('file');
const fileAgain = result.get('file');
expect(fileAgain.url()).toMatch(/123.txt$/);
done();
}).catch((e) => {
@@ -587,7 +587,7 @@ describe('Parse.File testing', () => {
var query = new Parse.Query('FileTest');
return query.first();
}).then(result => {
let fileAgain = result.get('file');
const fileAgain = result.get('file');
expect(fileAgain.url().indexOf('https://mydomain/parse')).toBe(0);
done();
}).catch((e) => {
+47 -4
View File
@@ -1,12 +1,12 @@
'use strict';
var request = require('request');
let Config = require('../src/Config');
const Config = require('../src/Config');
describe('a GlobalConfig', () => {
beforeEach(done => {
let config = new Config('test');
let query = on_db('mongo', () => {
const config = new Config('test');
const query = on_db('mongo', () => {
// Legacy is with an int...
return { objectId: 1 };
}, () => {
@@ -56,6 +56,49 @@ describe('a GlobalConfig', () => {
});
});
it('can add and retrive files', (done) => {
request.put({
url : 'http://localhost:8378/1/config',
json : true,
body : { params: { file: { __type: 'File', name: 'name', url: 'http://url' } } },
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Master-Key' : 'test'
}
}, (error, response, body) => {
expect(response.statusCode).toEqual(200);
expect(body.result).toEqual(true);
Parse.Config.get().then((res) => {
const file = res.get('file');
expect(file.name()).toBe('name');
expect(file.url()).toBe('http://url');
done();
});
});
});
it('can add and retrive Geopoints', (done) => {
const geopoint = new Parse.GeoPoint(10,-20);
request.put({
url : 'http://localhost:8378/1/config',
json : true,
body : { params: { point: geopoint.toJSON() } },
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Master-Key' : 'test'
}
}, (error, response, body) => {
expect(response.statusCode).toEqual(200);
expect(body.result).toEqual(true);
Parse.Config.get().then((res) => {
const point = res.get('point');
expect(point.latitude).toBe(10);
expect(point.longitude).toBe(-20);
done();
});
});
});
it('properly handles delete op', (done) => {
request.put({
url : 'http://localhost:8378/1/config',
@@ -104,7 +147,7 @@ describe('a GlobalConfig', () => {
});
it('failed getting config when it is missing', (done) => {
let config = new Config('test');
const config = new Config('test');
config.database.adapter.deleteObjectsByQuery(
'_GlobalConfig',
{ fields: { params: { __type: 'String' } } },
+40 -39
View File
@@ -7,8 +7,8 @@ var express = require("express");
var bodyParser = require('body-parser');
var port = 12345;
var hookServerURL = "http://localhost:"+port;
let AppCache = require('../src/cache').AppCache;
var hookServerURL = "http://localhost:" + port;
const AppCache = require('../src/cache').AppCache;
var app = express();
app.use(bodyParser.json({ 'type': '*/*' }))
@@ -26,7 +26,7 @@ describe('Hooks', () => {
});
it("should have no triggers registered", (done) => {
Parse.Hooks.getTriggers().then( (res) => {
Parse.Hooks.getTriggers().then((res) => {
expect(res.constructor).toBe(Array.prototype.constructor);
done();
}, (err) => {
@@ -129,7 +129,7 @@ describe('Hooks', () => {
});
it("should fail to register hooks without Master Key", (done) => {
request.post(Parse.serverURL+"/hooks/functions", {
request.post(Parse.serverURL + "/hooks/functions", {
headers: {
"X-Parse-Application-Id": Parse.applicationId,
"X-Parse-REST-API-Key": Parse.restKey,
@@ -143,11 +143,13 @@ describe('Hooks', () => {
});
it("should fail trying to create two times the same function", (done) => {
Parse.Hooks.createFunction("my_new_function", "http://url.com").then( () => {
Parse.Hooks.createFunction("my_new_function", "http://url.com")
.then(() => new Promise(resolve => setTimeout(resolve, 100)))
.then(() => {
return Parse.Hooks.createFunction("my_new_function", "http://url.com")
}, () => {
fail("should create a new function");
}).then( () => {
}).then(() => {
fail("should not be able to create the same function");
}, (err) => {
expect(err).not.toBe(undefined);
@@ -166,11 +168,11 @@ describe('Hooks', () => {
});
it("should fail trying to create two times the same trigger", (done) => {
Parse.Hooks.createTrigger("MyClass", "beforeSave", "http://url.com").then( () => {
Parse.Hooks.createTrigger("MyClass", "beforeSave", "http://url.com").then(() => {
return Parse.Hooks.createTrigger("MyClass", "beforeSave", "http://url.com")
}, () => {
fail("should create a new trigger");
}).then( () => {
}).then(() => {
fail("should not be able to create the same trigger");
}, (err) => {
expect(err).not.toBe(undefined);
@@ -189,7 +191,7 @@ describe('Hooks', () => {
});
it("should fail trying to update a function that don't exist", (done) => {
Parse.Hooks.updateFunction("A_COOL_FUNCTION", "http://url.com").then( () => {
Parse.Hooks.updateFunction("A_COOL_FUNCTION", "http://url.com").then(() => {
fail("Should not succeed")
}, (err) => {
expect(err).not.toBe(undefined);
@@ -214,7 +216,7 @@ describe('Hooks', () => {
});
it("should fail trying to update a trigger that don't exist", (done) => {
Parse.Hooks.updateTrigger("AClassName","beforeSave", "http://url.com").then( () => {
Parse.Hooks.updateTrigger("AClassName","beforeSave", "http://url.com").then(() => {
fail("Should not succeed")
}, (err) => {
expect(err).not.toBe(undefined);
@@ -240,7 +242,7 @@ describe('Hooks', () => {
it("should fail trying to create a malformed function", (done) => {
Parse.Hooks.createFunction("MyFunction").then( (res) => {
Parse.Hooks.createFunction("MyFunction").then((res) => {
fail(res);
}, (err) => {
expect(err).not.toBe(undefined);
@@ -254,7 +256,7 @@ describe('Hooks', () => {
});
it("should fail trying to create a malformed function (REST)", (done) => {
request.post(Parse.serverURL+"/hooks/functions", {
request.post(Parse.serverURL + "/hooks/functions", {
headers: {
"X-Parse-Application-Id": Parse.applicationId,
"X-Parse-Master-Key": Parse.masterKey,
@@ -272,18 +274,18 @@ describe('Hooks', () => {
it("should create hooks and properly preload them", (done) => {
var promises = [];
for (var i = 0; i<5; i++) {
promises.push(Parse.Hooks.createTrigger("MyClass"+i, "beforeSave", "http://url.com/beforeSave/"+i));
promises.push(Parse.Hooks.createFunction("AFunction"+i, "http://url.com/function"+i));
for (var i = 0; i < 5; i++) {
promises.push(Parse.Hooks.createTrigger("MyClass" + i, "beforeSave", "http://url.com/beforeSave/" + i));
promises.push(Parse.Hooks.createFunction("AFunction" + i, "http://url.com/function" + i));
}
Parse.Promise.when(promises).then(function(){
for (var i=0; i<5; i++) {
for (var i = 0; i < 5; i++) {
// Delete everything from memory, as the server just started
triggers.removeTrigger("beforeSave", "MyClass"+i, Parse.applicationId);
triggers.removeFunction("AFunction"+i, Parse.applicationId);
expect(triggers.getTrigger("MyClass"+i, "beforeSave", Parse.applicationId)).toBeUndefined();
expect(triggers.getFunction("AFunction"+i, Parse.applicationId)).toBeUndefined();
triggers.removeTrigger("beforeSave", "MyClass" + i, Parse.applicationId);
triggers.removeFunction("AFunction" + i, Parse.applicationId);
expect(triggers.getTrigger("MyClass" + i, "beforeSave", Parse.applicationId)).toBeUndefined();
expect(triggers.getFunction("AFunction" + i, Parse.applicationId)).toBeUndefined();
}
const hooksController = new HooksController(Parse.applicationId, AppCache.get('test').databaseController);
return hooksController.load()
@@ -292,9 +294,9 @@ describe('Hooks', () => {
fail('Should properly create all hooks');
done();
}).then(function() {
for (var i=0; i<5; i++) {
expect(triggers.getTrigger("MyClass"+i, "beforeSave", Parse.applicationId)).not.toBeUndefined();
expect(triggers.getFunction("AFunction"+i, Parse.applicationId)).not.toBeUndefined();
for (var i = 0; i < 5; i++) {
expect(triggers.getTrigger("MyClass" + i, "beforeSave", Parse.applicationId)).not.toBeUndefined();
expect(triggers.getFunction("AFunction" + i, Parse.applicationId)).not.toBeUndefined();
}
done();
}, (err) => {
@@ -310,7 +312,7 @@ describe('Hooks', () => {
res.json({success:"OK!"});
});
Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/SomeFunction").then(function(){
Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL + "/SomeFunction").then(function(){
return Parse.Cloud.run("SOME_TEST_FUNCTION")
}, (err) => {
jfail(err);
@@ -332,7 +334,7 @@ describe('Hooks', () => {
res.json({error: {code: 1337, error: "hacking that one!"}});
});
// The function is deleted as the DB is dropped between calls
Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/SomeFunctionError").then(function(){
Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL + "/SomeFunctionError").then(function(){
return Parse.Cloud.run("SOME_TEST_FUNCTION")
}, (err) => {
jfail(err);
@@ -362,7 +364,7 @@ describe('Hooks', () => {
}
});
Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/ExpectingKey").then(function(){
Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL + "/ExpectingKey").then(function(){
return Parse.Cloud.run("SOME_TEST_FUNCTION")
}, (err) => {
jfail(err);
@@ -389,7 +391,7 @@ describe('Hooks', () => {
}
});
Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/ExpectingKeyAlso").then(function(){
Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL + "/ExpectingKeyAlso").then(function(){
return Parse.Cloud.run("SOME_TEST_FUNCTION")
}, (err) => {
jfail(err);
@@ -421,8 +423,8 @@ describe('Hooks', () => {
// But this should override the key upon return
res.json({success: object});
});
// The function is delete as the DB is dropped between calls
Parse.Hooks.createTrigger("SomeRandomObject", "beforeSave" ,hookServerURL+"/BeforeSaveSome").then(function(){
// The function is deleted as the DB is dropped between calls
Parse.Hooks.createTrigger("SomeRandomObject", "beforeSave", hookServerURL + "/BeforeSaveSome").then(function () {
const obj = new Parse.Object("SomeRandomObject");
return obj.save();
}).then(function(res) {
@@ -444,7 +446,7 @@ describe('Hooks', () => {
object.set('hello', "world");
res.json({success: object});
});
Parse.Hooks.createTrigger("SomeRandomObject2", "beforeSave" ,hookServerURL+"/BeforeSaveSome2").then(function(){
Parse.Hooks.createTrigger("SomeRandomObject2", "beforeSave", hookServerURL + "/BeforeSaveSome2").then(function(){
const obj = new Parse.Object("SomeRandomObject2");
return obj.save();
}).then(function(res) {
@@ -470,20 +472,19 @@ describe('Hooks', () => {
res.json({success: {}});
})
});
// The function is delete as the DB is dropped between calls
Parse.Hooks.createTrigger("SomeRandomObject", "afterSave" ,hookServerURL+"/AfterSaveSome").then(function(){
// The function is deleted as the DB is dropped between calls
Parse.Hooks.createTrigger("SomeRandomObject", "afterSave", hookServerURL + "/AfterSaveSome").then(function(){
const obj = new Parse.Object("SomeRandomObject");
return obj.save();
}).then(function() {
var promise = new Parse.Promise();
// Wait a bit here as it's an after save
setTimeout(function(){
// Wait a bit here as it's an after save
setTimeout(() => {
expect(triggerCount).toBe(1);
var q = new Parse.Query("AnotherObject");
q.get(newObjectId).then(function(r){
promise.resolve(r);
});
}, 300)
new Parse.Query("AnotherObject")
.get(newObjectId)
.then((r) => promise.resolve(r));
}, 500);
return promise;
}).then(function(res){
expect(res.get("foo")).toEqual("bar");
+39 -32
View File
@@ -2,15 +2,19 @@
// These tests check the Installations functionality of the REST API.
// Ported from installation_collection_test.go
let auth = require('../src/Auth');
let Config = require('../src/Config');
let Parse = require('parse/node').Parse;
let rest = require('../src/rest');
let request = require("request");
const auth = require('../src/Auth');
const Config = require('../src/Config');
const Parse = require('parse/node').Parse;
const rest = require('../src/rest');
const request = require("request");
let config;
let database;
let defaultColumns = require('../src/Controllers/SchemaController').defaultColumns;
const defaultColumns = require('../src/Controllers/SchemaController').defaultColumns;
const delay = function delay(delay) {
return new Promise(resolve => setTimeout(resolve, delay));
}
const installationSchema = { fields: Object.assign({}, defaultColumns._Default, defaultColumns._Installation) };
@@ -130,7 +134,7 @@ describe('Installations', () => {
};
rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => {
let query = new Parse.Query(Parse.Installation);
const query = new Parse.Query(Parse.Installation);
return query.find()
}).then(() => {
fail('Should not succeed!');
@@ -151,7 +155,7 @@ describe('Installations', () => {
};
rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => {
let query = new Parse.Query(Parse.Installation);
const query = new Parse.Query(Parse.Installation);
return query.find({useMasterKey: true});
}).then((results) => {
expect(results.length).toEqual(1);
@@ -288,9 +292,9 @@ describe('Installations', () => {
expect(results.length).toEqual(1);
expect(results[0]['_id']).toEqual(secondObject._id);
done();
}).catch((error) => {
jfail(error);
done();
}).catch((error) => {
jfail(error);
done();
});
});
@@ -542,12 +546,14 @@ describe('Installations', () => {
};
return rest.create(config, auth.nobody(config), '_Installation', input);
})
.then(() => delay(100))
.then(() => database.adapter.find('_Installation', installationSchema, {installationId: installId1}, {}))
.then((results) => {
expect(results.length).toEqual(1);
firstObject = results[0];
return database.adapter.find('_Installation', installationSchema, {installationId: installId2}, {});
})
.then(() => delay(100))
.then(() => database.adapter.find('_Installation', installationSchema, {installationId: installId2}, {}))
.then(results => {
expect(results.length).toEqual(1);
secondObject = results[0];
@@ -558,6 +564,7 @@ describe('Installations', () => {
};
return rest.update(config, auth.nobody(config), '_Installation', secondObject.objectId, input);
})
.then(() => delay(100))
.then(() => database.adapter.find('_Installation', installationSchema, {objectId: firstObject.objectId}, {}))
.then(results => {
// The first object should have been deleted
@@ -842,15 +849,15 @@ describe('Installations', () => {
});
it('allows you to get your own installation (regression test for #1718)', done => {
let installId = '12345678-abcd-abcd-abcd-123456789abc';
let device = 'android';
let input = {
const installId = '12345678-abcd-abcd-abcd-123456789abc';
const device = 'android';
const input = {
'installationId': installId,
'deviceType': device
};
rest.create(config, auth.nobody(config), '_Installation', input)
.then(createResult => {
let headers = {
const headers = {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
@@ -871,15 +878,15 @@ describe('Installations', () => {
});
it('allows you to update installation from header (#2090)', done => {
let installId = '12345678-abcd-abcd-abcd-123456789abc';
let device = 'android';
let input = {
const installId = '12345678-abcd-abcd-abcd-123456789abc';
const device = 'android';
const input = {
'installationId': installId,
'deviceType': device
};
rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => {
let headers = {
const headers = {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
'X-Parse-Installation-Id': installId
@@ -905,15 +912,15 @@ describe('Installations', () => {
});
it('allows you to update installation with masterKey', done => {
let installId = '12345678-abcd-abcd-abcd-123456789abc';
let device = 'android';
let input = {
const installId = '12345678-abcd-abcd-abcd-123456789abc';
const device = 'android';
const input = {
'installationId': installId,
'deviceType': device
};
rest.create(config, auth.nobody(config), '_Installation', input)
.then(createResult => {
let installationObj = Parse.Installation.createWithoutData(createResult.response.objectId);
const installationObj = Parse.Installation.createWithoutData(createResult.response.objectId);
installationObj.set('customField', 'custom value');
return installationObj.save(null, {useMasterKey: true});
}).then(updateResult => {
@@ -928,14 +935,14 @@ describe('Installations', () => {
});
it('should properly handle installation save #2780', done => {
let installId = '12345678-abcd-abcd-abcd-123456789abc';
let device = 'android';
let input = {
const installId = '12345678-abcd-abcd-abcd-123456789abc';
const device = 'android';
const input = {
'installationId': installId,
'deviceType': device
};
rest.create(config, auth.nobody(config), '_Installation', input).then(() => {
let query = new Parse.Query(Parse.Installation);
const query = new Parse.Query(Parse.Installation);
query.equalTo('installationId', installId);
query.first({useMasterKey: true}).then((installation) => {
return installation.save({
@@ -951,14 +958,14 @@ describe('Installations', () => {
});
it('should properly reject updating installationId', done => {
let installId = '12345678-abcd-abcd-abcd-123456789abc';
let device = 'android';
let input = {
const installId = '12345678-abcd-abcd-abcd-123456789abc';
const device = 'android';
const input = {
'installationId': installId,
'deviceType': device
};
rest.create(config, auth.nobody(config), '_Installation', input).then(() => {
let query = new Parse.Query(Parse.Installation);
const query = new Parse.Query(Parse.Installation);
query.equalTo('installationId', installId);
query.first({useMasterKey: true}).then((installation) => {
return installation.save({
+2 -2
View File
@@ -358,7 +358,7 @@ describe('ParseLiveQueryServer', function() {
expect(args[0]).toBe(parseWebSocket);
expect(JSON.stringify(args[1])).toBe(updateRequest);
expect(parseLiveQueryServer._handleUnsubscribe).toHaveBeenCalled();
let unsubArgs = parseLiveQueryServer._handleUnsubscribe.calls.mostRecent().args;
const unsubArgs = parseLiveQueryServer._handleUnsubscribe.calls.mostRecent().args;
expect(unsubArgs.length).toBe(3);
expect(unsubArgs[2]).toBe(false);
expect(parseLiveQueryServer._handleSubscribe).toHaveBeenCalled();
@@ -928,7 +928,7 @@ describe('ParseLiveQueryServer', function() {
}
}
});
parseLiveQueryServer._matchesACL(acl, client, requestId).then(function(isMatched) {
expect(isMatched).toBe(false);
done();
+35 -35
View File
@@ -596,8 +596,8 @@ describe('Parse.Object testing', () => {
var query = new Parse.Query('X');
return query.get(x1.id);
}).then((x3) => {
let stuff = x3.get('stuff');
let expected = [1, 2, 4];
const stuff = x3.get('stuff');
const expected = [1, 2, 4];
expect(stuff.length).toBe(expected.length);
for (var i of stuff) {
expect(expected.indexOf(i) >= 0).toBe(true);
@@ -628,12 +628,12 @@ describe('Parse.Object testing', () => {
var query = new Parse.Query('X');
return query.get(x1.id);
}).then((x3) => {
let stuff = x3.get('stuff');
let target = [1, {'hello': 'world'}, {'foo': 'bar'}, {'bar': 'baz'}];
const stuff = x3.get('stuff');
const target = [1, {'hello': 'world'}, {'foo': 'bar'}, {'bar': 'baz'}];
expect(stuff.length).toEqual(target.length);
let found = 0;
for (let thing in target) {
for (let st in stuff) {
for (const thing in target) {
for (const st in stuff) {
if (st == thing) {
found++;
}
@@ -1390,7 +1390,7 @@ describe('Parse.Object testing', () => {
}
equal(itemsAgain.length, numItems, "Should get the array back");
itemsAgain.forEach(function(item, i) {
var newValue = i*2;
var newValue = i * 2;
item.set("x", newValue);
});
return Parse.Object.saveAll(itemsAgain);
@@ -1400,7 +1400,7 @@ describe('Parse.Object testing', () => {
equal(fetchedItemsAgain.length, numItems,
"Number of items fetched should not change");
fetchedItemsAgain.forEach(function(item, i) {
equal(item.get("x"), i*2);
equal(item.get("x"), i * 2);
});
done();
});
@@ -1457,7 +1457,7 @@ describe('Parse.Object testing', () => {
}
equal(itemsAgain.length, numItems, "Should get the array back");
itemsAgain.forEach(function(item, i) {
var newValue = i*2;
var newValue = i * 2;
item.set("x", newValue);
});
return Parse.Object.saveAll(itemsAgain);
@@ -1467,7 +1467,7 @@ describe('Parse.Object testing', () => {
equal(fetchedItemsAgain.length, numItems,
"Number of items fetched should not change");
fetchedItemsAgain.forEach(function(item, i) {
equal(item.get("x"), i*2);
equal(item.get("x"), i * 2);
});
done();
},
@@ -1581,7 +1581,7 @@ describe('Parse.Object testing', () => {
return;
}
itemsAgain.forEach(function(item, i) {
item.set("x", i*2);
item.set("x", i * 2);
});
return Parse.Object.saveAll(itemsAgain);
}).then(function() {
@@ -1619,7 +1619,7 @@ describe('Parse.Object testing', () => {
return;
}
itemsAgain.forEach(function(item, i) {
item.set("x", i*2);
item.set("x", i * 2);
});
return Parse.Object.saveAll(itemsAgain);
}).then(function() {
@@ -1842,10 +1842,10 @@ describe('Parse.Object testing', () => {
"_nested": "key"
}
});
object.save().then( res => {
object.save().then(res => {
ok(res);
return res.fetch();
}).then( res => {
}).then(res => {
const foo = res.get("foo");
expect(foo["_bar"]).toEqual("_");
expect(foo["baz_bar"]).toEqual(1);
@@ -1853,7 +1853,7 @@ describe('Parse.Object testing', () => {
expect(foo["_0"]).toEqual("underscore_zero");
expect(foo["_more"]["_nested"]).toEqual("key");
done();
}).fail( err => {
}).fail(err => {
jfail(err);
fail("should not fail");
done();
@@ -1861,15 +1861,15 @@ describe('Parse.Object testing', () => {
});
it('should have undefined includes when object is missing', (done) => {
let obj1 = new Parse.Object("AnObject");
let obj2 = new Parse.Object("AnObject");
const obj1 = new Parse.Object("AnObject");
const obj2 = new Parse.Object("AnObject");
Parse.Object.saveAll([obj1, obj2]).then(() => {
obj1.set("obj", obj2);
// Save the pointer, delete the pointee
return obj1.save().then(() => { return obj2.destroy() });
}).then(() => {
let query = new Parse.Query("AnObject");
const query = new Parse.Query("AnObject");
query.include("obj");
return query.find();
}).then((res) => {
@@ -1877,7 +1877,7 @@ describe('Parse.Object testing', () => {
if (res[0]) {
expect(res[0].get("obj")).toBe(undefined);
}
let query = new Parse.Query("AnObject");
const query = new Parse.Query("AnObject");
return query.find();
}).then((res) => {
expect(res.length).toBe(1);
@@ -1896,16 +1896,16 @@ describe('Parse.Object testing', () => {
});
it('should have undefined includes when object is missing on deeper path', (done) => {
let obj1 = new Parse.Object("AnObject");
let obj2 = new Parse.Object("AnObject");
let obj3 = new Parse.Object("AnObject");
const obj1 = new Parse.Object("AnObject");
const obj2 = new Parse.Object("AnObject");
const obj3 = new Parse.Object("AnObject");
Parse.Object.saveAll([obj1, obj2, obj3]).then(() => {
obj1.set("obj", obj2);
obj2.set("obj", obj3);
// Save the pointer, delete the pointee
return Parse.Object.saveAll([obj1, obj2]).then(() => { return obj3.destroy() });
}).then(() => {
let query = new Parse.Query("AnObject");
const query = new Parse.Query("AnObject");
query.include("obj.obj");
return query.get(obj1.id);
}).then((res) => {
@@ -1919,9 +1919,9 @@ describe('Parse.Object testing', () => {
});
it('should handle includes on null arrays #2752', (done) => {
let obj1 = new Parse.Object("AnObject");
let obj2 = new Parse.Object("AnotherObject");
let obj3 = new Parse.Object("NestedObject");
const obj1 = new Parse.Object("AnObject");
const obj2 = new Parse.Object("AnotherObject");
const obj3 = new Parse.Object("NestedObject");
obj3.set({
"foo": "bar"
})
@@ -1933,13 +1933,13 @@ describe('Parse.Object testing', () => {
obj1.set("objects", [null, null, obj2]);
return obj1.save();
}).then(() => {
let query = new Parse.Query("AnObject");
const query = new Parse.Query("AnObject");
query.include("objects.key");
return query.find();
}).then((res) => {
let obj = res[0];
const obj = res[0];
expect(obj.get("objects")).not.toBe(undefined);
let array = obj.get("objects");
const array = obj.get("objects");
expect(Array.isArray(array)).toBe(true);
expect(array[0]).toBe(null);
expect(array[1]).toBe(null);
@@ -1952,8 +1952,8 @@ describe('Parse.Object testing', () => {
});
it('should handle select and include #2786', (done) => {
let score = new Parse.Object("GameScore");
let player = new Parse.Object("Player");
const score = new Parse.Object("GameScore");
const player = new Parse.Object("Player");
score.set({
"score": 1234
});
@@ -1963,14 +1963,14 @@ describe('Parse.Object testing', () => {
player.set("other", "value");
return player.save();
}).then(() => {
let query = new Parse.Query("Player");
const query = new Parse.Query("Player");
query.include("gameScore");
query.select("gameScore");
return query.find();
}).then((res) => {
let obj = res[0];
let gameScore = obj.get("gameScore");
let other = obj.get("other");
const obj = res[0];
const gameScore = obj.get("gameScore");
const other = obj.get("other");
expect(other).toBeUndefined();
expect(gameScore).not.toBeUndefined();
expect(gameScore.get("score")).toBe(1234);
+2 -2
View File
@@ -59,7 +59,7 @@ describe('ParsePubSub', function() {
});
it('can create publisher/sub with custom adapter', function() {
let adapter = {
const adapter = {
createPublisher: jasmine.createSpy('createPublisher'),
createSubscriber: jasmine.createSpy('createSubscriber')
}
@@ -82,7 +82,7 @@ describe('ParsePubSub', function() {
});
it('can create publisher/sub with custom function adapter', function() {
let adapter = {
const adapter = {
createPublisher: jasmine.createSpy('createPublisher'),
createSubscriber: jasmine.createSpy('createSubscriber')
}
+122 -52
View File
@@ -114,7 +114,7 @@ describe('Parse.Query testing', () => {
// Only cake3 is liked only by user1
return query.find().then(function(results){
equal(results.length, 1);
let cake = results[0];
const cake = results[0];
expect(cake.id).toBe(cake3.id);
});
}).then(function(){
@@ -816,7 +816,7 @@ describe('Parse.Query testing', () => {
var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i });
};
Parse.Object.saveAll([3, 1, 2].map(makeBoxedNumber)).then( function() {
Parse.Object.saveAll([3, 1, 2].map(makeBoxedNumber)).then(function() {
var query = new Parse.Query(BoxedNumber);
query.descending("number");
query.find(expectSuccess({
@@ -864,7 +864,7 @@ describe('Parse.Query testing', () => {
return new BoxedNumber({ number: num, string: strings[i] });
};
let objects = [3, 1, 3, 2].map(makeBoxedNumber);
const objects = [3, 1, 3, 2].map(makeBoxedNumber);
Parse.Object.saveAll(objects)
.then(() => {
var query = new Parse.Query(BoxedNumber);
@@ -1566,26 +1566,26 @@ describe('Parse.Query testing', () => {
});
it('properly includes array', (done) => {
let objects = [];
const objects = [];
let total = 0;
while(objects.length != 5) {
let object = new Parse.Object('AnObject');
const object = new Parse.Object('AnObject');
object.set('key', objects.length);
total += objects.length;
objects.push(object);
}
Parse.Object.saveAll(objects).then(() => {
let object = new Parse.Object("AContainer");
const object = new Parse.Object("AContainer");
object.set('objects', objects);
return object.save();
}).then(() => {
let query = new Parse.Query('AContainer');
const query = new Parse.Query('AContainer');
query.include('objects');
return query.find()
}).then((results) => {
expect(results.length).toBe(1);
let res = results[0];
let objects = res.get('objects');
const res = results[0];
const objects = res.get('objects');
expect(objects.length).toBe(5);
objects.forEach((object) => {
total -= object.get('key');
@@ -1599,61 +1599,62 @@ describe('Parse.Query testing', () => {
});
it('properly includes array of mixed objects', (done) => {
let objects = [];
const objects = [];
let total = 0;
while(objects.length != 5) {
let object = new Parse.Object('AnObject');
const object = new Parse.Object('AnObject');
object.set('key', objects.length);
total += objects.length;
objects.push(object);
}
while(objects.length != 10) {
let object = new Parse.Object('AnotherObject');
const object = new Parse.Object('AnotherObject');
object.set('key', objects.length);
total += objects.length;
objects.push(object);
}
Parse.Object.saveAll(objects).then(() => {
let object = new Parse.Object("AContainer");
const object = new Parse.Object("AContainer");
object.set('objects', objects);
return object.save();
}).then(() => {
let query = new Parse.Query('AContainer');
const query = new Parse.Query('AContainer');
query.include('objects');
return query.find()
}).then((results) => {
expect(results.length).toBe(1);
let res = results[0];
let objects = res.get('objects');
const res = results[0];
const objects = res.get('objects');
expect(objects.length).toBe(10);
objects.forEach((object) => {
total -= object.get('key');
});
expect(total).toBe(0);
done()
}, () => {
}, (e) => {
fail('should not fail');
fail(JSON.stringify(e));
done();
})
});
it('properly nested array of mixed objects with bad ids', (done) => {
let objects = [];
const objects = [];
let total = 0;
while(objects.length != 5) {
let object = new Parse.Object('AnObject');
const object = new Parse.Object('AnObject');
object.set('key', objects.length);
objects.push(object);
}
while(objects.length != 10) {
let object = new Parse.Object('AnotherObject');
const object = new Parse.Object('AnotherObject');
object.set('key', objects.length);
objects.push(object);
}
Parse.Object.saveAll(objects).then(() => {
let object = new Parse.Object("AContainer");
for (var i=0; i<objects.length; i++) {
if (i%2 == 0) {
const object = new Parse.Object("AContainer");
for (var i = 0; i < objects.length; i++) {
if (i % 2 == 0) {
objects[i].id = 'randomThing'
} else {
total += objects[i].get('key');
@@ -1662,13 +1663,13 @@ describe('Parse.Query testing', () => {
object.set('objects', objects);
return object.save();
}).then(() => {
let query = new Parse.Query('AContainer');
const query = new Parse.Query('AContainer');
query.include('objects');
return query.find()
}).then((results) => {
expect(results.length).toBe(1);
let res = results[0];
let objects = res.get('objects');
const res = results[0];
const objects = res.get('objects');
expect(objects.length).toBe(5);
objects.forEach((object) => {
total -= object.get('key');
@@ -1683,25 +1684,25 @@ describe('Parse.Query testing', () => {
});
it('properly fetches nested pointers', (done) => {
let color = new Parse.Object('Color');
const color = new Parse.Object('Color');
color.set('hex','#133733');
let circle = new Parse.Object('Circle');
const circle = new Parse.Object('Circle');
circle.set('radius', 1337);
Parse.Object.saveAll([color, circle]).then(() => {
circle.set('color', color);
let badCircle = new Parse.Object('Circle');
const badCircle = new Parse.Object('Circle');
badCircle.id = 'badId';
let complexFigure = new Parse.Object('ComplexFigure');
const complexFigure = new Parse.Object('ComplexFigure');
complexFigure.set('consistsOf', [circle, badCircle]);
return complexFigure.save();
}).then(() => {
let q = new Parse.Query('ComplexFigure');
const q = new Parse.Query('ComplexFigure');
q.include('consistsOf.color');
return q.find()
}).then((results) => {
expect(results.length).toBe(1);
let figure = results[0];
const figure = results[0];
expect(figure.get('consistsOf').length).toBe(1);
expect(figure.get('consistsOf')[0].get('color').get('hex')).toBe('#133733');
done();
@@ -2357,15 +2358,15 @@ describe('Parse.Query testing', () => {
});
it('supports include on the wrong key type (#2262)', function(done) {
let childObject = new Parse.Object('TestChildObject');
const childObject = new Parse.Object('TestChildObject');
childObject.set('hello', 'world');
childObject.save().then(() => {
let obj = new Parse.Object('TestObject');
const obj = new Parse.Object('TestObject');
obj.set('foo', 'bar');
obj.set('child', childObject);
return obj.save();
}).then(() => {
let q = new Parse.Query('TestObject');
const q = new Parse.Query('TestObject');
q.include('child');
q.include('child.parent');
q.include('createdAt');
@@ -2401,7 +2402,7 @@ describe('Parse.Query testing', () => {
it('query match on array with multiple objects', (done) => {
var target1 = {__type: 'Pointer', className: 'TestObject', objectId: 'abc'};
var target2 = {__type: 'Pointer', className: 'TestObject', objectId: '123'};
var obj= new Parse.Object('TestObject');
var obj = new Parse.Object('TestObject');
obj.set('someObjs', [target1, target2]);
obj.save().then(() => {
var query = new Parse.Query('TestObject');
@@ -2435,7 +2436,7 @@ describe('Parse.Query testing', () => {
var user = new Parse.User();
user.set("username", "foo");
user.set("password", "bar");
return user.save().then( (user) => {
return user.save().then((user) => {
var objIdQuery = new Parse.Query("_User").equalTo("objectId", user.id);
var blockedUserQuery = user.relation("blockedUsers").query();
@@ -2467,6 +2468,35 @@ describe('Parse.Query testing', () => {
});
});
it("should match a key in an array (#3195)", function(done) {
var AuthorObject = Parse.Object.extend("Author");
var GroupObject = Parse.Object.extend("Group");
var PostObject = Parse.Object.extend("Post");
return new AuthorObject().save().then((user) => {
const post = new PostObject({
author: user
});
const group = new GroupObject({
members: [user],
});
return Parse.Promise.when(post.save(), group.save());
}).then((p) => {
return new Parse.Query(PostObject)
.matchesKeyInQuery("author", "members", new Parse.Query(GroupObject))
.find()
.then((r) => {
expect(r.length).toEqual(1);
if (r.length > 0) {
expect(r[0].id).toEqual(p.id);
}
done();
}, done.fail);
});
});
it('should find objects with array of pointers', (done) => {
var objects = [];
while(objects.length != 5) {
@@ -2485,13 +2515,13 @@ describe('Parse.Query testing', () => {
}
})
container.set('objects', pointers);
let container2 = new Parse.Object('Container');
const container2 = new Parse.Object('Container');
container2.set('objects', pointers.slice(2, 3));
return Parse.Object.saveAll([container, container2]);
}).then(() => {
let inQuery = new Parse.Query('ContainedObject');
const inQuery = new Parse.Query('ContainedObject');
inQuery.greaterThanOrEqualTo('index', 1);
let query = new Parse.Query('Container');
const query = new Parse.Query('Container');
query.matchesQuery('objects', inQuery);
return query.find();
}).then((results) => {
@@ -2507,16 +2537,16 @@ describe('Parse.Query testing', () => {
})
it('query with two OR subqueries (regression test #1259)', done => {
let relatedObject = new Parse.Object('Class2');
const relatedObject = new Parse.Object('Class2');
relatedObject.save().then(relatedObject => {
let anObject = new Parse.Object('Class1');
let relation = anObject.relation('relation');
const anObject = new Parse.Object('Class1');
const relation = anObject.relation('relation');
relation.add(relatedObject);
return anObject.save();
}).then(anObject => {
let q1 = anObject.relation('relation').query();
const q1 = anObject.relation('relation').query();
q1.doesNotExist('nonExistantKey1');
let q2 = anObject.relation('relation').query();
const q2 = anObject.relation('relation').query();
q2.doesNotExist('nonExistantKey2');
Parse.Query.or(q1, q2).find().then(results => {
expect(results.length).toEqual(1);
@@ -2529,14 +2559,14 @@ describe('Parse.Query testing', () => {
});
it('objectId containedIn with multiple large array', done => {
let obj = new Parse.Object('MyClass');
const obj = new Parse.Object('MyClass');
obj.save().then(obj => {
let longListOfStrings = [];
const longListOfStrings = [];
for (let i = 0; i < 130; i++) {
longListOfStrings.push(i.toString());
}
longListOfStrings.push(obj.id);
let q = new Parse.Query('MyClass');
const q = new Parse.Query('MyClass');
q.containedIn('objectId', longListOfStrings);
q.containedIn('objectId', longListOfStrings);
return q.find();
@@ -2655,6 +2685,46 @@ describe('Parse.Query testing', () => {
});
});
it('select nested keys 2 level without include (issue #3185)', function(done) {
var Foobar = new Parse.Object('Foobar');
var BarBaz = new Parse.Object('Barbaz');
var Bazoo = new Parse.Object('Bazoo');
Bazoo.set('some', 'thing');
Bazoo.set('otherSome', 'value');
Bazoo.save().then(() => {
BarBaz.set('key', 'value');
BarBaz.set('otherKey', 'value');
BarBaz.set('bazoo', Bazoo);
return BarBaz.save();
}).then(() => {
Foobar.set('foo', 'bar');
Foobar.set('fizz', 'buzz');
Foobar.set('barBaz', BarBaz);
return Foobar.save();
}).then(function(savedFoobar){
var foobarQuery = new Parse.Query('Foobar');
foobarQuery.select(['fizz', 'barBaz.key', 'barBaz.bazoo.some']);
return foobarQuery.get(savedFoobar.id);
}).then((foobarObj) => {
equal(foobarObj.get('fizz'), 'buzz');
equal(foobarObj.get('foo'), undefined);
if (foobarObj.has('barBaz')) {
equal(foobarObj.get('barBaz').get('key'), 'value');
equal(foobarObj.get('barBaz').get('otherKey'), undefined);
if (foobarObj.get('barBaz').has('bazoo')) {
equal(foobarObj.get('barBaz').get('bazoo').get('some'), 'thing');
equal(foobarObj.get('barBaz').get('bazoo').get('otherSome'), undefined);
} else {
fail('bazoo should be set');
}
} else {
fail('barBaz should be set');
}
done();
})
});
it('properly handles nested ors', function(done) {
var objects = [];
while(objects.length != 4) {
@@ -2663,13 +2733,13 @@ describe('Parse.Query testing', () => {
objects.push(obj)
}
Parse.Object.saveAll(objects).then(() => {
let q0 = new Parse.Query('Object');
const q0 = new Parse.Query('Object');
q0.equalTo('x', 0);
let q1 = new Parse.Query('Object');
const q1 = new Parse.Query('Object');
q1.equalTo('x', 1);
let q2 = new Parse.Query('Object');
const q2 = new Parse.Query('Object');
q2.equalTo('x', 2);
let or01 = Parse.Query.or(q0,q1);
const or01 = Parse.Query.or(q0,q1);
return Parse.Query.or(or01, q2).find();
}).then((results) => {
expect(results.length).toBe(3);
+56 -47
View File
@@ -249,35 +249,35 @@ describe('Parse.Relation testing', () => {
});
it("queries on relation fields with multiple containedIn (regression test for #1271)", (done) => {
let ChildObject = Parse.Object.extend("ChildObject");
let childObjects = [];
const ChildObject = Parse.Object.extend("ChildObject");
const childObjects = [];
for (let i = 0; i < 10; i++) {
childObjects.push(new ChildObject({x: i}));
}
Parse.Object.saveAll(childObjects).then(() => {
let ParentObject = Parse.Object.extend("ParentObject");
let parent = new ParentObject();
const ParentObject = Parse.Object.extend("ParentObject");
const parent = new ParentObject();
parent.set("x", 4);
let parent1Children = parent.relation("child");
const parent1Children = parent.relation("child");
parent1Children.add(childObjects[0]);
parent1Children.add(childObjects[1]);
parent1Children.add(childObjects[2]);
let parent2 = new ParentObject();
const parent2 = new ParentObject();
parent2.set("x", 3);
let parent2Children = parent2.relation("child");
const parent2Children = parent2.relation("child");
parent2Children.add(childObjects[4]);
parent2Children.add(childObjects[5]);
parent2Children.add(childObjects[6]);
let parent2OtherChildren = parent2.relation("otherChild");
const parent2OtherChildren = parent2.relation("otherChild");
parent2OtherChildren.add(childObjects[0]);
parent2OtherChildren.add(childObjects[1]);
parent2OtherChildren.add(childObjects[2]);
return Parse.Object.saveAll([parent, parent2]);
}).then(() => {
let objectsWithChild0InBothChildren = new Parse.Query(ParentObject);
const objectsWithChild0InBothChildren = new Parse.Query(ParentObject);
objectsWithChild0InBothChildren.containedIn("child", [childObjects[0]]);
objectsWithChild0InBothChildren.containedIn("otherChild", [childObjects[0]]);
return objectsWithChild0InBothChildren.find();
@@ -285,7 +285,7 @@ describe('Parse.Relation testing', () => {
//No parent has child 0 in both it's "child" and "otherChild" field;
expect(objectsWithChild0InBothChildren.length).toEqual(0);
}).then(() => {
let objectsWithChild4andOtherChild1 = new Parse.Query(ParentObject);
const objectsWithChild4andOtherChild1 = new Parse.Query(ParentObject);
objectsWithChild4andOtherChild1.containedIn("child", [childObjects[4]]);
objectsWithChild4andOtherChild1.containedIn("otherChild", [childObjects[1]]);
return objectsWithChild4andOtherChild1.find();
@@ -510,24 +510,24 @@ describe('Parse.Relation testing', () => {
});
it('should properly get related objects with unfetched queries', (done) => {
let objects = [];
let owners = [];
let allObjects = [];
const objects = [];
const owners = [];
const allObjects = [];
// Build 10 Objects and 10 owners
while (objects.length != 10) {
let object = new Parse.Object('AnObject');
const object = new Parse.Object('AnObject');
object.set({
index: objects.length,
even: objects.length % 2 == 0
});
objects.push(object);
let owner = new Parse.Object('AnOwner');
const owner = new Parse.Object('AnOwner');
owners.push(owner);
allObjects.push(object);
allObjects.push(owner);
}
let anotherOwner = new Parse.Object('AnotherOwner');
const anotherOwner = new Parse.Object('AnotherOwner');
return Parse.Object.saveAll(allObjects.concat([anotherOwner])).then(() => {
// put all the AnObject into the anotherOwner relationKey
@@ -539,13 +539,13 @@ describe('Parse.Relation testing', () => {
return Parse.Object.saveAll(owners.concat([anotherOwner]));
}).then(() => {
// Query on the relation of another owner
let object = new Parse.Object('AnotherOwner');
const object = new Parse.Object('AnotherOwner');
object.id = anotherOwner.id;
let relationQuery = object.relation('relationKey').query();
const relationQuery = object.relation('relationKey').query();
// Just get the even ones
relationQuery.equalTo('even', true);
// Make the query on anOwner
let query = new Parse.Query('AnOwner');
const query = new Parse.Query('AnOwner');
// where key match the relation query.
query.matchesQuery('key', relationQuery);
query.include('key');
@@ -558,13 +558,13 @@ describe('Parse.Relation testing', () => {
return Promise.resolve();
}).then(() => {
// Query on the relation of another owner
let object = new Parse.Object('AnotherOwner');
const object = new Parse.Object('AnotherOwner');
object.id = anotherOwner.id;
let relationQuery = object.relation('relationKey').query();
const relationQuery = object.relation('relationKey').query();
// Just get the even ones
relationQuery.equalTo('even', true);
// Make the query on anOwner
let query = new Parse.Query('AnOwner');
const query = new Parse.Query('AnOwner');
// where key match the relation query.
query.doesNotMatchQuery('key', relationQuery);
query.include('key');
@@ -575,6 +575,9 @@ describe('Parse.Relation testing', () => {
expect(result.get('key').get('even')).toBe(false);
});
done();
}, (e) => {
fail(JSON.stringify(e));
done();
})
});
@@ -586,19 +589,19 @@ describe('Parse.Relation testing', () => {
new RestaurantObject({ ratings: 5, location: "Djibouti" }),
new RestaurantObject({ ratings: 3, location: "Ouagadougou" }),
];
let persons = [
const persons = [
new PersonObject({ name: "Bob", hometown: "Djibouti" }),
new PersonObject({ name: "Tom", hometown: "Ouagadougou" }),
new PersonObject({ name: "Billy", hometown: "Detroit" }),
];
let owner = new OwnerObject({name: 'Joe'});
let allObjects = [owner].concat(restaurants).concat(persons);
const owner = new OwnerObject({name: 'Joe'});
const allObjects = [owner].concat(restaurants).concat(persons);
expect(allObjects.length).toEqual(6);
Parse.Object.saveAll([owner].concat(restaurants).concat(persons)).then(function() {
owner.relation('restaurants').add(restaurants);
return owner.save()
}).then(() => {
let unfetchedOwner = new OwnerObject();
const unfetchedOwner = new OwnerObject();
unfetchedOwner.id = owner.id;
var query = unfetchedOwner.relation('restaurants').query();
query.greaterThan("ratings", 4);
@@ -613,6 +616,9 @@ describe('Parse.Relation testing', () => {
done();
}
}));
}, (e) => {
fail(JSON.stringify(e));
done();
});
});
@@ -624,19 +630,19 @@ describe('Parse.Relation testing', () => {
new RestaurantObject({ ratings: 5, location: "Djibouti" }),
new RestaurantObject({ ratings: 3, location: "Ouagadougou" }),
];
let persons = [
const persons = [
new PersonObject({ name: "Bob", hometown: "Djibouti" }),
new PersonObject({ name: "Tom", hometown: "Ouagadougou" }),
new PersonObject({ name: "Billy", hometown: "Detroit" }),
];
let owner = new OwnerObject({name: 'Joe'});
let allObjects = [owner].concat(restaurants).concat(persons);
const owner = new OwnerObject({name: 'Joe'});
const allObjects = [owner].concat(restaurants).concat(persons);
expect(allObjects.length).toEqual(6);
Parse.Object.saveAll([owner].concat(restaurants).concat(persons)).then(function() {
owner.relation('restaurants').add(restaurants);
return owner.save()
}).then(() => {
let unfetchedOwner = new OwnerObject();
const unfetchedOwner = new OwnerObject();
unfetchedOwner.id = owner.id;
var query = unfetchedOwner.relation('restaurants').query();
query.greaterThan("ratings", 4);
@@ -653,25 +659,28 @@ describe('Parse.Relation testing', () => {
done();
}
}));
}, (e) => {
fail(JSON.stringify(e));
done();
});
});
it('relations are not bidirectional (regression test for #871)', done => {
let PersonObject = Parse.Object.extend("Person");
let p1 = new PersonObject();
let p2 = new PersonObject();
const PersonObject = Parse.Object.extend("Person");
const p1 = new PersonObject();
const p2 = new PersonObject();
Parse.Object.saveAll([p1, p2]).then(results => {
let p1 = results[0];
let p2 = results[1];
let relation = p1.relation('relation');
const p1 = results[0];
const p2 = results[1];
const relation = p1.relation('relation');
relation.add(p2);
p1.save().then(() => {
let query = new Parse.Query(PersonObject);
const query = new Parse.Query(PersonObject);
query.equalTo('relation', p1);
query.find().then(results => {
expect(results.length).toEqual(0);
let query = new Parse.Query(PersonObject);
const query = new Parse.Query(PersonObject);
query.equalTo('relation', p2);
query.find().then(results => {
expect(results.length).toEqual(1);
@@ -685,12 +694,12 @@ describe('Parse.Relation testing', () => {
it('can query roles in Cloud Code (regession test #1489)', done => {
Parse.Cloud.define('isAdmin', (request, response) => {
let query = new Parse.Query(Parse.Role);
const query = new Parse.Query(Parse.Role);
query.equalTo('name', 'admin');
query.first({ useMasterKey: true })
.then(role => {
let relation = new Parse.Relation(role, 'users');
let admins = relation.query();
const relation = new Parse.Relation(role, 'users');
const admins = relation.query();
admins.equalTo('username', request.user.get('username'));
admins.first({ useMasterKey: true })
.then(user => {
@@ -712,16 +721,16 @@ describe('Parse.Relation testing', () => {
});
});
let adminUser = new Parse.User();
const adminUser = new Parse.User();
adminUser.set('username', 'name');
adminUser.set('password', 'pass');
adminUser.signUp()
.then(adminUser => {
let adminACL = new Parse.ACL();
const adminACL = new Parse.ACL();
adminACL.setPublicReadAccess(true);
// Create admin role
let adminRole = new Parse.Role('admin', adminACL);
const adminRole = new Parse.Role('admin', adminACL);
adminRole.getUsers().add(adminUser);
adminRole.save()
.then(() => {
@@ -739,13 +748,13 @@ describe('Parse.Relation testing', () => {
});
it('can be saved without error', done => {
let obj1 = new Parse.Object('PPAP');
const obj1 = new Parse.Object('PPAP');
obj1.save()
.then(() => {
let newRelation = obj1.relation('aRelation');
const newRelation = obj1.relation('aRelation');
newRelation.add(obj1);
obj1.save().then(() => {
let relation = obj1.get('aRelation');
const relation = obj1.get('aRelation');
obj1.set('aRelation', relation);
obj1.save().then(() => {
done();
+85 -22
View File
@@ -13,7 +13,7 @@ describe('Parse Role testing', () => {
createTestUser().then((x) => {
user = x;
let acl = new Parse.ACL();
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(false);
role = new Parse.Object('_Role');
@@ -98,10 +98,10 @@ describe('Parse Role testing', () => {
var user,
auth,
getAllRolesSpy;
createTestUser().then( (newUser) => {
createTestUser().then((newUser) => {
user = newUser;
return createAllRoles(user);
}).then ( (roles) => {
}).then ((roles) => {
var rootRoleObj = roleObjs[rootRole];
roles.forEach(function(role, i) {
// Add all roles to the RootRole
@@ -115,16 +115,16 @@ describe('Parse Role testing', () => {
});
return Parse.Object.saveAll(roles, { useMasterKey: true });
}).then( () => {
}).then(() => {
auth = new Auth({config: new Config("test"), isMaster: true, user: user});
getAllRolesSpy = spyOn(auth, "_getAllRolesNamesForRoleIds").and.callThrough();
return auth._loadRoles();
}).then ( (roles) => {
}).then ((roles) => {
expect(roles.length).toEqual(4);
allRoles.forEach(function(name) {
expect(roles.indexOf("role:"+name)).not.toBe(-1);
expect(roles.indexOf("role:" + name)).not.toBe(-1);
});
// 1 Query for the initial setup
@@ -135,7 +135,7 @@ describe('Parse Role testing', () => {
// 1 call for the 2nd layer
expect(getAllRolesSpy.calls.count()).toEqual(2);
done()
}).catch( () => {
}).catch(() => {
fail("should succeed");
done();
});
@@ -145,27 +145,27 @@ describe('Parse Role testing', () => {
it("should recursively load roles", (done) => {
var rolesNames = ["FooRole", "BarRole", "BazRole"];
var roleIds = {};
createTestUser().then( (user) => {
createTestUser().then((user) => {
// Put the user on the 1st role
return createRole(rolesNames[0], null, user).then( (aRole) => {
return createRole(rolesNames[0], null, user).then((aRole) => {
roleIds[aRole.get("name")] = aRole.id;
// set the 1st role as a sibling of the second
// user will should have 2 role now
return createRole(rolesNames[1], aRole, null);
}).then( (anotherRole) => {
}).then((anotherRole) => {
roleIds[anotherRole.get("name")] = anotherRole.id;
// set this role as a sibling of the last
// the user should now have 3 roles
return createRole(rolesNames[2], anotherRole, null);
}).then( (lastRole) => {
}).then((lastRole) => {
roleIds[lastRole.get("name")] = lastRole.id;
var auth = new Auth({ config: new Config("test"), isMaster: true, user: user });
return auth._loadRoles();
})
}).then( (roles) => {
}).then((roles) => {
expect(roles.length).toEqual(3);
rolesNames.forEach( (name) => {
expect(roles.indexOf('role:'+name)).not.toBe(-1);
rolesNames.forEach((name) => {
expect(roles.indexOf('role:' + name)).not.toBe(-1);
});
done();
}, function(){
@@ -193,11 +193,11 @@ describe('Parse Role testing', () => {
});
it("Should properly resolve roles", (done) => {
let admin = new Parse.Role("Admin", new Parse.ACL());
let moderator = new Parse.Role("Moderator", new Parse.ACL());
let superModerator = new Parse.Role("SuperModerator", new Parse.ACL());
let contentManager = new Parse.Role('ContentManager', new Parse.ACL());
let superContentManager = new Parse.Role('SuperContentManager', new Parse.ACL());
const admin = new Parse.Role("Admin", new Parse.ACL());
const moderator = new Parse.Role("Moderator", new Parse.ACL());
const superModerator = new Parse.Role("SuperModerator", new Parse.ACL());
const contentManager = new Parse.Role('ContentManager', new Parse.ACL());
const superContentManager = new Parse.Role('SuperContentManager', new Parse.ACL());
Parse.Object.saveAll([admin, moderator, contentManager, superModerator, superContentManager], {useMasterKey: true}).then(() => {
contentManager.getRoles().add([moderator, superContentManager]);
moderator.getRoles().add([admin, superModerator]);
@@ -207,7 +207,7 @@ describe('Parse Role testing', () => {
var auth = new Auth({ config: new Config("test"), isMaster: true });
// For each role, fetch their sibling, what they inherit
// return with result and roleId for later comparison
let promises = [admin, moderator, contentManager, superModerator].map((role) => {
const promises = [admin, moderator, contentManager, superModerator].map((role) => {
return auth._getAllRolesNamesForRoleIds([role.id]).then((result) => {
return Parse.Promise.as({
id: role.id,
@@ -220,8 +220,8 @@ describe('Parse Role testing', () => {
return Parse.Promise.when(promises);
}).then((results) => {
results.forEach((result) => {
let id = result.id;
let roleNames = result.roleNames;
const id = result.id;
const roleNames = result.roleNames;
if (id == admin.id) {
expect(roleNames.length).toBe(2);
expect(roleNames.indexOf("Moderator")).not.toBe(-1);
@@ -347,4 +347,67 @@ describe('Parse Role testing', () => {
})
});
it('should add multiple users to a role and remove users', (done) => {
var user, user2, user3;
var role;
var obj;
var prACL = new Parse.ACL();
prACL.setPublicReadAccess(true);
prACL.setPublicWriteAccess(true);
createTestUser().then((x) => {
user = x;
user2 = new Parse.User();
return user2.save({ username: 'user2', password: 'omgbbq' });
}).then(() => {
user3 = new Parse.User();
return user3.save({ username: 'user3', password: 'omgbbq' });
}).then(() => {
role = new Parse.Role('sharedRole', prACL);
var users = role.relation('users');
users.add(user);
users.add(user2);
users.add(user3);
return role.save({}, { useMasterKey: true });
}).then(() => {
// query for saved role and get 3 users
var query = new Parse.Query('_Role');
query.equalTo('name', 'sharedRole');
return query.find({ useMasterKey: true });
}).then((role) => {
expect(role.length).toEqual(1);
var users = role[0].relation('users').query();
return users.find({ useMasterKey: true });
}).then((users) => {
expect(users.length).toEqual(3);
obj = new Parse.Object('TestObjectRoles');
obj.set('ACL', prACL);
return obj.save(null, { useMasterKey: true });
}).then(() => {
// Above, the Admin role was added to the Customer role.
// An object secured by the Customer ACL should be able to be edited by the Admin user.
obj.set('changedByUsers', true);
return obj.save(null, { sessionToken: user.getSessionToken() });
}).then(() => {
// query for saved role and get 3 users
var query = new Parse.Query('_Role');
query.equalTo('name', 'sharedRole');
return query.find({ useMasterKey: true });
}).then((role) => {
expect(role.length).toEqual(1);
var users = role[0].relation('users');
users.remove(user);
users.remove(user3);
return role[0].save({}, { useMasterKey: true });
}).then((role) =>{
var users = role.relation('users').query();
return users.find({ useMasterKey: true });
}).then((users) => {
expect(users.length).toEqual(1);
expect(users[0].get('username')).toEqual('user2');
done();
});
});
});
+20 -4
View File
@@ -73,7 +73,7 @@ describe('ParseServerRESTController', () => {
let userId;
Parse.User.signUp('user', 'pass').then((user) => {
userId = user.id;
let sessionToken = user.getSessionToken();
const sessionToken = user.getSessionToken();
return RESTController.request("GET", "/users/me", undefined, {sessionToken});
}).then((res) => {
// Result is in JSON format
@@ -104,8 +104,9 @@ describe('ParseServerRESTController', () => {
});
it('ensures no session token is created on creating users', (done) => {
RESTController.request("POST", "/classes/_User", {username: "hello", password: "world"}).then(() => {
let query = new Parse.Query('_Session');
RESTController.request("POST", "/classes/_User", {username: "hello", password: "world"}).then((user) => {
expect(user.sessionToken).toBeUndefined();
const query = new Parse.Query('_Session');
return query.find({useMasterKey: true});
}).then(sessions => {
expect(sessions.length).toBe(0);
@@ -115,4 +116,19 @@ describe('ParseServerRESTController', () => {
done();
});
});
});
it('ensures a session token is created when passing installationId != cloud', (done) => {
RESTController.request("POST", "/classes/_User", {username: "hello", password: "world"}, {installationId: 'my-installation'}).then((user) => {
expect(user.sessionToken).not.toBeUndefined();
const query = new Parse.Query('_Session');
return query.find({useMasterKey: true});
}).then(sessions => {
expect(sessions.length).toBe(1);
expect(sessions[0].get('installationId')).toBe('my-installation');
done();
}, (err) => {
jfail(err);
done();
});
});
});
+35 -35
View File
@@ -141,8 +141,8 @@ describe('Parse.User testing', () => {
});
it('should respect ACL without locking user out', (done) => {
let user = new Parse.User();
let ACL = new Parse.ACL();
const user = new Parse.User();
const ACL = new Parse.ACL();
ACL.setPublicReadAccess(false);
ACL.setPublicWriteAccess(false);
user.setUsername('asdf');
@@ -163,7 +163,7 @@ describe('Parse.User testing', () => {
expect(perms[user.id].write).toBe(true);
expect(perms['*']).toBeUndefined();
// Try to lock out user
let newACL = new Parse.ACL();
const newACL = new Parse.ACL();
newACL.setReadAccess(user.id, false);
newACL.setWriteAccess(user.id, false);
user.setACL(newACL);
@@ -190,13 +190,13 @@ describe('Parse.User testing', () => {
});
it("user login with files", (done) => {
let file = new Parse.File("yolo.txt", [1,2,3], "text/plain");
const file = new Parse.File("yolo.txt", [1,2,3], "text/plain");
file.save().then((file) => {
return Parse.User.signUp("asdf", "zxcv", { "file" : file });
}).then(() => {
return Parse.User.logIn("asdf", "zxcv");
}).then((user) => {
let fileAgain = user.get('file');
const fileAgain = user.get('file');
ok(fileAgain.name());
ok(fileAgain.url());
done();
@@ -1153,11 +1153,11 @@ describe('Parse.User testing', () => {
it('returns authData when authed and logged in with provider (regression test for #1498)', done => {
Parse.Object.enableSingleInstance();
let provider = getMockFacebookProvider();
const provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith('facebook', {
success: user => {
let userQuery = new Parse.Query(Parse.User);
const userQuery = new Parse.Query(Parse.User);
userQuery.get(user.id)
.then(user => {
expect(user.get('authData')).not.toBeUndefined();
@@ -1169,18 +1169,18 @@ describe('Parse.User testing', () => {
});
it('log in with provider with files', done => {
let provider = getMockFacebookProvider();
const provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider);
let file = new Parse.File("yolo.txt", [1, 2, 3], "text/plain");
const file = new Parse.File("yolo.txt", [1, 2, 3], "text/plain");
file.save().then(file => {
let user = new Parse.User();
const user = new Parse.User();
user.set('file', file);
return user._linkWith('facebook', {});
}).then(user => {
expect(user._isLinked("facebook")).toBeTruthy();
return Parse.User._logInWith('facebook', {});
}).then(user => {
let fileAgain = user.get('file');
const fileAgain = user.get('file');
expect(fileAgain.name()).toMatch(/yolo.txt$/);
expect(fileAgain.url()).toMatch(/yolo.txt$/);
}).then(() => {
@@ -1535,7 +1535,7 @@ describe('Parse.User testing', () => {
strictEqual(provider.authData.expiration_date, provider.synchronizedExpiration);
ok(model._isLinked("facebook"), "User should be linked to facebook");
Parse.User._registerAuthenticationProvider(mockProvider);
let objectId = model.id;
const objectId = model.id;
model._linkWith("myoauth", {
success: function(model) {
expect(model.id).toEqual(objectId);
@@ -1571,7 +1571,7 @@ describe('Parse.User testing', () => {
Parse.User._logInWith("facebook", {
success: function(model) {
Parse.User._registerAuthenticationProvider(mockProvider);
let objectId = model.id;
const objectId = model.id;
model._linkWith("myoauth", {
success: function() {
Parse.User._registerAuthenticationProvider(secondProvider);
@@ -1612,7 +1612,7 @@ describe('Parse.User testing', () => {
strictEqual(provider.authData.expiration_date, provider.synchronizedExpiration);
ok(model._isLinked("facebook"), "User should be linked to facebook");
Parse.User._registerAuthenticationProvider(mockProvider);
let objectId = model.id;
const objectId = model.id;
model._linkWith("myoauth", {
success: function(model) {
expect(model.id).toEqual(objectId);
@@ -1650,7 +1650,7 @@ describe('Parse.User testing', () => {
Parse.User._logInWith("facebook", {
success: function() {
Parse.User.logOut().then(() => {
let user = new Parse.User();
const user = new Parse.User();
user.setUsername('user');
user.setPassword('password');
return user.signUp().then(() => {
@@ -1675,10 +1675,10 @@ describe('Parse.User testing', () => {
Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("facebook", {
success: function(model) {
let userId = model.id;
const userId = model.id;
Parse.User.logOut().then(() => {
request.post({
url:Parse.serverURL+'/classes/_User',
url:Parse.serverURL + '/classes/_User',
headers: {
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-REST-API-Key': 'rest'
@@ -1688,7 +1688,7 @@ describe('Parse.User testing', () => {
// make sure the location header is properly set
expect(userId).not.toBeUndefined();
expect(body.objectId).toEqual(userId);
expect(res.headers.location).toEqual(Parse.serverURL+'/users/'+userId);
expect(res.headers.location).toEqual(Parse.serverURL + '/users/' + userId);
done();
});
});
@@ -1722,7 +1722,7 @@ describe('Parse.User testing', () => {
it('should have authData in beforeSave and afterSave', (done) => {
Parse.Cloud.beforeSave('_User', (request, response) => {
let authData = request.object.get('authData');
const authData = request.object.get('authData');
expect(authData).not.toBeUndefined();
if (authData) {
expect(authData.facebook.id).toEqual('8675309');
@@ -1734,7 +1734,7 @@ describe('Parse.User testing', () => {
});
Parse.Cloud.afterSave('_User', (request, response) => {
let authData = request.object.get('authData');
const authData = request.object.get('authData');
expect(authData).not.toBeUndefined();
if (authData) {
expect(authData.facebook.id).toEqual('8675309');
@@ -2326,7 +2326,7 @@ describe('Parse.User testing', () => {
});
it_exclude_dbs(['postgres'])('should cleanup null authData keys (regression test for #935)', (done) => {
let database = new Config(Parse.applicationId).database;
const database = new Config(Parse.applicationId).database;
database.create('_User', {
username: 'user',
_hashed_password: '$2a$10$8/wZJyEuiEaobBBqzTG.jeY.XSFJd0rzaN//ososvEI4yLqI.4aie',
@@ -2349,7 +2349,7 @@ describe('Parse.User testing', () => {
})
})
}).then((user) => {
let authData = user.authData;
const authData = user.authData;
expect(user.username).toEqual('user');
expect(authData).toBeUndefined();
done();
@@ -2360,7 +2360,7 @@ describe('Parse.User testing', () => {
});
it_exclude_dbs(['postgres'])('should not serve null authData keys', (done) => {
let database = new Config(Parse.applicationId).database;
const database = new Config(Parse.applicationId).database;
database.create('_User', {
username: 'user',
_hashed_password: '$2a$10$8/wZJyEuiEaobBBqzTG.jeY.XSFJd0rzaN//ososvEI4yLqI.4aie',
@@ -2370,7 +2370,7 @@ describe('Parse.User testing', () => {
.equalTo('username', 'user')
.first({useMasterKey: true});
}).then((user) => {
let authData = user.get('authData');
const authData = user.get('authData');
expect(user.get('username')).toEqual('user');
expect(authData).toBeUndefined();
done();
@@ -2385,7 +2385,7 @@ describe('Parse.User testing', () => {
req.object.set('foo', 'bar');
res.success();
});
let originalSessionToken;
let originalUserId;
// Simulate anonymous user save
@@ -2463,7 +2463,7 @@ describe('Parse.User testing', () => {
});
it('should send email when upgrading from anon', (done) => {
let emailCalled = false;
let emailOptions;
var emailAdapter = {
@@ -2570,7 +2570,7 @@ describe('Parse.User testing', () => {
expect(req.object.get('username')).toEqual('User');
res.success();
});
let user = new Parse.User()
const user = new Parse.User()
user.setUsername('User');
user.setPassword('pass');
user.signUp().then(()=> {
@@ -2587,7 +2587,7 @@ describe('Parse.User testing', () => {
expect(req.user.get('han')).toEqual('solo');
res.success({});
});
let user = new Parse.User();
const user = new Parse.User();
user.setUsername('harrison');
user.setPassword('ford');
user.signUp().then(() => {
@@ -2645,19 +2645,19 @@ describe('Parse.User testing', () => {
});
it('should not create extraneous session tokens', (done) => {
let config = new Config(Parse.applicationId);
const config = new Config(Parse.applicationId);
config.database.loadSchema().then((s) => {
// Lock down the _User class for creation
return s.addClassIfNotExists('_User', {}, {create: {}})
}).then(() => {
let user = new Parse.User();
const user = new Parse.User();
return user.save({'username': 'user', 'password': 'pass'});
}).then(() => {
fail('should not be able to save the user');
}, () => {
return Promise.resolve();
}).then(() => {
let q = new Parse.Query('_Session');
const q = new Parse.Query('_Session');
return q.find({useMasterKey: true})
}).then((res) => {
// We should have no session created
@@ -2713,7 +2713,7 @@ describe('Parse.User testing', () => {
}, (err, res, body) => {
Parse.User.become(body.sessionToken)
.then(user => {
let obj = new Parse.Object('TestObject');
const obj = new Parse.Object('TestObject');
obj.setACL(new Parse.ACL(user));
return obj.save()
.then(() => {
@@ -2751,7 +2751,7 @@ describe('Parse.User testing', () => {
}, (err, res, body) => {
Parse.User.become(body.sessionToken)
.then(user => {
let obj = new Parse.Object('TestObject');
const obj = new Parse.Object('TestObject');
obj.setACL(new Parse.ACL(user));
return obj.save()
.then(() => {
@@ -2768,8 +2768,8 @@ describe('Parse.User testing', () => {
});
});
it('should not fail querying non existing relations', done => {
let user = new Parse.User();
it('should not fail querying non existing relations', done => {
const user = new Parse.User();
user.set({
username: 'hello',
password: 'world'
+4 -1
View File
@@ -14,7 +14,9 @@ describe('ParseWebSocketServer', function() {
it('can handle connect event when ws is open', function(done) {
var onConnectCallback = jasmine.createSpy('onConnectCallback');
var parseWebSocketServer = new ParseWebSocketServer({}, onConnectCallback, 5).server;
var http = require('http');
var server = http.createServer();
var parseWebSocketServer = new ParseWebSocketServer(server, onConnectCallback, 5).server;
var ws = {
readyState: 0,
OPEN: 0,
@@ -27,6 +29,7 @@ describe('ParseWebSocketServer', function() {
// Make sure we ping to the client
setTimeout(function() {
expect(ws.ping).toHaveBeenCalled();
server.close();
done();
}, 10)
});
+301 -7
View File
@@ -147,14 +147,14 @@ describe("Password Policy: ", () => {
reconfigureServer({
appName: 'passwordPolicy',
passwordPolicy: {
validatorPattern: "abc" // string is not a valid setting
validatorPattern: 1234 // number is not a valid setting
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
fail('passwordPolicy.validatorPattern type test failed');
done();
}).catch(err => {
expect(err).toEqual('passwordPolicy.validatorPattern must be a RegExp.');
expect(err).toEqual('passwordPolicy.validatorPattern must be a regex string or RegExp object.');
done();
});
});
@@ -197,6 +197,28 @@ describe("Password Policy: ", () => {
})
});
it('signup should fail if password does not conform to the policy enforced using validatorPattern string', (done) => {
const user = new Parse.User();
reconfigureServer({
appName: 'passwordPolicy',
passwordPolicy: {
validatorPattern: "^.{8,}" // password should contain at least 8 char
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
user.setUsername("user1");
user.setPassword("less");
user.set('email', 'user1@parse.com');
user.signUp().then(() => {
fail('Should have failed as password does not conform to the policy.');
done();
}).catch((error) => {
expect(error.code).toEqual(142);
done();
});
})
});
it('signup should succeed if password conforms to the policy enforced using validatorPattern', (done) => {
const user = new Parse.User();
reconfigureServer({
@@ -231,6 +253,40 @@ describe("Password Policy: ", () => {
})
});
it('signup should succeed if password conforms to the policy enforced using validatorPattern string', (done) => {
const user = new Parse.User();
reconfigureServer({
appName: 'passwordPolicy',
passwordPolicy: {
validatorPattern: "[!@#$]+" // password should contain at least one special char
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
user.setUsername("user1");
user.setPassword("p@sswrod");
user.set('email', 'user1@parse.com');
user.signUp().then(() => {
Parse.User.logOut().then(() => {
Parse.User.logIn("user1", "p@sswrod").then(function () {
done();
}).catch((err) => {
jfail(err);
fail("Should be able to login");
done();
});
}).catch((error) => {
jfail(error);
fail('logout should have succeeded');
done();
});
}).catch((error) => {
jfail(error);
fail('Signup should have succeeded as password conforms to the policy.');
done();
});
})
});
it('signup should fail if password does not conform to the policy enforced using validatorCallback', (done) => {
const user = new Parse.User();
reconfigureServer({
@@ -409,12 +465,12 @@ describe("Password Policy: ", () => {
fail("should login with new password");
done();
});
}).catch((error)=> {
}).catch((error) => {
jfail(error);
fail("Failed to POST request password reset");
done();
});
}).catch((error)=> {
}).catch((error) => {
jfail(error);
fail("Failed to get the reset link");
done();
@@ -839,7 +895,7 @@ describe("Password Policy: ", () => {
reconfigureServer({
appName: 'passwordPolicy',
passwordPolicy: {
maxPasswordAge: 0.5/(24*60*60) // 0.5 sec
maxPasswordAge: 0.5 / (24 * 60 * 60) // 0.5 sec
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
@@ -880,7 +936,7 @@ describe("Password Policy: ", () => {
reconfigureServer({
appName: 'passwordPolicy',
passwordPolicy: {
maxPasswordAge: 0.5/(24*60*60) // 0.5 sec
maxPasswordAge: 0.5 / (24 * 60 * 60) // 0.5 sec
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
@@ -979,7 +1035,7 @@ describe("Password Policy: ", () => {
appName: 'passwordPolicy',
emailAdapter: emailAdapter,
passwordPolicy: {
maxPasswordAge: 0.5/(24*60*60) // 0.5 sec
maxPasswordAge: 0.5 / (24 * 60 * 60) // 0.5 sec
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
@@ -1010,4 +1066,242 @@ describe("Password Policy: ", () => {
});
});
it('should fail if passwordPolicy.maxPasswordHistory is not a number', done => {
reconfigureServer({
appName: 'passwordPolicy',
passwordPolicy: {
maxPasswordHistory: "not a number"
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
fail('passwordPolicy.maxPasswordHistory "not a number" test failed');
done();
}).catch(err => {
expect(err).toEqual('passwordPolicy.maxPasswordHistory must be an integer ranging 0 - 20');
done();
});
});
it('should fail if passwordPolicy.maxPasswordHistory is a negative number', done => {
reconfigureServer({
appName: 'passwordPolicy',
passwordPolicy: {
maxPasswordHistory: -10
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
fail('passwordPolicy.maxPasswordHistory negative number test failed');
done();
}).catch(err => {
expect(err).toEqual('passwordPolicy.maxPasswordHistory must be an integer ranging 0 - 20');
done();
});
});
it('should fail if passwordPolicy.maxPasswordHistory is greater than 20', done => {
reconfigureServer({
appName: 'passwordPolicy',
passwordPolicy: {
maxPasswordHistory: 21
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
fail('passwordPolicy.maxPasswordHistory negative number test failed');
done();
}).catch(err => {
expect(err).toEqual('passwordPolicy.maxPasswordHistory must be an integer ranging 0 - 20');
done();
});
});
it('should fail to reset if the new password is same as the last password', done => {
const user = new Parse.User();
const emailAdapter = {
sendVerificationEmail: () => Promise.resolve(),
sendPasswordResetEmail: options => {
requestp.get({
uri: options.link,
followRedirect: false,
simple: false,
resolveWithFullResponse: true
}).then(response => {
expect(response.statusCode).toEqual(302);
const re = /http:\/\/localhost:8378\/1\/apps\/choose_password\?token=([a-zA-Z0-9]+)\&id=test\&username=user1/;
const match = response.body.match(re);
if (!match) {
fail("should have a token");
return Promise.reject("Invalid password link");
}
return Promise.resolve(match[1]); // token
}).then(token => {
return new Promise((resolve, reject) => {
requestp.post({
uri: "http://localhost:8378/1/apps/test/request_password_reset",
body: `new_password=user1&token=${token}&username=user1`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
followRedirect: false,
simple: false,
resolveWithFullResponse: true
}).then(response => {
resolve([response, token]);
}).catch(error => {
reject(error);
});
});
}).then(data => {
const response = data[0];
const token = data[1];
expect(response.statusCode).toEqual(302);
expect(response.body).toEqual(`Found. Redirecting to http://localhost:8378/1/apps/choose_password?username=user1&token=${token}&id=test&error=New%20password%20should%20not%20be%20the%20same%20as%20last%201%20passwords.&app=passwordPolicy`);
done();
return Promise.resolve();
}).catch(error => {
jfail(error);
fail("Repeat password test failed");
done();
});
},
sendMail: () => {
}
};
reconfigureServer({
appName: 'passwordPolicy',
verifyUserEmails: false,
emailAdapter: emailAdapter,
passwordPolicy: {
maxPasswordHistory: 1
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
user.setUsername("user1");
user.setPassword("user1");
user.set('email', 'user1@parse.com');
user.signUp().then(() => {
return Parse.User.logOut();
}).then(() => {
return Parse.User.requestPasswordReset('user1@parse.com');
}).catch(error => {
jfail(error);
fail("SignUp or reset request failed");
done();
});
});
});
it('should fail if the new password is same as the previous one', done => {
const user = new Parse.User();
reconfigureServer({
appName: 'passwordPolicy',
verifyUserEmails: false,
passwordPolicy: {
maxPasswordHistory: 5
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
user.setUsername("user1");
user.setPassword("user1");
user.set('email', 'user1@parse.com');
user.signUp().then(() => {
// try to set the same password as the previous one
user.setPassword('user1');
return user.save();
}).then(() => {
fail("should have failed because the new password is same as the old");
done();
}).catch(error => {
expect(error.message).toEqual('New password should not be the same as last 5 passwords.');
expect(error.code).toEqual(Parse.Error.VALIDATION_ERROR);
done();
});
});
});
it('should fail if the new password is same as the 5th oldest one and policy does not allow the previous 5', done => {
const user = new Parse.User();
reconfigureServer({
appName: 'passwordPolicy',
verifyUserEmails: false,
passwordPolicy: {
maxPasswordHistory: 5
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
user.setUsername("user1");
user.setPassword("user1");
user.set('email', 'user1@parse.com');
user.signUp().then(() => {
// build history
user.setPassword('user2');
return user.save();
}).then(() => {
user.setPassword('user3');
return user.save();
}).then(() => {
user.setPassword('user4');
return user.save();
}).then(() => {
user.setPassword('user5');
return user.save();
}).then(() => {
// set the same password as the initial one
user.setPassword('user1');
return user.save();
}).then(() => {
fail("should have failed because the new password is same as the old");
done();
}).catch(error => {
expect(error.message).toEqual('New password should not be the same as last 5 passwords.');
expect(error.code).toEqual(Parse.Error.VALIDATION_ERROR);
done();
});
});
});
it('should succeed if the new password is same as the 6th oldest one and policy does not allow only previous 5', done => {
const user = new Parse.User();
reconfigureServer({
appName: 'passwordPolicy',
verifyUserEmails: false,
passwordPolicy: {
maxPasswordHistory: 5
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
user.setUsername("user1");
user.setPassword("user1");
user.set('email', 'user1@parse.com');
user.signUp().then(() => {
// build history
user.setPassword('user2');
return user.save();
}).then(() => {
user.setPassword('user3');
return user.save();
}).then(() => {
user.setPassword('user4');
return user.save();
}).then(() => {
user.setPassword('user5');
return user.save();
}).then(() => {
user.setPassword('user6'); // this pushes initial password out of history
return user.save();
}).then(() => {
// set the same password as the initial one
user.setPassword('user1');
return user.save();
}).then(() => {
done();
}).catch(() => {
fail("should have succeeded because the new password is not in history");
done();
});
});
});
})
+77 -77
View File
@@ -8,9 +8,9 @@ describe('Pointer Permissions', () => {
});
it('should work with find', (done) => {
let config = new Config(Parse.applicationId);
let user = new Parse.User();
let user2 = new Parse.User();
const config = new Config(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
username: 'user1',
password: 'password'
@@ -19,8 +19,8 @@ describe('Pointer Permissions', () => {
username: 'user2',
password: 'password'
});
let obj = new Parse.Object('AnObject');
let obj2 = new Parse.Object('AnObject');
const obj = new Parse.Object('AnObject');
const obj2 = new Parse.Object('AnObject');
Parse.Object.saveAll([user, user2]).then(() => {
obj.set('owner', user);
@@ -33,7 +33,7 @@ describe('Pointer Permissions', () => {
}).then(() => {
return Parse.User.logIn('user1', 'password');
}).then(() => {
let q = new Parse.Query('AnObject');
const q = new Parse.Query('AnObject');
return q.find();
}).then((res) => {
expect(res.length).toBe(1);
@@ -47,9 +47,9 @@ describe('Pointer Permissions', () => {
it('should work with write', (done) => {
let config = new Config(Parse.applicationId);
let user = new Parse.User();
let user2 = new Parse.User();
const config = new Config(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
username: 'user1',
password: 'password'
@@ -58,8 +58,8 @@ describe('Pointer Permissions', () => {
username: 'user2',
password: 'password'
});
let obj = new Parse.Object('AnObject');
let obj2 = new Parse.Object('AnObject');
const obj = new Parse.Object('AnObject');
const obj2 = new Parse.Object('AnObject');
Parse.Object.saveAll([user, user2]).then(() => {
obj.set('owner', user);
@@ -91,7 +91,7 @@ describe('Pointer Permissions', () => {
fail('User should be able to update');
return Promise.resolve();
}).then(() => {
let q = new Parse.Query('AnObject');
const q = new Parse.Query('AnObject');
return q.find();
}, () => {
fail('should login with user 2');
@@ -112,9 +112,9 @@ describe('Pointer Permissions', () => {
});
it('should let a proper user find', (done) => {
let config = new Config(Parse.applicationId);
let user = new Parse.User();
let user2 = new Parse.User();
const config = new Config(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
username: 'user1',
password: 'password'
@@ -123,8 +123,8 @@ describe('Pointer Permissions', () => {
username: 'user2',
password: 'password'
});
let obj = new Parse.Object('AnObject');
let obj2 = new Parse.Object('AnObject');
const obj = new Parse.Object('AnObject');
const obj2 = new Parse.Object('AnObject');
user.signUp().then(() => {
return user2.signUp()
}).then(() => {
@@ -137,18 +137,18 @@ describe('Pointer Permissions', () => {
return schema.updateClass('AnObject', {}, {find: {}, get:{}, readUserFields: ['owner']})
});
}).then(() => {
let q = new Parse.Query('AnObject');
const q = new Parse.Query('AnObject');
return q.find();
}).then((res) => {
expect(res.length).toBe(0);
}).then(() => {
return Parse.User.logIn('user2', 'password');
}).then(() => {
let q = new Parse.Query('AnObject');
const q = new Parse.Query('AnObject');
return q.find();
}).then((res) => {
expect(res.length).toBe(0);
let q = new Parse.Query('AnObject');
const q = new Parse.Query('AnObject');
return q.get(obj.id);
}).then(() => {
fail('User 2 should not get the obj1 object');
@@ -159,7 +159,7 @@ describe('Pointer Permissions', () => {
}).then(() => {
return Parse.User.logIn('user1', 'password');
}).then(() => {
let q = new Parse.Query('AnObject');
const q = new Parse.Query('AnObject');
return q.find();
}).then((res) => {
expect(res.length).toBe(1);
@@ -172,13 +172,13 @@ describe('Pointer Permissions', () => {
});
it('should not allow creating objects', (done) => {
let config = new Config(Parse.applicationId);
let user = new Parse.User();
const config = new Config(Parse.applicationId);
const user = new Parse.User();
user.set({
username: 'user1',
password: 'password'
});
let obj = new Parse.Object('AnObject');
const obj = new Parse.Object('AnObject');
user.save().then(() => {
return config.database.loadSchema().then((schema) => {
return schema.addClassIfNotExists('AnObject', {owner: {type:'Pointer', targetClass: '_User'}}, {create: {}, writeUserFields: ['owner'], readUserFields: ['owner']});
@@ -198,9 +198,9 @@ describe('Pointer Permissions', () => {
});
it('should handle multiple writeUserFields', done => {
let config = new Config(Parse.applicationId);
let user = new Parse.User();
let user2 = new Parse.User();
const config = new Config(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
username: 'user1',
password: 'password'
@@ -209,7 +209,7 @@ describe('Pointer Permissions', () => {
username: 'user2',
password: 'password'
});
let obj = new Parse.Object('AnObject');
const obj = new Parse.Object('AnObject');
Parse.Object.saveAll([user, user2])
.then(() => {
obj.set('owner', user);
@@ -224,7 +224,7 @@ describe('Pointer Permissions', () => {
.then(() => obj.save({hello: 'fromUser2'}))
.then(() => Parse.User.logOut())
.then(() => {
let q = new Parse.Query('AnObject');
const q = new Parse.Query('AnObject');
return q.first();
})
.then(result => {
@@ -237,7 +237,7 @@ describe('Pointer Permissions', () => {
});
it('should prevent creating pointer permission on missing field', (done) => {
let config = new Config(Parse.applicationId);
const config = new Config(Parse.applicationId);
config.database.loadSchema().then((schema) => {
return schema.addClassIfNotExists('AnObject', {}, {create: {}, writeUserFields: ['owner'], readUserFields: ['owner']});
}).then(() => {
@@ -250,7 +250,7 @@ describe('Pointer Permissions', () => {
});
it('should prevent creating pointer permission on bad field', (done) => {
let config = new Config(Parse.applicationId);
const config = new Config(Parse.applicationId);
config.database.loadSchema().then((schema) => {
return schema.addClassIfNotExists('AnObject', {owner: {type: 'String'}}, {create: {}, writeUserFields: ['owner'], readUserFields: ['owner']});
}).then(() => {
@@ -263,8 +263,8 @@ describe('Pointer Permissions', () => {
});
it('should prevent creating pointer permission on bad field', (done) => {
let config = new Config(Parse.applicationId);
let object = new Parse.Object('AnObject');
const config = new Config(Parse.applicationId);
const object = new Parse.Object('AnObject');
object.set('owner', 'value');
object.save().then(() => {
return config.database.loadSchema();
@@ -288,9 +288,9 @@ describe('Pointer Permissions', () => {
The owner is another user than the ACL
*/
let config = new Config(Parse.applicationId);
let user = new Parse.User();
let user2 = new Parse.User();
const config = new Config(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
username: 'user1',
password: 'password'
@@ -299,9 +299,9 @@ describe('Pointer Permissions', () => {
username: 'user2',
password: 'password'
});
let obj = new Parse.Object('AnObject');
const obj = new Parse.Object('AnObject');
Parse.Object.saveAll([user, user2]).then(() => {
let ACL = new Parse.ACL();
const ACL = new Parse.ACL();
ACL.setReadAccess(user, true);
ACL.setWriteAccess(user, true);
obj.setACL(ACL);
@@ -333,9 +333,9 @@ describe('Pointer Permissions', () => {
PointerPerm: "owner"
ACL: logged in user has access
*/
let config = new Config(Parse.applicationId);
let user = new Parse.User();
let user2 = new Parse.User();
const config = new Config(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
username: 'user1',
password: 'password'
@@ -344,9 +344,9 @@ describe('Pointer Permissions', () => {
username: 'user2',
password: 'password'
});
let obj = new Parse.Object('AnObject');
const obj = new Parse.Object('AnObject');
Parse.Object.saveAll([user, user2]).then(() => {
let ACL = new Parse.ACL();
const ACL = new Parse.ACL();
ACL.setReadAccess(user, true);
ACL.setWriteAccess(user, true);
obj.setACL(ACL);
@@ -378,9 +378,9 @@ describe('Pointer Permissions', () => {
PointerPerm: "owner"
ACL: logged in user has access
*/
let config = new Config(Parse.applicationId);
let user = new Parse.User();
let user2 = new Parse.User();
const config = new Config(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
username: 'user1',
password: 'password'
@@ -389,9 +389,9 @@ describe('Pointer Permissions', () => {
username: 'user2',
password: 'password'
});
let obj = new Parse.Object('AnObject');
const obj = new Parse.Object('AnObject');
Parse.Object.saveAll([user, user2]).then(() => {
let ACL = new Parse.ACL();
const ACL = new Parse.ACL();
ACL.setWriteAccess(user, true);
ACL.setWriteAccess(user2, true);
obj.setACL(ACL);
@@ -425,9 +425,9 @@ describe('Pointer Permissions', () => {
The owner is another user than the ACL
*/
let config = new Config(Parse.applicationId);
let user = new Parse.User();
let user2 = new Parse.User();
const config = new Config(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
username: 'user1',
password: 'password'
@@ -436,9 +436,9 @@ describe('Pointer Permissions', () => {
username: 'user2',
password: 'password'
});
let obj = new Parse.Object('AnObject');
const obj = new Parse.Object('AnObject');
Parse.Object.saveAll([user, user2]).then(() => {
let ACL = new Parse.ACL();
const ACL = new Parse.ACL();
ACL.setReadAccess(user, true);
ACL.setWriteAccess(user, true);
obj.setACL(ACL);
@@ -470,9 +470,9 @@ describe('Pointer Permissions', () => {
PointerPerm: "owner" : read
ACL: logged in user has access
*/
let config = new Config(Parse.applicationId);
let user = new Parse.User();
let user2 = new Parse.User();
const config = new Config(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
username: 'user1',
password: 'password'
@@ -481,9 +481,9 @@ describe('Pointer Permissions', () => {
username: 'user2',
password: 'password'
});
let obj = new Parse.Object('AnObject');
const obj = new Parse.Object('AnObject');
Parse.Object.saveAll([user, user2]).then(() => {
let ACL = new Parse.ACL();
const ACL = new Parse.ACL();
ACL.setReadAccess(user, true);
ACL.setWriteAccess(user, true);
ACL.setReadAccess(user2, true);
@@ -517,9 +517,9 @@ describe('Pointer Permissions', () => {
PointerPerm: "owner" : read // proper owner
ACL: logged in user has not access
*/
let config = new Config(Parse.applicationId);
let user = new Parse.User();
let user2 = new Parse.User();
const config = new Config(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
username: 'user1',
password: 'password'
@@ -528,9 +528,9 @@ describe('Pointer Permissions', () => {
username: 'user2',
password: 'password'
});
let obj = new Parse.Object('AnObject');
const obj = new Parse.Object('AnObject');
Parse.Object.saveAll([user, user2]).then(() => {
let ACL = new Parse.ACL();
const ACL = new Parse.ACL();
ACL.setReadAccess(user, true);
ACL.setWriteAccess(user, true);
obj.setACL(ACL);
@@ -556,8 +556,8 @@ describe('Pointer Permissions', () => {
});
it('should let master key find objects', (done) => {
let config = new Config(Parse.applicationId);
let object = new Parse.Object('AnObject');
const config = new Config(Parse.applicationId);
const object = new Parse.Object('AnObject');
object.set('hello', 'world');
return object.save().then(() => {
return config.database.loadSchema().then((schema) => {
@@ -565,7 +565,7 @@ describe('Pointer Permissions', () => {
return schema.updateClass('AnObject', {owner: {type: 'Pointer', targetClass: '_User'}}, {find: {}, get: {}, readUserFields: ['owner']});
});
}).then(() => {
let q = new Parse.Query('AnObject');
const q = new Parse.Query('AnObject');
return q.find();
}).then(() => {
@@ -573,7 +573,7 @@ describe('Pointer Permissions', () => {
expect(err.code).toBe(101);
return Promise.resolve();
}).then(() => {
let q = new Parse.Query('AnObject');
const q = new Parse.Query('AnObject');
return q.find({useMasterKey: true});
}).then((objects) => {
expect(objects.length).toBe(1);
@@ -585,8 +585,8 @@ describe('Pointer Permissions', () => {
});
it('should let master key get objects', (done) => {
let config = new Config(Parse.applicationId);
let object = new Parse.Object('AnObject');
const config = new Config(Parse.applicationId);
const object = new Parse.Object('AnObject');
object.set('hello', 'world');
return object.save().then(() => {
return config.database.loadSchema().then((schema) => {
@@ -594,7 +594,7 @@ describe('Pointer Permissions', () => {
return schema.updateClass('AnObject', {owner: {type: 'Pointer', targetClass: '_User'}}, {find: {}, get: {}, readUserFields: ['owner']});
});
}).then(() => {
let q = new Parse.Query('AnObject');
const q = new Parse.Query('AnObject');
return q.get(object.id);
}).then(() => {
@@ -602,7 +602,7 @@ describe('Pointer Permissions', () => {
expect(err.code).toBe(101);
return Promise.resolve();
}).then(() => {
let q = new Parse.Query('AnObject');
const q = new Parse.Query('AnObject');
return q.get(object.id, {useMasterKey: true});
}).then((objectAgain) => {
expect(objectAgain).not.toBeUndefined();
@@ -616,8 +616,8 @@ describe('Pointer Permissions', () => {
it('should let master key update objects', (done) => {
let config = new Config(Parse.applicationId);
let object = new Parse.Object('AnObject');
const config = new Config(Parse.applicationId);
const object = new Parse.Object('AnObject');
object.set('hello', 'world');
return object.save().then(() => {
return config.database.loadSchema().then((schema) => {
@@ -643,8 +643,8 @@ describe('Pointer Permissions', () => {
});
it('should let master key delete objects', (done) => {
let config = new Config(Parse.applicationId);
let object = new Parse.Object('AnObject');
const config = new Config(Parse.applicationId);
const object = new Parse.Object('AnObject');
object.set('hello', 'world');
return object.save().then(() => {
return config.database.loadSchema().then((schema) => {
@@ -669,7 +669,7 @@ describe('Pointer Permissions', () => {
});
it('should fail with invalid pointer perms', (done) => {
let config = new Config(Parse.applicationId);
const config = new Config(Parse.applicationId);
config.database.loadSchema().then((schema) => {
// Lock the update, and let only owner write
return schema.addClassIfNotExists('AnObject', {owner: {type: 'Pointer', targetClass: '_User'}}, {delete: {}, writeUserFields: 'owner'});
@@ -680,7 +680,7 @@ describe('Pointer Permissions', () => {
});
it('should fail with invalid pointer perms', (done) => {
let config = new Config(Parse.applicationId);
const config = new Config(Parse.applicationId);
config.database.loadSchema().then((schema) => {
// Lock the update, and let only owner write
return schema.addClassIfNotExists('AnObject', {owner: {type: 'Pointer', targetClass: '_User'}}, {delete: {}, writeUserFields: ['owner', 'invalid']});
+1 -1
View File
@@ -20,7 +20,7 @@ function createProduct() {
}
describe("test validate_receipt endpoint", () => {
beforeEach( done => {
beforeEach(done => {
createProduct().then(done).fail(function(){
done();
});
+146 -118
View File
@@ -2,10 +2,11 @@
var PushController = require('../src/Controllers/PushController').PushController;
var StatusHandler = require('../src/StatusHandler');
var Config = require('../src/Config');
var validatePushType = require('../src/Push/utils').validatePushType;
const successfulTransmissions = function(body, installations) {
let promises = installations.map((device) => {
const promises = installations.map((device) => {
return Promise.resolve({
transmitted: true,
device: device,
@@ -17,7 +18,7 @@ const successfulTransmissions = function(body, installations) {
const successfulIOS = function(body, installations) {
let promises = installations.map((device) => {
const promises = installations.map((device) => {
return Promise.resolve({
transmitted: device.deviceType == "ios",
device: device,
@@ -35,7 +36,7 @@ describe('PushController', () => {
var validPushTypes = ['ios', 'android'];
expect(function(){
PushController.validatePushType(where, validPushTypes);
validatePushType(where, validPushTypes);
}).not.toThrow();
done();
});
@@ -48,7 +49,7 @@ describe('PushController', () => {
var validPushTypes = ['ios', 'android'];
expect(function(){
PushController.validatePushType(where, validPushTypes);
validatePushType(where, validPushTypes);
}).not.toThrow();
done();
});
@@ -63,7 +64,7 @@ describe('PushController', () => {
var validPushTypes = ['ios', 'android'];
expect(function(){
PushController.validatePushType(where, validPushTypes);
validatePushType(where, validPushTypes);
}).not.toThrow();
done();
});
@@ -76,7 +77,7 @@ describe('PushController', () => {
var validPushTypes = ['ios', 'android'];
expect(function(){
PushController.validatePushType(where, validPushTypes);
validatePushType(where, validPushTypes);
}).toThrow();
done();
});
@@ -89,7 +90,7 @@ describe('PushController', () => {
var validPushTypes = ['ios', 'android'];
expect(function(){
PushController.validatePushType(where, validPushTypes);
validatePushType(where, validPushTypes);
}).toThrow();
done();
});
@@ -131,37 +132,13 @@ describe('PushController', () => {
});
it('properly increment badges', (done) => {
var payload = {data:{
alert: "Hello World!",
badge: "Increment",
}}
var installations = [];
while(installations.length != 10) {
let installation = new Parse.Object("_Installation");
installation.set("installationId", "installation_"+installations.length);
installation.set("deviceToken","device_token_"+installations.length)
installation.set("badge", installations.length);
installation.set("originalBadge", installations.length);
installation.set("deviceType", "ios");
installations.push(installation);
}
while(installations.length != 15) {
let installation = new Parse.Object("_Installation");
installation.set("installationId", "installation_"+installations.length);
installation.set("deviceToken","device_token_"+installations.length)
installation.set("deviceType", "android");
installations.push(installation);
}
var pushAdapter = {
send: function(body, installations) {
var badge = body.data.badge;
installations.forEach((installation) => {
if (installation.deviceType == "ios") {
expect(installation.badge).toEqual(badge);
expect(installation.originalBadge+1).toEqual(installation.badge);
expect(installation.originalBadge + 1).toEqual(installation.badge);
} else {
expect(installation.badge).toBeUndefined();
}
@@ -172,14 +149,39 @@ describe('PushController', () => {
return ["ios", "android"];
}
}
var payload = {data:{
alert: "Hello World!",
badge: "Increment",
}}
var installations = [];
while(installations.length != 10) {
const installation = new Parse.Object("_Installation");
installation.set("installationId", "installation_" + installations.length);
installation.set("deviceToken","device_token_" + installations.length)
installation.set("badge", installations.length);
installation.set("originalBadge", installations.length);
installation.set("deviceType", "ios");
installations.push(installation);
}
while(installations.length != 15) {
const installation = new Parse.Object("_Installation");
installation.set("installationId", "installation_" + installations.length);
installation.set("deviceToken","device_token_" + installations.length)
installation.set("deviceType", "android");
installations.push(installation);
}
var config = new Config(Parse.applicationId);
var auth = {
isMaster: true
}
var pushController = new PushController(pushAdapter, Parse.applicationId, defaultConfiguration.push);
Parse.Object.saveAll(installations).then(() => {
var pushController = new PushController();
reconfigureServer({
push: { adapter: pushAdapter }
}).then(() => {
return Parse.Object.saveAll(installations)
}).then(() => {
return pushController.sendPush(payload, {}, config, auth);
}).then(() => {
done();
@@ -187,26 +189,10 @@ describe('PushController', () => {
jfail(err);
done();
});
});
it('properly set badges to 1', (done) => {
var payload = {data: {
alert: "Hello World!",
badge: 1,
}}
var installations = [];
while(installations.length != 10) {
var installation = new Parse.Object("_Installation");
installation.set("installationId", "installation_"+installations.length);
installation.set("deviceToken","device_token_"+installations.length)
installation.set("badge", installations.length);
installation.set("originalBadge", installations.length);
installation.set("deviceType", "ios");
installations.push(installation);
}
var pushAdapter = {
send: function(body, installations) {
var badge = body.data.badge;
@@ -221,13 +207,32 @@ describe('PushController', () => {
}
}
var payload = {data: {
alert: "Hello World!",
badge: 1,
}}
var installations = [];
while(installations.length != 10) {
var installation = new Parse.Object("_Installation");
installation.set("installationId", "installation_" + installations.length);
installation.set("deviceToken","device_token_" + installations.length)
installation.set("badge", installations.length);
installation.set("originalBadge", installations.length);
installation.set("deviceType", "ios");
installations.push(installation);
}
var config = new Config(Parse.applicationId);
var auth = {
isMaster: true
}
var pushController = new PushController(pushAdapter, Parse.applicationId, defaultConfiguration.push);
Parse.Object.saveAll(installations).then(() => {
var pushController = new PushController();
reconfigureServer({
push: { adapter: pushAdapter }
}).then(() => {
return Parse.Object.saveAll(installations)
}).then(() => {
return pushController.sendPush(payload, {}, config, auth);
}).then(() => {
done();
@@ -235,7 +240,6 @@ describe('PushController', () => {
fail("should not fail");
done();
});
});
it('properly set badges to 1 with complex query #2903 #3022', (done) => {
@@ -249,8 +253,8 @@ describe('PushController', () => {
var installations = [];
while(installations.length != 10) {
var installation = new Parse.Object("_Installation");
installation.set("installationId", "installation_"+installations.length);
installation.set("deviceToken","device_token_"+installations.length)
installation.set("installationId", "installation_" + installations.length);
installation.set("deviceToken","device_token_" + installations.length)
installation.set("badge", installations.length);
installation.set("originalBadge", installations.length);
installation.set("deviceType", "ios");
@@ -276,19 +280,28 @@ describe('PushController', () => {
var auth = {
isMaster: true
}
var pushController = new PushController(pushAdapter, Parse.applicationId, defaultConfiguration.push);
Parse.Object.saveAll(installations).then((installations) => {
let objectIds = installations.map(installation => {
var pushController = new PushController();
reconfigureServer({
push: {
adapter: pushAdapter
}
}).then(() => {
return Parse.Object.saveAll(installations)
}).then((installations) => {
const objectIds = installations.map(installation => {
return installation.id;
})
let where = {
const where = {
objectId: {'$in': objectIds.slice(0, 5)}
}
return pushController.sendPush(payload, where, config, auth);
}).then(() => {
return new Promise((res) => {
setTimeout(res, 300);
});
}).then(() => {
expect(matchedInstallationsCount).toBe(5);
let query = new Parse.Query(Parse.Installation);
const query = new Parse.Query(Parse.Installation);
query.equalTo('badge', 1);
return query.find({useMasterKey: true});
}).then((installations) => {
@@ -304,9 +317,9 @@ describe('PushController', () => {
var installations = [];
while(installations.length != 10) {
let installation = new Parse.Object("_Installation");
installation.set("installationId", "installation_"+installations.length);
installation.set("deviceToken","device_token_"+installations.length)
const installation = new Parse.Object("_Installation");
installation.set("installationId", "installation_" + installations.length);
installation.set("deviceToken","device_token_" + installations.length)
installation.set("badge", installations.length);
installation.set("originalBadge", installations.length);
installation.set("deviceType", "ios");
@@ -314,9 +327,9 @@ describe('PushController', () => {
}
while(installations.length != 15) {
let installation = new Parse.Object("_Installation");
installation.set("installationId", "installation_"+installations.length);
installation.set("deviceToken","device_token_"+installations.length)
const installation = new Parse.Object("_Installation");
installation.set("installationId", "installation_" + installations.length);
installation.set("deviceToken","device_token_" + installations.length)
installation.set("deviceType", "android");
installations.push(installation);
}
@@ -338,46 +351,50 @@ describe('PushController', () => {
var auth = {
isMaster: true
}
var pushController = new PushController(pushAdapter, Parse.applicationId, defaultConfiguration.push);
Parse.Object.saveAll(installations).then(() => {
return pushController.sendPush(payload, {}, config, auth);
var pushController = new PushController();
reconfigureServer({
push: { adapter: pushAdapter }
}).then(() => {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 1000);
});
}).then(() => {
let query = new Parse.Query('_PushStatus');
return query.find({useMasterKey: true});
}).then((results) => {
expect(results.length).toBe(1);
let result = results[0];
expect(result.createdAt instanceof Date).toBe(true);
expect(result.updatedAt instanceof Date).toBe(true);
expect(result.id.length).toBe(10);
expect(result.get('source')).toEqual('rest');
expect(result.get('query')).toEqual(JSON.stringify({}));
expect(typeof result.get('payload')).toEqual("string");
expect(JSON.parse(result.get('payload'))).toEqual(payload.data);
expect(result.get('status')).toEqual('succeeded');
expect(result.get('numSent')).toEqual(10);
expect(result.get('sentPerType')).toEqual({
'ios': 10 // 10 ios
});
expect(result.get('numFailed')).toEqual(5);
expect(result.get('failedPerType')).toEqual({
'android': 5 // android
});
return Parse.Object.saveAll(installations)
})
.then(() => {
return pushController.sendPush(payload, {}, config, auth);
}).then(() => {
// it is enqueued so it can take time
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 1000);
});
}).then(() => {
const query = new Parse.Query('_PushStatus');
return query.find({useMasterKey: true});
}).then((results) => {
expect(results.length).toBe(1);
const result = results[0];
expect(result.createdAt instanceof Date).toBe(true);
expect(result.updatedAt instanceof Date).toBe(true);
expect(result.id.length).toBe(10);
expect(result.get('source')).toEqual('rest');
expect(result.get('query')).toEqual(JSON.stringify({}));
expect(typeof result.get('payload')).toEqual("string");
expect(JSON.parse(result.get('payload'))).toEqual(payload.data);
expect(result.get('status')).toEqual('succeeded');
expect(result.get('numSent')).toEqual(10);
expect(result.get('sentPerType')).toEqual({
'ios': 10 // 10 ios
});
expect(result.get('numFailed')).toEqual(5);
expect(result.get('failedPerType')).toEqual({
'android': 5 // android
});
// Try to get it without masterKey
let query = new Parse.Query('_PushStatus');
return query.find();
}).then((results) => {
expect(results.length).toBe(0);
done();
});
const query = new Parse.Query('_PushStatus');
return query.find();
}).then((results) => {
expect(results.length).toBe(0);
done();
});
});
it('should properly report failures in _PushStatus', (done) => {
@@ -393,7 +410,7 @@ describe('PushController', () => {
return ["ios"];
}
}
let where = { 'channels': {
const where = { 'channels': {
'$ins': ['Giants', 'Mets']
}};
var payload = {data: {
@@ -404,19 +421,23 @@ describe('PushController', () => {
var auth = {
isMaster: true
}
var pushController = new PushController(pushAdapter, Parse.applicationId, defaultConfiguration.push);
pushController.sendPush(payload, where, config, auth).then(() => {
var pushController = new PushController();
reconfigureServer({
push: { adapter: pushAdapter }
}).then(() => {
return pushController.sendPush(payload, where, config, auth)
}).then(() => {
fail('should not succeed');
done();
}).catch(() => {
let query = new Parse.Query('_PushStatus');
const query = new Parse.Query('_PushStatus');
query.find({useMasterKey: true}).then((results) => {
expect(results.length).toBe(1);
let pushStatus = results[0];
const pushStatus = results[0];
expect(pushStatus.get('status')).toBe('failed');
done();
});
})
});
});
it('should support full RESTQuery for increment', (done) => {
@@ -433,13 +454,12 @@ describe('PushController', () => {
return ["ios"];
}
}
var config = new Config(Parse.applicationId);
var auth = {
isMaster: true
}
let where = {
const where = {
'deviceToken': {
'$inQuery': {
'where': {
@@ -450,8 +470,12 @@ describe('PushController', () => {
}
}
var pushController = new PushController(pushAdapter, Parse.applicationId, defaultConfiguration.push);
pushController.sendPush(payload, where, config, auth).then(() => {
var pushController = new PushController();
reconfigureServer({
push: { adapter: pushAdapter }
}).then(() => {
return pushController.sendPush(payload, where, config, auth);
}).then(() => {
done();
}).catch((err) => {
jfail(err);
@@ -480,7 +504,7 @@ describe('PushController', () => {
isMaster: true
}
let where = {
const where = {
'deviceToken': {
'$inQuery': {
'where': {
@@ -491,8 +515,12 @@ describe('PushController', () => {
}
}
var pushController = new PushController(pushAdapter, Parse.applicationId, defaultConfiguration.push);
pushController.sendPush(payload, where, config, auth).then(() => {
var pushController = new PushController();
reconfigureServer({
push: { adapter: pushAdapter }
}).then(() => {
pushController.sendPush(payload, where, config, auth)
}).then(() => {
done();
}).catch(() => {
fail('should not fail');
+1 -1
View File
@@ -70,7 +70,7 @@ describe('PushRouter', () => {
it('sends a push through REST', (done) => {
request.post({
url: Parse.serverURL+"/push",
url: Parse.serverURL + "/push",
json: true,
body: {
'channels': {
+57
View File
@@ -0,0 +1,57 @@
var PushWorker = require('../src').PushWorker;
var Config = require('../src/Config');
describe('PushWorker', () => {
it('should run with small batch', (done) => {
const batchSize = 3;
var sendCount = 0;
reconfigureServer({
push: {
queueOptions: {
disablePushWorker: true,
batchSize
}
}
}).then(() => {
expect(new Config('test').pushWorker).toBeUndefined();
new PushWorker({
send: (body, installations) => {
expect(installations.length <= batchSize).toBe(true);
sendCount += installations.length;
return Promise.resolve();
},
getValidPushTypes: function() {
return ['ios', 'android']
}
});
var installations = [];
while(installations.length != 10) {
var installation = new Parse.Object("_Installation");
installation.set("installationId", "installation_" + installations.length);
installation.set("deviceToken","device_token_" + installations.length)
installation.set("badge", 1);
installation.set("deviceType", "ios");
installations.push(installation);
}
return Parse.Object.saveAll(installations);
}).then(() => {
return Parse.Push.send({
where: {
deviceType: 'ios'
},
data: {
alert: 'Hello world!'
}
}, {useMasterKey: true})
}).then(() => {
return new Promise((resolve) => {
setTimeout(resolve, 500);
});
}).then(() => {
expect(sendCount).toBe(10);
done();
}).catch(err => {
jfail(err);
})
});
});
+62
View File
@@ -412,4 +412,66 @@ describe('matchesQuery', function() {
expect(matchesQuery(caltrainStation, q)).toBe(false);
expect(matchesQuery(santaClara, q)).toBe(false);
});
it('matches on subobjects with dot notation', function() {
var message = {
id: new Id('Message', 'O1'),
text: "content",
status: {x: "read", y: "delivered"}
};
var q = new Parse.Query('Message');
q.equalTo("status.x", "read");
expect(matchesQuery(message, q)).toBe(true);
q = new Parse.Query('Message');
q.equalTo("status.z", "read");
expect(matchesQuery(message, q)).toBe(false);
q = new Parse.Query('Message');
q.equalTo("status.x", "delivered");
expect(matchesQuery(message, q)).toBe(false);
q = new Parse.Query('Message');
q.notEqualTo("status.x", "read");
expect(matchesQuery(message, q)).toBe(false);
q = new Parse.Query('Message');
q.notEqualTo("status.z", "read");
expect(matchesQuery(message, q)).toBe(true);
q = new Parse.Query('Message');
q.notEqualTo("status.x", "delivered");
expect(matchesQuery(message, q)).toBe(true);
q = new Parse.Query('Message');
q.exists("status.x");
expect(matchesQuery(message, q)).toBe(true);
q = new Parse.Query('Message');
q.exists("status.z");
expect(matchesQuery(message, q)).toBe(false);
q = new Parse.Query('Message');
q.exists("nonexistent.x");
expect(matchesQuery(message, q)).toBe(false);
q = new Parse.Query('Message');
q.doesNotExist("status.x");
expect(matchesQuery(message, q)).toBe(false);
q = new Parse.Query('Message');
q.doesNotExist("status.z");
expect(matchesQuery(message, q)).toBe(true);
q = new Parse.Query('Message');
q.doesNotExist("nonexistent.z");
expect(matchesQuery(message, q)).toBe(true);
q = new Parse.Query('Message');
q.equalTo("status.x", "read");
q.doesNotExist("status.y");
expect(matchesQuery(message, q)).toBe(false);
});
});
+10 -10
View File
@@ -172,8 +172,8 @@ describe('rest query', () => {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest'
};
let p0 = rp.get({
const p0 = rp.get({
headers: headers,
url: 'http://localhost:8378/1/classes/TestParameterEncode?'
+ querystring.stringify({
@@ -181,19 +181,19 @@ describe('rest query', () => {
limit: 1
}).replace('=', '%3D'),
}).then(fail, (response) => {
let error = response.error;
const error = response.error;
var b = JSON.parse(error);
expect(b.code).toEqual(Parse.Error.INVALID_QUERY);
});
let p1 = rp.get({
const p1 = rp.get({
headers: headers,
url: 'http://localhost:8378/1/classes/TestParameterEncode?'
+ querystring.stringify({
limit: 1
}).replace('=', '%3D'),
}).then(fail, (response) => {
let error = response.error;
const error = response.error;
var b = JSON.parse(error);
expect(b.code).toEqual(Parse.Error.INVALID_QUERY);
});
@@ -235,21 +235,21 @@ describe('rest query', () => {
});
it('makes sure null pointers are handed correctly #2189', done => {
let object = new Parse.Object('AnObject');
let anotherObject = new Parse.Object('AnotherObject');
const object = new Parse.Object('AnObject');
const anotherObject = new Parse.Object('AnotherObject');
anotherObject.save().then(() => {
object.set('values', [null, null, anotherObject]);
return object.save();
}).then(() => {
let query = new Parse.Query('AnObject');
const query = new Parse.Query('AnObject');
query.include('values');
return query.first();
}).then((result) => {
let values = result.get('values');
const values = result.get('values');
expect(values.length).toBe(3);
let anotherObjectFound = false;
let nullCounts = 0;
for(let value of values) {
for(const value of values) {
if (value === null) {
nullCounts++;
} else if (value instanceof Parse.Object) {
+5 -5
View File
@@ -22,7 +22,7 @@ describe_only_db('mongo')('revocable sessions', () => {
});
it('should upgrade legacy session token', done => {
let user = Parse.Object.fromJSON({
const user = Parse.Object.fromJSON({
className: '_User',
objectId: '1234567890',
sessionToken: sessionToken
@@ -49,7 +49,7 @@ describe_only_db('mongo')('revocable sessions', () => {
});
it('should be able to become with revocable session token', done => {
let user = Parse.Object.fromJSON({
const user = Parse.Object.fromJSON({
className: '_User',
objectId: '1234567890',
sessionToken: sessionToken
@@ -71,7 +71,7 @@ describe_only_db('mongo')('revocable sessions', () => {
it('should not upgrade bad legacy session token', done => {
rp.post({
url: Parse.serverURL+'/upgradeToRevocableSession',
url: Parse.serverURL + '/upgradeToRevocableSession',
headers: {
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-Rest-API-Key': 'rest',
@@ -92,7 +92,7 @@ describe_only_db('mongo')('revocable sessions', () => {
it('should not crash without session token #2720', done => {
rp.post({
url: Parse.serverURL+'/upgradeToRevocableSession',
url: Parse.serverURL + '/upgradeToRevocableSession',
headers: {
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-Rest-API-Key': 'rest'
@@ -109,4 +109,4 @@ describe_only_db('mongo')('revocable sessions', () => {
done();
});
});
})
})
+267 -8
View File
@@ -708,7 +708,7 @@ describe('SchemaController', () => {
}, () => {
expect(exist).toEqual(false);
});
})
.then(() => schema.deleteField('relationField', 'NewClass', config.database))
.then(() => schema.reloadData())
@@ -824,9 +824,9 @@ describe('SchemaController', () => {
});
it('yields a proper schema mismatch error (#2661)', done => {
let anObject = new Parse.Object('AnObject');
let anotherObject = new Parse.Object('AnotherObject');
let someObject = new Parse.Object('SomeObject');
const anObject = new Parse.Object('AnObject');
const anotherObject = new Parse.Object('AnotherObject');
const someObject = new Parse.Object('SomeObject');
Parse.Object.saveAll([anObject, anotherObject, someObject]).then(() => {
anObject.set('pointer', anotherObject);
return anObject.save();
@@ -844,8 +844,8 @@ describe('SchemaController', () => {
});
it('yields a proper schema mismatch error bis (#2661)', done => {
let anObject = new Parse.Object('AnObject');
let someObject = new Parse.Object('SomeObject');
const anObject = new Parse.Object('AnObject');
const someObject = new Parse.Object('SomeObject');
Parse.Object.saveAll([anObject, someObject]).then(() => {
anObject.set('number', 1);
return anObject.save();
@@ -863,8 +863,8 @@ describe('SchemaController', () => {
});
it('yields a proper schema mismatch error ter (#2661)', done => {
let anObject = new Parse.Object('AnObject');
let someObject = new Parse.Object('SomeObject');
const anObject = new Parse.Object('AnObject');
const someObject = new Parse.Object('SomeObject');
Parse.Object.saveAll([anObject, someObject]).then(() => {
anObject.set('pointer', someObject);
return anObject.save();
@@ -880,4 +880,263 @@ describe('SchemaController', () => {
done();
});
});
it('properly handles volatile _Schemas', done => {
function validateSchemaStructure(schema) {
expect(schema.hasOwnProperty('className')).toBe(true);
expect(schema.hasOwnProperty('fields')).toBe(true);
expect(schema.hasOwnProperty('classLevelPermissions')).toBe(true);
}
function validateSchemaDataStructure(schemaData) {
Object.keys(schemaData).forEach(className => {
const schema = schemaData[className];
// Hooks has className...
if (className != '_Hooks') {
expect(schema.hasOwnProperty('className')).toBe(false);
}
expect(schema.hasOwnProperty('fields')).toBe(false);
expect(schema.hasOwnProperty('classLevelPermissions')).toBe(false);
});
}
let schema;
config.database.loadSchema().then(s => {
schema = s;
return schema.getOneSchema('_User', false);
}).then(userSchema => {
validateSchemaStructure(userSchema);
validateSchemaDataStructure(schema.data);
return schema.getOneSchema('_PushStatus', true);
}).then(pushStatusSchema => {
validateSchemaStructure(pushStatusSchema);
validateSchemaDataStructure(schema.data);
done();
});
});
});
describe('Class Level Permissions for requiredAuth', () => {
beforeEach(() => {
config = new Config('test');
});
function createUser() {
const user = new Parse.User();
user.set("username", "hello");
user.set("password", "world");
return user.signUp(null);
}
it('required auth test find', (done) => {
config.database.loadSchema().then((schema) => {
// Just to create a valid class
return schema.validateObject('Stuff', {foo: 'bar'});
}).then((schema) => {
return schema.setPermissions('Stuff', {
'find': {
'requiresAuthentication': true
}
});
}).then(() => {
var query = new Parse.Query('Stuff');
return query.find();
}).then(() => {
fail('Class permissions should have rejected this query.');
done();
}, (e) => {
expect(e.message).toEqual('Permission denied, user needs to be authenticated.');
done();
});
});
it('required auth test find authenticated', (done) => {
config.database.loadSchema().then((schema) => {
// Just to create a valid class
return schema.validateObject('Stuff', {foo: 'bar'});
}).then((schema) => {
return schema.setPermissions('Stuff', {
'find': {
'requiresAuthentication': true
}
});
}).then(() => {
return createUser();
}).then(() => {
var query = new Parse.Query('Stuff');
return query.find();
}).then((results) => {
expect(results.length).toEqual(0);
done();
}, (e) => {
console.error(e);
fail("Should not have failed");
done();
});
});
it('required auth should allow create authenticated', (done) => {
config.database.loadSchema().then((schema) => {
// Just to create a valid class
return schema.validateObject('Stuff', {foo: 'bar'});
}).then((schema) => {
return schema.setPermissions('Stuff', {
'create': {
'requiresAuthentication': true
}
});
}).then(() => {
return createUser();
}).then(() => {
const stuff = new Parse.Object('Stuff');
stuff.set('foo', 'bar');
return stuff.save();
}).then(() => {
done();
}, (e) => {
console.error(e);
fail("Should not have failed");
done();
});
});
it('required auth should reject create when not authenticated', (done) => {
config.database.loadSchema().then((schema) => {
// Just to create a valid class
return schema.validateObject('Stuff', {foo: 'bar'});
}).then((schema) => {
return schema.setPermissions('Stuff', {
'create': {
'requiresAuthentication': true
}
});
}).then(() => {
const stuff = new Parse.Object('Stuff');
stuff.set('foo', 'bar');
return stuff.save();
}).then(() => {
fail('Class permissions should have rejected this query.');
done();
}, (e) => {
expect(e.message).toEqual('Permission denied, user needs to be authenticated.');
done();
});
});
it('required auth test create/get/update/delete authenticated', (done) => {
config.database.loadSchema().then((schema) => {
// Just to create a valid class
return schema.validateObject('Stuff', {foo: 'bar'});
}).then((schema) => {
return schema.setPermissions('Stuff', {
'create': {
'requiresAuthentication': true
},
'get': {
'requiresAuthentication': true
},
'delete': {
'requiresAuthentication': true
},
'update': {
'requiresAuthentication': true
}
});
}).then(() => {
return createUser();
}).then(() => {
const stuff = new Parse.Object('Stuff');
stuff.set('foo', 'bar');
return stuff.save().then(() => {
const query = new Parse.Query('Stuff');
return query.get(stuff.id);
});
}).then((gotStuff) => {
return gotStuff.save({'foo': 'baz'}).then(() => {
return gotStuff.destroy();
})
}).then(() => {
done();
}, (e) => {
console.error(e);
fail("Should not have failed");
done();
});
});
it('required auth test create/get/update/delete not authenitcated', (done) => {
config.database.loadSchema().then((schema) => {
// Just to create a valid class
return schema.validateObject('Stuff', {foo: 'bar'});
}).then((schema) => {
return schema.setPermissions('Stuff', {
'get': {
'requiresAuthentication': true
},
'delete': {
'requiresAuthentication': true
},
'update': {
'requiresAuthentication': true
},
'create': {
'*': true
}
});
}).then(() => {
const stuff = new Parse.Object('Stuff');
stuff.set('foo', 'bar');
return stuff.save().then(() => {
const query = new Parse.Query('Stuff');
return query.get(stuff.id);
});
}).then(() => {
fail("Should not succeed!");
done();
}, (e) => {
expect(e.message).toEqual('Permission denied, user needs to be authenticated.');
done();
});
});
it('required auth test create/get/update/delete not authenitcated', (done) => {
config.database.loadSchema().then((schema) => {
// Just to create a valid class
return schema.validateObject('Stuff', {foo: 'bar'});
}).then((schema) => {
return schema.setPermissions('Stuff', {
'find': {
'requiresAuthentication': true
},
'delete': {
'requiresAuthentication': true
},
'update': {
'requiresAuthentication': true
},
'create': {
'*': true
},
'get': {
'*': true
}
});
}).then(() => {
const stuff = new Parse.Object('Stuff');
stuff.set('foo', 'bar');
return stuff.save().then(() => {
const query = new Parse.Query('Stuff');
return query.get(stuff.id);
})
}).then((result) => {
expect(result.get('foo')).toEqual('bar');
const query = new Parse.Query('Stuff');
return query.find();
}).then(() => {
fail("Should not succeed!");
done();
}, (e) => {
expect(e.message).toEqual('Permission denied, user needs to be authenticated.');
done();
});
});
})
+8 -10
View File
@@ -4,13 +4,14 @@ describe('SessionTokenCache', function() {
beforeEach(function(done) {
var Parse = require('parse/node');
// Mock parse
var mockUser = {
become: jasmine.createSpy('become').and.returnValue(Parse.Promise.as({
id: 'userId'
}))
}
jasmine.mockLibrary('parse/node', 'User', mockUser);
spyOn(Parse, "Query").and.returnValue({
first: jasmine.createSpy("first").and.returnValue(Parse.Promise.as(new Parse.Object("_Session", {
user: new Parse.User({id:"userId"})
}))),
equalTo: function(){}
})
done();
});
@@ -46,7 +47,4 @@ describe('SessionTokenCache', function() {
});
});
afterEach(function() {
jasmine.restoreLibrary('parse/node', 'User');
});
});
+5 -5
View File
@@ -1,4 +1,4 @@
let twitter = require('../src/authDataManager/twitter');
const twitter = require('../src/Adapters/Auth/twitter');
describe('Twitter Auth', () => {
it('should use the proper configuration', () => {
@@ -10,9 +10,9 @@ describe('Twitter Auth', () => {
}, {
consumer_key: 'world'
}]).consumer_key).toEqual('hello')
// Multiple options, consumer_key not found
expect(function(){
expect(function(){
twitter.handleMultipleConfigurations({
consumer_key: 'some',
}, [{
@@ -23,7 +23,7 @@ describe('Twitter Auth', () => {
}).toThrow();
// Multiple options, consumer_key not found
expect(function(){
expect(function(){
twitter.handleMultipleConfigurations({
auth_token: 'token',
}, [{
@@ -47,4 +47,4 @@ describe('Twitter Auth', () => {
consumer_key: 'hello'
}).consumer_key).toEqual('hello');
});
});
});
+15 -15
View File
@@ -1,19 +1,19 @@
'use strict';
const Parse = require("parse/node");
let Config = require('../src/Config');
const Config = require('../src/Config');
describe('Uniqueness', function() {
it('fail when create duplicate value in unique field', done => {
let obj = new Parse.Object('UniqueField');
const obj = new Parse.Object('UniqueField');
obj.set('unique', 'value');
obj.save().then(() => {
expect(obj.id).not.toBeUndefined();
let config = new Config('test');
const config = new Config('test');
return config.database.adapter.ensureUniqueness('UniqueField', { fields: { unique: { __type: 'String' } } }, ['unique'])
})
.then(() => {
let obj = new Parse.Object('UniqueField');
const obj = new Parse.Object('UniqueField');
obj.set('unique', 'value');
return obj.save()
}).then(() => {
@@ -26,18 +26,18 @@ describe('Uniqueness', function() {
});
it('unique indexing works on pointer fields', done => {
let obj = new Parse.Object('UniquePointer');
const obj = new Parse.Object('UniquePointer');
obj.save({ string: 'who cares' })
.then(() => obj.save({ ptr: obj }))
.then(() => {
let config = new Config('test');
const config = new Config('test');
return config.database.adapter.ensureUniqueness('UniquePointer', { fields: {
string: { __type: 'String' },
ptr: { __type: 'Pointer', targetClass: 'UniquePointer' }
} }, ['ptr']);
})
.then(() => {
let newObj = new Parse.Object('UniquePointer')
const newObj = new Parse.Object('UniquePointer')
newObj.set('ptr', obj)
return newObj.save()
})
@@ -52,13 +52,13 @@ describe('Uniqueness', function() {
});
it('fails when attempting to ensure uniqueness of fields that are not currently unique', done => {
let o1 = new Parse.Object('UniqueFail');
const o1 = new Parse.Object('UniqueFail');
o1.set('key', 'val');
let o2 = new Parse.Object('UniqueFail');
const o2 = new Parse.Object('UniqueFail');
o2.set('key', 'val');
Parse.Object.saveAll([o1, o2])
.then(() => {
let config = new Config('test');
const config = new Config('test');
return config.database.adapter.ensureUniqueness('UniqueFail', { fields: { key: { __type: 'String' } } }, ['key']);
})
.catch(error => {
@@ -68,28 +68,28 @@ describe('Uniqueness', function() {
});
it_exclude_dbs(['postgres'])('can do compound uniqueness', done => {
let config = new Config('test');
const config = new Config('test');
config.database.adapter.ensureUniqueness('CompoundUnique', { fields: { k1: { __type: 'String' }, k2: { __type: 'String' } } }, ['k1', 'k2'])
.then(() => {
let o1 = new Parse.Object('CompoundUnique');
const o1 = new Parse.Object('CompoundUnique');
o1.set('k1', 'v1');
o1.set('k2', 'v2');
return o1.save();
})
.then(() => {
let o2 = new Parse.Object('CompoundUnique');
const o2 = new Parse.Object('CompoundUnique');
o2.set('k1', 'v1');
o2.set('k2', 'not a dupe');
return o2.save();
})
.then(() => {
let o3 = new Parse.Object('CompoundUnique');
const o3 = new Parse.Object('CompoundUnique');
o3.set('k1', 'not a dupe');
o3.set('k2', 'v2');
return o3.save();
})
.then(() => {
let o4 = new Parse.Object('CompoundUnique');
const o4 = new Parse.Object('CompoundUnique');
o4.set('k1', 'v1');
o4.set('k2', 'v2');
return o4.save();
+59
View File
@@ -0,0 +1,59 @@
var UserController = require('../src/Controllers/UserController').UserController;
var emailAdapter = require('./MockEmailAdapter')
var AppCache = require('../src/cache').AppCache;
describe('UserController', () => {
var user = {
_email_verify_token: 'testToken',
username: 'testUser',
email: 'test@example.com'
}
describe('sendVerificationEmail', () => {
describe('parseFrameURL not provided', () => {
it('uses publicServerURL', (done) => {
AppCache.put(defaultConfiguration.appId, Object.assign({}, defaultConfiguration, {
publicServerURL: 'http://www.example.com',
customPages: {
parseFrameURL: undefined
}
}))
emailAdapter.sendVerificationEmail = (options) => {
expect(options.link).toEqual('http://www.example.com/apps/test/verify_email?token=testToken&username=testUser')
done()
}
var userController = new UserController(emailAdapter, 'test', {
verifyUserEmails: true
})
userController.sendVerificationEmail(user)
})
})
describe('parseFrameURL provided', () => {
it('uses parseFrameURL and includes the destination in the link parameter', (done) => {
AppCache.put(defaultConfiguration.appId, Object.assign({}, defaultConfiguration, {
publicServerURL: 'http://www.example.com',
customPages: {
parseFrameURL: 'http://someother.example.com/handle-parse-iframe'
}
}))
emailAdapter.sendVerificationEmail = (options) => {
expect(options.link).toEqual('http://someother.example.com/handle-parse-iframe?link=%2Fapps%2Ftest%2Fverify_email&token=testToken&username=testUser')
done()
}
var userController = new UserController(emailAdapter, 'test', {
verifyUserEmails: true
})
userController.sendVerificationEmail(user)
})
})
})
});
+503
View File
@@ -0,0 +1,503 @@
'use strict';
const Parse = require('parse/node');
const request = require('request-promise');
// const Config = require('../src/Config');
const EMAIL = 'foo@bar.com';
const ZIP = '10001';
const SSN = '999-99-9999';
describe('Personally Identifiable Information', () => {
let user;
beforeEach(done => {
return Parse.User.signUp('tester', 'abc')
.then(loggedInUser => user = loggedInUser)
.then(() => Parse.User.logIn(user.get('username'), 'abc'))
.then(() => user
.set('email', EMAIL)
.set('zip', ZIP)
.set('ssn', SSN)
.save())
.then(() => done());
});
it('should be able to get own PII via API with object', (done) => {
const userObj = new (Parse.Object.extend(Parse.User));
userObj.id = user.id;
userObj.fetch().then(
fetchedUser => {
expect(fetchedUser.get('email')).toBe(EMAIL);
}, e => console.error('error', e))
.done(() => done());
});
it('should not be able to get PII via API with object', (done) => {
Parse.User.logOut()
.then(() => {
const userObj = new (Parse.Object.extend(Parse.User));
userObj.id = user.id;
userObj.fetch().then(
fetchedUser => {
expect(fetchedUser.get('email')).toBe(undefined);
})
.fail(e => {
done.fail(JSON.stringify(e));
})
.done(() => done());
});
});
it('should be able to get PII via API with object using master key', (done) => {
Parse.User.logOut()
.then(() => {
const userObj = new (Parse.Object.extend(Parse.User));
userObj.id = user.id;
userObj.fetch({ useMasterKey: true }).then(
fetchedUser => {
expect(fetchedUser.get('email')).toBe(EMAIL);
}, e => console.error('error', e))
.done(() => done());
});
});
it('should be able to get own PII via API with Find', (done) => {
new Parse.Query(Parse.User)
.first()
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(EMAIL);
expect(fetchedUser.get('zip')).toBe(ZIP);
expect(fetchedUser.get('ssn')).toBe(SSN);
done();
});
});
it('should not get PII via API with Find', (done) => {
Parse.User.logOut()
.then(() => new Parse.Query(Parse.User)
.first()
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(undefined);
expect(fetchedUser.get('zip')).toBe(ZIP);
expect(fetchedUser.get('ssn')).toBe(SSN);
done();
})
);
});
it('should get PII via API with Find using master key', (done) => {
Parse.User.logOut()
.then(() => new Parse.Query(Parse.User)
.first({ useMasterKey: true })
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(EMAIL);
expect(fetchedUser.get('zip')).toBe(ZIP);
expect(fetchedUser.get('ssn')).toBe(SSN);
done();
})
);
});
it('should be able to get own PII via API with Get', (done) => {
new Parse.Query(Parse.User)
.get(user.id)
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(EMAIL);
expect(fetchedUser.get('zip')).toBe(ZIP);
expect(fetchedUser.get('ssn')).toBe(SSN);
done();
});
});
it('should not get PII via API with Get', (done) => {
Parse.User.logOut()
.then(() => new Parse.Query(Parse.User)
.get(user.id)
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(undefined);
expect(fetchedUser.get('zip')).toBe(ZIP);
expect(fetchedUser.get('ssn')).toBe(SSN);
done();
})
);
});
it('should get PII via API with Get using master key', (done) => {
Parse.User.logOut()
.then(() => new Parse.Query(Parse.User)
.get(user.id, { useMasterKey: true })
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(EMAIL);
expect(fetchedUser.get('zip')).toBe(ZIP);
expect(fetchedUser.get('ssn')).toBe(SSN);
done();
})
);
});
it('should not get PII via REST', (done) => {
request.get({
url: 'http://localhost:8378/1/classes/_User',
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Javascript-Key': 'test'
}
})
.then(
result => {
const fetchedUser = result.results[0];
expect(fetchedUser.zip).toBe(ZIP);
expect(fetchedUser.email).toBe(undefined);
},
e => console.error('error', e.message)
).done(() => done());
});
it('should get PII via REST with self credentials', (done) => {
request.get({
url: 'http://localhost:8378/1/classes/_User',
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Javascript-Key': 'test',
'X-Parse-Session-Token': user.getSessionToken()
}
})
.then(
result => {
const fetchedUser = result.results[0];
expect(fetchedUser.zip).toBe(ZIP);
expect(fetchedUser.email).toBe(EMAIL);
},
e => console.error('error', e.message)
).done(() => done());
});
it('should get PII via REST using master key', (done) => {
request.get({
url: 'http://localhost:8378/1/classes/_User',
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Master-Key': 'test'
}
})
.then(
result => {
const fetchedUser = result.results[0];
expect(fetchedUser.zip).toBe(ZIP);
expect(fetchedUser.email).toBe(EMAIL);
},
e => console.error('error', e.message)
).done(() => done());
});
it('should not get PII via REST by ID', (done) => {
request.get({
url: `http://localhost:8378/1/classes/_User/${user.id}`,
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Javascript-Key': 'test'
}
})
.then(
result => {
const fetchedUser = result;
expect(fetchedUser.zip).toBe(ZIP);
expect(fetchedUser.email).toBe(undefined);
},
e => console.error('error', e.message)
).done(() => done());
});
it('should get PII via REST by ID with self credentials', (done) => {
request.get({
url: `http://localhost:8378/1/classes/_User/${user.id}`,
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Javascript-Key': 'test',
'X-Parse-Session-Token': user.getSessionToken()
}
})
.then(
result => {
const fetchedUser = result;
expect(fetchedUser.zip).toBe(ZIP);
expect(fetchedUser.email).toBe(EMAIL);
},
e => console.error('error', e.message)
).done(() => done());
});
it('should get PII via REST by ID with master key', (done) => {
request.get({
url: `http://localhost:8378/1/classes/_User/${user.id}`,
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Javascript-Key': 'test',
'X-Parse-Master-Key': 'test',
}
})
.then(
result => {
const fetchedUser = result;
expect(fetchedUser.zip).toBe(ZIP);
expect(fetchedUser.email).toBe(EMAIL);
},
e => console.error('error', e.message)
).done(() => done());
});
describe('with configured sensitive fields', () => {
beforeEach((done) => {
reconfigureServer({ userSensitiveFields: ['ssn', 'zip'] })
.then(() => done());
});
it('should be able to get own PII via API with object', (done) => {
const userObj = new (Parse.Object.extend(Parse.User));
userObj.id = user.id;
userObj.fetch().then(
fetchedUser => {
expect(fetchedUser.get('email')).toBe(EMAIL);
expect(fetchedUser.get('zip')).toBe(ZIP);
expect(fetchedUser.get('ssn')).toBe(SSN);
done();
}, e => done.fail(e));
});
it('should not be able to get PII via API with object', (done) => {
Parse.User.logOut()
.then(() => {
const userObj = new (Parse.Object.extend(Parse.User));
userObj.id = user.id;
userObj.fetch().then(
fetchedUser => {
expect(fetchedUser.get('email')).toBe(undefined);
expect(fetchedUser.get('zip')).toBe(undefined);
expect(fetchedUser.get('ssn')).toBe(undefined);
}, e => console.error('error', e))
.done(() => done());
});
});
it('should be able to get PII via API with object using master key', (done) => {
Parse.User.logOut()
.then(() => {
const userObj = new (Parse.Object.extend(Parse.User));
userObj.id = user.id;
userObj.fetch({ useMasterKey: true }).then(
fetchedUser => {
expect(fetchedUser.get('email')).toBe(EMAIL);
expect(fetchedUser.get('zip')).toBe(ZIP);
expect(fetchedUser.get('ssn')).toBe(SSN);
}, e => console.error('error', e))
.done(() => done());
});
});
it('should be able to get own PII via API with Find', (done) => {
new Parse.Query(Parse.User)
.first()
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(EMAIL);
expect(fetchedUser.get('zip')).toBe(ZIP);
expect(fetchedUser.get('ssn')).toBe(SSN);
done();
});
});
it('should not get PII via API with Find', (done) => {
Parse.User.logOut()
.then(() => new Parse.Query(Parse.User)
.first()
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(undefined);
expect(fetchedUser.get('zip')).toBe(undefined);
expect(fetchedUser.get('ssn')).toBe(undefined);
done();
})
);
});
it('should get PII via API with Find using master key', (done) => {
Parse.User.logOut()
.then(() => new Parse.Query(Parse.User)
.first({ useMasterKey: true })
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(EMAIL);
expect(fetchedUser.get('zip')).toBe(ZIP);
expect(fetchedUser.get('ssn')).toBe(SSN);
done();
})
);
});
it('should be able to get own PII via API with Get', (done) => {
new Parse.Query(Parse.User)
.get(user.id)
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(EMAIL);
expect(fetchedUser.get('zip')).toBe(ZIP);
expect(fetchedUser.get('ssn')).toBe(SSN);
done();
});
});
it('should not get PII via API with Get', (done) => {
Parse.User.logOut()
.then(() => new Parse.Query(Parse.User)
.get(user.id)
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(undefined);
expect(fetchedUser.get('zip')).toBe(undefined);
expect(fetchedUser.get('ssn')).toBe(undefined);
done();
})
);
});
it('should get PII via API with Get using master key', (done) => {
Parse.User.logOut()
.then(() => new Parse.Query(Parse.User)
.get(user.id, { useMasterKey: true })
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(EMAIL);
expect(fetchedUser.get('zip')).toBe(ZIP);
expect(fetchedUser.get('ssn')).toBe(SSN);
done();
})
);
});
it('should not get PII via REST', (done) => {
request.get({
url: 'http://localhost:8378/1/classes/_User',
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Javascript-Key': 'test'
}
})
.then(
result => {
const fetchedUser = result.results[0];
expect(fetchedUser.zip).toBe(undefined);
expect(fetchedUser.ssn).toBe(undefined);
expect(fetchedUser.email).toBe(undefined);
},
e => console.error('error', e.message)
).done(() => done());
});
it('should get PII via REST with self credentials', (done) => {
request.get({
url: 'http://localhost:8378/1/classes/_User',
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Javascript-Key': 'test',
'X-Parse-Session-Token': user.getSessionToken()
}
})
.then(
result => {
const fetchedUser = result.results[0];
expect(fetchedUser.zip).toBe(ZIP);
expect(fetchedUser.email).toBe(EMAIL);
expect(fetchedUser.ssn).toBe(SSN);
},
e => console.error('error', e.message)
).done(() => done());
});
it('should get PII via REST using master key', (done) => {
request.get({
url: 'http://localhost:8378/1/classes/_User',
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Master-Key': 'test'
}
})
.then(
result => {
const fetchedUser = result.results[0];
expect(fetchedUser.zip).toBe(ZIP);
expect(fetchedUser.email).toBe(EMAIL);
expect(fetchedUser.ssn).toBe(SSN);
},
e => console.error('error', e.message)
).done(() => done());
});
it('should not get PII via REST by ID', (done) => {
request.get({
url: `http://localhost:8378/1/classes/_User/${user.id}`,
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Javascript-Key': 'test'
}
})
.then(
result => {
const fetchedUser = result;
expect(fetchedUser.zip).toBe(undefined);
expect(fetchedUser.email).toBe(undefined);
},
e => console.error('error', e.message)
).done(() => done());
});
it('should get PII via REST by ID with self credentials', (done) => {
request.get({
url: `http://localhost:8378/1/classes/_User/${user.id}`,
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Javascript-Key': 'test',
'X-Parse-Session-Token': user.getSessionToken()
}
})
.then(
result => {
const fetchedUser = result;
expect(fetchedUser.zip).toBe(ZIP);
expect(fetchedUser.email).toBe(EMAIL);
},
e => console.error('error', e.message)
).done(() => done());
});
it('should get PII via REST by ID with master key', (done) => {
request.get({
url: `http://localhost:8378/1/classes/_User/${user.id}`,
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Javascript-Key': 'test',
'X-Parse-Master-Key': 'test',
}
})
.then(
result => {
const fetchedUser = result;
expect(fetchedUser.zip).toBe(ZIP);
expect(fetchedUser.email).toBe(EMAIL);
},
e => console.error('error', e.message)
).done(() => done());
});
});
});
+15 -13
View File
@@ -1,8 +1,8 @@
"use strict";
let MockEmailAdapterWithOptions = require('./MockEmailAdapterWithOptions');
let request = require('request');
let Config = require("../src/Config");
const MockEmailAdapterWithOptions = require('./MockEmailAdapterWithOptions');
const request = require('request');
const Config = require("../src/Config");
describe("Custom Pages, Email Verification, Password Reset", () => {
it("should set the custom pages", (done) => {
@@ -12,7 +12,8 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
invalidLink: "myInvalidLink",
verifyEmailSuccess: "myVerifyEmailSuccess",
choosePassword: "myChoosePassword",
passwordResetSuccess: "myPasswordResetSuccess"
passwordResetSuccess: "myPasswordResetSuccess",
parseFrameURL: "http://example.com/handle-parse-iframe"
},
publicServerURL: "https://my.public.server.com/1"
})
@@ -22,6 +23,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
expect(config.verifyEmailSuccessURL).toEqual("myVerifyEmailSuccess");
expect(config.choosePasswordURL).toEqual("myChoosePassword");
expect(config.passwordResetSuccessURL).toEqual("myPasswordResetSuccess");
expect(config.parseFrameURL).toEqual("http://example.com/handle-parse-iframe");
expect(config.verifyEmailURL).toEqual("https://my.public.server.com/1/apps/test/verify_email");
expect(config.requestResetPasswordURL).toEqual("https://my.public.server.com/1/apps/test/request_password_reset");
done();
@@ -251,7 +253,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}),
})
.then(() => {
let user = new Parse.User();
const user = new Parse.User();
user.setPassword("asdf");
user.setUsername("zxcv");
user.set("email", "testInvalidConfig@parse.com");
@@ -338,7 +340,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}),
})
.then(() => {
let user = new Parse.User();
const user = new Parse.User();
user.setPassword("asdf");
user.setUsername("zxcv");
user.set("email", "testInvalidConfig@parse.com");
@@ -370,7 +372,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}),
})
.then(() => {
let user = new Parse.User();
const user = new Parse.User();
user.setPassword("asdf");
user.setUsername("zxcv");
user.set("email", "testInvalidConfig@parse.com");
@@ -401,7 +403,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}),
})
.then(() => {
let user = new Parse.User();
const user = new Parse.User();
user.setPassword("asdf");
user.setUsername("zxcv");
user.set("email", "testInvalidConfig@parse.com");
@@ -429,7 +431,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
emailAdapter: undefined,
})
.then(() => {
let user = new Parse.User();
const user = new Parse.User();
user.setPassword("asdf");
user.setUsername("zxcv");
user.set("email", "testInvalidConfig@parse.com");
@@ -461,7 +463,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}),
})
.then(() => {
let user = new Parse.User();
const user = new Parse.User();
user.setPassword("asdf");
user.setUsername("zxcv");
user.set("email", "testInvalidConfig@parse.com");
@@ -480,7 +482,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
});
it('succeeds sending a password reset username if appName, publicServerURL, and email adapter are prodvided', done => {
let adapter = MockEmailAdapterWithOptions({
const adapter = MockEmailAdapterWithOptions({
fromAddress: 'parse@example.com',
apiKey: 'k',
domain: 'd',
@@ -500,7 +502,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
emailAdapter: adapter
})
.then(() => {
let user = new Parse.User();
const user = new Parse.User();
user.setPassword("asdf");
user.setUsername("testValidConfig@parse.com");
user.signUp(null)
@@ -819,7 +821,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
expect(response.body).toEqual('Found. Redirecting to http://localhost:8378/1/apps/password_reset_success.html?username=zxcv');
Parse.User.logIn("zxcv", "hello").then(function(){
let config = new Config('test');
const config = new Config('test');
config.database.adapter.find('_User', { fields: {} }, { 'username': 'zxcv' }, { limit: 1 })
.then(results => {
// _perishable_token should be unset after reset password
+4 -4
View File
@@ -60,14 +60,14 @@ describe('verbose logs', () => {
reconfigureServer({ verbose: true })
.then(() => createTestUser())
.then(() => {
let winstonLoggerAdapter = new WinstonLoggerAdapter();
const winstonLoggerAdapter = new WinstonLoggerAdapter();
return winstonLoggerAdapter.query({
from: new Date(Date.now() - 500),
size: 100,
level: 'verbose'
});
}).then((results) => {
let logString = JSON.stringify(results);
const logString = JSON.stringify(results);
expect(logString.match(/\*\*\*\*\*\*\*\*/g).length).not.toBe(0);
expect(logString.match(/moon-y/g)).toBe(null);
@@ -79,13 +79,13 @@ describe('verbose logs', () => {
headers: headers,
url: 'http://localhost:8378/1/login?username=test&password=moon-y'
}, () => {
let winstonLoggerAdapter = new WinstonLoggerAdapter();
const winstonLoggerAdapter = new WinstonLoggerAdapter();
return winstonLoggerAdapter.query({
from: new Date(Date.now() - 500),
size: 100,
level: 'verbose'
}).then((results) => {
let logString = JSON.stringify(results);
const logString = JSON.stringify(results);
expect(logString.match(/\*\*\*\*\*\*\*\*/g).length).not.toBe(0);
expect(logString.match(/moon-y/g)).toBe(null);
done();
+9 -9
View File
@@ -9,35 +9,35 @@ const publicServerURLNaked = 'http://domain.com/';
describe('batch', () => {
it('should return the proper url', () => {
let internalURL = batch.makeBatchRoutingPathFunction(originalURL)('/parse/classes/Object');
const internalURL = batch.makeBatchRoutingPathFunction(originalURL)('/parse/classes/Object');
expect(internalURL).toEqual('/classes/Object');
});
it('should return the proper url same public/local endpoint', () => {
let originalURL = '/parse/batch';
let internalURL = batch.makeBatchRoutingPathFunction(originalURL, serverURL, publicServerURL)('/parse/classes/Object');
const originalURL = '/parse/batch';
const internalURL = batch.makeBatchRoutingPathFunction(originalURL, serverURL, publicServerURL)('/parse/classes/Object');
expect(internalURL).toEqual('/classes/Object');
});
it('should return the proper url with different public/local mount', () => {
let originalURL = '/parse/batch';
let internalURL = batch.makeBatchRoutingPathFunction(originalURL, serverURL1, publicServerURL)('/parse/classes/Object');
const originalURL = '/parse/batch';
const internalURL = batch.makeBatchRoutingPathFunction(originalURL, serverURL1, publicServerURL)('/parse/classes/Object');
expect(internalURL).toEqual('/classes/Object');
});
it('should return the proper url with naked public', () => {
let originalURL = '/batch';
let internalURL = batch.makeBatchRoutingPathFunction(originalURL, serverURL, publicServerURLNaked)('/classes/Object');
const originalURL = '/batch';
const internalURL = batch.makeBatchRoutingPathFunction(originalURL, serverURL, publicServerURLNaked)('/classes/Object');
expect(internalURL).toEqual('/classes/Object');
});
it('should return the proper url with naked local', () => {
let originalURL = '/parse/batch';
let internalURL = batch.makeBatchRoutingPathFunction(originalURL, serverURLNaked, publicServerURL)('/parse/classes/Object');
const originalURL = '/parse/batch';
const internalURL = batch.makeBatchRoutingPathFunction(originalURL, serverURLNaked, publicServerURL)('/parse/classes/Object');
expect(internalURL).toEqual('/classes/Object');
});
+9 -10
View File
@@ -1,11 +1,11 @@
"use strict"
// Sets up a Parse API server for testing.
const SpecReporter = require('jasmine-spec-reporter');
const SpecReporter = require('jasmine-spec-reporter').SpecReporter;
jasmine.DEFAULT_TIMEOUT_INTERVAL = process.env.PARSE_SERVER_TEST_TIMEOUT || 5000;
jasmine.getEnv().clearReporters();
jasmine.getEnv().addReporter(new SpecReporter());
jasmine.getEnv().addReporter(new SpecReporter());
global.on_db = (db, callback, elseCallback) => {
if (process.env.PARSE_SERVER_TEST_DB == db) {
@@ -102,7 +102,7 @@ var defaultConfiguration = {
bundleId: 'bundleId',
}
},
oauth: { // Override the facebook provider
auth: { // Override the facebook provider
facebook: mockFacebook(),
myoauth: {
module: path.resolve(__dirname, "myoauth") // relative path as it's run from src
@@ -114,7 +114,7 @@ if (process.env.PARSE_SERVER_TEST_CACHE === 'redis') {
defaultConfiguration.cacheAdapter = new RedisCacheAdapter();
}
let openConnections = {};
const openConnections = {};
// Set up a default API server for testing with default configuration.
var app = express();
@@ -125,7 +125,7 @@ app.use('/1', () => {
});
var server = app.listen(port);
server.on('connection', connection => {
let key = `${connection.remoteAddress}:${connection.remotePort}`;
const key = `${connection.remoteAddress}:${connection.remotePort}`;
openConnections[key] = connection;
connection.on('close', () => { delete openConnections[key] });
});
@@ -134,7 +134,7 @@ const reconfigureServer = changedConfiguration => {
return new Promise((resolve, reject) => {
server.close(() => {
try {
let newConfiguration = Object.assign({}, defaultConfiguration, changedConfiguration, {
const newConfiguration = Object.assign({}, defaultConfiguration, changedConfiguration, {
__indexBuildCompletionCallbackForTests: indexBuildPromise => indexBuildPromise.then(resolve, reject)
});
cache.clear();
@@ -147,7 +147,7 @@ const reconfigureServer = changedConfiguration => {
});
server = app.listen(port);
server.on('connection', connection => {
let key = `${connection.remoteAddress}:${connection.remotePort}`;
const key = `${connection.remoteAddress}:${connection.remotePort}`;
openConnections[key] = connection;
connection.on('close', () => { delete openConnections[key] });
});
@@ -167,7 +167,7 @@ Parse.serverURL = 'http://localhost:' + port + '/1';
Parse.Promise.disableAPlusCompliant();
// 10 minutes timeout
beforeAll(startDB, 10*60*1000);
beforeAll(startDB, 10 * 60 * 1000);
afterAll(stopDB);
@@ -203,7 +203,7 @@ beforeEach(done => {
});
afterEach(function(done) {
let afterLogOut = () => {
const afterLogOut = () => {
if (Object.keys(openConnections).length > 0) {
fail('There were open connections to the server left after the test finished');
}
@@ -370,7 +370,6 @@ function mockFacebook() {
}
// This is polluting, but, it makes it way easier to directly port old tests.
global.Parse = Parse;
global.TestObject = TestObject;
+4 -4
View File
@@ -207,7 +207,7 @@ describe('server', () => {
it('can create a parse-server v2', done => {
let objId;
let server
let parseServer = ParseServer.ParseServer(Object.assign({},
const parseServer = ParseServer.ParseServer(Object.assign({},
defaultConfiguration, {
appId: "anOtherTestApp",
masterKey: "anOtherTestMasterKey",
@@ -216,16 +216,16 @@ describe('server', () => {
promise
.then(() => {
expect(Parse.applicationId).toEqual("anOtherTestApp");
let app = express();
const app = express();
app.use('/parse', parseServer);
server = app.listen(12667);
let obj = new Parse.Object("AnObject");
const obj = new Parse.Object("AnObject");
return obj.save()
})
.then(obj => {
objId = obj.id;
let q = new Parse.Query("AnObject");
const q = new Parse.Query("AnObject");
return q.first();
})
.then(obj => {
+1 -1
View File
@@ -31,4 +31,4 @@ describe('parsers', () => {
expect(parser(1)).toEqual(true);
expect(parser(2)).toEqual(false);
});
});
});
+10 -10
View File
@@ -7,10 +7,10 @@ var rest = require('../src/rest');
var request = require('request');
var config = new Config('test');
let database = config.database;
const database = config.database;
describe('rest create', () => {
beforeEach(() => {
config = new Config('test');
});
@@ -28,7 +28,7 @@ describe('rest create', () => {
});
it('handles array, object, date', (done) => {
let now = new Date();
const now = new Date();
var obj = {
array: [1, 2, 3],
object: {foo: 'bar'},
@@ -52,23 +52,23 @@ describe('rest create', () => {
});
it('handles object and subdocument', done => {
let obj = { subdoc: {foo: 'bar', wu: 'tan'} };
const obj = { subdoc: {foo: 'bar', wu: 'tan'} };
rest.create(config, auth.nobody(config), 'MyClass', obj)
.then(() => database.adapter.find('MyClass', { fields: {} }, {}, {}))
.then(results => {
expect(results.length).toEqual(1);
let mob = results[0];
const mob = results[0];
expect(typeof mob.subdoc).toBe('object');
expect(mob.subdoc.foo).toBe('bar');
expect(mob.subdoc.wu).toBe('tan');
expect(typeof mob.objectId).toEqual('string');
let obj = { 'subdoc.wu': 'clan' };
const obj = { 'subdoc.wu': 'clan' };
return rest.update(config, auth.nobody(config), 'MyClass', mob.objectId, obj)
})
.then(() => database.adapter.find('MyClass', { fields: {} }, {}, {}))
.then(results => {
expect(results.length).toEqual(1);
let mob = results[0];
const mob = results[0];
expect(typeof mob.subdoc).toBe('object');
expect(mob.subdoc.foo).toBe('bar');
expect(mob.subdoc.wu).toBe('clan');
@@ -267,7 +267,7 @@ describe('rest create', () => {
});
it('stores pointers', done => {
let obj = {
const obj = {
foo: 'bar',
aPointer: {
__type: 'Pointer',
@@ -282,7 +282,7 @@ describe('rest create', () => {
}}, {}, {}))
.then(results => {
expect(results.length).toEqual(1);
let output = results[0];
const output = results[0];
expect(typeof output.foo).toEqual('string');
expect(typeof output._p_aPointer).toEqual('undefined');
expect(output._p_aPointer).toBeUndefined();
@@ -374,7 +374,7 @@ describe('rest create', () => {
var session = r.results[0];
var actual = new Date(session.expiresAt.iso);
var expected = new Date(now.getTime() + (sessionLength*1000));
var expected = new Date(now.getTime() + (sessionLength * 1000));
expect(actual.getFullYear()).toEqual(expected.getFullYear());
expect(actual.getMonth()).toEqual(expected.getMonth());
+60 -60
View File
@@ -23,7 +23,7 @@ var hasAllPODobject = () => {
return obj;
};
let defaultClassLevelPermissions = {
const defaultClassLevelPermissions = {
find: {
'*': true
},
@@ -1008,7 +1008,7 @@ describe('schemas', () => {
it('should fail setting schema permissions with invalid key', done => {
let object = new Parse.Object('AClass');
const object = new Parse.Object('AClass');
object.save().then(() => {
request.put({
url: 'http://localhost:8378/1/schemas/AClass',
@@ -1056,7 +1056,7 @@ describe('schemas', () => {
}
}, (error) => {
expect(error).toEqual(null);
let object = new Parse.Object('AClass');
const object = new Parse.Object('AClass');
object.set('hello', 'world');
return object.save().then(() => {
fail('should not be able to add a field');
@@ -1085,7 +1085,7 @@ describe('schemas', () => {
}
}, (error) => {
expect(error).toEqual(null);
let object = new Parse.Object('AClass');
const object = new Parse.Object('AClass');
object.set('hello', 'world');
return object.save().then(() => {
done();
@@ -1230,7 +1230,7 @@ describe('schemas', () => {
}
return new Promise((resolve, reject) => {
op({
url: 'http://localhost:8378/1/schemas/'+className,
url: 'http://localhost:8378/1/schemas/' + className,
headers: masterKeyHeaders,
json: true,
body: {
@@ -1249,15 +1249,15 @@ describe('schemas', () => {
}
it('validate CLP 1', done => {
let user = new Parse.User();
const user = new Parse.User();
user.setUsername('user');
user.setPassword('user');
let admin = new Parse.User();
const admin = new Parse.User();
admin.setUsername('admin');
admin.setPassword('admin');
let role = new Parse.Role('admin', new Parse.ACL());
const role = new Parse.Role('admin', new Parse.ACL());
setPermissionsOnClass('AClass', {
'find': {
@@ -1270,11 +1270,11 @@ describe('schemas', () => {
return role.save(null, {useMasterKey: true});
}).then(() => {
return Parse.User.logIn('user', 'user').then(() => {
let obj = new Parse.Object('AClass');
const obj = new Parse.Object('AClass');
return obj.save(null, {useMasterKey: true});
})
}).then(() => {
let query = new Parse.Query('AClass');
const query = new Parse.Query('AClass');
return query.find().then(() => {
fail('Use should hot be able to find!')
}, (err) => {
@@ -1283,28 +1283,28 @@ describe('schemas', () => {
})
}).then(() => {
return Parse.User.logIn('admin', 'admin');
}).then( () => {
let query = new Parse.Query('AClass');
}).then(() => {
const query = new Parse.Query('AClass');
return query.find();
}).then((results) => {
expect(results.length).toBe(1);
done();
}).catch( (err) => {
}).catch((err) => {
jfail(err);
done();
})
});
it('validate CLP 2', done => {
let user = new Parse.User();
const user = new Parse.User();
user.setUsername('user');
user.setPassword('user');
let admin = new Parse.User();
const admin = new Parse.User();
admin.setUsername('admin');
admin.setPassword('admin');
let role = new Parse.Role('admin', new Parse.ACL());
const role = new Parse.Role('admin', new Parse.ACL());
setPermissionsOnClass('AClass', {
'find': {
@@ -1317,11 +1317,11 @@ describe('schemas', () => {
return role.save(null, {useMasterKey: true});
}).then(() => {
return Parse.User.logIn('user', 'user').then(() => {
let obj = new Parse.Object('AClass');
const obj = new Parse.Object('AClass');
return obj.save(null, {useMasterKey: true});
})
}).then(() => {
let query = new Parse.Query('AClass');
const query = new Parse.Query('AClass');
return query.find().then(() => {
fail('User should not be able to find!')
}, (err) => {
@@ -1337,7 +1337,7 @@ describe('schemas', () => {
}
}, true);
}).then(() => {
let query = new Parse.Query('AClass');
const query = new Parse.Query('AClass');
return query.find().then((result) => {
expect(result.length).toBe(1);
}, () => {
@@ -1346,28 +1346,28 @@ describe('schemas', () => {
});
}).then(() => {
return Parse.User.logIn('admin', 'admin');
}).then( () => {
let query = new Parse.Query('AClass');
}).then(() => {
const query = new Parse.Query('AClass');
return query.find();
}).then((results) => {
expect(results.length).toBe(1);
done();
}).catch( (err) => {
}).catch((err) => {
jfail(err);
done();
})
});
it('validate CLP 3', done => {
let user = new Parse.User();
const user = new Parse.User();
user.setUsername('user');
user.setPassword('user');
let admin = new Parse.User();
const admin = new Parse.User();
admin.setUsername('admin');
admin.setPassword('admin');
let role = new Parse.Role('admin', new Parse.ACL());
const role = new Parse.Role('admin', new Parse.ACL());
setPermissionsOnClass('AClass', {
'find': {
@@ -1380,11 +1380,11 @@ describe('schemas', () => {
return role.save(null, {useMasterKey: true});
}).then(() => {
return Parse.User.logIn('user', 'user').then(() => {
let obj = new Parse.Object('AClass');
const obj = new Parse.Object('AClass');
return obj.save(null, {useMasterKey: true});
})
}).then(() => {
let query = new Parse.Query('AClass');
const query = new Parse.Query('AClass');
return query.find().then(() => {
fail('User should not be able to find!')
}, (err) => {
@@ -1395,7 +1395,7 @@ describe('schemas', () => {
// delete all CLP
return setPermissionsOnClass('AClass', null, true);
}).then(() => {
let query = new Parse.Query('AClass');
const query = new Parse.Query('AClass');
return query.find().then((result) => {
expect(result.length).toBe(1);
}, () => {
@@ -1404,8 +1404,8 @@ describe('schemas', () => {
});
}).then(() => {
return Parse.User.logIn('admin', 'admin');
}).then( () => {
let query = new Parse.Query('AClass');
}).then(() => {
const query = new Parse.Query('AClass');
return query.find();
}).then((results) => {
expect(results.length).toBe(1);
@@ -1417,15 +1417,15 @@ describe('schemas', () => {
});
it('validate CLP 4', done => {
let user = new Parse.User();
const user = new Parse.User();
user.setUsername('user');
user.setPassword('user');
let admin = new Parse.User();
const admin = new Parse.User();
admin.setUsername('admin');
admin.setPassword('admin');
let role = new Parse.Role('admin', new Parse.ACL());
const role = new Parse.Role('admin', new Parse.ACL());
setPermissionsOnClass('AClass', {
'find': {
@@ -1438,11 +1438,11 @@ describe('schemas', () => {
return role.save(null, {useMasterKey: true});
}).then(() => {
return Parse.User.logIn('user', 'user').then(() => {
let obj = new Parse.Object('AClass');
const obj = new Parse.Object('AClass');
return obj.save(null, {useMasterKey: true});
})
}).then(() => {
let query = new Parse.Query('AClass');
const query = new Parse.Query('AClass');
return query.find().then(() => {
fail('User should not be able to find!')
}, (err) => {
@@ -1461,7 +1461,7 @@ describe('schemas', () => {
return Promise.resolve();
})
}).then(() => {
let query = new Parse.Query('AClass');
const query = new Parse.Query('AClass');
return query.find().then(() => {
fail('User should not be able to find!')
}, (err) => {
@@ -1470,38 +1470,38 @@ describe('schemas', () => {
});
}).then(() => {
return Parse.User.logIn('admin', 'admin');
}).then( () => {
let query = new Parse.Query('AClass');
}).then(() => {
const query = new Parse.Query('AClass');
return query.find();
}).then((results) => {
expect(results.length).toBe(1);
done();
}).catch( (err) => {
}).catch((err) => {
jfail(err);
done();
})
});
it('validate CLP 5', done => {
let user = new Parse.User();
const user = new Parse.User();
user.setUsername('user');
user.setPassword('user');
let user2 = new Parse.User();
const user2 = new Parse.User();
user2.setUsername('user2');
user2.setPassword('user2');
let admin = new Parse.User();
const admin = new Parse.User();
admin.setUsername('admin');
admin.setPassword('admin');
let role = new Parse.Role('admin', new Parse.ACL());
const role = new Parse.Role('admin', new Parse.ACL());
Promise.resolve().then(() => {
return Parse.Object.saveAll([user, user2, admin, role], {useMasterKey: true});
}).then(()=> {
role.relation('users').add(admin);
return role.save(null, {useMasterKey: true}).then(() => {
let perm = {
const perm = {
find: {}
};
// let the user find
@@ -1510,11 +1510,11 @@ describe('schemas', () => {
})
}).then(() => {
return Parse.User.logIn('user', 'user').then(() => {
let obj = new Parse.Object('AClass');
const obj = new Parse.Object('AClass');
return obj.save();
})
}).then(() => {
let query = new Parse.Query('AClass');
const query = new Parse.Query('AClass');
return query.find().then((res) => {
expect(res.length).toEqual(1);
}, () => {
@@ -1523,8 +1523,8 @@ describe('schemas', () => {
})
}).then(() => {
return Parse.User.logIn('admin', 'admin');
}).then( () => {
let query = new Parse.Query('AClass');
}).then(() => {
const query = new Parse.Query('AClass');
return query.find();
}).then(() => {
fail("should not be able to read!");
@@ -1534,8 +1534,8 @@ describe('schemas', () => {
return Promise.resolve();
}).then(() => {
return Parse.User.logIn('user2', 'user2');
}).then( () => {
let query = new Parse.Query('AClass');
}).then(() => {
const query = new Parse.Query('AClass');
return query.find();
}).then(() => {
fail("should not be able to read!");
@@ -1557,13 +1557,13 @@ describe('schemas', () => {
delete: {'*': true},
addField:{'*': true}
}).then(() => {
let obj = new Parse.Object('AnObject');
let anotherObject = new Parse.Object('AnotherObject');
const obj = new Parse.Object('AnObject');
const anotherObject = new Parse.Object('AnotherObject');
return obj.save({
anotherObject
})
}).then(() => {
let query = new Parse.Query('AnObject');
const query = new Parse.Query('AnObject');
query.include('anotherObject');
return query.find();
}).then((res) => {
@@ -1625,11 +1625,11 @@ describe('schemas', () => {
});
it("regression test for #1991", done => {
let user = new Parse.User();
const user = new Parse.User();
user.setUsername('user');
user.setPassword('user');
let role = new Parse.Role('admin', new Parse.ACL());
let obj = new Parse.Object('AnObject');
const role = new Parse.Role('admin', new Parse.ACL());
const obj = new Parse.Object('AnObject');
Parse.Object.saveAll([user, role]).then(() => {
role.relation('users').add(user);
return role.save(null, {useMasterKey: true});
@@ -1648,7 +1648,7 @@ describe('schemas', () => {
}).then(() => {
return obj.destroy();
}).then(() => {
let query = new Parse.Query('AnObject');
const query = new Parse.Query('AnObject');
return query.find();
}).then((results) => {
expect(results.length).toBe(0);
@@ -1661,8 +1661,8 @@ describe('schemas', () => {
});
it('regression test for #2246', done => {
let profile = new Parse.Object('UserProfile');
let user = new Parse.User();
const profile = new Parse.Object('UserProfile');
const user = new Parse.User();
function initialize() {
return user.save({
username: 'user',
@@ -1684,7 +1684,7 @@ describe('schemas', () => {
}).then(() => {
return Parse.User.logIn('user', 'password')
}).then(() => {
let query = new Parse.Query('_User');
const query = new Parse.Query('_User');
query.include('userProfile');
return query.get(user.id);
}).then((user) => {
+12
View File
@@ -0,0 +1,12 @@
module.exports = {
validateAppId: function() {
return Promise.resolve();
},
validateAuthData: function(authData) {
if (authData.token == 'my-token') {
return Promise.resolve();
}
return Promise.reject();
}
}
+14
View File
@@ -0,0 +1,14 @@
module.exports = function(validAuthData) {
return {
validateAppId: function() {
return Promise.resolve();
},
validateAuthData: function(authData) {
if (authData.token == validAuthData.token) {
return Promise.resolve();
}
return Promise.reject();
}
}
}
+7 -7
View File
@@ -11,7 +11,7 @@ export class AccountLockout {
* set _failed_login_count to value
*/
_setFailedLoginCount(value) {
let query = {
const query = {
username: this._user.username
};
@@ -84,8 +84,8 @@ export class AccountLockout {
}
/**
* if the failed login count is greater than the threshold
* then sets lockout expiration to 'currenttime + accountPolicy.duration', i.e., account is locked out for the next 'accountPolicy.duration' minutes
* if the failed login count is greater than the threshold
* then sets lockout expiration to 'currenttime + accountPolicy.duration', i.e., account is locked out for the next 'accountPolicy.duration' minutes
* else do nothing
*/
_setLockoutExpiration() {
@@ -98,7 +98,7 @@ export class AccountLockout {
const now = new Date();
const updateFields = {
_account_lockout_expires_at: Parse._encode(new Date(now.getTime() + this._config.accountLockout.duration*60*1000))
_account_lockout_expires_at: Parse._encode(new Date(now.getTime() + this._config.accountLockout.duration * 60 * 1000))
};
this._config.database.update('_User', query, updateFields)
@@ -147,8 +147,8 @@ export class AccountLockout {
* set and/or increment _failed_login_count
* if _failed_login_count > threshold
* set the _account_lockout_expires_at to current_time + accountPolicy.duration
* else
* do nothing
* else
* do nothing
*/
_handleFailedLoginAttempt() {
return new Promise((resolve, reject) => {
@@ -175,7 +175,7 @@ export class AccountLockout {
if (!this._config.accountLockout) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
this._notLocked()
.then(() => {
+1
View File
@@ -17,6 +17,7 @@ export function loadAdapter(adapter, defaultAdapter, options) {
}
}
} else if (typeof adapter === "string") {
/* eslint-disable */
adapter = require(adapter);
// If it's define as a module, get the default
if (adapter.default) {
+2 -2
View File
@@ -1,6 +1,6 @@
/*eslint no-unused-vars: "off"*/
export class AnalyticsAdapter {
/*
@param parameters: the analytics request body, analytics info will be in the dimensions property
@param req: the original http request
@@ -8,7 +8,7 @@ export class AnalyticsAdapter {
appOpened(parameters, req) {
return Promise.resolve({});
}
/*
@param eventName: the name of the custom eventName
@param parameters: the analytics request body, analytics info will be in the dimensions property
+22
View File
@@ -0,0 +1,22 @@
/*eslint no-unused-vars: "off"*/
export class AuthAdapter {
/*
@param appIds: the specified app ids in the configuration
@param authData: the client provided authData
@returns a promise that resolves if the applicationId is valid
*/
validateAppId(appIds, authData) {
return Promise.resolve({});
}
/*
@param authData: the client provided authData
@param options: additional options
*/
validateAuthData(authData, options) {
return Promise.resolve({});
}
}
export default AuthAdapter;
@@ -36,7 +36,7 @@ OAuth.prototype.send = function(method, path, params, body){
OAuth.prototype.buildRequest = function(method, path, params, body) {
if (path.indexOf("/") != 0) {
path = "/"+path;
path = "/" + path;
}
if (params && Object.keys(params).length > 0) {
path += "?" + OAuth.buildParameterString(params);
@@ -118,7 +118,7 @@ OAuth.nonce = function(){
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < 30; i++ )
for(var i = 0; i < 30; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
@@ -162,7 +162,7 @@ OAuth.signRequest = function(request, oauth_parameters, consumer_secret, auth_to
oauth_parameters.oauth_nonce = OAuth.nonce();
}
if (!oauth_parameters.oauth_timestamp) {
oauth_parameters.oauth_timestamp = Math.floor(new Date().getTime()/1000);
oauth_parameters.oauth_timestamp = Math.floor(new Date().getTime() / 1000);
}
if (!oauth_parameters.oauth_signature_method) {
oauth_parameters.oauth_signature_method = OAuth.signatureMethod;
@@ -172,7 +172,7 @@ OAuth.signRequest = function(request, oauth_parameters, consumer_secret, auth_to
}
if(!auth_token_secret){
auth_token_secret="";
auth_token_secret = "";
}
// Force GET method if unset
if (!request.method) {
@@ -193,7 +193,7 @@ OAuth.signRequest = function(request, oauth_parameters, consumer_secret, auth_to
var parameterString = OAuth.buildParameterString(signatureParams);
// Build the signature string
var url = "https://"+request.host+""+request.path;
var url = "https://" + request.host + "" + request.path;
var signatureString = OAuth.buildSignatureString(request.method, url, parameterString);
// Hash the signature string
@@ -210,7 +210,7 @@ OAuth.signRequest = function(request, oauth_parameters, consumer_secret, auth_to
// Set the authorization header
var authHeader = Object.keys(oauth_parameters).sort().map(function(key){
var value = oauth_parameters[key];
return key+'="'+value+'"';
return key + '="' + value + '"';
}).join(", ")
request.headers.Authorization = 'OAuth ' + authHeader;
@@ -221,4 +221,4 @@ OAuth.signRequest = function(request, oauth_parameters, consumer_secret, auth_to
}
module.exports = OAuth;
module.exports = OAuth;
@@ -27,7 +27,7 @@ function request(path, access_token) {
host: 'api.github.com',
path: '/' + path,
headers: {
'Authorization': 'bearer '+access_token,
'Authorization': 'bearer ' + access_token,
'User-Agent': 'parse-server'
}
}, function(res) {
@@ -3,7 +3,7 @@ var https = require('https');
var Parse = require('parse/node').Parse;
function validateIdToken(id, token) {
return request("tokeninfo?id_token="+token)
return request("tokeninfo?id_token=" + token)
.then((response) => {
if (response && (response.sub == id || response.user_id == id)) {
return;
@@ -15,7 +15,7 @@ function validateIdToken(id, token) {
}
function validateAuthToken(id, token) {
return request("tokeninfo?access_token="+token)
return request("tokeninfo?access_token=" + token)
.then((response) => {
if (response && (response.sub == id || response.user_id == id)) {
return;
@@ -29,7 +29,7 @@ function validateAuthToken(id, token) {
// Returns a promise that fulfills if this user id is valid.
function validateAuthData(authData) {
if (authData.id_token) {
return validateIdToken(authData.id, authData.id_token);
return validateIdToken(authData.id, authData.id_token);
} else {
return validateAuthToken(authData.id, authData.access_token).then(() => {
// Validation with auth token worked
+115
View File
@@ -0,0 +1,115 @@
import loadAdapter from '../AdapterLoader';
const facebook = require('./facebook');
const instagram = require("./instagram");
const linkedin = require("./linkedin");
const meetup = require("./meetup");
const google = require("./google");
const github = require("./github");
const twitter = require("./twitter");
const spotify = require("./spotify");
const digits = require("./twitter"); // digits tokens are validated by twitter
const janrainengage = require("./janrainengage");
const janraincapture = require("./janraincapture");
const vkontakte = require("./vkontakte");
const qq = require("./qq");
const wechat = require("./wechat");
const weibo = require("./weibo");
const anonymous = {
validateAuthData: () => {
return Promise.resolve();
},
validateAppId: () => {
return Promise.resolve();
}
}
const providers = {
facebook,
instagram,
linkedin,
meetup,
google,
github,
twitter,
spotify,
anonymous,
digits,
janrainengage,
janraincapture,
vkontakte,
qq,
wechat,
weibo
}
function authDataValidator(adapter, appIds, options) {
return function(authData) {
return adapter.validateAuthData(authData, options).then(() => {
if (appIds) {
return adapter.validateAppId(appIds, authData, options);
}
return Promise.resolve();
});
}
}
function loadAuthAdapter(provider, authOptions) {
const defaultAdapter = providers[provider];
const adapter = Object.assign({}, defaultAdapter);
const providerOptions = authOptions[provider];
if (!defaultAdapter && !providerOptions) {
return;
}
const appIds = providerOptions ? providerOptions.appIds : undefined;
// Try the configuration methods
if (providerOptions) {
const optionalAdapter = loadAdapter(providerOptions, undefined, providerOptions);
if (optionalAdapter) {
['validateAuthData', 'validateAppId'].forEach((key) => {
if (optionalAdapter[key]) {
adapter[key] = optionalAdapter[key];
}
});
}
}
if (!adapter.validateAuthData || !adapter.validateAppId) {
return;
}
return {adapter, appIds, providerOptions};
}
module.exports = function(authOptions = {}, enableAnonymousUsers = true) {
let _enableAnonymousUsers = enableAnonymousUsers;
const setEnableAnonymousUsers = function(enable) {
_enableAnonymousUsers = enable;
}
// To handle the test cases on configuration
const getValidatorForProvider = function(provider) {
if (provider === 'anonymous' && !_enableAnonymousUsers) {
return;
}
const {
adapter,
appIds,
providerOptions
} = loadAuthAdapter(provider, authOptions);
return authDataValidator(adapter, appIds, providerOptions);
}
return Object.freeze({
getValidatorForProvider,
setEnableAnonymousUsers
})
}
module.exports.loadAuthAdapter = loadAuthAdapter;
@@ -4,7 +4,7 @@ var Parse = require('parse/node').Parse;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData) {
return request("users/self/?access_token="+authData.access_token)
return request("users/self/?access_token=" + authData.access_token)
.then((response) => {
if (response && response.data && response.data.id == authData.id) {
return;
@@ -27,7 +27,7 @@ function request(path, access_token) {
host: 'api.meetup.com',
path: '/2/' + path,
headers: {
'Authorization': 'bearer '+access_token
'Authorization': 'bearer ' + access_token
}
}, function(res) {
var data = '';
@@ -26,12 +26,12 @@ function graphRequest(path) {
data += chunk;
});
res.on('end', function () {
var starPos=data.indexOf("(");
var endPos=data.indexOf(")");
if(starPos==-1||endPos==-1){
var starPos = data.indexOf("(");
var endPos = data.indexOf(")");
if(starPos == -1 || endPos == -1){
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'qq auth is invalid for this user.');
}
data=data.substring(starPos+1,endPos-1);
data = data.substring(starPos + 1,endPos - 1);
data = JSON.parse(data);
resolve(data);
});
@@ -41,7 +41,7 @@ function request(path, access_token) {
host: 'api.spotify.com',
path: '/v1/' + path,
headers: {
'Authorization': 'Bearer '+access_token
'Authorization': 'Bearer ' + access_token
}
}, function(res) {
var data = '';
@@ -1,7 +1,7 @@
// Helper functions for accessing the twitter API.
var OAuth = require('./OAuth1Client');
var Parse = require('parse/node').Parse;
var logger = require('../logger').default;
var logger = require('../../logger').default;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData, options) {
@@ -10,9 +10,9 @@ function validateAuthData(authData, options) {
client.host = "api.twitter.com";
client.auth_token = authData.auth_token;
client.auth_token_secret = authData.auth_token_secret;
return client.get("/1.1/account/verify_credentials.json").then((data) => {
if (data && data.id_str == ''+authData.id) {
if (data && data.id_str == '' + authData.id) {
return;
}
throw new Parse.Error(
@@ -28,7 +28,7 @@ function validateAppId() {
function handleMultipleConfigurations(authData, options) {
if (Array.isArray(options)) {
let consumer_key = authData.consumer_key;
const consumer_key = authData.consumer_key;
if (!consumer_key) {
logger.error('Twitter Auth', 'Multiple twitter configurations are available, by no consumer_key was sent by the client.');
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Twitter auth is invalid for this user.');
@@ -4,10 +4,10 @@
var https = require('https');
var Parse = require('parse/node').Parse;
var logger = require('../logger').default;
var logger = require('../../logger').default;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData, params) {
function validateAuthData(authData, params) {
return vkOAuth2Request(params).then(function (response) {
if (response && response && response.access_token) {
return request("api.vk.com", "method/secure.checkToken?token=" + authData.access_token + "&client_secret=" + params.appSecret + "&access_token=" + response.access_token).then(function (response) {
@@ -25,7 +25,7 @@ function validateAuthData(authData, params) {
function vkOAuth2Request(params) {
var promise = new Parse.Promise();
return promise.then(function(){
if (!params || !params.appIds || !params.appIds.length || !params.appSecret || !params.appSecret.length ) {
if (!params || !params.appIds || !params.appIds.length || !params.appSecret || !params.appSecret.length) {
logger.error('Vk Auth', 'Vk auth is not configured. Missing appIds or appSecret.');
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Vk auth is not configured. Missing appIds or appSecret.');
}
@@ -59,4 +59,4 @@ function request(host, path) {
module.exports = {
validateAppId: validateAppId,
validateAuthData: validateAuthData
};
};
@@ -4,7 +4,7 @@ var Parse = require('parse/node').Parse;
// Returns a promise that fulfills iff this user id is valid.
function validateAuthData(authData) {
return graphRequest('auth?access_token=' + authData.access_token +'&openid=' +authData.id).then(function (data) {
return graphRequest('auth?access_token=' + authData.access_token + '&openid=' + authData.id).then(function (data) {
if (data.errcode == 0) {
return;
}
+1 -1
View File
@@ -10,7 +10,7 @@ export class InMemoryCache {
}
get(key) {
let record = this.cache[key];
const record = this.cache[key];
if (record == null) {
return null;
}
+1 -1
View File
@@ -8,7 +8,7 @@ export class InMemoryCacheAdapter {
get(key) {
return new Promise((resolve) => {
let record = this.cache.get(key);
const record = this.cache.get(key);
if (record == null) {
return resolve(null);
}
+1 -1
View File
@@ -71,7 +71,7 @@ export class RedisCacheAdapter {
debug('clear');
this.p = this.p.then(() => {
return new Promise((resolve) => {
this.client.flushall(function() {
this.client.flushdb(function() {
resolve();
});
});
+1 -1
View File
@@ -12,7 +12,7 @@ export class MailAdapter {
* - subject: the subject of the email
*/
sendMail(options) {}
/* You can implement those methods if you want
* to provide HTML templates etc...
*/
+4 -4
View File
@@ -30,7 +30,7 @@ export class GridStoreAdapter extends FilesAdapter {
// Returns a promise
createFile(filename: string, data) {
return this._connect().then(database => {
let gridStore = new GridStore(database, filename, 'w');
const gridStore = new GridStore(database, filename, 'w');
return gridStore.open();
}).then(gridStore => {
return gridStore.write(data);
@@ -41,7 +41,7 @@ export class GridStoreAdapter extends FilesAdapter {
deleteFile(filename: string) {
return this._connect().then(database => {
let gridStore = new GridStore(database, filename, 'r');
const gridStore = new GridStore(database, filename, 'r');
return gridStore.open();
}).then((gridStore) => {
return gridStore.unlink();
@@ -54,7 +54,7 @@ export class GridStoreAdapter extends FilesAdapter {
return this._connect().then(database => {
return GridStore.exist(database, filename)
.then(() => {
let gridStore = new GridStore(database, filename, 'r');
const gridStore = new GridStore(database, filename, 'r');
return gridStore.open();
});
}).then(gridStore => {
@@ -69,7 +69,7 @@ export class GridStoreAdapter extends FilesAdapter {
getFileStream(filename: string) {
return this._connect().then(database => {
return GridStore.exist(database, filename).then(() => {
let gridStore = new GridStore(database, filename, 'r');
const gridStore = new GridStore(database, filename, 'r');
return gridStore.open();
});
});
+6 -6
View File
@@ -9,9 +9,9 @@ const logger = new winston.Logger();
const additionalTransports = [];
function updateTransports(options) {
let transports = Object.assign({}, logger.transports);
const transports = Object.assign({}, logger.transports);
if (options) {
let silent = options.silent;
const silent = options.silent;
delete options.silent;
if (_.isNull(options.dirname)) {
delete transports['parse-server'];
@@ -21,12 +21,12 @@ function updateTransports(options) {
Object.assign({}, {
filename: 'parse-server.info',
name: 'parse-server',
}, options));
}, options, { timestamp: true }));
transports['parse-server-error'] = new (DailyRotateFile)(
Object.assign({}, {
filename: 'parse-server.err',
name: 'parse-server-error',
}, options, { level: 'error'}));
}, options, { level: 'error', timestamp: true }));
}
transports.console = new (winston.transports.Console)(
@@ -84,8 +84,8 @@ export function addTransport(transport) {
}
export function removeTransport(transport) {
let transportName = typeof transport == 'string' ? transport : transport.name;
let transports = Object.assign({}, logger.transports);
const transportName = typeof transport == 'string' ? transport : transport.name;
const transports = Object.assign({}, logger.transports);
delete transports[transportName];
logger.configure({
transports: _.values(transports)
+5 -5
View File
@@ -28,11 +28,11 @@ export class WinstonLoggerAdapter extends LoggerAdapter {
options = {};
}
// defaults to 7 days prior
let from = options.from || new Date(Date.now() - (7 * MILLISECONDS_IN_A_DAY));
let until = options.until || new Date();
let limit = options.size || 10;
let order = options.order || 'desc';
let level = options.level || 'info';
const from = options.from || new Date(Date.now() - (7 * MILLISECONDS_IN_A_DAY));
const until = options.until || new Date();
const limit = options.size || 10;
const order = options.order || 'desc';
const level = options.level || 'info';
const queryOptions = {
from,
@@ -0,0 +1,65 @@
import events from 'events';
const emitter = new events.EventEmitter();
const subscriptions = new Map();
function unsubscribe(channel: string) {
if (!subscriptions.has(channel)) {
//console.log('No channel to unsub from');
return;
}
//console.log('unsub ', channel);
emitter.removeListener(channel, subscriptions.get(channel));
subscriptions.delete(channel);
}
class Publisher {
emitter: any;
constructor(emitter: any) {
this.emitter = emitter;
}
publish(channel: string, message: string): void {
this.emitter.emit(channel, message);
}
}
class Consumer extends events.EventEmitter {
emitter: any;
constructor(emitter: any) {
super();
this.emitter = emitter;
}
subscribe(channel: string): void {
unsubscribe(channel);
const handler = (message) => {
this.emit('message', channel, message);
}
subscriptions.set(channel, handler);
this.emitter.on(channel, handler);
}
unsubscribe(channel: string): void {
unsubscribe(channel);
}
}
function createPublisher(): any {
return new Publisher(emitter);
}
function createSubscriber(): any {
return new Consumer(emitter);
}
const EventEmitterMQ = {
createPublisher,
createSubscriber
}
export {
EventEmitterMQ
}
+3 -3
View File
@@ -1,6 +1,6 @@
import events from 'events';
let emitter = new events.EventEmitter();
const emitter = new events.EventEmitter();
class Publisher {
emitter: any;
@@ -25,7 +25,7 @@ class Subscriber extends events.EventEmitter {
}
subscribe(channel: string): void {
let handler = (message) => {
const handler = (message) => {
this.emit('message', channel, message);
}
this.subscriptions.set(channel, handler);
@@ -49,7 +49,7 @@ function createSubscriber(): any {
return new Subscriber(emitter);
}
let EventEmitterPubSub = {
const EventEmitterPubSub = {
createPublisher,
createSubscriber
}
+5 -2
View File
@@ -1,3 +1,4 @@
// @flow
/*eslint no-unused-vars: "off"*/
// Push Adapter
//
@@ -11,13 +12,15 @@
// android push and APNS for ios push.
export class PushAdapter {
send(devices, installations, pushStatus) { }
send(body: any, installations: any[], pushStatus: any): ?Promise<*> {}
/**
* Get an array of valid push types.
* @returns {Array} An array of valid push types
*/
getValidPushTypes() {}
getValidPushTypes(): string[] {
return []
}
}
export default PushAdapter;
@@ -1,5 +1,5 @@
let mongodb = require('mongodb');
let Collection = mongodb.Collection;
const mongodb = require('mongodb');
const Collection = mongodb.Collection;
export default class MongoCollection {
_mongoCollection:Collection;
@@ -21,7 +21,7 @@ export default class MongoCollection {
throw error;
}
// Figure out what key needs an index
let key = error.message.match(/field=([A-Za-z_0-9]+) /)[1];
const key = error.message.match(/field=([A-Za-z_0-9]+) /)[1];
if (!key) {
throw error;
}
@@ -50,7 +50,7 @@ export default class MongoCollection {
}
count(query, { skip, limit, sort, maxTimeMS } = {}) {
let countOperation = this._mongoCollection.count(query, { skip, limit, sort, maxTimeMS });
const countOperation = this._mongoCollection.count(query, { skip, limit, sort, maxTimeMS });
return countOperation;
}
@@ -73,7 +73,7 @@ function mongoSchemaToParseSchema(mongoSchema) {
}
function _mongoSchemaQueryFromNameQuery(name: string, query) {
let object = { _id: name };
const object = { _id: name };
if (query) {
Object.keys(query).forEach(key => {
object[key] = query[key];
@@ -83,7 +83,6 @@ function _mongoSchemaQueryFromNameQuery(name: string, query) {
}
// Returns a type suitable for inserting into mongo _SCHEMA collection.
// Does no validation. That is expected to be done in Parse Server.
function parseFieldTypeToMongoFieldType({ type, targetClass }) {
@@ -15,8 +15,8 @@ import Parse from 'parse/node';
import _ from 'lodash';
import defaults from '../../../defaults';
let mongodb = require('mongodb');
let MongoClient = mongodb.MongoClient;
const mongodb = require('mongodb');
const MongoClient = mongodb.MongoClient;
const MongoSchemaCollectionName = '_SCHEMA';
@@ -53,14 +53,14 @@ const convertParseSchemaToMongoSchema = ({...schema}) => {
// Returns { code, error } if invalid, or { result }, an object
// suitable for inserting into _SCHEMA collection, otherwise.
const mongoSchemaFromFieldsAndClassNameAndCLP = (fields, className, classLevelPermissions) => {
let mongoObject = {
const mongoObject = {
_id: className,
objectId: 'string',
updatedAt: 'string',
createdAt: 'string'
};
for (let fieldName in fields) {
for (const fieldName in fields) {
mongoObject[fieldName] = MongoSchemaCollection.parseFieldTypeToMongoFieldType(fields[fieldName]);
}
@@ -157,7 +157,7 @@ export class MongoStorageAdapter {
createClass(className, schema) {
schema = convertParseSchemaToMongoSchema(schema);
let mongoObject = mongoSchemaFromFieldsAndClassNameAndCLP(schema.fields, className, schema.classLevelPermissions);
const mongoObject = mongoSchemaFromFieldsAndClassNameAndCLP(schema.fields, className, schema.classLevelPermissions);
mongoObject._id = className;
return this._schemaCollection()
.then(schemaCollection => schemaCollection._collection.insertOne(mongoObject))
@@ -282,7 +282,7 @@ export class MongoStorageAdapter {
schema = convertParseSchemaToMongoSchema(schema);
return this._adaptiveCollection(className)
.then(collection => {
let mongoWhere = transformWhere(className, query, schema);
const mongoWhere = transformWhere(className, query, schema);
return collection.deleteMany(mongoWhere)
})
.then(({ result }) => {
@@ -327,9 +327,9 @@ export class MongoStorageAdapter {
// Executes a find. Accepts: className, query in Parse format, and { skip, limit, sort }.
find(className, schema, query, { skip, limit, sort, keys }) {
schema = convertParseSchemaToMongoSchema(schema);
let mongoWhere = transformWhere(className, query, schema);
let mongoSort = _.mapKeys(sort, (value, fieldName) => transformKey(className, fieldName, schema));
let mongoKeys = _.reduce(keys, (memo, key) => {
const mongoWhere = transformWhere(className, query, schema);
const mongoSort = _.mapKeys(sort, (value, fieldName) => transformKey(className, fieldName, schema));
const mongoKeys = _.reduce(keys, (memo, key) => {
memo[transformKey(className, key, schema)] = 1;
return memo;
}, {});
@@ -351,8 +351,8 @@ export class MongoStorageAdapter {
// which is why we use sparse indexes.
ensureUniqueness(className, schema, fieldNames) {
schema = convertParseSchemaToMongoSchema(schema);
let indexCreationRequest = {};
let mongoFieldNames = fieldNames.map(fieldName => transformKey(className, fieldName, schema));
const indexCreationRequest = {};
const mongoFieldNames = fieldNames.map(fieldName => transformKey(className, fieldName, schema));
mongoFieldNames.forEach(fieldName => {
indexCreationRequest[fieldName] = 1;
});

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