Compare commits

..
443 Commits
Author SHA1 Message Date
semantic-release-bot e0cca580e7 chore(release): 5.2.1-alpha.2 [skip ci]
## [5.2.1-alpha.2](https://github.com/parse-community/parse-server/compare/5.2.1-alpha.1...5.2.1-alpha.2) (2022-03-26)

### Performance Improvements

* reduce database operations when using the constant parameter in Cloud Function validation ([#7892](https://github.com/parse-community/parse-server/issues/7892)) ([48bd512](https://github.com/parse-community/parse-server/commit/48bd512eeb47666967dff8c5e723ddc5b7801daa))
2022-03-26 14:30:48 +00:00
dblythy 48bd512eeb perf: reduce database operations when using the constant parameter in Cloud Function validation (#7892) 2022-03-26 15:29:39 +01:00
semantic-release-bot b3199d7397 chore(release): 5.2.1-alpha.1 [skip ci]
## [5.2.1-alpha.1](https://github.com/parse-community/parse-server/compare/5.2.0...5.2.1-alpha.1) (2022-03-26)

### Bug Fixes

* return correct response when revert is used in beforeSave ([#7839](https://github.com/parse-community/parse-server/issues/7839)) ([f63fb2b](https://github.com/parse-community/parse-server/commit/f63fb2b338c908f0e7a648d338c26b9daa50c8f2))
2022-03-26 02:40:21 +00:00
dblythy f63fb2b338 fix: return correct response when revert is used in beforeSave (#7839) 2022-03-26 03:39:16 +01:00
Manuel 9ef19687ba ci: fix node engine check (#7891) 2022-03-25 19:47:05 +01:00
semantic-release-bot 852bb4782a chore(release): 5.2.0 [skip ci]
# [5.2.0](https://github.com/parse-community/parse-server/compare/5.1.1...5.2.0) (2022-03-24)

### Bug Fixes

* security bump minimist from 1.2.5 to 1.2.6 ([#7884](https://github.com/parse-community/parse-server/issues/7884)) ([c5cf282](https://github.com/parse-community/parse-server/commit/c5cf282d11ffdc023764f8e7539a2bd6bc246fe1))
* sensitive keyword detection may produce false positives ([#7881](https://github.com/parse-community/parse-server/issues/7881)) ([0d6f9e9](https://github.com/parse-community/parse-server/commit/0d6f9e951d9e186e95e96d8869066ce7022bad02))

### Features

* improved LiveQuery error logging with additional information ([#7837](https://github.com/parse-community/parse-server/issues/7837)) ([443a509](https://github.com/parse-community/parse-server/commit/443a5099059538d379fe491793a5871fcbb4f377))
2022-03-24 18:23:57 +00:00
Manuel 9c414804ac build: release 2022-03-24 19:18:30 +01:00
mtrezza ff5b39123b ci: release commit 2022-03-24 18:16:15 +00:00
semantic-release-bot 2aeae76d80 chore(release): 5.2.0-beta.2 [skip ci]
# [5.2.0-beta.2](https://github.com/parse-community/parse-server/compare/5.2.0-beta.1...5.2.0-beta.2) (2022-03-24)

### Bug Fixes

* security bump minimist from 1.2.5 to 1.2.6 ([#7884](https://github.com/parse-community/parse-server/issues/7884)) ([c5cf282](https://github.com/parse-community/parse-server/commit/c5cf282d11ffdc023764f8e7539a2bd6bc246fe1))
* sensitive keyword detection may produce false positives ([#7881](https://github.com/parse-community/parse-server/issues/7881)) ([0d6f9e9](https://github.com/parse-community/parse-server/commit/0d6f9e951d9e186e95e96d8869066ce7022bad02))
2022-03-24 18:13:50 +00:00
Manuel 065141f00e build: release beta 2022-03-24 19:12:47 +01:00
mtrezza 0575952509 ci: release commit 2022-03-24 18:12:13 +00:00
semantic-release-bot bc07a3ff3a chore(release): 5.2.0-alpha.3 [skip ci]
# [5.2.0-alpha.3](https://github.com/parse-community/parse-server/compare/5.2.0-alpha.2...5.2.0-alpha.3) (2022-03-24)

### Bug Fixes

* security bump minimist from 1.2.5 to 1.2.6 ([#7884](https://github.com/parse-community/parse-server/issues/7884)) ([c5cf282](https://github.com/parse-community/parse-server/commit/c5cf282d11ffdc023764f8e7539a2bd6bc246fe1))
2022-03-24 13:42:07 +00:00
dependabot[bot] c5cf282d11 fix: security bump minimist from 1.2.5 to 1.2.6 (#7884) 2022-03-24 14:41:04 +01:00
Manuel e2333ba262 docs: add release instructions to contribution guide (#7885) 2022-03-24 03:33:31 +01:00
semantic-release-bot 892c6f94d5 chore(release): 5.2.0-alpha.2 [skip ci]
# [5.2.0-alpha.2](https://github.com/parse-community/parse-server/compare/5.2.0-alpha.1...5.2.0-alpha.2) (2022-03-24)

### Bug Fixes

* sensitive keyword detection may produce false positives ([#7881](https://github.com/parse-community/parse-server/issues/7881)) ([0d6f9e9](https://github.com/parse-community/parse-server/commit/0d6f9e951d9e186e95e96d8869066ce7022bad02))
2022-03-24 01:55:04 +00:00
Manuel 0d6f9e951d fix: sensitive keyword detection may produce false positives (#7881) 2022-03-24 02:54:07 +01:00
semantic-release-bot 765cfd02dc chore(release): 5.2.0-beta.1 [skip ci]
# [5.2.0-beta.1](https://github.com/parse-community/parse-server/compare/5.1.1...5.2.0-beta.1) (2022-03-23)

### Features

* improved LiveQuery error logging with additional information ([#7837](https://github.com/parse-community/parse-server/issues/7837)) ([443a509](https://github.com/parse-community/parse-server/commit/443a5099059538d379fe491793a5871fcbb4f377))
2022-03-23 01:22:38 +00:00
Manuel ccd3d86137 build: release beta 2022-03-23 02:19:37 +01:00
mtrezza 693d72060d ci: release commit 2022-03-23 01:15:29 +00:00
semantic-release-bot 2b7f772a1b chore(release): 5.2.0-alpha.1 [skip ci]
# [5.2.0-alpha.1](https://github.com/parse-community/parse-server/compare/5.1.1...5.2.0-alpha.1) (2022-03-23)

### Features

* improved LiveQuery error logging with additional information ([#7837](https://github.com/parse-community/parse-server/issues/7837)) ([443a509](https://github.com/parse-community/parse-server/commit/443a5099059538d379fe491793a5871fcbb4f377))
2022-03-23 01:12:46 +00:00
dblythy 443a509905 feat: improved LiveQuery error logging with additional information (#7837) 2022-03-23 02:11:39 +01:00
Manuel 2830021990 build: release 2022-03-23 00:45:30 +01:00
Manuel d2d12d3d69 build: release 2022-03-23 00:39:13 +01:00
Manuel 1099ebbcd8 ci: fix backmerge credentials (#7876) 2022-03-23 00:26:36 +01:00
Manuel 4c50c4d11c ci: add backmerge branches (#7874) 2022-03-23 00:09:49 +01:00
Manuel e9d23830a3 docs: improve reverting in CONTRIBUTION guide (#7866) 2022-03-22 23:21:14 +01:00
semantic-release-bot 01096b360a chore(release): 5.1.1 [skip ci]
## [5.1.1](https://github.com/parse-community/parse-server/compare/5.1.0...5.1.1) (2022-03-18)

### Reverts

* ci: temporarily disable breaking change detection ([#7861](https://github.com/parse-community/parse-server/issues/7861)) ([effed92](https://github.com/parse-community/parse-server/commit/effed92cabd88676fdf9eca2e079a4d8be017f1b))
2022-03-18 15:14:57 +00:00
Manuel effed92cab revert: ci: temporarily disable breaking change detection (#7861)
This reverts commit ef9ee66640.
2022-03-18 16:13:29 +01:00
Manuel 9cdc6ca5b3 docs: update changelog (#7864) 2022-03-18 16:06:49 +01:00
semantic-release-bot 158a974c89 chore(release): 5.1.0 [skip ci]
# [5.1.0](https://github.com/parse-community/parse-server/compare/5.0.0...5.1.0) (2022-03-18)

### Bug Fixes

* adding or modifying a nested property requires addField permissions ([#7679](https://github.com/parse-community/parse-server/issues/7679)) ([6a6248b](https://github.com/parse-community/parse-server/commit/6a6248b6cb2e732d17131e18e659943b894ed2f1))
* bump nanoid from 3.1.25 to 3.2.0 ([#7781](https://github.com/parse-community/parse-server/issues/7781)) ([f5f63bf](https://github.com/parse-community/parse-server/commit/f5f63bfc64d3481ed944ceb5e9f50b33dccd1ce9))
* bump node-fetch from 2.6.1 to 3.1.1 ([#7782](https://github.com/parse-community/parse-server/issues/7782)) ([9082351](https://github.com/parse-community/parse-server/commit/90823514113a1a085ebc818f7109b3fd7591346f))
* node engine compatibility did not include node 16 ([#7739](https://github.com/parse-community/parse-server/issues/7739)) ([ea7c014](https://github.com/parse-community/parse-server/commit/ea7c01400f992a1263543706fe49b6174758a2d6))
* node engine range has no upper limit to exclude incompatible node versions ([#7692](https://github.com/parse-community/parse-server/issues/7692)) ([573558d](https://github.com/parse-community/parse-server/commit/573558d3adcbcc6222c92003829867e1a73eef94))
* package.json & package-lock.json to reduce vulnerabilities ([#7823](https://github.com/parse-community/parse-server/issues/7823)) ([5ca2288](https://github.com/parse-community/parse-server/commit/5ca228882332b65f3ac05407e6e4da1ee3ef3749))
* schema cache not cleared in some cases ([#7678](https://github.com/parse-community/parse-server/issues/7678)) ([5af6e5d](https://github.com/parse-community/parse-server/commit/5af6e5dfaa129b1a350afcba4fb381b21c4cc35d))
* security upgrade follow-redirects from 1.14.6 to 1.14.7 ([#7769](https://github.com/parse-community/parse-server/issues/7769)) ([8f5a861](https://github.com/parse-community/parse-server/commit/8f5a8618cfa7ed9a2a239a095abffa8f3fd8d31a))
* security upgrade follow-redirects from 1.14.7 to 1.14.8 ([#7801](https://github.com/parse-community/parse-server/issues/7801)) ([70088a9](https://github.com/parse-community/parse-server/commit/70088a95a78393da2a4ac68be81e63107747626a))
* security vulnerability that allows remote code execution (GHSA-p6h4-93qp-jhcm) ([#7844](https://github.com/parse-community/parse-server/issues/7844)) ([e569f40](https://github.com/parse-community/parse-server/commit/e569f402b1fd8648fb0d1523b71b2a03273902a5))
* server crash using GraphQL due to missing @apollo/client peer dependency ([#7787](https://github.com/parse-community/parse-server/issues/7787)) ([08089d6](https://github.com/parse-community/parse-server/commit/08089d6fcbb215412448ce7d92b21b9fe6c929f2))
* unable to use objectId size higher than 19 on GraphQL API ([#7627](https://github.com/parse-community/parse-server/issues/7627)) ([ed86c80](https://github.com/parse-community/parse-server/commit/ed86c807721cc52a1a5a9dea0b768717eec269ed))
* upgrade mime from 2.5.2 to 3.0.0 ([#7725](https://github.com/parse-community/parse-server/issues/7725)) ([f5ef98b](https://github.com/parse-community/parse-server/commit/f5ef98bde32083403c0e30a12162fcc1e52cac37))
* upgrade parse from 3.3.1 to 3.4.0 ([#7723](https://github.com/parse-community/parse-server/issues/7723)) ([d4c1f47](https://github.com/parse-community/parse-server/commit/d4c1f473073764cb0570c633fc4a30669c2ce889))
* upgrade winston from 3.5.0 to 3.5.1 ([#7820](https://github.com/parse-community/parse-server/issues/7820)) ([4af253d](https://github.com/parse-community/parse-server/commit/4af253d1f8654a6f57b5137ad310cdacadc922cc))

### Features

* add Cloud Code context to `ParseObject.fetch` ([#7779](https://github.com/parse-community/parse-server/issues/7779)) ([315290d](https://github.com/parse-community/parse-server/commit/315290d16110110938f80a6b779cc2d1db58c552))
* add Idempotency to Postgres ([#7750](https://github.com/parse-community/parse-server/issues/7750)) ([0c3feaa](https://github.com/parse-community/parse-server/commit/0c3feaaa1751964c0db89f25674935c3354b1538))
* add support for Node 16 ([#7707](https://github.com/parse-community/parse-server/issues/7707)) ([45cc58c](https://github.com/parse-community/parse-server/commit/45cc58c7e5e640a46c5d508019a3aa81242964b1))
* bump required node engine to >=12.22.10 ([#7846](https://github.com/parse-community/parse-server/issues/7846)) ([5ace99d](https://github.com/parse-community/parse-server/commit/5ace99d542a11e422af46d9fd6b1d3d2513b34cf))
* support `postgresql` protocol in database URI ([#7757](https://github.com/parse-community/parse-server/issues/7757)) ([caf4a23](https://github.com/parse-community/parse-server/commit/caf4a2341f554b28e3918c53e7e897a3ca47bf8b))
* support relativeTime query constraint on Postgres ([#7747](https://github.com/parse-community/parse-server/issues/7747)) ([16b1b2a](https://github.com/parse-community/parse-server/commit/16b1b2a19714535ca805f2dbb3b561d8f6a519a7))
* upgrade to MongoDB Node.js driver 4.x for MongoDB 5.0 support ([#7794](https://github.com/parse-community/parse-server/issues/7794)) ([f88aa2a](https://github.com/parse-community/parse-server/commit/f88aa2a62a533e5344d1c13dd38c5a0b283a480a))

### Reverts

* refactor: allow ES import for cloud string if package type is module ([b64640c](https://github.com/parse-community/parse-server/commit/b64640c5705f733798783e68d216e957044ef23c))
* update node engine to 2.22.0 ([#7827](https://github.com/parse-community/parse-server/issues/7827)) ([f235412](https://github.com/parse-community/parse-server/commit/f235412c1b6c2b173b7531f285429ea7214b56a2))
2022-03-18 14:48:03 +00:00
Manuel Trezza 1593575a87 build: release 2022-03-18 15:17:12 +01:00
Manuel ef9ee66640 ci: temporarily disable breaking change detection (#7861) 2022-03-18 15:02:41 +01:00
Manuel d5db318db8 ci: temporarily disable braking change detection (#7860) 2022-03-18 14:38:52 +01:00
semantic-release-bot 9fa80eb4ed chore(release): 5.0.0-beta.10 [skip ci]
# [5.0.0-beta.10](https://github.com/parse-community/parse-server/compare/5.0.0-beta.9...5.0.0-beta.10) (2022-03-15)

### Bug Fixes

* adding or modifying a nested property requires addField permissions ([#7679](https://github.com/parse-community/parse-server/issues/7679)) ([6a6248b](https://github.com/parse-community/parse-server/commit/6a6248b6cb2e732d17131e18e659943b894ed2f1))
* bump nanoid from 3.1.25 to 3.2.0 ([#7781](https://github.com/parse-community/parse-server/issues/7781)) ([f5f63bf](https://github.com/parse-community/parse-server/commit/f5f63bfc64d3481ed944ceb5e9f50b33dccd1ce9))
* bump node-fetch from 2.6.1 to 3.1.1 ([#7782](https://github.com/parse-community/parse-server/issues/7782)) ([9082351](https://github.com/parse-community/parse-server/commit/90823514113a1a085ebc818f7109b3fd7591346f))
* node engine compatibility did not include node 16 ([#7739](https://github.com/parse-community/parse-server/issues/7739)) ([ea7c014](https://github.com/parse-community/parse-server/commit/ea7c01400f992a1263543706fe49b6174758a2d6))
* node engine range has no upper limit to exclude incompatible node versions ([#7692](https://github.com/parse-community/parse-server/issues/7692)) ([573558d](https://github.com/parse-community/parse-server/commit/573558d3adcbcc6222c92003829867e1a73eef94))
* package.json & package-lock.json to reduce vulnerabilities ([#7823](https://github.com/parse-community/parse-server/issues/7823)) ([5ca2288](https://github.com/parse-community/parse-server/commit/5ca228882332b65f3ac05407e6e4da1ee3ef3749))
* schema cache not cleared in some cases ([#7678](https://github.com/parse-community/parse-server/issues/7678)) ([5af6e5d](https://github.com/parse-community/parse-server/commit/5af6e5dfaa129b1a350afcba4fb381b21c4cc35d))
* security upgrade follow-redirects from 1.14.6 to 1.14.7 ([#7769](https://github.com/parse-community/parse-server/issues/7769)) ([8f5a861](https://github.com/parse-community/parse-server/commit/8f5a8618cfa7ed9a2a239a095abffa8f3fd8d31a))
* security upgrade follow-redirects from 1.14.7 to 1.14.8 ([#7801](https://github.com/parse-community/parse-server/issues/7801)) ([70088a9](https://github.com/parse-community/parse-server/commit/70088a95a78393da2a4ac68be81e63107747626a))
* security vulnerability that allows remote code execution (GHSA-p6h4-93qp-jhcm) ([#7844](https://github.com/parse-community/parse-server/issues/7844)) ([e569f40](https://github.com/parse-community/parse-server/commit/e569f402b1fd8648fb0d1523b71b2a03273902a5))
* server crash using GraphQL due to missing @apollo/client peer dependency ([#7787](https://github.com/parse-community/parse-server/issues/7787)) ([08089d6](https://github.com/parse-community/parse-server/commit/08089d6fcbb215412448ce7d92b21b9fe6c929f2))
* unable to use objectId size higher than 19 on GraphQL API ([#7627](https://github.com/parse-community/parse-server/issues/7627)) ([ed86c80](https://github.com/parse-community/parse-server/commit/ed86c807721cc52a1a5a9dea0b768717eec269ed))
* upgrade mime from 2.5.2 to 3.0.0 ([#7725](https://github.com/parse-community/parse-server/issues/7725)) ([f5ef98b](https://github.com/parse-community/parse-server/commit/f5ef98bde32083403c0e30a12162fcc1e52cac37))
* upgrade parse from 3.3.1 to 3.4.0 ([#7723](https://github.com/parse-community/parse-server/issues/7723)) ([d4c1f47](https://github.com/parse-community/parse-server/commit/d4c1f473073764cb0570c633fc4a30669c2ce889))
* upgrade winston from 3.5.0 to 3.5.1 ([#7820](https://github.com/parse-community/parse-server/issues/7820)) ([4af253d](https://github.com/parse-community/parse-server/commit/4af253d1f8654a6f57b5137ad310cdacadc922cc))

### Features

* add Cloud Code context to `ParseObject.fetch` ([#7779](https://github.com/parse-community/parse-server/issues/7779)) ([315290d](https://github.com/parse-community/parse-server/commit/315290d16110110938f80a6b779cc2d1db58c552))
* add Idempotency to Postgres ([#7750](https://github.com/parse-community/parse-server/issues/7750)) ([0c3feaa](https://github.com/parse-community/parse-server/commit/0c3feaaa1751964c0db89f25674935c3354b1538))
* add support for Node 16 ([#7707](https://github.com/parse-community/parse-server/issues/7707)) ([45cc58c](https://github.com/parse-community/parse-server/commit/45cc58c7e5e640a46c5d508019a3aa81242964b1))
* bump required node engine to >=12.22.10 ([#7846](https://github.com/parse-community/parse-server/issues/7846)) ([5ace99d](https://github.com/parse-community/parse-server/commit/5ace99d542a11e422af46d9fd6b1d3d2513b34cf))
* support `postgresql` protocol in database URI ([#7757](https://github.com/parse-community/parse-server/issues/7757)) ([caf4a23](https://github.com/parse-community/parse-server/commit/caf4a2341f554b28e3918c53e7e897a3ca47bf8b))
* support relativeTime query constraint on Postgres ([#7747](https://github.com/parse-community/parse-server/issues/7747)) ([16b1b2a](https://github.com/parse-community/parse-server/commit/16b1b2a19714535ca805f2dbb3b561d8f6a519a7))
* upgrade to MongoDB Node.js driver 4.x for MongoDB 5.0 support ([#7794](https://github.com/parse-community/parse-server/issues/7794)) ([f88aa2a](https://github.com/parse-community/parse-server/commit/f88aa2a62a533e5344d1c13dd38c5a0b283a480a))

### Reverts

* refactor: allow ES import for cloud string if package type is module ([b64640c](https://github.com/parse-community/parse-server/commit/b64640c5705f733798783e68d216e957044ef23c))
* update node engine to 2.22.0 ([#7827](https://github.com/parse-community/parse-server/issues/7827)) ([f235412](https://github.com/parse-community/parse-server/commit/f235412c1b6c2b173b7531f285429ea7214b56a2))

### BREAKING CHANGES

* This requires Node.js version >=12.22.10. ([5ace99d](5ace99d))
* The MongoDB GridStore adapter has been removed. By default, Parse Server already uses GridFS, so if you do not manually use the GridStore adapter, you can ignore this change. ([f88aa2a](f88aa2a))
* Removes official Node 15 support which has reached it end-of-life date. ([45cc58c](45cc58c))
2022-03-15 00:13:57 +00:00
Manuel ff16839450 build: release beta 2022-03-15 01:12:57 +01:00
Manuel 0c1b75fcbe Merge branch 'beta' into build-release-beta-19837863611 2022-03-15 00:56:54 +01:00
mtrezza 69781ce0cc ci: release commit 2022-03-14 23:51:23 +00:00
Manuel 2eebc68f21 docs: fix release link in CHANGELOG (#7856) 2022-03-14 18:20:12 +01:00
Manuel 79e00e1dee docs: update changelog (#7855) 2022-03-14 13:57:39 +01:00
semantic-release-bot 46c9a91627 chore(release): 5.0.0 [skip ci]
# [5.0.0](https://github.com/parse-community/parse-server/compare/4.5.0...5.0.0) (2022-03-14)

### Bug Fixes

* add deprecation warning for `Parse.Cloud.httpRequest` ([#7595](https://github.com/parse-community/parse-server/issues/7595)) ([ab1dddd](https://github.com/parse-community/parse-server/commit/ab1dddd406589800e1a8ebe8381b9da702e9c641))
* add support for descending sorting of full text search ([#7496](https://github.com/parse-community/parse-server/issues/7496)) ([8ed9442](https://github.com/parse-community/parse-server/commit/8ed94421e69b1d4fde4ec3625a1f4cfbd6d39c2b))
* allow LiveQuery on Parse.Session ([#7554](https://github.com/parse-community/parse-server/issues/7554)) ([caee281](https://github.com/parse-community/parse-server/commit/caee281bc58901fea7cead21d6a9a0bb2022d91b))
* combined `and` query with relational query condition returns incorrect results ([#7593](https://github.com/parse-community/parse-server/issues/7593)) ([174886e](https://github.com/parse-community/parse-server/commit/174886e385e091c6bbd4a84891ef95f80b50d05c))
* empty file tags cause upload error for some providers ([#7300](https://github.com/parse-community/parse-server/issues/7300)) ([4d16702](https://github.com/parse-community/parse-server/commit/4d167026aebed38bf3a3b74599ab3771d1da3245))
* **Logger:** Handle interpolating stdout ([#7114](https://github.com/parse-community/parse-server/issues/7114)) ([1ede078](https://github.com/parse-community/parse-server/commit/1ede078154213d3426cc492612ce41bdb1eda43b))
* improve security by deprecating creating users with public access by default ([#7319](https://github.com/parse-community/parse-server/issues/7319)) ([484c2e8](https://github.com/parse-community/parse-server/commit/484c2e81cace608eb28508a0926b17b3ba9e6233))
* node engine range has no upper limit to exclude incompatible node versions ([#7693](https://github.com/parse-community/parse-server/issues/7693)) ([6a54dac](https://github.com/parse-community/parse-server/commit/6a54dac24d9fb63a44f311b8d414f4aa64140f32))
* package.json & package-lock.json to reduce vulnerabilities ([#7112](https://github.com/parse-community/parse-server/issues/7112)) ([7b8d8dd](https://github.com/parse-community/parse-server/commit/7b8d8ddbb0de583621a4d2ede95793c6516bc4c0))
* package.json & package-lock.json to reduce vulnerabilities ([#7218](https://github.com/parse-community/parse-server/issues/7218)) ([0476832](https://github.com/parse-community/parse-server/commit/047683219daf7940590db1237f6826a038bdc41d))
* package.json & package-lock.json to reduce vulnerabilities ([#7373](https://github.com/parse-community/parse-server/issues/7373)) ([b6843de](https://github.com/parse-community/parse-server/commit/b6843de904bf273bf664d94536defa39f91751b3))
* package.json & package-lock.json to reduce vulnerabilities ([#7405](https://github.com/parse-community/parse-server/issues/7405)) ([d915bac](https://github.com/parse-community/parse-server/commit/d915bacee7c6ded60b303582d2a6b85d42dc3cf4))
* package.json & package-lock.json to reduce vulnerabilities ([#7423](https://github.com/parse-community/parse-server/issues/7423)) ([bea4707](https://github.com/parse-community/parse-server/commit/bea4707783febc0fc6ea055835ffbc517cd2b067))
* package.json & package-lock.json to reduce vulnerabilities ([#7509](https://github.com/parse-community/parse-server/issues/7509)) ([65c967a](https://github.com/parse-community/parse-server/commit/65c967a4c446aebb535cbbbcb0ceb38d45da7859))
* Pass customObjectId in beforeSave ([#7167](https://github.com/parse-community/parse-server/issues/7167)) ([7224cde](https://github.com/parse-community/parse-server/commit/7224cde0232d79fea0f4b2d0bc2cb7641ec467d8)), closes [#6733](https://github.com/parse-community/parse-server/issues/6733)
* **utils:** permutation helper ([#7355](https://github.com/parse-community/parse-server/issues/7355)) ([91be6bb](https://github.com/parse-community/parse-server/commit/91be6bb59a61c126b7a25431655064342464905c))
* schema cache not cleared in some cases ([#7771](https://github.com/parse-community/parse-server/issues/7771)) ([3b92fa1](https://github.com/parse-community/parse-server/commit/3b92fa1ca9e8889127a32eba913d68309397ca2c))
* security upgrade follow-redirects from 1.14.2 to 1.14.7 ([#7772](https://github.com/parse-community/parse-server/issues/7772)) ([4bd34b1](https://github.com/parse-community/parse-server/commit/4bd34b189bc9f5aa2e70b7e7c1a456e91b6de773))
* security upgrade follow-redirects from 1.14.7 to 1.14.8 ([#7802](https://github.com/parse-community/parse-server/issues/7802)) ([7029b27](https://github.com/parse-community/parse-server/commit/7029b274ca87bc8058617f29865d683dc3b351a1))
* security vulnerability that allows remote code execution (GHSA-p6h4-93qp-jhcm) ([#7843](https://github.com/parse-community/parse-server/issues/7843)) ([971adb5](https://github.com/parse-community/parse-server/commit/971adb54387b0ede31be05ca407d5f35b4575c83))
* set objects in afterFind triggers ([#7311](https://github.com/parse-community/parse-server/issues/7311)) ([68a3a87](https://github.com/parse-community/parse-server/commit/68a3a875017d545253f0438c5d4c1c2b6c6c3b22))
* setting a field to null does not delete it via GraphQL API ([#7649](https://github.com/parse-community/parse-server/issues/7649)) ([626fad2](https://github.com/parse-community/parse-server/commit/626fad2e71017dcc62196c487de5f908fa43000b))
* unable to use objectId size higher than 19 on GraphQL API ([#7722](https://github.com/parse-community/parse-server/issues/7722)) ([8ee0445](https://github.com/parse-community/parse-server/commit/8ee0445c0aeeb88dff2559b46ade408071d22143))
* upgrade @apollographql/graphql-playground-html from 1.6.26 to 1.6.27 ([#7274](https://github.com/parse-community/parse-server/issues/7274)) ([a05e9b1](https://github.com/parse-community/parse-server/commit/a05e9b1c0fee8ad917812637256faa1e0a1b40f6))
* upgrade @apollographql/graphql-playground-html from 1.6.27 to 1.6.28 ([#7411](https://github.com/parse-community/parse-server/issues/7411)) ([c58bf57](https://github.com/parse-community/parse-server/commit/c58bf57f51ebc9df3a624fb3ecdacdf4647f1dea))
* upgrade @apollographql/graphql-playground-html from 1.6.28 to 1.6.29 ([#7473](https://github.com/parse-community/parse-server/issues/7473)) ([39f7c83](https://github.com/parse-community/parse-server/commit/39f7c831e6493cff9cd64195b64e886fda4624f8))
* upgrade @parse/simple-mailgun-adapter from 1.1.0 to 1.2.0 ([#7109](https://github.com/parse-community/parse-server/issues/7109)) ([8ff0d08](https://github.com/parse-community/parse-server/commit/8ff0d08dcf5a9ada931359df3e78543445312f15))
* upgrade apollo-server-express from 2.19.0 to 2.19.1 ([#7122](https://github.com/parse-community/parse-server/issues/7122)) ([33bdd87](https://github.com/parse-community/parse-server/commit/33bdd8709266f17489c319e43b3f2a7d8ea27fd5))
* upgrade apollo-server-express from 2.19.1 to 2.19.2 ([#7165](https://github.com/parse-community/parse-server/issues/7165)) ([4b6e9ff](https://github.com/parse-community/parse-server/commit/4b6e9ffc3d2c1969c285c94f7cf2cfc7af03227e))
* upgrade apollo-server-express from 2.19.2 to 2.20.0 ([#7239](https://github.com/parse-community/parse-server/issues/7239)) ([d10e990](https://github.com/parse-community/parse-server/commit/d10e99007b70816707944060905cff7da5018eb0))
* upgrade apollo-server-express from 2.21.0 to 2.21.1 ([#7308](https://github.com/parse-community/parse-server/issues/7308)) ([3dc4597](https://github.com/parse-community/parse-server/commit/3dc459746dbd4a2d245f2bde688cd087a5b74703))
* upgrade apollo-server-express from 2.21.1 to 2.22.1 ([#7357](https://github.com/parse-community/parse-server/issues/7357)) ([25690ad](https://github.com/parse-community/parse-server/commit/25690ad515551bda33dd581789ffeb9a218c8033))
* upgrade apollo-server-express from 2.22.1 to 2.22.2 ([#7362](https://github.com/parse-community/parse-server/issues/7362)) ([181fbf9](https://github.com/parse-community/parse-server/commit/181fbf9d46bee61b5c67a411b4a41c38d201cc73))
* upgrade apollo-server-express from 2.22.2 to 2.23.0 ([#7380](https://github.com/parse-community/parse-server/issues/7380)) ([87476da](https://github.com/parse-community/parse-server/commit/87476da31e28e064fa7192998c67de9c31ac18a6))
* upgrade apollo-server-express from 2.23.0 to 2.24.0 ([#7395](https://github.com/parse-community/parse-server/issues/7395)) ([ff5755b](https://github.com/parse-community/parse-server/commit/ff5755b05ac554a107a443a8870f4c2442b0a5f3))
* upgrade apollo-server-express from 2.24.0 to 2.24.1 ([#7424](https://github.com/parse-community/parse-server/issues/7424)) ([bfdb6a9](https://github.com/parse-community/parse-server/commit/bfdb6a93e8c0d78524820b32abaff174776520f3))
* upgrade apollo-server-express from 2.24.1 to 2.25.0 ([#7435](https://github.com/parse-community/parse-server/issues/7435)) ([4e5eba6](https://github.com/parse-community/parse-server/commit/4e5eba6c6c7bc6e643ac6477df15beea1ba60364))
* upgrade apollo-server-express from 2.25.0 to 2.25.1 ([#7449](https://github.com/parse-community/parse-server/issues/7449)) ([682f1bf](https://github.com/parse-community/parse-server/commit/682f1bf14388e134fbd993e274f5738ec2e57e02))
* upgrade apollo-server-express from 2.25.1 to 2.25.2 ([#7465](https://github.com/parse-community/parse-server/issues/7465)) ([1fe4708](https://github.com/parse-community/parse-server/commit/1fe47087a92c80e7ee8cc6e3e26b3a67f8df68ee))
* upgrade follow-redirects from 1.13.0 to 1.13.1 ([#7106](https://github.com/parse-community/parse-server/issues/7106)) ([16b4aad](https://github.com/parse-community/parse-server/commit/16b4aadfe2b5b5b24e6e3bbe22c93a92f02c9eb3))
* upgrade follow-redirects from 1.13.1 to 1.13.2 ([#7194](https://github.com/parse-community/parse-server/issues/7194)) ([738ba9f](https://github.com/parse-community/parse-server/commit/738ba9fc704a770bd1e2af23bca31ed7202f99cd))
* upgrade follow-redirects from 1.13.2 to 1.13.3 ([#7285](https://github.com/parse-community/parse-server/issues/7285)) ([d144819](https://github.com/parse-community/parse-server/commit/d144819d21b59b11dc957346748ce3200349a6b7))
* upgrade follow-redirects from 1.13.3 to 1.14.0 ([#7389](https://github.com/parse-community/parse-server/issues/7389)) ([38c01c6](https://github.com/parse-community/parse-server/commit/38c01c6bc32fe769c3a636e45b389e2a995c2ee6))
* upgrade follow-redirects from 1.14.0 to 1.14.1 ([#7408](https://github.com/parse-community/parse-server/issues/7408)) ([8976ecc](https://github.com/parse-community/parse-server/commit/8976ecc4a9c91eeb1d0f3448eff7720b43c7747a))
* upgrade graphql from 15.4.0 to 15.5.0 ([#7201](https://github.com/parse-community/parse-server/issues/7201)) ([5a09687](https://github.com/parse-community/parse-server/commit/5a0968721d6d04cdde86d3df569a77910bcae803))
* upgrade graphql from 15.5.0 to 15.5.1 ([#7462](https://github.com/parse-community/parse-server/issues/7462)) ([bbd7ee7](https://github.com/parse-community/parse-server/commit/bbd7ee7313e19c43b15e16027439739590393dd1))
* upgrade graphql from 15.5.1 to 15.5.2 ([#7587](https://github.com/parse-community/parse-server/issues/7587)) ([dee4d96](https://github.com/parse-community/parse-server/commit/dee4d9662749eb699891c8a3797fa0b0467c6355))
* upgrade graphql from 15.5.2 to 15.5.3 ([#7596](https://github.com/parse-community/parse-server/issues/7596)) ([bcbc035](https://github.com/parse-community/parse-server/commit/bcbc035627c552a7940bec4ae210ca1522215246))
* upgrade graphql from 15.5.3 to 15.6.0 ([#7612](https://github.com/parse-community/parse-server/issues/7612)) ([407ed6e](https://github.com/parse-community/parse-server/commit/407ed6ee36ea42d7eb525f42b1f3da6f41230504))
* upgrade graphql-relay from 0.6.0 to 0.7.0 ([#7443](https://github.com/parse-community/parse-server/issues/7443)) ([770e36f](https://github.com/parse-community/parse-server/commit/770e36ff43c42e4ed3db73a30436079a0460a1f0))
* upgrade graphql-relay from 0.7.0 to 0.8.0 ([#7467](https://github.com/parse-community/parse-server/issues/7467)) ([9923cd3](https://github.com/parse-community/parse-server/commit/9923cd3869ab80e70c5ca9765628ba0a28a6facc))
* upgrade graphql-tag from 2.10.1 to 2.12.0 ([#7234](https://github.com/parse-community/parse-server/issues/7234)) ([add67fd](https://github.com/parse-community/parse-server/commit/add67fdd2284a58386f6afd35edeaa8534579e33))
* upgrade graphql-tag from 2.12.0 to 2.12.1 ([#7282](https://github.com/parse-community/parse-server/issues/7282)) ([36de1db](https://github.com/parse-community/parse-server/commit/36de1db65dc3c2bbf8f8051ee1862a06ef41e7f9))
* upgrade graphql-tag from 2.12.1 to 2.12.2 ([#7325](https://github.com/parse-community/parse-server/issues/7325)) ([50e5557](https://github.com/parse-community/parse-server/commit/50e55571fdaa1ac3ca43d215c4bc62136d684873))
* upgrade graphql-tag from 2.12.2 to 2.12.4 ([#7396](https://github.com/parse-community/parse-server/issues/7396)) ([8099cb0](https://github.com/parse-community/parse-server/commit/8099cb05a48956b073f3e7d96c30b69292c06adc))
* upgrade graphql-tag from 2.12.4 to 2.12.5 ([#7466](https://github.com/parse-community/parse-server/issues/7466)) ([2b3355c](https://github.com/parse-community/parse-server/commit/2b3355cb022724838499a5d83c0d532040953566))
* upgrade jwks-rsa from 1.11.0 to 1.12.0 ([#7102](https://github.com/parse-community/parse-server/issues/7102)) ([029edbf](https://github.com/parse-community/parse-server/commit/029edbf706c4b1754afbb5ce69600a373b91cb9b))
* upgrade jwks-rsa from 1.12.1 to 1.12.2 ([#7147](https://github.com/parse-community/parse-server/issues/7147)) ([bcb2b52](https://github.com/parse-community/parse-server/commit/bcb2b52f7a1322a780b95b77081827d6c8c25840))
* upgrade jwks-rsa from 1.12.2 to 1.12.3 ([#7284](https://github.com/parse-community/parse-server/issues/7284)) ([a53d74c](https://github.com/parse-community/parse-server/commit/a53d74c13b86d43e1694132feddccce6ee2bede9))
* upgrade ldapjs from 2.2.2 to 2.2.3 ([#7095](https://github.com/parse-community/parse-server/issues/7095)) ([fb465e5](https://github.com/parse-community/parse-server/commit/fb465e599e8768b9e229ec8689e033d7063e50b3))
* upgrade ldapjs from 2.2.3 to 2.2.4 ([#7275](https://github.com/parse-community/parse-server/issues/7275)) ([35f0c55](https://github.com/parse-community/parse-server/commit/35f0c55e93dc0572049a85befbc80175620f7d29))
* upgrade ldapjs from 2.2.4 to 2.3.0 ([#7436](https://github.com/parse-community/parse-server/issues/7436)) ([7df6c02](https://github.com/parse-community/parse-server/commit/7df6c020b18b8ea9d04b718fa4e070be800b9268))
* upgrade ldapjs from 2.3.0 to 2.3.1 ([#7524](https://github.com/parse-community/parse-server/issues/7524)) ([dee5a13](https://github.com/parse-community/parse-server/commit/dee5a13a85336cdd9d3bcd938c4118fffe8b9670))
* upgrade mime from 2.4.6 to 2.4.7 ([#7110](https://github.com/parse-community/parse-server/issues/7110)) ([fefcabe](https://github.com/parse-community/parse-server/commit/fefcabe858f3817dca337390c2198abbf12f9bdf))
* upgrade mime from 2.4.7 to 2.5.0 ([#7166](https://github.com/parse-community/parse-server/issues/7166)) ([6097e82](https://github.com/parse-community/parse-server/commit/6097e82194772847954dc2c2b7559543cc7531cc))
* upgrade mime from 2.5.0 to 2.5.2 ([#7261](https://github.com/parse-community/parse-server/issues/7261)) ([687f4b7](https://github.com/parse-community/parse-server/commit/687f4b7cf245ce578674a4cc0e0d276b23d5780d))
* upgrade mongodb from 3.6.6 to 3.6.7 ([#7425](https://github.com/parse-community/parse-server/issues/7425)) ([61affe2](https://github.com/parse-community/parse-server/commit/61affe26293f7218e88878d027514d68975cfc8c))
* upgrade mongodb from 3.6.7 to 3.6.8 ([#7430](https://github.com/parse-community/parse-server/issues/7430)) ([c36588e](https://github.com/parse-community/parse-server/commit/c36588e3c2d16fab3f38aecc77f0e827bda38f95))
* upgrade mongodb from 3.6.8 to 3.6.9 ([#7445](https://github.com/parse-community/parse-server/issues/7445)) ([17cf1a4](https://github.com/parse-community/parse-server/commit/17cf1a46e557b502b132c415b922508e032209a9))
* upgrade mongodb from 3.6.9 to 3.6.10 ([#7474](https://github.com/parse-community/parse-server/issues/7474)) ([45d29cc](https://github.com/parse-community/parse-server/commit/45d29cc58c373c9e1d489dbd7a750f2a0f6bc89b))
* upgrade mustache from 4.1.0 to 4.2.0 ([#7358](https://github.com/parse-community/parse-server/issues/7358)) ([94b7b32](https://github.com/parse-community/parse-server/commit/94b7b320062579e788df6c9f72d7a786f98f7cc5))
* upgrade parse from 3.1.0 to 3.2.0 ([#7378](https://github.com/parse-community/parse-server/issues/7378)) ([e9f54e2](https://github.com/parse-community/parse-server/commit/e9f54e2bddd8430864b1628ab077a0a3aae73e47))
* upgrade pg-promise from 10.10.1 to 10.10.2 ([#7399](https://github.com/parse-community/parse-server/issues/7399)) ([d365f1f](https://github.com/parse-community/parse-server/commit/d365f1f7cb44cfdeac9931308ff25dcd9ba3d79b))
* upgrade pg-promise from 10.10.2 to 10.11.0 ([#7510](https://github.com/parse-community/parse-server/issues/7510)) ([a967e79](https://github.com/parse-community/parse-server/commit/a967e7921961ea7a33ae9ff02555839cecf2b15f))
* upgrade pg-promise from 10.8.1 to 10.8.6 ([#7118](https://github.com/parse-community/parse-server/issues/7118)) ([8851810](https://github.com/parse-community/parse-server/commit/8851810a85747456cd2f3e5d3876371306b8c23d))
* upgrade pg-promise from 10.8.6 to 10.8.7 ([#7148](https://github.com/parse-community/parse-server/issues/7148)) ([231c669](https://github.com/parse-community/parse-server/commit/231c669133eea494f2db7f23fdff2e9d004c9e18))
* upgrade pg-promise from 10.8.7 to 10.9.0 ([#7168](https://github.com/parse-community/parse-server/issues/7168)) ([fcacd4d](https://github.com/parse-community/parse-server/commit/fcacd4d24e34ff48367d2c68bb97743b8a20216c))
* upgrade pg-promise from 10.9.0 to 10.9.1 ([#7170](https://github.com/parse-community/parse-server/issues/7170)) ([cca493b](https://github.com/parse-community/parse-server/commit/cca493b9fb33a4c34eaaf624ec4aedd18b11dca7))
* upgrade pg-promise from 10.9.1 to 10.9.2 ([#7209](https://github.com/parse-community/parse-server/issues/7209)) ([c05102b](https://github.com/parse-community/parse-server/commit/c05102b90c925498459b45c755298cb482ac596c))
* upgrade redis from 3.1.1 to 3.1.2 ([#7387](https://github.com/parse-community/parse-server/issues/7387)) ([f65bd22](https://github.com/parse-community/parse-server/commit/f65bd228fb3491ba217558ec288dd2ee60d0d37d))
* upgrade semver from 7.3.2 to 7.3.4 ([#7092](https://github.com/parse-community/parse-server/issues/7092)) ([7e687b1](https://github.com/parse-community/parse-server/commit/7e687b1e943372d105ca359177824241af278534))
* upgrade subscriptions-transport-ws from 0.9.19 to 0.10.0 ([#7450](https://github.com/parse-community/parse-server/issues/7450)) ([d36a53b](https://github.com/parse-community/parse-server/commit/d36a53b2bfade99942e3c9b827c9abb38d2de26b))
* upgrade uuid from 8.3.1 to 8.3.2 ([#7101](https://github.com/parse-community/parse-server/issues/7101)) ([f17a063](https://github.com/parse-community/parse-server/commit/f17a063209b451da291918dac165e177f0bee6a0))
* upgrade winston-daily-rotate-file from 4.5.0 to 4.5.1 ([#7309](https://github.com/parse-community/parse-server/issues/7309)) ([8643ae4](https://github.com/parse-community/parse-server/commit/8643ae438f1ea48c93d2860889568f9f3a5a62b8))
* upgrade winston-daily-rotate-file from 4.5.1 to 4.5.2 ([#7376](https://github.com/parse-community/parse-server/issues/7376)) ([e143fb1](https://github.com/parse-community/parse-server/commit/e143fb1bf6a52bb21c483fbf72f74d2282cfbeee))
* upgrade winston-daily-rotate-file from 4.5.2 to 4.5.3 ([#7398](https://github.com/parse-community/parse-server/issues/7398)) ([e9d8ed4](https://github.com/parse-community/parse-server/commit/e9d8ed4acb03160c8f6d669859fe57d8281937b4))
* upgrade winston-daily-rotate-file from 4.5.3 to 4.5.4 ([#7402](https://github.com/parse-community/parse-server/issues/7402)) ([4f80a5f](https://github.com/parse-community/parse-server/commit/4f80a5f4afbc008d2f642ee0c581a25483240e9a))
* upgrade winston-daily-rotate-file from 4.5.4 to 4.5.5 ([#7407](https://github.com/parse-community/parse-server/issues/7407)) ([5abbeeb](https://github.com/parse-community/parse-server/commit/5abbeeb8d11be810993c528b8458be894039a5fc))
* upgrade ws from 7.4.0 to 7.4.1 ([#7098](https://github.com/parse-community/parse-server/issues/7098)) ([1068838](https://github.com/parse-community/parse-server/commit/106883809c96a758bb23ae6dd7fff7465fbd8f60))
* upgrade ws from 7.4.1 to 7.4.2 ([#7132](https://github.com/parse-community/parse-server/issues/7132)) ([857d4ec](https://github.com/parse-community/parse-server/commit/857d4ecfd5a383d6debd849a1af1d45820aee0c0))
* upgrade ws from 7.4.2 to 7.4.3 ([#7224](https://github.com/parse-community/parse-server/issues/7224)) ([ec8f784](https://github.com/parse-community/parse-server/commit/ec8f78424f0043fa74ef1f3a7baa96a3d1e95b59))
* upgrade ws from 7.4.3 to 7.4.4 ([#7298](https://github.com/parse-community/parse-server/issues/7298)) ([a080e4c](https://github.com/parse-community/parse-server/commit/a080e4c766c33cc5b5c304bbdba69e93743f9db1))
* upgrade ws from 7.4.4 to 7.4.5 ([#7381](https://github.com/parse-community/parse-server/issues/7381)) ([34f3dd9](https://github.com/parse-community/parse-server/commit/34f3dd9e7e1908b713355ddb235b1e5d02634663))
* upgrade ws from 7.5.3 to 8.2.1 ([#7580](https://github.com/parse-community/parse-server/issues/7580)) ([c3da290](https://github.com/parse-community/parse-server/commit/c3da2908fabfa4f7f49c0f6d5b3d32de692dd388))
* upgrade ws from 8.2.1 to 8.2.2 ([#7598](https://github.com/parse-community/parse-server/issues/7598)) ([20cb333](https://github.com/parse-community/parse-server/commit/20cb3333aba67fb89e4e2cda586c559bdb4a23ef))

### Features

* add support for Postgres 14 ([#7644](https://github.com/parse-community/parse-server/issues/7644)) ([090350a](https://github.com/parse-community/parse-server/commit/090350a7a0fac945394ca1cb24b290316ef06aa7))
* add user-defined schema and migrations ([#7418](https://github.com/parse-community/parse-server/issues/7418)) ([25d5c30](https://github.com/parse-community/parse-server/commit/25d5c30be2111be332eb779eb0697774a17da7af))
* alphabetical graphql api, fix internal reassign, enhanced Graphql schema cache system ([#7344](https://github.com/parse-community/parse-server/issues/7344)) ([85ef721](https://github.com/parse-community/parse-server/commit/85ef7217b04e36395e46316004293e9c8ca67df9))
* bump required node engine to >=12.22.10 ([#7848](https://github.com/parse-community/parse-server/issues/7848)) ([23a3488](https://github.com/parse-community/parse-server/commit/23a3488f15511fafbe0e1d7ff0ef8355f9cb0215))
* **LiveQuery:** Support $and, $nor, $containedBy, $geoWithin ([#7113](https://github.com/parse-community/parse-server/issues/7113)) ([93781b2](https://github.com/parse-community/parse-server/commit/93781b2195d8074032d2c4dfd77a56acf17dc9e1))
* **AggregateRouter:** support native mongodb syntax in aggregation pipelines ([#7339](https://github.com/parse-community/parse-server/issues/7339)) ([8fddac3](https://github.com/parse-community/parse-server/commit/8fddac39bf866886c3b432219acc4d5e8169ddc0))

### Reverts

* refactor: allow ES import for cloud string if package type is module ([#7691](https://github.com/parse-community/parse-server/issues/7691)) ([200d4ba](https://github.com/parse-community/parse-server/commit/200d4ba9a527016a65668738c7728696f443bd53))

### BREAKING CHANGES

* This requires Node.js version >=12.22.10. ([23a3488](23a3488))
* To delete a field via the GraphQL API, the field value has to be set to `null`. Previously, setting a field value to `null` would save a null value in the database, which was not according to the [GraphQL specs](https://spec.graphql.org/June2018/#sec-Null-Value). To delete a file field use `file: null`, the previous way of using `file: { file: null }` has become obsolete. ([626fad2](626fad2))
2022-03-14 12:43:23 +00:00
Manuel 33dcf6dd7b build: release 5.0 2022-03-14 13:42:06 +01:00
Manuel 1f6e19fcce docs: add major release instructions to CONTRIBUTING guide (#7854) 2022-03-13 13:44:24 +01:00
Manuel b2a2a7e1f5 Merge branch 'release' into build-release 2022-03-12 18:45:53 +01:00
Manuel 50072bdd38 ci: add branch name change (#7853) 2022-03-12 18:45:07 +01:00
Manuel 2dceec7359 docs: improve explanation for commit type usage in CONTRIBUTING guide (#7849) 2022-03-12 16:23:25 +01:00
semantic-release-bot f5ef2e9162 chore(release): 5.0.0-beta.9 [skip ci]
# [5.0.0-beta.9](https://github.com/parse-community/parse-server/compare/5.0.0-beta.8...5.0.0-beta.9) (2022-03-12)

### Features

* bump required node engine to >=12.22.10 ([#7848](https://github.com/parse-community/parse-server/issues/7848)) ([23a3488](https://github.com/parse-community/parse-server/commit/23a3488f15511fafbe0e1d7ff0ef8355f9cb0215))

### BREAKING CHANGES

* This requires Node.js version >=12.22.10. ([23a3488](23a3488))
2022-03-12 15:17:00 +00:00
Manuel 23a3488f15 feat: bump required node engine to >=12.22.10 (#7848)
BREAKING CHANGE: This requires Node.js version >=12.22.10.
2022-03-12 16:15:45 +01:00
semantic-release-bot 3e68491df0 chore(release): 5.0.0-alpha.29 [skip ci]
# [5.0.0-alpha.29](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.28...5.0.0-alpha.29) (2022-03-12)

### Features

* bump required node engine to >=12.22.10 ([#7846](https://github.com/parse-community/parse-server/issues/7846)) ([5ace99d](https://github.com/parse-community/parse-server/commit/5ace99d542a11e422af46d9fd6b1d3d2513b34cf))

### BREAKING CHANGES

* This requires Node.js version >=12.22.10. ([5ace99d](5ace99d))
2022-03-12 14:12:38 +00:00
Manuel 5ace99d542 feat: bump required node engine to >=12.22.10 (#7846)
BREAKING CHANGE: This requires Node.js version >=12.22.10.
2022-03-12 15:10:44 +01:00
semantic-release-bot 9b344da9d0 chore(release): 5.0.0-alpha.28 [skip ci]
# [5.0.0-alpha.28](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.27...5.0.0-alpha.28) (2022-03-12)

### Bug Fixes

* security vulnerability that allows remote code execution (GHSA-p6h4-93qp-jhcm) ([#7844](https://github.com/parse-community/parse-server/issues/7844)) ([e569f40](https://github.com/parse-community/parse-server/commit/e569f402b1fd8648fb0d1523b71b2a03273902a5))
2022-03-12 13:48:37 +00:00
Manuel e569f402b1 fix: security vulnerability that allows remote code execution (GHSA-p6h4-93qp-jhcm) (#7844) 2022-03-12 14:47:23 +01:00
Manuel 972b800ae4 docs: add revert commit instructions to CONTRIBUTING guide (#7845) 2022-03-12 14:30:59 +01:00
semantic-release-bot 6bc021ee14 chore(release): 5.0.0-alpha.27 [skip ci]
# [5.0.0-alpha.27](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.26...5.0.0-alpha.27) (2022-03-12)

### Reverts

* update node engine to 2.22.0 ([#7827](https://github.com/parse-community/parse-server/issues/7827)) ([f235412](https://github.com/parse-community/parse-server/commit/f235412c1b6c2b173b7531f285429ea7214b56a2))
2022-03-12 13:14:36 +00:00
Manuel f235412c1b revert: update node engine to 2.22.0 (#7827)
This reverts commit 8a126fc1a2.
2022-03-12 14:13:38 +01:00
semantic-release-bot d35cd47c08 chore(release): 5.0.0-beta.8 [skip ci]
# [5.0.0-beta.8](https://github.com/parse-community/parse-server/compare/5.0.0-beta.7...5.0.0-beta.8) (2022-03-12)

### Bug Fixes

* security vulnerability that allows remote code execution (GHSA-p6h4-93qp-jhcm) ([#7843](https://github.com/parse-community/parse-server/issues/7843)) ([971adb5](https://github.com/parse-community/parse-server/commit/971adb54387b0ede31be05ca407d5f35b4575c83))
2022-03-12 12:50:48 +00:00
Manuel 971adb5438 fix: security vulnerability that allows remote code execution (GHSA-p6h4-93qp-jhcm) (#7843) 2022-03-12 13:49:57 +01:00
Antonio Davi Macedo Coelho de Castro 8a126fc1a2 Update node engine to 2.22.0 (#7827) 2022-02-25 15:01:15 -08:00
semantic-release-bot ad5d17953b chore(release): 5.0.0-alpha.26 [skip ci]
# [5.0.0-alpha.26](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.25...5.0.0-alpha.26) (2022-02-25)

### Bug Fixes

* package.json & package-lock.json to reduce vulnerabilities ([#7823](https://github.com/parse-community/parse-server/issues/7823)) ([5ca2288](https://github.com/parse-community/parse-server/commit/5ca228882332b65f3ac05407e6e4da1ee3ef3749))
2022-02-25 16:57:59 +00:00
Snyk bot 5ca2288823 fix: package.json & package-lock.json to reduce vulnerabilities (#7823)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-NODEFETCH-2342118
2022-02-25 08:56:29 -08:00
semantic-release-bot 9806912045 chore(release): 5.0.0-alpha.25 [skip ci]
# [5.0.0-alpha.25](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.24...5.0.0-alpha.25) (2022-02-23)

### Bug Fixes

* upgrade winston from 3.5.0 to 3.5.1 ([#7820](https://github.com/parse-community/parse-server/issues/7820)) ([4af253d](https://github.com/parse-community/parse-server/commit/4af253d1f8654a6f57b5137ad310cdacadc922cc))
2022-02-23 00:56:33 +00:00
Snyk bot 4af253d1f8 fix: upgrade winston from 3.5.0 to 3.5.1 (#7820) 2022-02-23 01:55:33 +01:00
Snyk bot 2a6cec173e refactor: upgrade winston from 3.4.0 to 3.5.0 (#7817) 2022-02-20 18:26:13 +01:00
Snyk bot c7012012aa refactor: upgrade winston-daily-rotate-file from 4.5.5 to 4.6.0 (#7816) 2022-02-18 21:44:52 +01:00
Snyk bot 8cece4a2a8 refactor: upgrade @apollo/client from 3.5.7 to 3.5.8 (#7814) 2022-02-16 23:48:05 +01:00
Snyk bot 7a30d7c885 refactor: upgrade lru-cache from 5.1.1 to 6.0.0 (#7813) 2022-02-15 12:42:13 +01:00
Snyk bot b6a20d9e9f refactor: upgrade winston from 3.3.3 to 3.4.0 (#7812) 2022-02-14 10:13:35 +01:00
Snyk bot 82c3015dc0 refactor: upgrade @parse/push-adapter from 3.4.1 to 4.1.0 (#7810) 2022-02-13 11:14:57 +01:00
semantic-release-bot a48015c3b0 chore(release): 5.0.0-beta.7 [skip ci]
# [5.0.0-beta.7](https://github.com/parse-community/parse-server/compare/5.0.0-beta.6...5.0.0-beta.7) (2022-02-10)

### Bug Fixes

* security upgrade follow-redirects from 1.14.7 to 1.14.8 ([#7802](https://github.com/parse-community/parse-server/issues/7802)) ([7029b27](https://github.com/parse-community/parse-server/commit/7029b274ca87bc8058617f29865d683dc3b351a1))
2022-02-10 11:12:15 +00:00
semantic-release-bot d678a43696 chore(release): 5.0.0-alpha.24 [skip ci]
# [5.0.0-alpha.24](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.23...5.0.0-alpha.24) (2022-02-10)

### Bug Fixes

* security upgrade follow-redirects from 1.14.7 to 1.14.8 ([#7801](https://github.com/parse-community/parse-server/issues/7801)) ([70088a9](https://github.com/parse-community/parse-server/commit/70088a95a78393da2a4ac68be81e63107747626a))
2022-02-10 11:11:17 +00:00
Snyk bot 7029b274ca fix: security upgrade follow-redirects from 1.14.7 to 1.14.8 (#7802) 2022-02-10 12:11:08 +01:00
Snyk bot 70088a95a7 fix: security upgrade follow-redirects from 1.14.7 to 1.14.8 (#7801) 2022-02-10 12:10:14 +01:00
Snyk bot fc9d77f1d4 refactor: upgrade jwks-rsa from 1.12.3 to 2.0.5 (#7800) 2022-02-09 19:07:53 +01:00
Snyk bot c6b2032039 refactor: upgrade @apollo/client from 3.4.17 to 3.5.7 (#7797) 2022-02-08 11:02:45 +01:00
semantic-release-bot 43cc97d99f chore(release): 5.0.0-alpha.23 [skip ci]
# [5.0.0-alpha.23](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.22...5.0.0-alpha.23) (2022-02-06)

### Bug Fixes

* server crash using GraphQL due to missing @apollo/client peer dependency ([#7787](https://github.com/parse-community/parse-server/issues/7787)) ([08089d6](https://github.com/parse-community/parse-server/commit/08089d6fcbb215412448ce7d92b21b9fe6c929f2))
2022-02-06 23:10:52 +00:00
Antoine Cormouls 08089d6fcb fix: server crash using GraphQL due to missing @apollo/client peer dependency (#7787) 2022-02-07 00:09:41 +01:00
semantic-release-bot 1e05309e79 chore(release): 5.0.0-alpha.22 [skip ci]
# [5.0.0-alpha.22](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.21...5.0.0-alpha.22) (2022-02-06)

### Features

* upgrade to MongoDB Node.js driver 4.x for MongoDB 5.0 support ([#7794](https://github.com/parse-community/parse-server/issues/7794)) ([f88aa2a](https://github.com/parse-community/parse-server/commit/f88aa2a62a533e5344d1c13dd38c5a0b283a480a))

### BREAKING CHANGES

* The MongoDB GridStore adapter has been removed. By default, Parse Server already uses GridFS, so if you do not manually use the GridStore adapter, you can ignore this change. ([f88aa2a](f88aa2a))
2022-02-06 17:31:41 +00:00
Antoine Cormouls f88aa2a62a feat: upgrade to MongoDB Node.js driver 4.x for MongoDB 5.0 support (#7794)
BREAKING CHANGE: The MongoDB GridStore adapter has been removed. By default, Parse Server already uses GridFS, so if you do not manually use the GridStore adapter, you can ignore this change.
2022-02-06 18:30:36 +01:00
semantic-release-bot 1299f0697c chore(release): 5.0.0-alpha.21 [skip ci]
# [5.0.0-alpha.21](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.20...5.0.0-alpha.21) (2022-01-25)

### Features

* add Cloud Code context to `ParseObject.fetch` ([#7779](https://github.com/parse-community/parse-server/issues/7779)) ([315290d](https://github.com/parse-community/parse-server/commit/315290d16110110938f80a6b779cc2d1db58c552))
2022-01-25 11:41:15 +00:00
yog27ray 315290d161 feat: add Cloud Code context to ParseObject.fetch (#7779) 2022-01-25 12:40:22 +01:00
Snyk bot 433e82f1df refactor: upgrade parse from 3.4.0 to 3.4.1 (#7783) 2022-01-25 01:42:55 +01:00
semantic-release-bot 350b59ac5f chore(release): 5.0.0-alpha.20 [skip ci]
# [5.0.0-alpha.20](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.19...5.0.0-alpha.20) (2022-01-22)

### Bug Fixes

* bump node-fetch from 2.6.1 to 3.1.1 ([#7782](https://github.com/parse-community/parse-server/issues/7782)) ([9082351](https://github.com/parse-community/parse-server/commit/90823514113a1a085ebc818f7109b3fd7591346f))
2022-01-22 13:32:51 +00:00
dependabot[bot] 9082351411 fix: bump node-fetch from 2.6.1 to 3.1.1 (#7782) 2022-01-22 14:31:45 +01:00
semantic-release-bot f105d7aef1 chore(release): 5.0.0-alpha.19 [skip ci]
# [5.0.0-alpha.19](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.18...5.0.0-alpha.19) (2022-01-22)

### Bug Fixes

* bump nanoid from 3.1.25 to 3.2.0 ([#7781](https://github.com/parse-community/parse-server/issues/7781)) ([f5f63bf](https://github.com/parse-community/parse-server/commit/f5f63bfc64d3481ed944ceb5e9f50b33dccd1ce9))
2022-01-22 12:59:57 +00:00
dependabot[bot] f5f63bfc64 fix: bump nanoid from 3.1.25 to 3.2.0 (#7781) 2022-01-22 13:54:53 +01:00
Snyk bot 826aa79b9f refactor: upgrade express from 4.17.1 to 4.17.2 (#7776) 2022-01-14 14:22:30 +01:00
semantic-release-bot be37266595 chore(release): 5.0.0-beta.6 [skip ci]
# [5.0.0-beta.6](https://github.com/parse-community/parse-server/compare/5.0.0-beta.5...5.0.0-beta.6) (2022-01-13)

### Bug Fixes

* security upgrade follow-redirects from 1.14.2 to 1.14.7 ([#7772](https://github.com/parse-community/parse-server/issues/7772)) ([4bd34b1](https://github.com/parse-community/parse-server/commit/4bd34b189bc9f5aa2e70b7e7c1a456e91b6de773))
2022-01-13 11:43:30 +00:00
Snyk bot 4bd34b189b fix: security upgrade follow-redirects from 1.14.2 to 1.14.7 (#7772) 2022-01-13 12:42:25 +01:00
semantic-release-bot c720fbba5a chore(release): 5.0.0-alpha.18 [skip ci]
# [5.0.0-alpha.18](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.17...5.0.0-alpha.18) (2022-01-13)

### Bug Fixes

* security upgrade follow-redirects from 1.14.6 to 1.14.7 ([#7769](https://github.com/parse-community/parse-server/issues/7769)) ([8f5a861](https://github.com/parse-community/parse-server/commit/8f5a8618cfa7ed9a2a239a095abffa8f3fd8d31a))
2022-01-13 02:14:07 +00:00
semantic-release-bot f90461e693 chore(release): 5.0.0-beta.5 [skip ci]
# [5.0.0-beta.5](https://github.com/parse-community/parse-server/compare/5.0.0-beta.4...5.0.0-beta.5) (2022-01-13)

### Bug Fixes

* schema cache not cleared in some cases ([#7771](https://github.com/parse-community/parse-server/issues/7771)) ([3b92fa1](https://github.com/parse-community/parse-server/commit/3b92fa1ca9e8889127a32eba913d68309397ca2c))
2022-01-13 02:06:03 +00:00
Snyk bot 8f5a8618cf fix: security upgrade follow-redirects from 1.14.6 to 1.14.7 (#7769) 2022-01-13 03:05:15 +01:00
Manuel 3b92fa1ca9 fix: schema cache not cleared in some cases (#7771) 2022-01-13 03:04:49 +01:00
semantic-release-bot 98abd7112c chore(release): 5.0.0-alpha.17 [skip ci]
# [5.0.0-alpha.17](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.16...5.0.0-alpha.17) (2022-01-13)

### Bug Fixes

* schema cache not cleared in some cases ([#7678](https://github.com/parse-community/parse-server/issues/7678)) ([5af6e5d](https://github.com/parse-community/parse-server/commit/5af6e5dfaa129b1a350afcba4fb381b21c4cc35d))
2022-01-13 01:04:40 +00:00
ThornWu 5af6e5dfaa fix: schema cache not cleared in some cases (#7678) 2022-01-13 02:03:33 +01:00
Corey a5ffb95022 refactor: remove deprecated url.parse() method (#7751) 2022-01-06 15:26:00 +01:00
Corey a43638f300 test: improve transaction tests to use async/await (#7759) 2022-01-04 00:49:43 +01:00
Snyk bot d05fb9f2fa refactor: upgrade graphql from 15.7.0 to 15.7.1 (#7706) 2022-01-03 15:56:55 +01:00
semantic-release-bot 410a1c74fb chore(release): 5.0.0-alpha.16 [skip ci]
# [5.0.0-alpha.16](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.15...5.0.0-alpha.16) (2022-01-02)

### Features

* add Idempotency to Postgres ([#7750](https://github.com/parse-community/parse-server/issues/7750)) ([0c3feaa](https://github.com/parse-community/parse-server/commit/0c3feaaa1751964c0db89f25674935c3354b1538))
2022-01-02 18:26:55 +00:00
Corey 0c3feaaa17 feat: add Idempotency to Postgres (#7750) 2022-01-02 19:25:53 +01:00
Corey 5e363eae44 refactor: remove unnecessary error checking in PostgresAdapter (#7761) 2022-01-02 18:43:12 +01:00
Corey 7af5de4b98 test: improve PushController tests (#7760) 2022-01-02 15:51:49 +01:00
semantic-release-bot 75b9a56e0a chore(release): 5.0.0-alpha.15 [skip ci]
# [5.0.0-alpha.15](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.14...5.0.0-alpha.15) (2022-01-02)

### Features

* support `postgresql` protocol in database URI ([#7757](https://github.com/parse-community/parse-server/issues/7757)) ([caf4a23](https://github.com/parse-community/parse-server/commit/caf4a2341f554b28e3918c53e7e897a3ca47bf8b))
2022-01-02 14:26:36 +00:00
Corey caf4a2341f feat: support postgresql protocol in database URI (#7757) 2022-01-02 15:25:43 +01:00
Corey 912edacb53 test: make GraphQL server test more reliable (#7758) 2022-01-02 14:59:00 +01:00
Corey b106ffc994 ci: test server with PostGIS 3.2 (#7752) 2022-01-02 01:45:00 +01:00
semantic-release-bot acfdc54a06 chore(release): 5.0.0-alpha.14 [skip ci]
# [5.0.0-alpha.14](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.13...5.0.0-alpha.14) (2022-01-02)

### Features

* support relativeTime query constraint on Postgres ([#7747](https://github.com/parse-community/parse-server/issues/7747)) ([16b1b2a](https://github.com/parse-community/parse-server/commit/16b1b2a19714535ca805f2dbb3b561d8f6a519a7))
2022-01-02 00:11:48 +00:00
Corey 16b1b2a197 feat: support relativeTime query constraint on Postgres (#7747) 2022-01-02 01:10:54 +01:00
Snyk bot 7448521cb9 refactor: upgrade body-parser from 1.19.0 to 1.19.1 (#7756) 2022-01-01 21:22:03 +01:00
Snyk bot 9e477591fd refactor: upgrade follow-redirects from 1.14.5 to 1.14.6 (#7755) 2021-12-31 00:38:26 +01:00
semantic-release-bot 191d80b667 chore(release): 5.0.0-alpha.13 [skip ci]
# [5.0.0-alpha.13](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.12...5.0.0-alpha.13) (2021-12-08)

### Bug Fixes

* node engine compatibility did not include node 16 ([#7739](https://github.com/parse-community/parse-server/issues/7739)) ([ea7c014](https://github.com/parse-community/parse-server/commit/ea7c01400f992a1263543706fe49b6174758a2d6))
2021-12-08 10:20:38 +00:00
Manuel ea7c01400f fix: node engine compatibility did not include node 16 (#7739) 2021-12-08 11:19:38 +01:00
semantic-release-bot ac789c8537 chore(release): 5.0.0-alpha.12 [skip ci]
# [5.0.0-alpha.12](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.11...5.0.0-alpha.12) (2021-12-06)

### Bug Fixes

* adding or modifying a nested property requires addField permissions ([#7679](https://github.com/parse-community/parse-server/issues/7679)) ([6a6248b](https://github.com/parse-community/parse-server/commit/6a6248b6cb2e732d17131e18e659943b894ed2f1))
2021-12-06 23:54:00 +00:00
Ben Devore 6a6248b6cb fix: adding or modifying a nested property requires addField permissions (#7679) 2021-12-07 00:52:59 +01:00
semantic-release-bot e7c7f44265 chore(release): 5.0.0-alpha.11 [skip ci]
# [5.0.0-alpha.11](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.10...5.0.0-alpha.11) (2021-11-29)

### Bug Fixes

* upgrade mime from 2.5.2 to 3.0.0 ([#7725](https://github.com/parse-community/parse-server/issues/7725)) ([f5ef98b](https://github.com/parse-community/parse-server/commit/f5ef98bde32083403c0e30a12162fcc1e52cac37))
2021-11-29 23:51:26 +00:00
Snyk bot f5ef98bde3 fix: upgrade mime from 2.5.2 to 3.0.0 (#7725) 2021-11-30 00:50:25 +01:00
semantic-release-bot 37ac29d798 chore(release): 5.0.0-alpha.10 [skip ci]
# [5.0.0-alpha.10](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.9...5.0.0-alpha.10) (2021-11-29)

### Bug Fixes

* upgrade parse from 3.3.1 to 3.4.0 ([#7723](https://github.com/parse-community/parse-server/issues/7723)) ([d4c1f47](https://github.com/parse-community/parse-server/commit/d4c1f473073764cb0570c633fc4a30669c2ce889))
2021-11-29 17:20:43 +00:00
Snyk bot d4c1f47307 fix: upgrade parse from 3.3.1 to 3.4.0 (#7723) 2021-11-29 18:19:48 +01:00
Snyk bot 7dad413a17 refactor: upgrade graphql-tag from 2.12.5 to 2.12.6 (#7726) 2021-11-29 17:58:02 +01:00
Snyk bot 35ac4c3e68 refactor: upgrade subscriptions-transport-ws from 0.10.0 to 0.11.0 (#7727) 2021-11-28 15:44:33 +01:00
semantic-release-bot 66347dc44a chore(release): 5.0.0-beta.4 [skip ci]
# [5.0.0-beta.4](https://github.com/parse-community/parse-server/compare/5.0.0-beta.3...5.0.0-beta.4) (2021-11-27)

### Bug Fixes

* unable to use objectId size higher than 19 on GraphQL API ([#7722](https://github.com/parse-community/parse-server/issues/7722)) ([8ee0445](https://github.com/parse-community/parse-server/commit/8ee0445c0aeeb88dff2559b46ade408071d22143))
2021-11-27 12:37:38 +00:00
Manuel 8ee0445c0a fix: unable to use objectId size higher than 19 on GraphQL API (#7722) 2021-11-27 13:36:49 +01:00
semantic-release-bot 1b4d9324de chore(release): 5.0.0-alpha.9 [skip ci]
# [5.0.0-alpha.9](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.8...5.0.0-alpha.9) (2021-11-27)

### Bug Fixes

* unable to use objectId size higher than 19 on GraphQL API ([#7627](https://github.com/parse-community/parse-server/issues/7627)) ([ed86c80](https://github.com/parse-community/parse-server/commit/ed86c807721cc52a1a5a9dea0b768717eec269ed))
2021-11-27 11:28:15 +00:00
Antoine Cormouls ed86c80772 fix: unable to use objectId size higher than 19 on GraphQL API (#7627) 2021-11-27 12:27:08 +01:00
Corey c789f6c979 refactor: test moved to correct test group (#7717) 2021-11-25 19:16:46 +01:00
Snyk bot 260290409e refactor: upgrade follow-redirects from 1.14.4 to 1.14.5 (#7712) 2021-11-21 14:49:37 +01:00
Manuel 899da8d765 docs: remove node 15 from badge; add node 17 to compatibility table (#7709) 2021-11-18 23:44:10 +01:00
semantic-release-bot fea308a01a chore(release): 5.0.0-alpha.8 [skip ci]
# [5.0.0-alpha.8](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.7...5.0.0-alpha.8) (2021-11-18)

### Features

* add support for Node 16 ([#7707](https://github.com/parse-community/parse-server/issues/7707)) ([45cc58c](https://github.com/parse-community/parse-server/commit/45cc58c7e5e640a46c5d508019a3aa81242964b1))

### BREAKING CHANGES

* Removes official Node 15 support which has reached it end-of-life date. ([45cc58c](45cc58c))
2021-11-18 22:38:42 +00:00
Marvin ROGER 45cc58c7e5 feat: add support for Node 16 (#7707)
BREAKING CHANGE: Removes official Node 15 support which has reached it end-of-life date.
2021-11-18 23:37:47 +01:00
Snyk bot ae99b92809 refactor: upgrade graphql from 15.6.1 to 15.7.0 (#7704) 2021-11-17 13:28:34 +01:00
Snyk bot 251ff0ef71 refactor: upgrade graphql from 15.6.0 to 15.6.1 (#7696) 2021-11-14 04:14:21 +01:00
Snyk bot 426ccdc8f3 refactor: upgrade ws from 8.2.2 to 8.2.3 (#7698) 2021-11-14 03:31:05 +01:00
Snyk bot a2fefde4ba refactor: upgrade pg-promise from 10.11.0 to 10.11.1 (#7697) 2021-11-14 03:14:01 +01:00
Snyk bot 3d7ed8dfac refactor: upgrade @parse/fs-files-adapter from 1.2.0 to 1.2.1 (#7695) 2021-11-13 20:11:52 +01:00
Snyk bot e4aa1cb0a0 refactor: upgrade follow-redirects from 1.14.2 to 1.14.4 (#7694) 2021-11-13 00:47:02 +01:00
semantic-release-bot 2923833b25 chore(release): 5.0.0-beta.3 [skip ci]
# [5.0.0-beta.3](https://github.com/parse-community/parse-server/compare/5.0.0-beta.2...5.0.0-beta.3) (2021-11-12)

### Bug Fixes

* node engine range has no upper limit to exclude incompatible node versions ([#7693](https://github.com/parse-community/parse-server/issues/7693)) ([6a54dac](https://github.com/parse-community/parse-server/commit/6a54dac24d9fb63a44f311b8d414f4aa64140f32))
2021-11-12 18:11:20 +00:00
Manuel 6a54dac24d fix: node engine range has no upper limit to exclude incompatible node versions (#7693) 2021-11-12 19:10:17 +01:00
semantic-release-bot d72717d23a chore(release): 5.0.0-alpha.7 [skip ci]
# [5.0.0-alpha.7](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.6...5.0.0-alpha.7) (2021-11-12)

### Bug Fixes

* node engine range has no upper limit to exclude incompatible node versions ([#7692](https://github.com/parse-community/parse-server/issues/7692)) ([573558d](https://github.com/parse-community/parse-server/commit/573558d3adcbcc6222c92003829867e1a73eef94))
2021-11-12 17:38:15 +00:00
Manuel 573558d3ad fix: node engine range has no upper limit to exclude incompatible node versions (#7692) 2021-11-12 18:37:03 +01:00
semantic-release-bot 32b7194139 chore(release): 5.0.0-beta.2 [skip ci]
# [5.0.0-beta.2](https://github.com/parse-community/parse-server/compare/5.0.0-beta.1...5.0.0-beta.2) (2021-11-10)

### Reverts

* refactor: allow ES import for cloud string if package type is module ([#7691](https://github.com/parse-community/parse-server/issues/7691)) ([200d4ba](https://github.com/parse-community/parse-server/commit/200d4ba9a527016a65668738c7728696f443bd53))
2021-11-10 15:50:43 +00:00
Manuel 200d4ba9a5 revert: refactor: allow ES import for cloud string if package type is module (#7691)
This reverts commit 0225340ccb.
2021-11-10 16:49:47 +01:00
semantic-release-bot d35eeb825e chore(release): 5.0.0-alpha.6 [skip ci]
# [5.0.0-alpha.6](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.5...5.0.0-alpha.6) (2021-11-10)

### Reverts

* refactor: allow ES import for cloud string if package type is module ([b64640c](https://github.com/parse-community/parse-server/commit/b64640c5705f733798783e68d216e957044ef23c))
2021-11-10 15:27:17 +00:00
Manuel b64640c570 revert: refactor: allow ES import for cloud string if package type is module
This reverts commit 0225340ccb.
2021-11-10 16:26:20 +01:00
Corey 611bd9baaa docs: add FS storage to docs (#7681) 2021-11-08 01:30:15 +01:00
Manuel 31960b59b0 docs: fix sponsor links in readme 2021-11-03 23:44:24 +01:00
Manuel 69fd494ab2 docs: add bronze sponsor and add sponsor widgets to README 2021-11-03 23:03:13 +01:00
Manuel Trezza b6a66761f0 docs: enable badge and changelog for beta release 2021-11-01 17:28:37 +01:00
Manuel Trezza 6962bfac65 docs: enable npm beta badge on README 2021-11-01 17:25:20 +01:00
Manuel Trezza e91e388366 docs: fix changelog which was expectedly incorrect on first beta release 2021-11-01 17:23:07 +01:00
semantic-release-bot 4f114068a1 chore(release): 5.0.0-beta.1 [skip ci]
# [5.0.0-beta.1](https://github.com/parse-community/parse-server/compare/4.5.0...5.0.0-beta.1) (2021-11-01)

### Bug Fixes

* add deprecation warning for `Parse.Cloud.httpRequest` ([#7595](https://github.com/parse-community/parse-server/issues/7595)) ([ab1dddd](https://github.com/parse-community/parse-server/commit/ab1dddd406589800e1a8ebe8381b9da702e9c641))
* add support for descending sorting of full text search ([#7496](https://github.com/parse-community/parse-server/issues/7496)) ([8ed9442](https://github.com/parse-community/parse-server/commit/8ed94421e69b1d4fde4ec3625a1f4cfbd6d39c2b))
* allow LiveQuery on Parse.Session ([#7554](https://github.com/parse-community/parse-server/issues/7554)) ([caee281](https://github.com/parse-community/parse-server/commit/caee281bc58901fea7cead21d6a9a0bb2022d91b))
* combined `and` query with relational query condition returns incorrect results ([#7593](https://github.com/parse-community/parse-server/issues/7593)) ([174886e](https://github.com/parse-community/parse-server/commit/174886e385e091c6bbd4a84891ef95f80b50d05c))
* empty file tags cause upload error for some providers ([#7300](https://github.com/parse-community/parse-server/issues/7300)) ([4d16702](https://github.com/parse-community/parse-server/commit/4d167026aebed38bf3a3b74599ab3771d1da3245))
* **Logger:** Handle interpolating stdout ([#7114](https://github.com/parse-community/parse-server/issues/7114)) ([1ede078](https://github.com/parse-community/parse-server/commit/1ede078154213d3426cc492612ce41bdb1eda43b))
* improve security by deprecating creating users with public access by default ([#7319](https://github.com/parse-community/parse-server/issues/7319)) ([484c2e8](https://github.com/parse-community/parse-server/commit/484c2e81cace608eb28508a0926b17b3ba9e6233))
* package.json & package-lock.json to reduce vulnerabilities ([#7112](https://github.com/parse-community/parse-server/issues/7112)) ([7b8d8dd](https://github.com/parse-community/parse-server/commit/7b8d8ddbb0de583621a4d2ede95793c6516bc4c0))
* package.json & package-lock.json to reduce vulnerabilities ([#7218](https://github.com/parse-community/parse-server/issues/7218)) ([0476832](https://github.com/parse-community/parse-server/commit/047683219daf7940590db1237f6826a038bdc41d))
* package.json & package-lock.json to reduce vulnerabilities ([#7373](https://github.com/parse-community/parse-server/issues/7373)) ([b6843de](https://github.com/parse-community/parse-server/commit/b6843de904bf273bf664d94536defa39f91751b3))
* package.json & package-lock.json to reduce vulnerabilities ([#7405](https://github.com/parse-community/parse-server/issues/7405)) ([d915bac](https://github.com/parse-community/parse-server/commit/d915bacee7c6ded60b303582d2a6b85d42dc3cf4))
* package.json & package-lock.json to reduce vulnerabilities ([#7423](https://github.com/parse-community/parse-server/issues/7423)) ([bea4707](https://github.com/parse-community/parse-server/commit/bea4707783febc0fc6ea055835ffbc517cd2b067))
* package.json & package-lock.json to reduce vulnerabilities ([#7509](https://github.com/parse-community/parse-server/issues/7509)) ([65c967a](https://github.com/parse-community/parse-server/commit/65c967a4c446aebb535cbbbcb0ceb38d45da7859))
* Pass customObjectId in beforeSave ([#7167](https://github.com/parse-community/parse-server/issues/7167)) ([7224cde](https://github.com/parse-community/parse-server/commit/7224cde0232d79fea0f4b2d0bc2cb7641ec467d8)), closes [#6733](https://github.com/parse-community/parse-server/issues/6733)
* **utils:** permutation helper ([#7355](https://github.com/parse-community/parse-server/issues/7355)) ([91be6bb](https://github.com/parse-community/parse-server/commit/91be6bb59a61c126b7a25431655064342464905c))
* set objects in afterFind triggers ([#7311](https://github.com/parse-community/parse-server/issues/7311)) ([68a3a87](https://github.com/parse-community/parse-server/commit/68a3a875017d545253f0438c5d4c1c2b6c6c3b22))
* setting a field to null does not delete it via GraphQL API ([#7649](https://github.com/parse-community/parse-server/issues/7649)) ([626fad2](https://github.com/parse-community/parse-server/commit/626fad2e71017dcc62196c487de5f908fa43000b))
* upgrade @apollographql/graphql-playground-html from 1.6.26 to 1.6.27 ([#7274](https://github.com/parse-community/parse-server/issues/7274)) ([a05e9b1](https://github.com/parse-community/parse-server/commit/a05e9b1c0fee8ad917812637256faa1e0a1b40f6))
* upgrade @apollographql/graphql-playground-html from 1.6.27 to 1.6.28 ([#7411](https://github.com/parse-community/parse-server/issues/7411)) ([c58bf57](https://github.com/parse-community/parse-server/commit/c58bf57f51ebc9df3a624fb3ecdacdf4647f1dea))
* upgrade @apollographql/graphql-playground-html from 1.6.28 to 1.6.29 ([#7473](https://github.com/parse-community/parse-server/issues/7473)) ([39f7c83](https://github.com/parse-community/parse-server/commit/39f7c831e6493cff9cd64195b64e886fda4624f8))
* upgrade @parse/simple-mailgun-adapter from 1.1.0 to 1.2.0 ([#7109](https://github.com/parse-community/parse-server/issues/7109)) ([8ff0d08](https://github.com/parse-community/parse-server/commit/8ff0d08dcf5a9ada931359df3e78543445312f15))
* upgrade apollo-server-express from 2.19.0 to 2.19.1 ([#7122](https://github.com/parse-community/parse-server/issues/7122)) ([33bdd87](https://github.com/parse-community/parse-server/commit/33bdd8709266f17489c319e43b3f2a7d8ea27fd5))
* upgrade apollo-server-express from 2.19.1 to 2.19.2 ([#7165](https://github.com/parse-community/parse-server/issues/7165)) ([4b6e9ff](https://github.com/parse-community/parse-server/commit/4b6e9ffc3d2c1969c285c94f7cf2cfc7af03227e))
* upgrade apollo-server-express from 2.19.2 to 2.20.0 ([#7239](https://github.com/parse-community/parse-server/issues/7239)) ([d10e990](https://github.com/parse-community/parse-server/commit/d10e99007b70816707944060905cff7da5018eb0))
* upgrade apollo-server-express from 2.21.0 to 2.21.1 ([#7308](https://github.com/parse-community/parse-server/issues/7308)) ([3dc4597](https://github.com/parse-community/parse-server/commit/3dc459746dbd4a2d245f2bde688cd087a5b74703))
* upgrade apollo-server-express from 2.21.1 to 2.22.1 ([#7357](https://github.com/parse-community/parse-server/issues/7357)) ([25690ad](https://github.com/parse-community/parse-server/commit/25690ad515551bda33dd581789ffeb9a218c8033))
* upgrade apollo-server-express from 2.22.1 to 2.22.2 ([#7362](https://github.com/parse-community/parse-server/issues/7362)) ([181fbf9](https://github.com/parse-community/parse-server/commit/181fbf9d46bee61b5c67a411b4a41c38d201cc73))
* upgrade apollo-server-express from 2.22.2 to 2.23.0 ([#7380](https://github.com/parse-community/parse-server/issues/7380)) ([87476da](https://github.com/parse-community/parse-server/commit/87476da31e28e064fa7192998c67de9c31ac18a6))
* upgrade apollo-server-express from 2.23.0 to 2.24.0 ([#7395](https://github.com/parse-community/parse-server/issues/7395)) ([ff5755b](https://github.com/parse-community/parse-server/commit/ff5755b05ac554a107a443a8870f4c2442b0a5f3))
* upgrade apollo-server-express from 2.24.0 to 2.24.1 ([#7424](https://github.com/parse-community/parse-server/issues/7424)) ([bfdb6a9](https://github.com/parse-community/parse-server/commit/bfdb6a93e8c0d78524820b32abaff174776520f3))
* upgrade apollo-server-express from 2.24.1 to 2.25.0 ([#7435](https://github.com/parse-community/parse-server/issues/7435)) ([4e5eba6](https://github.com/parse-community/parse-server/commit/4e5eba6c6c7bc6e643ac6477df15beea1ba60364))
* upgrade apollo-server-express from 2.25.0 to 2.25.1 ([#7449](https://github.com/parse-community/parse-server/issues/7449)) ([682f1bf](https://github.com/parse-community/parse-server/commit/682f1bf14388e134fbd993e274f5738ec2e57e02))
* upgrade apollo-server-express from 2.25.1 to 2.25.2 ([#7465](https://github.com/parse-community/parse-server/issues/7465)) ([1fe4708](https://github.com/parse-community/parse-server/commit/1fe47087a92c80e7ee8cc6e3e26b3a67f8df68ee))
* upgrade follow-redirects from 1.13.0 to 1.13.1 ([#7106](https://github.com/parse-community/parse-server/issues/7106)) ([16b4aad](https://github.com/parse-community/parse-server/commit/16b4aadfe2b5b5b24e6e3bbe22c93a92f02c9eb3))
* upgrade follow-redirects from 1.13.1 to 1.13.2 ([#7194](https://github.com/parse-community/parse-server/issues/7194)) ([738ba9f](https://github.com/parse-community/parse-server/commit/738ba9fc704a770bd1e2af23bca31ed7202f99cd))
* upgrade follow-redirects from 1.13.2 to 1.13.3 ([#7285](https://github.com/parse-community/parse-server/issues/7285)) ([d144819](https://github.com/parse-community/parse-server/commit/d144819d21b59b11dc957346748ce3200349a6b7))
* upgrade follow-redirects from 1.13.3 to 1.14.0 ([#7389](https://github.com/parse-community/parse-server/issues/7389)) ([38c01c6](https://github.com/parse-community/parse-server/commit/38c01c6bc32fe769c3a636e45b389e2a995c2ee6))
* upgrade follow-redirects from 1.14.0 to 1.14.1 ([#7408](https://github.com/parse-community/parse-server/issues/7408)) ([8976ecc](https://github.com/parse-community/parse-server/commit/8976ecc4a9c91eeb1d0f3448eff7720b43c7747a))
* upgrade graphql from 15.4.0 to 15.5.0 ([#7201](https://github.com/parse-community/parse-server/issues/7201)) ([5a09687](https://github.com/parse-community/parse-server/commit/5a0968721d6d04cdde86d3df569a77910bcae803))
* upgrade graphql from 15.5.0 to 15.5.1 ([#7462](https://github.com/parse-community/parse-server/issues/7462)) ([bbd7ee7](https://github.com/parse-community/parse-server/commit/bbd7ee7313e19c43b15e16027439739590393dd1))
* upgrade graphql from 15.5.1 to 15.5.2 ([#7587](https://github.com/parse-community/parse-server/issues/7587)) ([dee4d96](https://github.com/parse-community/parse-server/commit/dee4d9662749eb699891c8a3797fa0b0467c6355))
* upgrade graphql from 15.5.2 to 15.5.3 ([#7596](https://github.com/parse-community/parse-server/issues/7596)) ([bcbc035](https://github.com/parse-community/parse-server/commit/bcbc035627c552a7940bec4ae210ca1522215246))
* upgrade graphql from 15.5.3 to 15.6.0 ([#7612](https://github.com/parse-community/parse-server/issues/7612)) ([407ed6e](https://github.com/parse-community/parse-server/commit/407ed6ee36ea42d7eb525f42b1f3da6f41230504))
* upgrade graphql-relay from 0.6.0 to 0.7.0 ([#7443](https://github.com/parse-community/parse-server/issues/7443)) ([770e36f](https://github.com/parse-community/parse-server/commit/770e36ff43c42e4ed3db73a30436079a0460a1f0))
* upgrade graphql-relay from 0.7.0 to 0.8.0 ([#7467](https://github.com/parse-community/parse-server/issues/7467)) ([9923cd3](https://github.com/parse-community/parse-server/commit/9923cd3869ab80e70c5ca9765628ba0a28a6facc))
* upgrade graphql-tag from 2.10.1 to 2.12.0 ([#7234](https://github.com/parse-community/parse-server/issues/7234)) ([add67fd](https://github.com/parse-community/parse-server/commit/add67fdd2284a58386f6afd35edeaa8534579e33))
* upgrade graphql-tag from 2.12.0 to 2.12.1 ([#7282](https://github.com/parse-community/parse-server/issues/7282)) ([36de1db](https://github.com/parse-community/parse-server/commit/36de1db65dc3c2bbf8f8051ee1862a06ef41e7f9))
* upgrade graphql-tag from 2.12.1 to 2.12.2 ([#7325](https://github.com/parse-community/parse-server/issues/7325)) ([50e5557](https://github.com/parse-community/parse-server/commit/50e55571fdaa1ac3ca43d215c4bc62136d684873))
* upgrade graphql-tag from 2.12.2 to 2.12.4 ([#7396](https://github.com/parse-community/parse-server/issues/7396)) ([8099cb0](https://github.com/parse-community/parse-server/commit/8099cb05a48956b073f3e7d96c30b69292c06adc))
* upgrade graphql-tag from 2.12.4 to 2.12.5 ([#7466](https://github.com/parse-community/parse-server/issues/7466)) ([2b3355c](https://github.com/parse-community/parse-server/commit/2b3355cb022724838499a5d83c0d532040953566))
* upgrade jwks-rsa from 1.11.0 to 1.12.0 ([#7102](https://github.com/parse-community/parse-server/issues/7102)) ([029edbf](https://github.com/parse-community/parse-server/commit/029edbf706c4b1754afbb5ce69600a373b91cb9b))
* upgrade jwks-rsa from 1.12.1 to 1.12.2 ([#7147](https://github.com/parse-community/parse-server/issues/7147)) ([bcb2b52](https://github.com/parse-community/parse-server/commit/bcb2b52f7a1322a780b95b77081827d6c8c25840))
* upgrade jwks-rsa from 1.12.2 to 1.12.3 ([#7284](https://github.com/parse-community/parse-server/issues/7284)) ([a53d74c](https://github.com/parse-community/parse-server/commit/a53d74c13b86d43e1694132feddccce6ee2bede9))
* upgrade ldapjs from 2.2.2 to 2.2.3 ([#7095](https://github.com/parse-community/parse-server/issues/7095)) ([fb465e5](https://github.com/parse-community/parse-server/commit/fb465e599e8768b9e229ec8689e033d7063e50b3))
* upgrade ldapjs from 2.2.3 to 2.2.4 ([#7275](https://github.com/parse-community/parse-server/issues/7275)) ([35f0c55](https://github.com/parse-community/parse-server/commit/35f0c55e93dc0572049a85befbc80175620f7d29))
* upgrade ldapjs from 2.2.4 to 2.3.0 ([#7436](https://github.com/parse-community/parse-server/issues/7436)) ([7df6c02](https://github.com/parse-community/parse-server/commit/7df6c020b18b8ea9d04b718fa4e070be800b9268))
* upgrade ldapjs from 2.3.0 to 2.3.1 ([#7524](https://github.com/parse-community/parse-server/issues/7524)) ([dee5a13](https://github.com/parse-community/parse-server/commit/dee5a13a85336cdd9d3bcd938c4118fffe8b9670))
* upgrade mime from 2.4.6 to 2.4.7 ([#7110](https://github.com/parse-community/parse-server/issues/7110)) ([fefcabe](https://github.com/parse-community/parse-server/commit/fefcabe858f3817dca337390c2198abbf12f9bdf))
* upgrade mime from 2.4.7 to 2.5.0 ([#7166](https://github.com/parse-community/parse-server/issues/7166)) ([6097e82](https://github.com/parse-community/parse-server/commit/6097e82194772847954dc2c2b7559543cc7531cc))
* upgrade mime from 2.5.0 to 2.5.2 ([#7261](https://github.com/parse-community/parse-server/issues/7261)) ([687f4b7](https://github.com/parse-community/parse-server/commit/687f4b7cf245ce578674a4cc0e0d276b23d5780d))
* upgrade mongodb from 3.6.6 to 3.6.7 ([#7425](https://github.com/parse-community/parse-server/issues/7425)) ([61affe2](https://github.com/parse-community/parse-server/commit/61affe26293f7218e88878d027514d68975cfc8c))
* upgrade mongodb from 3.6.7 to 3.6.8 ([#7430](https://github.com/parse-community/parse-server/issues/7430)) ([c36588e](https://github.com/parse-community/parse-server/commit/c36588e3c2d16fab3f38aecc77f0e827bda38f95))
* upgrade mongodb from 3.6.8 to 3.6.9 ([#7445](https://github.com/parse-community/parse-server/issues/7445)) ([17cf1a4](https://github.com/parse-community/parse-server/commit/17cf1a46e557b502b132c415b922508e032209a9))
* upgrade mongodb from 3.6.9 to 3.6.10 ([#7474](https://github.com/parse-community/parse-server/issues/7474)) ([45d29cc](https://github.com/parse-community/parse-server/commit/45d29cc58c373c9e1d489dbd7a750f2a0f6bc89b))
* upgrade mustache from 4.1.0 to 4.2.0 ([#7358](https://github.com/parse-community/parse-server/issues/7358)) ([94b7b32](https://github.com/parse-community/parse-server/commit/94b7b320062579e788df6c9f72d7a786f98f7cc5))
* upgrade parse from 3.1.0 to 3.2.0 ([#7378](https://github.com/parse-community/parse-server/issues/7378)) ([e9f54e2](https://github.com/parse-community/parse-server/commit/e9f54e2bddd8430864b1628ab077a0a3aae73e47))
* upgrade pg-promise from 10.10.1 to 10.10.2 ([#7399](https://github.com/parse-community/parse-server/issues/7399)) ([d365f1f](https://github.com/parse-community/parse-server/commit/d365f1f7cb44cfdeac9931308ff25dcd9ba3d79b))
* upgrade pg-promise from 10.10.2 to 10.11.0 ([#7510](https://github.com/parse-community/parse-server/issues/7510)) ([a967e79](https://github.com/parse-community/parse-server/commit/a967e7921961ea7a33ae9ff02555839cecf2b15f))
* upgrade pg-promise from 10.8.1 to 10.8.6 ([#7118](https://github.com/parse-community/parse-server/issues/7118)) ([8851810](https://github.com/parse-community/parse-server/commit/8851810a85747456cd2f3e5d3876371306b8c23d))
* upgrade pg-promise from 10.8.6 to 10.8.7 ([#7148](https://github.com/parse-community/parse-server/issues/7148)) ([231c669](https://github.com/parse-community/parse-server/commit/231c669133eea494f2db7f23fdff2e9d004c9e18))
* upgrade pg-promise from 10.8.7 to 10.9.0 ([#7168](https://github.com/parse-community/parse-server/issues/7168)) ([fcacd4d](https://github.com/parse-community/parse-server/commit/fcacd4d24e34ff48367d2c68bb97743b8a20216c))
* upgrade pg-promise from 10.9.0 to 10.9.1 ([#7170](https://github.com/parse-community/parse-server/issues/7170)) ([cca493b](https://github.com/parse-community/parse-server/commit/cca493b9fb33a4c34eaaf624ec4aedd18b11dca7))
* upgrade pg-promise from 10.9.1 to 10.9.2 ([#7209](https://github.com/parse-community/parse-server/issues/7209)) ([c05102b](https://github.com/parse-community/parse-server/commit/c05102b90c925498459b45c755298cb482ac596c))
* upgrade redis from 3.1.1 to 3.1.2 ([#7387](https://github.com/parse-community/parse-server/issues/7387)) ([f65bd22](https://github.com/parse-community/parse-server/commit/f65bd228fb3491ba217558ec288dd2ee60d0d37d))
* upgrade semver from 7.3.2 to 7.3.4 ([#7092](https://github.com/parse-community/parse-server/issues/7092)) ([7e687b1](https://github.com/parse-community/parse-server/commit/7e687b1e943372d105ca359177824241af278534))
* upgrade subscriptions-transport-ws from 0.9.19 to 0.10.0 ([#7450](https://github.com/parse-community/parse-server/issues/7450)) ([d36a53b](https://github.com/parse-community/parse-server/commit/d36a53b2bfade99942e3c9b827c9abb38d2de26b))
* upgrade uuid from 8.3.1 to 8.3.2 ([#7101](https://github.com/parse-community/parse-server/issues/7101)) ([f17a063](https://github.com/parse-community/parse-server/commit/f17a063209b451da291918dac165e177f0bee6a0))
* upgrade winston-daily-rotate-file from 4.5.0 to 4.5.1 ([#7309](https://github.com/parse-community/parse-server/issues/7309)) ([8643ae4](https://github.com/parse-community/parse-server/commit/8643ae438f1ea48c93d2860889568f9f3a5a62b8))
* upgrade winston-daily-rotate-file from 4.5.1 to 4.5.2 ([#7376](https://github.com/parse-community/parse-server/issues/7376)) ([e143fb1](https://github.com/parse-community/parse-server/commit/e143fb1bf6a52bb21c483fbf72f74d2282cfbeee))
* upgrade winston-daily-rotate-file from 4.5.2 to 4.5.3 ([#7398](https://github.com/parse-community/parse-server/issues/7398)) ([e9d8ed4](https://github.com/parse-community/parse-server/commit/e9d8ed4acb03160c8f6d669859fe57d8281937b4))
* upgrade winston-daily-rotate-file from 4.5.3 to 4.5.4 ([#7402](https://github.com/parse-community/parse-server/issues/7402)) ([4f80a5f](https://github.com/parse-community/parse-server/commit/4f80a5f4afbc008d2f642ee0c581a25483240e9a))
* upgrade winston-daily-rotate-file from 4.5.4 to 4.5.5 ([#7407](https://github.com/parse-community/parse-server/issues/7407)) ([5abbeeb](https://github.com/parse-community/parse-server/commit/5abbeeb8d11be810993c528b8458be894039a5fc))
* upgrade ws from 7.4.0 to 7.4.1 ([#7098](https://github.com/parse-community/parse-server/issues/7098)) ([1068838](https://github.com/parse-community/parse-server/commit/106883809c96a758bb23ae6dd7fff7465fbd8f60))
* upgrade ws from 7.4.1 to 7.4.2 ([#7132](https://github.com/parse-community/parse-server/issues/7132)) ([857d4ec](https://github.com/parse-community/parse-server/commit/857d4ecfd5a383d6debd849a1af1d45820aee0c0))
* upgrade ws from 7.4.2 to 7.4.3 ([#7224](https://github.com/parse-community/parse-server/issues/7224)) ([ec8f784](https://github.com/parse-community/parse-server/commit/ec8f78424f0043fa74ef1f3a7baa96a3d1e95b59))
* upgrade ws from 7.4.3 to 7.4.4 ([#7298](https://github.com/parse-community/parse-server/issues/7298)) ([a080e4c](https://github.com/parse-community/parse-server/commit/a080e4c766c33cc5b5c304bbdba69e93743f9db1))
* upgrade ws from 7.4.4 to 7.4.5 ([#7381](https://github.com/parse-community/parse-server/issues/7381)) ([34f3dd9](https://github.com/parse-community/parse-server/commit/34f3dd9e7e1908b713355ddb235b1e5d02634663))
* upgrade ws from 7.5.3 to 8.2.1 ([#7580](https://github.com/parse-community/parse-server/issues/7580)) ([c3da290](https://github.com/parse-community/parse-server/commit/c3da2908fabfa4f7f49c0f6d5b3d32de692dd388))
* upgrade ws from 8.2.1 to 8.2.2 ([#7598](https://github.com/parse-community/parse-server/issues/7598)) ([20cb333](https://github.com/parse-community/parse-server/commit/20cb3333aba67fb89e4e2cda586c559bdb4a23ef))

### Features

* add support for Postgres 14 ([#7644](https://github.com/parse-community/parse-server/issues/7644)) ([090350a](https://github.com/parse-community/parse-server/commit/090350a7a0fac945394ca1cb24b290316ef06aa7))
* add user-defined schema and migrations ([#7418](https://github.com/parse-community/parse-server/issues/7418)) ([25d5c30](https://github.com/parse-community/parse-server/commit/25d5c30be2111be332eb779eb0697774a17da7af))
* alphabetical graphql api, fix internal reassign, enhanced Graphql schema cache system ([#7344](https://github.com/parse-community/parse-server/issues/7344)) ([85ef721](https://github.com/parse-community/parse-server/commit/85ef7217b04e36395e46316004293e9c8ca67df9))
* **LiveQuery:** Support $and, $nor, $containedBy, $geoWithin ([#7113](https://github.com/parse-community/parse-server/issues/7113)) ([93781b2](https://github.com/parse-community/parse-server/commit/93781b2195d8074032d2c4dfd77a56acf17dc9e1))
* **AggregateRouter:** support native mongodb syntax in aggregation pipelines ([#7339](https://github.com/parse-community/parse-server/issues/7339)) ([8fddac3](https://github.com/parse-community/parse-server/commit/8fddac39bf866886c3b432219acc4d5e8169ddc0))

### BREAKING CHANGES

* To delete a field via the GraphQL API, the field value has to be set to `null`. Previously, setting a field value to `null` would save a null value in the database, which was not according to the [GraphQL specs](https://spec.graphql.org/June2018/#sec-Null-Value). To delete a file field use `file: null`, the previous way of using `file: { file: null }` has become obsolete. ([626fad2](626fad2))
2021-11-01 16:12:16 +00:00
Manuel e94a08ffdf build: release beta 2021-11-01 17:11:15 +01:00
semantic-release-bot ef47131fa4 chore(release): 5.0.0-alpha.5 [skip ci]
# [5.0.0-alpha.5](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.4...5.0.0-alpha.5) (2021-11-01)

### Features

* add user-defined schema and migrations ([#7418](https://github.com/parse-community/parse-server/issues/7418)) ([25d5c30](https://github.com/parse-community/parse-server/commit/25d5c30be2111be332eb779eb0697774a17da7af))
2021-11-01 13:30:00 +00:00
Samuel Denis-D'Ortun 25d5c30be2 feat: add user-defined schema and migrations (#7418) 2021-11-01 14:28:49 +01:00
Manuel 653d25731f docs: add Node 16 compatibility to README 2021-11-01 01:15:44 +01:00
Manuel 762162253d docs: slim compatibility tables in README 2021-11-01 01:12:16 +01:00
Manuel 42ecf6c613 docs: add versioning system to contribution guide (#7294) 2021-10-31 21:40:21 +01:00
semantic-release-bot 87e65d8207 chore(release): 5.0.0-alpha.4 [skip ci]
# [5.0.0-alpha.4](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.3...5.0.0-alpha.4) (2021-10-31)

### Features

* add support for Postgres 14 ([#7644](https://github.com/parse-community/parse-server/issues/7644)) ([090350a](https://github.com/parse-community/parse-server/commit/090350a7a0fac945394ca1cb24b290316ef06aa7))
2021-10-31 19:49:58 +00:00
Corey 090350a7a0 feat: add support for Postgres 14 (#7644) 2021-10-31 20:49:03 +01:00
Frans Bouwmeester 28fa7167e8 test: port test changes from 4.x LTS branch; upgrade spec reporter from 6.0.0 to 7.0.0 (#7667) 2021-10-30 19:21:24 +02:00
Manuel a359c0248b ci: add missing docker archs (#7666) 2021-10-29 20:05:49 +02:00
semantic-release-bot 62cc9cae7d chore(release): 5.0.0-alpha.3 [skip ci]
# [5.0.0-alpha.3](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.2...5.0.0-alpha.3) (2021-10-29)

### Bug Fixes

* combined `and` query with relational query condition returns incorrect results ([#7593](https://github.com/parse-community/parse-server/issues/7593)) ([174886e](https://github.com/parse-community/parse-server/commit/174886e385e091c6bbd4a84891ef95f80b50d05c))
2021-10-29 17:04:51 +00:00
Kingtous 174886e385 fix: combined and query with relational query condition returns incorrect results (#7593) 2021-10-29 19:03:50 +02:00
Manuel edb03f214d ci: increase docker ci timeout (#7664) 2021-10-29 18:21:38 +02:00
Manuel e1f8de80a7 ci: fix docker build with node:lts-alpine (#7663) 2021-10-29 17:57:37 +02:00
Manuel f1238eaf57 docs: adapt changelog links temporarily until stable release 2021-10-27 03:36:18 +02:00
Manuel 5dfc3b31ef ci: remove changelog check 2021-10-27 03:29:21 +02:00
Manuel 758e4b75e7 docs: updated changelog entry to PR template 2021-10-27 03:23:08 +02:00
semantic-release-bot 93321658c9 chore(release): 5.0.0-alpha.2 [skip ci]
# [5.0.0-alpha.2](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.1...5.0.0-alpha.2) (2021-10-27)

### Bug Fixes

* setting a field to null does not delete it via GraphQL API ([#7649](https://github.com/parse-community/parse-server/issues/7649)) ([626fad2](https://github.com/parse-community/parse-server/commit/626fad2e71017dcc62196c487de5f908fa43000b))

### BREAKING CHANGES

* To delete a field via the GraphQL API, the field value has to be set to `null`. Previously, setting a field value to `null` would save a null value in the database, which was not according to the [GraphQL specs](https://spec.graphql.org/June2018/#sec-Null-Value). To delete a file field use `file: null`, the previous way of using `file: { file: null }` has become obsolete. ([626fad2](626fad2))
2021-10-27 01:15:40 +00:00
Manuel 18a7838505 ci: fix auto release (#7657) 2021-10-27 03:07:10 +02:00
Manuel d3e914280d ci: add release automation (#7656) 2021-10-27 02:53:46 +02:00
Antoine Cormouls 626fad2e71 fix: setting a field to null does not delete it via GraphQL API (#7649)
BREAKING CHANGE: To delete a field via the GraphQL API, the field value has to be set to `null`. Previously, setting a field value to `null` would save a null value in the database, which was not according to the [GraphQL specs](https://spec.graphql.org/June2018/#sec-Null-Value). To delete a file field use `file: null`, the previous way of using `file: { file: null }` has become obsolete.
2021-10-27 01:33:48 +02:00
Manuel 4c29d4d23b docs: remove npm beta tag from README 2021-10-21 15:11:19 +02:00
Manuel 5a57475d3c docs: fix incorrect sponsor type in README 2021-10-21 15:04:49 +02:00
Manuel b4b46e6ba0 docs: restyle README header 2021-10-21 15:02:52 +02:00
dblythy 12eb6c823b refactor: replace hardcoded error codes with references (#7546) 2021-10-18 20:19:47 +02:00
Corey b5fc0d59db ci: enable more tests on Postgres adapter (#7641) 2021-10-18 16:51:56 +02:00
Snyk bot 80bf578cbd refactor: upgrade semver from 7.3.4 to 7.3.5 (#7343) 2021-10-18 14:05:03 +02:00
Snyk bot 6a2c21d282 refactor: upgrade follow-redirects from 1.14.1 to 1.14.2 (#7561) 2021-10-18 12:20:36 +02:00
Manuel 4643bf8263 ci: remove stale bot 2021-10-18 10:51:02 +02:00
Antoine Cormouls 68057c49f3 refactor: minor changes to remove mongo deprecation warnings (#7626) 2021-10-17 21:16:24 +02:00
Manuel 936b5ec9a7 ci: bump environment (#7630) 2021-10-17 20:22:43 +02:00
Snyk bot 1a3103a025 refactor: upgrade parse from 3.3.0 to 3.3.1 (#7638) 2021-10-16 11:57:22 +02:00
Manuel 527881fe9d ci: remove ci env check from PR CI (#7635) 2021-10-15 00:35:10 +02:00
Manuel 0ce6fb9a54 ci: fix typo in workflow text 2021-10-15 00:27:16 +02:00
Manuel 0e2cf989fd ci: refactor ci update scheduler 2021-10-15 00:12:51 +02:00
Manuel a48ff2062f ci: refactor ci update scheduler 2021-10-15 00:10:21 +02:00
Manuel fd12ca5fa3 ci: change workflow scheduler to node 14 2021-10-14 23:52:41 +02:00
Manuel 5791c11202 ci: add environment check scheduler (#7631) 2021-10-14 23:49:45 +02:00
Manuel 9a6bb6b1ef ci: disable npm publishing on release 2021-10-13 03:03:09 +02:00
Alysson Melo 2ac694d309 docs: update incorrect link to Back4App in README 2021-10-13 02:28:30 +02:00
Manuel 049dd6b3dc ci: fix docker build error 2021-10-13 01:59:51 +02:00
Manuel 825b302e0b ci: fix docker build error 2021-10-13 01:46:01 +02:00
Manuel 0525e4bdd2 ci: bump node version in release 2021-10-13 01:03:03 +02:00
Manuel ce57bf8c9c build: release 5.0.0-alpha.1 (#7617) 2021-10-13 00:58:22 +02:00
Manuel a00e9038f6 ci: bump environment (#7616) 2021-10-12 23:49:55 +02:00
Manuel 0d46d2b3eb ci: disable docker auto publish (#7615) 2021-10-12 23:29:10 +02:00
Snyk bot 407ed6ee36 fix: upgrade graphql from 15.5.3 to 15.6.0 (#7612) 2021-10-12 09:42:38 +02:00
Antoine Cormouls 85ef7217b0 feat: alphabetical graphql api, fix internal reassign, enhanced Graphql schema cache system (#7344) 2021-10-11 14:51:28 +02:00
Manuel 90b18bcccf docs: update contribution merge guide (#7611) 2021-10-10 20:11:33 +02:00
dblythy ab1dddd406 fix: add deprecation warning for Parse.Cloud.httpRequest (#7595) 2021-10-09 05:04:12 +02:00
dblythy 68a3a87501 fix: set objects in afterFind triggers (#7311) 2021-10-09 02:34:09 +02:00
Brandon Scott 197fcbda00 refactor: modernize HTTPRequest tests (#7604) 2021-10-08 22:44:40 +02:00
dblythy caee281bc5 fix: allow LiveQuery on Parse.Session (#7554) 2021-10-08 17:24:33 +02:00
dblythy 484c2e81ca fix: improve security by deprecating creating users with public access by default (#7319) 2021-10-08 05:24:20 +02:00
Snyk bot 2b5bf2261b refactor: upgrade graphql-relay from 0.8.0 to 0.9.0 (#7605)
Snyk has created this PR to upgrade graphql-relay from 0.8.0 to 0.9.0.

See this package in npm:
https://www.npmjs.com/package/graphql-relay

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=referral&page=upgrade-pr
2021-10-06 01:44:45 +02:00
Snyk botandManuel 20cb3333ab fix: upgrade ws from 8.2.1 to 8.2.2 (#7598)
Snyk has created this PR to upgrade ws from 8.2.1 to 8.2.2.

See this package in npm:
https://www.npmjs.com/package/ws

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=referral&page=upgrade-pr

Co-authored-by: Manuel <5673677+mtrezza@users.noreply.github.com>
2021-10-01 01:18:41 +02:00
dblythy d90c1591ad test: fix failing tests after removal of session token (#7599) 2021-09-30 13:41:04 +02:00
Manuel b86e3bfbb5 ci: add manual docker image release (#7597) 2021-09-30 05:06:43 +02:00
dblythyandManuel 834ae366f9 Merge pull request from GHSA-7pr3-p5fm-8r9x
* fix: strip sessionToken on _User LiveQuery

* delete authData

* add changelog

* Update package.json

* Update CHANGELOG.md

* add changes

* Update ParseLiveQuery.spec.js

Co-authored-by: Manuel <5673677+mtrezza@users.noreply.github.com>
2021-09-30 04:52:12 +02:00
Snyk botandManuel bcbc035627 fix: upgrade graphql from 15.5.2 to 15.5.3 (#7596)
Snyk has created this PR to upgrade graphql from 15.5.2 to 15.5.3.

See this package in npm:
https://www.npmjs.com/package/graphql

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=referral&page=upgrade-pr

Co-authored-by: Manuel <5673677+mtrezza@users.noreply.github.com>
2021-09-30 04:49:13 +02:00
Manuel c9633c1566 ci: bump environments (#7594)
* add issue bot for prs

* Update CHANGELOG.md

* Update issue-bot.yml

* bump MongoDB 5.0.2 to 5.0.3

* bump MongoDB 4.4.8 to 4.4.9

* bump MongoDB 4.2.16 to 4.2.17

* bump node 14.17.6 to 14.18.0
2021-09-29 17:09:49 +02:00
dependabot[bot] 0fa8f5e27b chore(deps): bump object-path from 0.11.7 to 0.11.8 (#7585) 2021-09-22 15:18:44 +02:00
Snyk bot dee4d96627 fix: upgrade graphql from 15.5.1 to 15.5.2 (#7587) 2021-09-22 09:49:39 +02:00
Snyk bot c3da2908fa fix: upgrade ws from 7.5.3 to 8.2.1 (#7580)
Snyk has created this PR to upgrade ws from 7.5.3 to 8.2.1.

See this package in npm:
https://www.npmjs.com/package/ws

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-09-19 15:05:08 +02:00
dblythy 8ed94421e6 fix: add support for descending sorting of full text search (#7496) 2021-09-15 16:15:08 +02:00
Manuel e9e3be1df8 ci: add node engine check (#7574)
* add issue bot for prs

* Update CHANGELOG.md

* Update issue-bot.yml

* replace node 15 with node 16

* Update CHANGELOG.md

* use node 16 as default node version

* ignore node 15 in ci self-check

* bumped madge for node deprecation DEP0148

* ci: add node engine check

* lint

* bump node engine

* Update ci.yml

* revert unnecessary changes

* Update CHANGELOG.md

* Update ci.yml
2021-09-14 16:29:56 +02:00
Manuel 3e4d1ecbf3 ci: bump mongodb (#7568)
* add issue bot for prs

* Update CHANGELOG.md

* Update issue-bot.yml

* bump ci
2021-09-14 15:48:37 +02:00
dblythyandManuel 0225340ccb refactor: allow ES import for cloud string if package type is module (#7560)
* allow module import for Parse Cloud

* Update .babelrc

* catch esm error

* Update ParseServer.js

* add tests

* Update CHANGELOG.md

* Update CloudCode.spec.js

Co-authored-by: Manuel <5673677+mtrezza@users.noreply.github.com>
2021-09-14 14:10:37 +02:00
Manuel fdb7dfba9f docs: update commit message (#7570)
* add issue bot for prs

* Update CHANGELOG.md

* Update issue-bot.yml

* Update CONTRIBUTING.md
2021-09-13 11:55:26 +02:00
Manuel 16e9a6f201 docs: add angular commit (#7567)
* add issue bot for prs

* Update CHANGELOG.md

* Update issue-bot.yml

* Update CONTRIBUTING.md
2021-09-10 23:55:50 +02:00
dependabot[bot] 1c626d50b5 chore(deps): bump axios from 0.21.1 to 0.21.4 (#7566)
Bumps [axios](https://github.com/axios/axios) from 0.21.1 to 0.21.4.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.21.1...v0.21.4)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-10 17:08:34 +02:00
Lukáš SmilekandManuel b185fad695 Additional explication for expireInactiveSessions in ParseServerOptions (#7552)
* Update docs.js

Additional explication for `expireInactiveSessions`

* Update index.js

Additional explication for `expireInactiveSessions`

* Update docs.js

correcting spelling error

* Update index.js

correcting spelling error

* Update Definitions.js

Co-authored-by: Manuel <5673677+mtrezza@users.noreply.github.com>
2021-09-10 15:49:20 +02:00
Manuel 429b959964 docs: Introduce deprecation ID for reference in comments and online search (#7562)
* add issue bot for prs

* Update CHANGELOG.md

* Update issue-bot.yml

* Update DEPRECATIONS.md

* Update CHANGELOG.md
2021-09-09 13:09:17 +02:00
Manuel 7807d6343d ci: Fix docker hub push (#7556)
* add issue bot for prs

* Update CHANGELOG.md

* Update issue-bot.yml

* fix docker run
2021-09-07 18:02:40 +02:00
Manuel 41f0a1de43 ci: update docker image building (#7555)
* add issue bot for prs

* Update CHANGELOG.md

* Update issue-bot.yml

* Update docker-publish.yml
2021-09-07 16:42:28 +02:00
Corey 24e9bdc639 ci: Fix docker image pushing to Docker Hub (#7548)
* add actions file

* nit

* add multi-platform

* add buildx

* reduce platforms

* remove arm7

* add back arm7

* add missing archs

* remove failing image

* add back in linux/s390x

* switch image name to parse-server

* remove failing images

* nit spelling

* Nit

* add comment about nightly builds
2021-09-07 14:35:03 +02:00
Manuel 5ab974dcd4 refactor: remove parse issue bot (#7544)
* add issue bot for prs

* Update CHANGELOG.md

* Update issue-bot.yml

* refactor: remove parse issue bot
2021-09-04 05:12:28 +02:00
Manuel 24188a39a7 refactor: remove restricted session field (#7543)
* add issue bot for prs

* Update CHANGELOG.md

* Update issue-bot.yml

* remove session restriction artifacts

* Update CHANGELOG.md

* Update CHANGELOG.md
2021-09-04 03:03:46 +02:00
Manuel 27832453e2 refactor: clean code (#7542)
* add issue bot for prs

* Update CHANGELOG.md

* Update issue-bot.yml

* reformat code
2021-09-03 01:23:15 +02:00
dependabot[bot] 6ad3e6f8ad chore(deps): bump object-path from 0.11.5 to 0.11.7 (#7535) 2021-09-02 14:41:44 +02:00
Manuel 6f77bb436e ci: bump ci environment (#7539)
* add issue bot for prs

* Update CHANGELOG.md

* Update issue-bot.yml

* bump node 14.17.5 to 14.17.6

* bump node 12.22.5 to 12.22.5

* Update CHANGELOG.md
2021-09-02 14:12:36 +02:00
Manuel f1da29f9c9 chore: bump package version to 4.10.3 (#7537)
* add issue bot for prs

* Update CHANGELOG.md

* Update issue-bot.yml

* bumped package version
2021-09-02 13:08:52 +02:00
308668c894 Merge pull request from GHSA-xqp8-w826-hh6x
* Added a test case that triggers the query parameter crash

* rest.js: validate the explain parameter to keep the nodejs driver from throwing an uncatchable exception and crashing the server (see https://jira.mongodb.org/browse/NODE-3463)
RestQuery.js: Check whether explain mode is enabled not by "!== true", but by the "!" operator. explain can have string values.
Added tests that validate correct behaviour on different explain values

* Refactor the new tests

* Simplify the new tests
Also do a sanity check on the explain results

* Test refactor

* Exclude queryPlannerExtended as it is not supported by the testing environment
  Simplifies the tests

* Restrict the changes to mongodb
  Moved the verification of the explain value from rest.js to MongoStorageAdapter.js
  Also restricted the relevant unit tests to mongodb

* Added changelog entry

* reformat changelog entry

* Update CHANGELOG.md

Co-authored-by: Kartal Kaan Bozdoğan <kartalkaanbozdogan@gmail.com>
Co-authored-by: Manuel <5673677+mtrezza@users.noreply.github.com>
2021-09-02 12:46:48 +02:00
Manuel 1e0d408ca3 ci: remove issue bot for PRs (#7531)
* add issue bot for prs

* Update CHANGELOG.md

* Update issue-bot.yml

* removing bot for prs
2021-08-27 21:18:11 +02:00
Manuel 5d31997f26 ci: add issue bot for PRs (#7530) 2021-08-27 20:51:48 +02:00
Manuel 26009563d8 refactor: uniform issue templates across repos (#7528)
* Update ---1-report-an-issue.md

* Update CHANGELOG.md
2021-08-27 17:06:44 +02:00
Manuel 4a0b4ebc34 ci(bot): add issue bot (#7523) 2021-08-26 19:19:20 +02:00
Snyk bot dee5a13a85 fix: upgrade ldapjs from 2.3.0 to 2.3.1 (#7524)
Snyk has created this PR to upgrade ldapjs from 2.3.0 to 2.3.1.

See this package in npm:
https://www.npmjs.com/package/ldapjs

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-08-25 11:32:40 +02:00
Manuel 36619fb646 fix typo in issue template 2021-08-25 02:01:44 +02:00
Manuel 2f557f86b2 removed text in README that is in DEPRECATIONS 2021-08-24 01:41:40 +02:00
Manuel 826d55c1b6 clarified deprecation plan 2021-08-24 01:39:53 +02:00
Manuel 05dd11f08d consolidated deprecations (#7516) 2021-08-24 01:36:52 +02:00
Manuel c0d7ac0f68 Merge release 4.10.2 (#7515)
* bump version

* Update CHANGELOG.md
2021-08-24 01:21:03 +02:00
Manuel f5f608ccf5 Merge release 4.10.1 (#7511)
* Update CHANGELOG.md

* bump version

* bumped mongodb@3.6.11
2021-08-24 00:56:40 +02:00
Manuel b1de21a89a ci(changelog): add changelog reminder (#7512)
* Update ci.yml

* Update CHANGELOG.md

* Update ci.yml

* Update ci.yml
2021-08-24 00:50:49 +02:00
Snyk bot a967e79219 fix: upgrade pg-promise from 10.10.2 to 10.11.0 (#7510) 2021-08-22 10:45:32 +02:00
Snyk bot 65c967a4c4 fix: package.json & package-lock.json to reduce vulnerabilities (#7509) 2021-08-22 10:25:47 +02:00
Manuel f3854f9354 improved pr template checkbox instructions 2021-08-21 12:41:58 +02:00
Manuel 517d8ae240 improved issue template checkbox instruction 2021-08-21 12:41:33 +02:00
Manuel 66cb0f05b0 Merge v4.10.0 into master (#7505)
* bump version

* Update CHANGELOG.md
2021-08-20 11:57:09 -07:00
Manuel c6fb88c298 adapt for master merge (#7501) 2021-08-18 15:22:52 -07:00
Manuel e28fdef489 fixed minor changelog typos 2021-08-18 19:11:49 +02:00
Manuel 6a82bd2df9 fixed changelog heading format 2021-08-18 19:09:34 +02:00
Manuel d31f16c6dc fixed changelog version link 2021-08-18 19:08:09 +02:00
Manuel 1cd0ae9c0a fixed changelog version link 2021-08-18 19:07:42 +02:00
Antonio Davi Macedo Coelho de CastroandCorey fc0fef5922 Merge pull request from GHSA-23r4-5mxp-c7g5 (#7497)
* Merge pull request from GHSA-23r4-5mxp-c7g5

* add anonymous login security fix

* add changelog entry

* update changelog

* Update package.json (#7498)

* Update package-lock.json (#7499)

Co-authored-by: Corey <coreyearleon@icloud.com>
2021-08-18 19:03:54 +02:00
Samuel Denis-D'Ortun c66a39fadc Remove quoted argument to fix issue on Windows (#7489) 2021-08-14 11:55:30 +02:00
Raschid J.F. Rafeally 8fddac39bf feat(AggregateRouter): support native mongodb syntax in aggregation pipelines (#7339) 2021-08-12 19:14:04 +02:00
Manuel 381e9bf014 bump node (#7487)
node 14.17.4 to 14.17.5
node 12.22.4 to 12.22.5
2021-08-11 23:32:13 +02:00
Manuel fda07aa45d Add deprecation plan (#7485)
* add deprecation plan

* Update DEPRECATIONS.md
2021-08-10 22:55:16 +02:00
dependabot[bot] f8c4f9fc54 chore(deps): bump path-parse from 1.0.6 to 1.0.7 (#7484)
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-10 13:16:16 -07:00
Manuel ae1edeb2ac Bump CI (#7482)
* mongodb 4.4.7 to 4.4.8

* node 14.17.3 to 14.17.4

* node 12.22.3 to 12.22.4

* mongodb 5.0.1 to 5.0.2
2021-08-09 04:11:36 +02:00
Snyk bot 45d29cc58c fix: upgrade mongodb from 3.6.9 to 3.6.10 (#7474)
Snyk has created this PR to upgrade mongodb from 3.6.9 to 3.6.10.

See this package in npm:
https://www.npmjs.com/package/mongodb

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-07-27 17:39:05 -07:00
Manuel cc3cd23b93 Fix missing password policy definitions (#7225)
* improved contribution guide for parameter groups

* improved resetTokenReuseIfValid docs

* improved resetTokenValidityDuration docs

* recreated definitions

* improved parameter group wording
2021-07-27 00:23:42 +02:00
CoreyandAntonio Davi Macedo Coelho de Castro c8e822b958 Accept context via header X-Parse-Cloud-Context (#7437)
* failing testcase

* add header

* switch to X-Parse-Cloud-Context header

* add back blank line that lint removed

* test replacing context header with body context. Add support for setting body with json string

* add back blank line

* cover error when _context body is wrong

* Update middlewares.js

* revert accidental status change

* make sure context always decodes to an object else throw error

* improve context object check

Co-authored-by: Antonio Davi Macedo Coelho de Castro <adavimacedo@gmail.com>
2021-07-25 21:17:03 -07:00
Snyk botandManuel Trezza c3b71ba5b6 [Snyk] Upgrade ws from 7.4.6 to 7.5.3 (#7457)
* fix: upgrade ws from 7.4.6 to 7.5.0

Snyk has created this PR to upgrade ws from 7.4.6 to 7.5.0.

See this package in npm:
https://www.npmjs.com/package/ws

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

* changed logging for circular obj

* upgraded to ws 7.5.3

Co-authored-by: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
2021-07-25 01:54:28 +02:00
Snyk bot 39f7c831e6 fix: upgrade @apollographql/graphql-playground-html from 1.6.28 to 1.6.29 (#7473)
Snyk has created this PR to upgrade @apollographql/graphql-playground-html from 1.6.28 to 1.6.29.

See this package in npm:
https://www.npmjs.com/package/@apollographql/graphql-playground-html

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-07-24 12:42:57 +02:00
Snyk botandManuel Trezza c58bf57f51 fix: upgrade @apollographql/graphql-playground-html from 1.6.27 to 1.6.28 (#7411)
Snyk has created this PR to upgrade @apollographql/graphql-playground-html from 1.6.27 to 1.6.28.

See this package in npm:
https://www.npmjs.com/package/@apollographql/graphql-playground-html

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
2021-07-23 22:45:54 +02:00
Snyk botandManuel Trezza bbd7ee7313 fix: upgrade graphql from 15.5.0 to 15.5.1 (#7462)
Snyk has created this PR to upgrade graphql from 15.5.0 to 15.5.1.

See this package in npm:
https://www.npmjs.com/package/graphql

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
2021-07-23 20:13:26 +02:00
Snyk botandManuel Trezza a95ad89736 [Snyk] Security upgrade parse from 3.2.0 to 3.3.0 (#7464)
* fix: package.json & package-lock.json to reduce vulnerabilities

The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-WS-1296835

* update user test

Co-authored-by: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
2021-07-23 18:04:03 +02:00
Snyk botandManuel Trezza 1fe47087a9 fix: upgrade apollo-server-express from 2.25.1 to 2.25.2 (#7465)
Snyk has created this PR to upgrade apollo-server-express from 2.25.1 to 2.25.2.

See this package in npm:
https://www.npmjs.com/package/apollo-server-express

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
2021-07-23 17:13:50 +02:00
Snyk botandManuel Trezza 2b3355cb02 fix: upgrade graphql-tag from 2.12.4 to 2.12.5 (#7466)
Snyk has created this PR to upgrade graphql-tag from 2.12.4 to 2.12.5.

See this package in npm:
https://www.npmjs.com/package/graphql-tag

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
2021-07-23 15:47:36 +02:00
Snyk botandManuel Trezza 9923cd3869 fix: upgrade graphql-relay from 0.7.0 to 0.8.0 (#7467)
Snyk has created this PR to upgrade graphql-relay from 0.7.0 to 0.8.0.

See this package in npm:
https://www.npmjs.com/package/graphql-relay

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
2021-07-23 15:05:31 +02:00
Manuel 470382253d Add MongoDB 5.0 support + bump CI env (#7469)
* bump CI env

* more bump

* more bump

* added mongodb 5.0

* added compatibility table entry

* added changelog entry

* added mongodb 5.0 to badge
2021-07-23 14:25:11 +02:00
Manuel 250008d379 changed twitter API endpoint for oauth test (#7472) 2021-07-23 12:46:26 +02:00
Manuel 1594afec64 add runtime deprecation warning (#7451) 2021-07-12 20:14:35 +02:00
Manuel 05882bc3ec bumped node (#7452) 2021-07-03 15:20:23 +02:00
Snyk bot 682f1bf143 fix: upgrade apollo-server-express from 2.25.0 to 2.25.1 (#7449)
Snyk has created this PR to upgrade apollo-server-express from 2.25.0 to 2.25.1.

See this package in npm:
https://www.npmjs.com/package/apollo-server-express

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-06-30 15:29:54 -07:00
Snyk bot d36a53b2bf fix: upgrade subscriptions-transport-ws from 0.9.19 to 0.10.0 (#7450)
Snyk has created this PR to upgrade subscriptions-transport-ws from 0.9.19 to 0.10.0.

See this package in npm:
https://www.npmjs.com/package/subscriptions-transport-ws

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-06-30 15:26:16 -07:00
Snyk bot 17cf1a46e5 fix: upgrade mongodb from 3.6.8 to 3.6.9 (#7445)
Snyk has created this PR to upgrade mongodb from 3.6.8 to 3.6.9.

See this package in npm:
https://www.npmjs.com/package/mongodb

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-06-27 22:00:47 -07:00
Snyk bot c36588e3c2 fix: upgrade mongodb from 3.6.7 to 3.6.8 (#7430)
Snyk has created this PR to upgrade mongodb from 3.6.7 to 3.6.8.

See this package in npm:
https://www.npmjs.com/package/mongodb

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-06-23 22:38:05 -07:00
Snyk bot 4e5eba6c6c fix: upgrade apollo-server-express from 2.24.1 to 2.25.0 (#7435)
Snyk has created this PR to upgrade apollo-server-express from 2.24.1 to 2.25.0.

See this package in npm:
https://www.npmjs.com/package/apollo-server-express

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-06-23 22:30:36 -07:00
Snyk bot 7df6c020b1 fix: upgrade ldapjs from 2.2.4 to 2.3.0 (#7436)
Snyk has created this PR to upgrade ldapjs from 2.2.4 to 2.3.0.

See this package in npm:
https://www.npmjs.com/package/ldapjs

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-06-23 22:30:11 -07:00
Snyk bot 770e36ff43 fix: upgrade graphql-relay from 0.6.0 to 0.7.0 (#7443)
Snyk has created this PR to upgrade graphql-relay from 0.6.0 to 0.7.0.

See this package in npm:
https://www.npmjs.com/package/graphql-relay

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-06-23 22:24:26 -07:00
Jason Posthuma d8dc524c08 Add check for property (#7421)
* Add check for property

* updated changelog

* Fixed logic returning false positive

* Added test case

* update change log
2021-06-21 16:11:15 -07:00
Manuel 3a2afda911 bump node version (#7441) 2021-06-20 19:31:32 +02:00
Olle Jonsson 10695194b2 CHANGELOG: typo fix braking->breaking [ci skip] (#7432) 2021-06-15 13:25:04 +02:00
Manuel f6a41729a7 bump mongo (#7429) 2021-06-10 17:36:20 -07:00
dependabot[bot] 0638e5e697 chore(deps): bump normalize-url from 4.5.0 to 4.5.1 (#7428)
Bumps [normalize-url](https://github.com/sindresorhus/normalize-url) from 4.5.0 to 4.5.1.
- [Release notes](https://github.com/sindresorhus/normalize-url/releases)
- [Commits](https://github.com/sindresorhus/normalize-url/commits)

---
updated-dependencies:
- dependency-name: normalize-url
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-10 15:21:20 -07:00
Snyk bot bfdb6a93e8 fix: upgrade apollo-server-express from 2.24.0 to 2.24.1 (#7424)
Snyk has created this PR to upgrade apollo-server-express from 2.24.0 to 2.24.1.

See this package in npm:
https://www.npmjs.com/package/apollo-server-express

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-06-10 15:00:00 -07:00
Snyk bot 61affe2629 fix: upgrade mongodb from 3.6.6 to 3.6.7 (#7425)
Snyk has created this PR to upgrade mongodb from 3.6.6 to 3.6.7.

See this package in npm:
https://www.npmjs.com/package/mongodb

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-06-10 14:59:16 -07:00
Snyk bot bea4707783 fix: package.json & package-lock.json to reduce vulnerabilities (#7423)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-WS-1296835
2021-06-10 14:56:37 -07:00
129f7bfa9b Add support for master key clients to create user sessions (#7406)
* 6641: Implement support for user impersonation: master key clients can log in as any user, without access to the user's credentials, and without presuming the user already has a session

* reworded changelog

* rebuilt package lock

* fit test

* using lodash flatMap

* bump to node 12 for postgres test

* revert test fit

* add node version to postgres CI

* revert package-lock

Co-authored-by: gormanfletcher <git@gormanfletcher.com>
Co-authored-by: Manuel <5673677+mtrezza@users.noreply.github.com>
2021-06-04 18:55:00 -05:00
Manuel 754c127d96 bump ci env (#7415)
* bumped node version

* bumped mongodb
2021-06-03 22:39:46 +02:00
Corey 6d13aeae2c Fix select exclude queries (#7242)
* fix keys and excludeKeys to work with JSON array strings

* make excludeKeys test more robust

* add changelog

* add select([]) functionality to fix)

* update changelog

* update keys

* add exclude test

* add select REST test and exclude JS SDK test

* add more tests

* add additional exclude test

* improved select test for testing JSON string array in REST

* improved exclude test for testing JSON string array in REST

* check for parse keys

* make include look like keys and excludeKeys

* nit

* Exclude nexted child fields

* add updates and show failing testcases

* working

* add more tests

* even more test cases

* use await for added tests

* lint

* Add suggestions
2021-06-03 14:54:44 -05:00
Snyk bot 5abbeeb8d1 fix: upgrade winston-daily-rotate-file from 4.5.4 to 4.5.5 (#7407)
Snyk has created this PR to upgrade winston-daily-rotate-file from 4.5.4 to 4.5.5.

See this package in npm:
https://www.npmjs.com/package/winston-daily-rotate-file

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-05-31 08:36:52 -07:00
Snyk bot 8976ecc4a9 fix: upgrade follow-redirects from 1.14.0 to 1.14.1 (#7408)
Snyk has created this PR to upgrade follow-redirects from 1.14.0 to 1.14.1.

See this package in npm:
https://www.npmjs.com/package/follow-redirects

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-05-30 22:25:27 -07:00
Snyk bot d915bacee7 fix: package.json & package-lock.json to reduce vulnerabilities (#7405)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-WS-1296835
2021-05-27 16:50:50 -07:00
Tom Fox 4253feed7d fix links (#7403) 2021-05-26 17:54:11 -07:00
Snyk bot 4f80a5f4af fix: upgrade winston-daily-rotate-file from 4.5.3 to 4.5.4 (#7402)
Snyk has created this PR to upgrade winston-daily-rotate-file from 4.5.3 to 4.5.4.

See this package in npm:
https://www.npmjs.com/package/winston-daily-rotate-file

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-05-25 15:40:31 -07:00
Kartal Kaan Bozdoğan 5e7c9d2e1a Fixed a bug affecting updates to nested pointers (#7392)
* Fixed a bug affecting updates to nested pointers
  Also created unit tests

* Marked the regression test for #7391 as pending for postgre
  The issue is not fixed yet
Use cont instead of var
2021-05-25 15:33:40 -07:00
Snyk bot 8099cb05a4 fix: upgrade graphql-tag from 2.12.2 to 2.12.4 (#7396)
Snyk has created this PR to upgrade graphql-tag from 2.12.2 to 2.12.4.

See this package in npm:
https://www.npmjs.com/package/graphql-tag

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-05-24 21:18:16 -07:00
Snyk bot d365f1f7cb fix: upgrade pg-promise from 10.10.1 to 10.10.2 (#7399)
Snyk has created this PR to upgrade pg-promise from 10.10.1 to 10.10.2.

See this package in npm:
https://www.npmjs.com/package/pg-promise

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-05-24 14:43:59 -07:00
dependabot[bot] 581f822cba chore(deps): bump browserslist from 4.16.3 to 4.16.6 (#7400)
Bumps [browserslist](https://github.com/browserslist/browserslist) from 4.16.3 to 4.16.6.
- [Release notes](https://github.com/browserslist/browserslist/releases)
- [Changelog](https://github.com/browserslist/browserslist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/browserslist/browserslist/compare/4.16.3...4.16.6)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-24 14:40:34 -07:00
Snyk bot ff5755b05a fix: upgrade apollo-server-express from 2.23.0 to 2.24.0 (#7395)
Snyk has created this PR to upgrade apollo-server-express from 2.23.0 to 2.24.0.

See this package in npm:
https://www.npmjs.com/package/apollo-server-express

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-05-24 09:26:47 -07:00
Snyk bot e9d8ed4acb fix: upgrade winston-daily-rotate-file from 4.5.2 to 4.5.3 (#7398)
Snyk has created this PR to upgrade winston-daily-rotate-file from 4.5.2 to 4.5.3.

See this package in npm:
https://www.npmjs.com/package/winston-daily-rotate-file

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-05-24 00:26:35 -07:00
Snyk bot 38c01c6bc3 fix: upgrade follow-redirects from 1.13.3 to 1.14.0 (#7389)
Snyk has created this PR to upgrade follow-redirects from 1.13.3 to 1.14.0.

See this package in npm:
https://www.npmjs.com/package/follow-redirects

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-05-17 15:17:52 -07:00
Snyk bot f65bd228fb fix: upgrade redis from 3.1.1 to 3.1.2 (#7387)
Snyk has created this PR to upgrade redis from 3.1.1 to 3.1.2.

See this package in npm:
https://www.npmjs.com/package/redis

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-05-14 11:40:31 -05:00
dependabot[bot] bdf73a0151 chore(deps): bump postcss from 8.2.9 to 8.2.15 (#7383)
Bumps [postcss](https://github.com/postcss/postcss) from 8.2.9 to 8.2.15.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.2.9...8.2.15)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-12 12:05:36 -05:00
Snyk bot 34f3dd9e7e fix: upgrade ws from 7.4.4 to 7.4.5 (#7381)
Snyk has created this PR to upgrade ws from 7.4.4 to 7.4.5.

See this package in npm:
https://www.npmjs.com/package/ws

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-05-12 11:58:47 -05:00
Snyk bot 87476da31e fix: upgrade apollo-server-express from 2.22.2 to 2.23.0 (#7380)
Snyk has created this PR to upgrade apollo-server-express from 2.22.2 to 2.23.0.

See this package in npm:
https://www.npmjs.com/package/apollo-server-express

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-05-12 11:57:40 -05:00
dblythy 51e08009f8 Fix: properly pass req.user to liveQuery triggers (#7296) 2021-05-02 11:23:46 +02:00
Snyk bot e9f54e2bdd fix: upgrade parse from 3.1.0 to 3.2.0 (#7378)
Snyk has created this PR to upgrade parse from 3.1.0 to 3.2.0.

See this package in npm:
https://www.npmjs.com/package/parse

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-05-01 10:37:17 -05:00
Snyk botandDiamond Lewis 755c49404d [Snyk] Upgrade pg-promise from 10.9.2 to 10.10.1 (#7286)
* fix: upgrade pg-promise from 10.9.2 to 10.9.3

Snyk has created this PR to upgrade pg-promise from 10.9.2 to 10.9.3.

See this package in npm:
https://www.npmjs.com/package/pg-promise

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

* bump pg-promise to 10.10.1

* fix add field if not exists

* lint

Co-authored-by: Diamond Lewis <findlewis@gmail.com>
2021-04-29 12:10:15 -05:00
Snyk bot e143fb1bf6 fix: upgrade winston-daily-rotate-file from 4.5.1 to 4.5.2 (#7376)
Snyk has created this PR to upgrade winston-daily-rotate-file from 4.5.1 to 4.5.2.

See this package in npm:
https://www.npmjs.com/package/winston-daily-rotate-file

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-04-28 12:03:44 -07:00
Snyk bot b6843de904 fix: package.json & package-lock.json to reduce vulnerabilities (#7373)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-REDIS-1255645
2021-04-27 16:29:27 -07:00
dependabot[bot] f43b1221d8 chore(deps): bump redis from 3.0.2 to 3.1.1 (#7375)
Bumps [redis](https://github.com/NodeRedis/node-redis) from 3.0.2 to 3.1.1.
- [Release notes](https://github.com/NodeRedis/node-redis/releases)
- [Changelog](https://github.com/NodeRedis/node-redis/blob/master/CHANGELOG.md)
- [Commits](https://github.com/NodeRedis/node-redis/compare/v3.0.2...v3.1.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-27 15:16:58 -07:00
dblythy 3638b0e791 Fix Twitter API Oauth Error (#7370) 2021-04-25 14:50:45 +02:00
Snyk bot 181fbf9d46 fix: upgrade apollo-server-express from 2.22.1 to 2.22.2 (#7362)
Snyk has created this PR to upgrade apollo-server-express from 2.22.1 to 2.22.2.

See this package in npm:
https://www.npmjs.com/package/apollo-server-express

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-04-20 21:02:48 -07:00
Snyk bot 94b7b32006 fix: upgrade mustache from 4.1.0 to 4.2.0 (#7358)
Snyk has created this PR to upgrade mustache from 4.1.0 to 4.2.0.

See this package in npm:
https://www.npmjs.com/package/mustache

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-04-18 22:23:42 -07:00
Rikard Teodorsson 64fc04cc26 Cloud Code validator issue with required: false (#7353)
* Only check the type of a parameter in the validator when the parameter is set to required or is not null

* Added test cases. Don't check type or options if required=false and no default value is set

* Added test cases. Don't check type or options if required=false and no default value is set

* Update const optional
2021-04-18 22:22:23 -07:00
Snyk bot 25690ad515 fix: upgrade apollo-server-express from 2.21.1 to 2.22.1 (#7357)
Snyk has created this PR to upgrade apollo-server-express from 2.21.1 to 2.22.1.

See this package in npm:
https://www.npmjs.com/package/apollo-server-express

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-04-18 22:17:49 -07:00
Manuel 91be6bb59a fix(utils): permutation helper (#7355)
* fix permutation helper

* fix typo
2021-04-17 00:22:01 +02:00
Manuel 484dc12334 bump CI env (#7352)
* bump CI env

* Revert "bump CI env"

This reverts commit d6eb582efe.

* exlcude mongodb 4.0.24
2021-04-16 17:51:27 +02:00
Snyk botandDiamond Lewis 3dc459746d fix: upgrade apollo-server-express from 2.21.0 to 2.21.1 (#7308)
Snyk has created this PR to upgrade apollo-server-express from 2.21.0 to 2.21.1.

See this package in npm:
https://www.npmjs.com/package/apollo-server-express

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: Diamond Lewis <findlewis@gmail.com>
2021-04-15 21:49:12 -07:00
Perceval Archimbaud 87dcd23b6a Fix #7340 by correclty computing function name for push event (#7341)
* Add a failing test for issue #7340

If any delay occurs after "message.event" assignation in
LiveQueryServer._onAfterSave, the next subscription or request with a different
event might overwrite it, and by that using the wrong "push" function name.

* Remove updade of message and use res.event instead

This prevent computing function name from a
incorrect event if multiple subscriptions override
one by one the message.event.

* Update CHANGELOG.md

* Replace setTimeout by async/await expressions
2021-04-13 14:47:14 -07:00
Manuel 45d00cee60 Add lock file version check to CI (#7333)
* Add lock file version check to CI

* Update CHANGELOG.md

* Update ci.yml

* test failing check with lock file version 2

* Revert "test failing check with lock file version 2"

This reverts commit a5b4293f31.
2021-04-09 19:25:26 -05:00
Snyk bot 50e55571fd fix: upgrade graphql-tag from 2.12.1 to 2.12.2 (#7325)
Snyk has created this PR to upgrade graphql-tag from 2.12.1 to 2.12.2.

See this package in npm:
https://www.npmjs.com/package/graphql-tag

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-04-09 12:53:16 -05:00
Manuel 2e11bf3b5c Remove S3 File Adapter (#7324)
* remove s3 adapter

* moved mock files adapter

* Update package-lock.json
2021-04-09 10:12:24 -05:00
Manuel bf732b9a6e Add build docker image to CI (#7332)
* add build docker image to CI

* remove node setup

* removed local dependency to test passing docker build

* Update CHANGELOG.md

* Revert "removed local dependency to test passing docker build"

This reverts commit a7801e1874.

* removed unnecessary docker build options

* fixed docker build
2021-04-09 16:40:03 +02:00
Snyk botandManuel Trezza 9ea355b463 [Snyk] Upgrade mongodb from 3.6.3 to 3.6.5 (#7322)
* fix: upgrade mongodb from 3.6.3 to 3.6.5

Snyk has created this PR to upgrade mongodb from 3.6.3 to 3.6.5.

See this package in npm:
https://www.npmjs.com/package/mongodb

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

* bump mongo 3.6.6

* update package-lock

* updated package-lock

* fix: upgrade winston-daily-rotate-file from 4.5.0 to 4.5.1 (#7309)

Snyk has created this PR to upgrade winston-daily-rotate-file from 4.5.0 to 4.5.1.

See this package in npm:
https://www.npmjs.com/package/winston-daily-rotate-file

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

* Bump CI environment, remove Postgres 10 support (#7323)

* bumped MongoDB to 4.4.5

* bump Node to 14.16.1

* removed obsolete COVERAGE_OPTION

* improved postges support note

* bump more node

* Remove MongoDB 3.6 support (EOL) (#7315)

* removed mongodb 3.6 support

* add changelog entry

* updated CI check

* bumped MongoDB to 4.4.5

* bump Node to 14.16.1

* removed obsolete COVERAGE_OPTION

* improved postges support note

* bump more node

* updated package lock

* Revert "bumped MongoDB to 4.4.5"

This reverts commit ce9c8108c3.

* skipping MongoDB 4.4.5 temporarily

* fixed bug in CI check that did not consider ignored versions when checking for newer versions

* removed Postgres 10 support

* updated Postgres versions

* renamed MongoDB CI tests

* fixed Postgres compatibility table

* fix Postgres badge

* Add deprecation policy (#7199)

* added phased deprecation policy

* fixed typo

* added changelog entry

* some rewording

* Fixed typo

* fixed typo

* Fixed typo

* updated deprecation policy

* remove empty line

* fix: upgrade mongodb from 3.6.3 to 3.6.5

Snyk has created this PR to upgrade mongodb from 3.6.3 to 3.6.5.

See this package in npm:
https://www.npmjs.com/package/mongodb

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

* bump mongo 3.6.6

* Update package-lock.json

Co-authored-by: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
2021-04-09 01:33:22 +02:00
Manuel a074fc9892 Add deprecation policy (#7199)
* added phased deprecation policy

* fixed typo

* added changelog entry

* some rewording

* Fixed typo

* fixed typo

* Fixed typo

* updated deprecation policy

* remove empty line
2021-04-09 00:50:09 +02:00
Manuel 8ba3f028b8 Bump CI environment, remove Postgres 10 support (#7323)
* bumped MongoDB to 4.4.5

* bump Node to 14.16.1

* removed obsolete COVERAGE_OPTION

* improved postges support note

* bump more node

* Remove MongoDB 3.6 support (EOL) (#7315)

* removed mongodb 3.6 support

* add changelog entry

* updated CI check

* bumped MongoDB to 4.4.5

* bump Node to 14.16.1

* removed obsolete COVERAGE_OPTION

* improved postges support note

* bump more node

* updated package lock

* Revert "bumped MongoDB to 4.4.5"

This reverts commit ce9c8108c3.

* skipping MongoDB 4.4.5 temporarily

* fixed bug in CI check that did not consider ignored versions when checking for newer versions

* removed Postgres 10 support

* updated Postgres versions

* renamed MongoDB CI tests

* fixed Postgres compatibility table

* fix Postgres badge
2021-04-09 00:11:58 +02:00
Snyk bot 8643ae438f fix: upgrade winston-daily-rotate-file from 4.5.0 to 4.5.1 (#7309)
Snyk has created this PR to upgrade winston-daily-rotate-file from 4.5.0 to 4.5.1.

See this package in npm:
https://www.npmjs.com/package/winston-daily-rotate-file

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-04-08 11:05:14 -05:00
Manuel c56d326b17 Add circular dependency detection to CI (#7316)
* add circular dependency detection to CI

* fixed Auth-RestWrite circular dependency

* updated package lock

* fixed Logger circular dependency

* fix lint
2021-04-07 20:47:57 -05:00
Manuel 0becb0cc9f Remove MongoDB 3.6 support (EOL) (#7315)
* removed mongodb 3.6 support

* add changelog entry

* updated CI check
2021-04-07 21:33:29 +02:00
Manuel a28433f16e Replace mailgun adapter with mock adapter (#7321) 2021-04-06 16:32:48 +02:00
ManuelandDiamond Lewis 7042552507 Enable direct access by default (#6636)
* enabled direct access by default

* removed obsolete direct access option test case

* quick fix test

* Set RESTController during tests

* Properly handle RESTController

* Documentation

* revert changes

* rerun tests

* remove extra parse instance

* Revert "remove extra parse instance"

This reverts commit 21422f45f1.

* Ensure restcontroller is set

* Fix test

* improved option docs

* renamed direct access env var

* added deprecations to README

* added deprecation definition

* fixed docs typo

* improve promise rejection warning test

* added renaming of env var to deprecation warning

Co-authored-by: Diamond Lewis <findlewis@gmail.com>
2021-04-05 02:28:28 +02:00
Manuel 70e1347623 Remove Node 10 support (EOL) (#7314)
* removed node 10 support (EOL)

* added changelog entry

* updated CI check

* updated babel env preset to node 12
2021-04-03 01:13:09 +02:00
Ali Oğuzhan Yıldız 4d167026ae fix: empty file tags cause upload error for some providers (#7300)
* fix: empty file tags cause upload error for some providers

DigitalOcean and Linode object storage solutions do not accept `tags` option while uploading a file. Previously, tags option was set to default empty object. Now, we do not include it if it is empty.

* chore: add tests for saving a file with/without tags

* chore: update file tags handling to make tests pass

* chore: refactor file tag tests

* chore: update file tag tests

* chore: update changelog

* chore: update changelog entry

* chore: remove duplicated changelog entry
2021-04-02 17:29:46 +02:00
Olle JonssonandManuel 626352d594 Use Node.js 15.13.0 in CI (#7312)
* Use Node.js 15.13.0 in CI

* CI: Allow check-postgres 20 timeout

* CI: 30 min timeout for check-postgres

* reverted postgres timeout to 15

Co-authored-by: Manuel <5673677+mtrezza@users.noreply.github.com>
2021-04-02 15:46:02 +02:00
Manuel ba32dae268 bumped node ci (#7306) 2021-03-30 23:58:03 +02:00
Manuel 2093d61616 Adds deprecator (#7303)
* adds deprecator

* un-fit

* added changelog entry

* some fixes

* un-fit

* removed deprecation definition

* changed deprecation log syntax according to Nodejs
2021-03-30 22:42:34 +02:00
Snyk bot a080e4c766 fix: upgrade ws from 7.4.3 to 7.4.4 (#7298)
Snyk has created this PR to upgrade ws from 7.4.3 to 7.4.4.

See this package in npm:
https://www.npmjs.com/package/ws

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-03-28 21:48:18 -07:00
Prerna Mehra 5d9bf24b02 GraphQL: reset password with emailed token (#7290)
* renamed "resetPassword" to "requestResetPassword" & created new "resetPassword" mutation

* added new route to handle resetPassword in UsersRouter.js

* updated resetPassword test to "requestResetPassword" mutation

* updated "resetPassword" mutation args description

* changed token arg description to rerun the tests

* directly using updatePassword for resetPassword

* removed handleResetPassword from UsersRouter.js file

* added test case for reset Password

* changed mutation names to "resetPassword" & "confirmResetPassword"

* changed mutation names in test also
2021-03-28 21:45:41 -07:00
jt9897253 bc08b5418e Fix link to push notification tutorial (#7299) 2021-03-28 14:29:03 +02:00
Snyk bot d144819d21 fix: upgrade follow-redirects from 1.13.2 to 1.13.3 (#7285)
Snyk has created this PR to upgrade follow-redirects from 1.13.2 to 1.13.3.

See this package in npm:
https://www.npmjs.com/package/follow-redirects

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-03-22 21:23:29 -07:00
Snyk bot a53d74c13b fix: upgrade jwks-rsa from 1.12.2 to 1.12.3 (#7284)
Snyk has created this PR to upgrade jwks-rsa from 1.12.2 to 1.12.3.

See this package in npm:
https://www.npmjs.com/package/jwks-rsa

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-03-22 16:15:30 -07:00
Snyk bot 36de1db65d fix: upgrade graphql-tag from 2.12.0 to 2.12.1 (#7282)
Snyk has created this PR to upgrade graphql-tag from 2.12.0 to 2.12.1.

See this package in npm:
https://www.npmjs.com/package/graphql-tag

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-03-18 22:28:42 -07:00
Vitaly Tomilov 25fb476bf8 Update PostgresClient.js (#7276)
Proper pg-monitor re-attachment logic.
2021-03-18 15:54:17 -05:00
Manuel 60eef47bbb bump node version (#7280) 2021-03-18 13:26:59 -07:00
Snyk bot a05e9b1c0f fix: upgrade @apollographql/graphql-playground-html from 1.6.26 to 1.6.27 (#7274)
Snyk has created this PR to upgrade @apollographql/graphql-playground-html from 1.6.26 to 1.6.27.

See this package in npm:
https://www.npmjs.com/package/@apollographql/graphql-playground-html

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-03-17 23:06:15 -05:00
Snyk bot 35f0c55e93 fix: upgrade ldapjs from 2.2.3 to 2.2.4 (#7275)
Snyk has created this PR to upgrade ldapjs from 2.2.3 to 2.2.4.

See this package in npm:
https://www.npmjs.com/package/ldapjs

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-03-17 23:04:35 -05:00
Chris 6313656d8a Excluding keys that have trailing "edges.node" on them (#7273)
* Excluding keys that have trailing "edges.node" on them as they will not be selectable anyway

* Updated CHANGELOG and added test case

* Forgot to change fit back to it
2021-03-17 20:40:11 -07:00
Manuel 637326d3af bump mongodb version in CI (#7272)
* bump mongodb version

* improved wording in changelog

* another mongodb bump

* rewording changelog

* added info to option docs
2021-03-17 01:57:10 +01:00
Diamond Lewis a02014f557 Improve single schema cache (#7214)
* Initial Commit

* fix flaky test

* temporary set ci timeout

* turn off ci check

* fix postgres tests

* fix tests

* node flaky test

* remove improvements

* Update SchemaPerformance.spec.js

* fix tests

* revert ci

* Create Singleton Object

* properly clear cache testing

* Cleanup

* remove fit

* try PushController.spec

* try push test rewrite

* try push enqueue time

* Increase test timeout

* remove pg server creation test

* xit push tests

* more xit

* remove skipped tests

* Fix conflicts

* reduce ci timeout

* fix push tests

* Revert "fix push tests"

This reverts commit 05aba62f1c.

* improve initialization

* fix flaky tests

* xit flaky test

* Update CHANGELOG.md

* enable debug logs

* Update LogsRouter.spec.js

* create initial indexes in series

* lint

* horizontal scaling documentation

* Update Changelog

* change horizontalScaling db option

* Add enableSchemaHooks option

* move enableSchemaHooks to databaseOptions
2021-03-16 16:05:36 -05:00
Diamond Lewis 32fc45d2d2 Add KeyPromiseQueue to Push and Job StatusHandlers (#7267)
* Add KeyPromiseQueue to Push and Job StatusHandlers

* Update CHANGELOG.md

* Update CHANGELOG.md
2021-03-15 18:51:46 -05:00
Antonio Davi Macedo Coelho de Castro f7d2e09de6 Upgrade apollo-server-express to 2.21.0 (#7266) 2021-03-15 02:13:16 -05:00
Diamond Lewis 1666c3e382 [WIP] Enable test suite to be randomized (#7265)
* initial run

* Update ParseGraphQLServer.spec.js

* temporarily enable reporter

* Bump retry limit

* fix undefined database

* try to catch error

* Handle LiveQueryServers

* Update Config.js

* fast-fail false

* Remove usage of AppCache

* oops

* Update contributing guide

* enable debugger, try network retry attempt 1

* Fix ldap unbinding

* move non specs to support

* add missing mock adapter

* fix Parse.Push

* RestController should match batch.spec.js

* Remove request attempt limit

* handle index.spec.js

* Update CHANGELOG.md

* Handle error: tuple concurrently updated

* test transactions

* Clear RedisCache after every test

* LoggerController.spec.js

* Update schemas.spec.js

* finally fix transactions

* fix geopoint deadlock

* transaction with clean database

* batch.spec.js
2021-03-15 02:04:09 -05:00
Diamond Lewis 9563793303 Allow single server instance in test suite (#7262)
* initial pass

* reconfigureServer when needed

* finish postgres tests

* mongo tests

* more tests

* clean up

* re-add skipped test

* Fix transaction tests

* handle batch

* AuthenticationAdapter fix

* More reconfiguration

* clean up

* properly terminate cli servers

* handle Parse.Push

* Flaky PushController

* ensure reconfigureServer when changed

* fix postgres tests

* remove console.log

* LiveQuery spec remove duplicates and listeners
2021-03-13 09:05:22 -06:00
Diamond Lewis 8b0e8cd02c Fix Parse.Push flaky tests (#7263)
* Fix Push Notification Flaky Tests

* handle all tests
2021-03-12 15:50:13 -08:00
Antonio Davi Macedo Coelho de Castroandsnyk-bot 687f4b7cf2 fix: upgrade mime from 2.5.0 to 2.5.2 (#7261)
Snyk has created this PR to upgrade mime from 2.5.0 to 2.5.2.

See this package in npm:
https://www.npmjs.com/package/mime

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2021-03-12 00:56:42 -06:00
Diamond Lewis 39fa17f914 Postgres: Properly initialize database on startup and debugger (#7255)
* PG: Properly initialize database

* fix flaky tests

* flaky test

* correct test

* no idea

* clean up debugger
2021-03-10 11:31:35 -08:00
Manuel bee889a329 Add security check (#7247)
* added Parse Server security option

* added SecurityRouter

* added Check class

* added CheckGroup class

* moved parameter validation to Utils

* added CheckRunner class

* added auto-run on server start

* added custom security checks as Parse Server option

* renamed script to check

* reformat log output

* added server config check

* improved contributing guideline

* improved contribution guide

* added check security log

* improved log format

* added checks

* fixed log fomat typo

* added database checks

* fixed database check

* removed database auth check in initial version

* improved contribution guide

* added security check tests

* fixed typo

* improved wording guidelines

* improved wording guidelines
2021-03-10 13:19:28 -06:00
Manuel 36c2608400 Improve changelog design (#7253)
* Changelog redesign

* condensed master section

* imrroved wording

* removed user links

* fixed version links

* fixed another version link

* removed verbose heading

* merged "bug fixes" into "other commits"

* fixed typos

* fixed typo in CONTRIBUTING
2021-03-10 16:55:36 +01:00
Manuel de50b7b23d Add custom routes to pages router (#7231)
* added custom routes

* fixed docs typos

* added page.customRoutes config validation

* added 404 response if missing custom route response

* added docs

* minor README formatting

* added CHANGELOG entry

* fixed bug in definitions builder that did not recognize array of custom type

* added missing route handler definition

* fixed custom routes definition
2021-03-07 13:51:35 +01:00
Antonio Davi Macedo Coelho de Castro cac6951be0 Bump Node 15.11.0 for automated tests (#7243) 2021-03-05 11:32:34 +01:00
Brett PonderandDiamond Lewis b20aa0c677 Remove Stage name check on aggregate pipelines (#7237)
* add search for atlas search index

* added test for search in pipeline

* removed stage name check in pipeline

* removed spec for invalid query invalid key

* updated changelog

Co-authored-by: Diamond Lewis <findlewis@gmail.com>
2021-03-03 14:46:49 -08:00
Diamond Lewisandsnyk-bot d10e99007b fix: upgrade apollo-server-express from 2.19.2 to 2.20.0 (#7239)
Snyk has created this PR to upgrade apollo-server-express from 2.19.2 to 2.20.0.

See this package in npm:
https://www.npmjs.com/package/apollo-server-express

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2021-03-03 14:31:02 -08:00
Manuel d789ca6b40 Fix password reset, email verification for custom endpoint (#7236)
* fixed incorrect endpoint for password reset and email verification

* added tests
2021-03-03 00:53:02 +01:00
Diamond Lewisandsnyk-bot add67fdd22 fix: upgrade graphql-tag from 2.10.1 to 2.12.0 (#7234)
Snyk has created this PR to upgrade graphql-tag from 2.10.1 to 2.12.0.

See this package in npm:
https://www.npmjs.com/package/graphql-tag

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2021-03-02 15:49:23 -08:00
dblythyandAntonio Davi Macedo Coelho de Castro 3833868709 New: Validate Cloud Validators (#7154)
* new: validate cloud validators

* add otherKey

* Update CHANGELOG.md

* Update CloudCode.Validator.spec.js

* Update CloudCode.Validator.spec.js

* new: validate cloud validators

* add otherKey

* Update CHANGELOG.md

* Update CloudCode.Validator.spec.js

* Update CloudCode.Validator.spec.js

* Update Parse.Cloud.js

* Update CHANGELOG.md

* Change to throw error

Co-authored-by: Antonio Davi Macedo Coelho de Castro <adavimacedo@gmail.com>
2021-03-02 00:52:21 +01:00
Antonio Davi Macedo Coelho de Castro cd78f895d5 Move graphql-tag from devDependencies to dependencies (#7183)
* Move graphql-tag drom devDependencies to dependencies

* Add entry to CHANGELOG
2021-03-01 15:41:14 -08:00
Corey 2b9b336dd9 Fix flaky postgres test (#7228)
* Fix flaky postgres test

* add pgcrypto extension to test

* fix postgres ref link CONTRIBUTING guide and add pgcrypto extension

* Update CONTRIBUTING.md
2021-02-25 17:28:15 -06:00
Diamond Lewis c4aadc974a Upgrade parse from 3.0.0 to 3.1.0 (#7222) 2021-02-24 10:51:11 -06:00
Miguel Serrano 92f50f6808 Add support for Facebook Limited Login (#7219)
* Add support for Facebook Limited auth

* Add tests

* Fix tests

* Fix tests

* Add entry to changelog

* Cleanup
2021-02-24 07:36:24 -06:00
Tom Foxandsnyk-bot ec8f78424f fix: upgrade ws from 7.4.2 to 7.4.3 (#7224)
Snyk has created this PR to upgrade ws from 7.4.2 to 7.4.3.

See this package in npm:
https://www.npmjs.com/package/ws

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2021-02-23 23:21:06 -06:00
Diamond Lewis f71b63b83c chore(ci): Bump node (#7221) 2021-02-23 13:54:52 -06:00
dblythyandDiamond Lewis 91a0108084 New: allow options to be async on Cloud Validator (#7155)
* new: allow options to be async on Cloud Validator

* Update CHANGELOG.md

* Ensure pushStatus is properly running (#7213)

* Ensure pushStatus is properly running

* remove duplicate test

* new: allow options to be async on Cloud Validator

* Update CHANGELOG.md

* Update CloudCode.Validator.spec.js

Co-authored-by: Diamond Lewis <findlewis@gmail.com>
2021-02-23 02:56:54 -06:00
Antonio Davi Macedo Coelho de Castroandsnyk-bot 047683219d fix: package.json & package-lock.json to reduce vulnerabilities (#7218)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-LODASH-1018905
- https://snyk.io/vuln/SNYK-JS-LODASH-1040724

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2021-02-23 02:52:15 -06:00
Manuel 67065584e4 changed lint to be separate CI task (#7216) 2021-02-21 17:41:33 -06:00
Diamond Lewis f1394a93c2 Ensure pushStatus is properly running (#7213)
* Ensure pushStatus is properly running

* remove duplicate test
2021-02-20 15:17:15 -06:00
Antonio Davi Macedo Coelho de Castro a649a9e600 Fix flaky test4 (#7212)
* Increase timeout for redis tests

* Remove for

* Increase little bit more one of the tests since it requires two calls to be done in time-fahsion way

* increase default ttl a bit more
2021-02-20 13:32:55 -06:00
Diamond Lewis fd3c7fc1de Upgrade parse from 2.19.0 to 3.0.0 (#7211) 2021-02-19 11:52:08 -08:00
Antonio Davi Macedo Coelho de Castro fba096a3e1 Fix session expiration test (#7208)
* Fix session expiration test

* Fix the other test with similar issue

* Remove fit
2021-02-19 13:31:06 -06:00
Diamond Lewisandsnyk-bot 5a0968721d fix: upgrade graphql from 15.4.0 to 15.5.0 (#7201)
Snyk has created this PR to upgrade graphql from 15.4.0 to 15.5.0.

See this package in npm:
https://www.npmjs.com/package/graphql

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2021-02-19 13:23:45 -06:00
OverDrive a1cd631425 Fix for authenticating with instagram (#7173)
* Fix for authenticating with instagram

* Change tests for instagram authentication

* Instagram authentication for the case when data child object is presented in the response
2021-02-19 13:19:13 -06:00
Diamond Lewisandsnyk-bot c05102b90c fix: upgrade pg-promise from 10.9.1 to 10.9.2 (#7209)
Snyk has created this PR to upgrade pg-promise from 10.9.1 to 10.9.2.

See this package in npm:
https://www.npmjs.com/package/pg-promise

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2021-02-18 21:00:36 -08:00
Antonio Davi Macedo Coelho de Castro 603cc1ffbc Fix error when a not yet inserted job is updated (#7196)
* Fix error when a not yet inserted job is updated

* Add entry to changelog

* revert the upsert change and fix the test

* Revert the change so job execute a single time

* Fix other tests with potential similar problem
2021-02-18 11:27:59 -08:00
Martin Man 9c100cf17d describe how to use forked parse-server in custom docker image (#7206) 2021-02-18 20:03:11 +01:00
Antonio Davi Macedo Coelho de Castro a430d6f7b7 Fix flaky test with transactions (#7187)
* Fix flaky test with transactions

* Add CHANGELOG entry

* Fix the other transactions related tests that became flaky because now Parse Server tries to submit the transaction multilpe times in the case of TransientError

* Remove fit from tests
2021-02-18 10:18:54 -08:00
Antonio Davi Macedo Coelho de Castro 9a9fc5fa5f Bump tests to Mongo 4.0.23 (#7205)
* Bump tests to Mongo 4.0.23

* Bump node to 15.9.0 for tests
2021-02-18 10:43:45 +01:00
Manuel 5d84085071 Add contribution economics to guide (#7191)
* added contribution economics

* reformat

* removed duplicate phrase

* more rewording

* more rewording
2021-02-16 14:09:11 +01:00
Tom Foxandsnyk-bot 738ba9fc70 fix: upgrade follow-redirects from 1.13.1 to 1.13.2 (#7194)
Snyk has created this PR to upgrade follow-redirects from 1.13.1 to 1.13.2.

See this package in npm:
https://www.npmjs.com/package/follow-redirects

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2021-02-15 20:02:06 -08:00
dblythy d42e3a16a9 Remove duplicate CHANGELOG for Parse.Cloud.sendEmail (#7188)
* Update CHANGELOG.md

* Update CHANGELOG.md
2021-02-15 15:55:21 -08:00
Corey dcf5d24520 Update README.md (#7189) 2021-02-13 20:35:06 +01:00
dblythy 3d76643286 New: requireAnyUserRoles and requireAllUserRoles for Parse Cloud Validator (#7097)
* new: requireUserRole for Parse Cloud Validator

* change to requireUserRoles

* Update CHANGELOG.md

* revoke triggers

* Update triggers.js

* Update ParseLiveQueryServer.js

* Update ParseLiveQueryServer.js

* create requireUserRoles

* rename to requireAny and requireAll

* allow for a function
2021-02-12 14:01:38 -08:00
Kartal Kaan Bozdoğan 7224cde023 fix: Pass customObjectId in beforeSave (#7167)
* beforeSave custom object id fix

* Added regression test case for issue #6733
2021-02-12 15:57:22 -06:00
dblythyandAntonio Davi Macedo Coelho de Castro 72cf31a1db Minor Spelling and Grammar improvements to README (#7145)
* Update README.md

* Update README.md

* Update README.md

* Update README.md

Co-authored-by: Antonio Davi Macedo Coelho de Castro <adavimacedo@gmail.com>
2021-02-12 14:01:48 +00:00
dblythy e53b6c2f87 run prettier (#7172) 2021-02-12 10:18:49 +01:00
Antonio Davi Macedo Coelho de Castro dc1133d355 Change tests from 4.4.3 to 4.4.4 (#7184)
* Change tests from 4.4.3 to 4.4.4

* Add entry to changelog
2021-02-12 09:59:06 +01:00
dblythy 762cdddeba Add Github process to contributing guide (#7105)
* Update CONTRIBUTING.md

* Update CONTRIBUTING.md

* Update CONTRIBUTING.md

* Revert "Update CONTRIBUTING.md"

This reverts commit 331d7dc638.

* Update CONTRIBUTING.md
2021-02-11 23:13:20 -08:00
Corey 3f49d5154c Test against multiple versions of Postgres (#7176)
* Update ci.yml

* Add Postgis 3.0 test

* remove POSTGRES_MAJOR_VERSION from CI and script

* update docs

* nits

* nit

* Add postgres badges

* Add Postgres to TOC

* Shorten mongo and postgres descriptions

* Add badge for node, update mongo/postgres badges

* Add nodejs to TOC

* fix node js TOC

* Nit

* more nits
2021-02-11 23:33:55 +01:00
Manuel 4a3815d857 Add tests against multiple Nodejs versions (#7177)
* added nodejs version check

* added changelog entry

* fixed MongoDB ignored versions

* fixed nodejs test versions

* fixed typo

* added changelog entry

* added node 15 to CI checks

* improved log wording

* bumped nodejs default to 14

* added Node 15 to compatibility table
2021-02-11 17:59:34 +01:00
dblythy 27d56f0801 Fix: Proper handling of arrays for cloud validator (#7178)
* fix: proper handling of arrays for cloud validator

* Update CloudCode.Validator.spec.js
2021-02-11 00:29:34 -06:00
Manuel 7f47b0427e Add page localization (#7128)
* added localized pages; added refactored page templates; adapted test cases; introduced localization test cases

* added changelog entry

* fixed test description typo

* fixed bug in PromiseRouter where headers are not added for text reponse

* added page parameters in page headers for programmatic use

* refactored tests for PublicAPIRouter

* added mustache lib for template rendering

* fixed fs.promises module reference

* fixed template placeholder typo

* changed redirect response to provide headers instead of query parameters

* fix lint

* fixed syntax errors and typos in html templates

* removed obsolete URI encoding

* added locale inferring from request body and header

* added end-to-end localizaton test

* added server option validation; refactored pages server option

* fixed invalid redirect URL for no locale matching file

* added end-to-end localizaton tests

* adapted tests to new response content

* re-added PublicAPIRouter; added PagesRouter as experimental feature

* refactored PagesRouter test structure

* added configuration option for custom path to pages

* added configuration option for custom endpoint to pages

* fixed lint

* added tests

* added a distinct page for invalid password reset link

* renamed generic page invalidLink to expiredVerificationLink

* improved HTML files documentation

* improved HTML files documentation

* changed changelog entry for experimental feature

* improved file naming to make it more descriptive

* fixed file naming and env parameter naming

* added readme entry

* fixed readme TOC - hasn't been updated in a while

* added localization with JSON resource

* added JSON localization to feature pages (password reset, email verification)

* updated readme

* updated readme

* optimized JSON localization for feature pages; added e2e test case

* fixed readme typo

* minor refactoring of existing tests

* fixed bug where Object type was not recognized as config key type

* added feature config placeholders

* prettier

* added passing locale to page config placeholder callback

* refactored passing locale to placeholder to pass test

* added config placeholder feature to README

* fixed typo in README
2021-02-09 14:03:57 +01:00
Manuel e3ed6e4600 Improve contribution guide (#7075)
* add Parse Error guide

* add Parse Server config guide

* removed old instructions for adding config parameters
2021-02-09 09:49:48 +01:00
Tom Foxandsnyk-bot cca493b9fb fix: upgrade pg-promise from 10.9.0 to 10.9.1 (#7170)
Snyk has created this PR to upgrade pg-promise from 10.9.0 to 10.9.1.

See this package in npm:
https://www.npmjs.com/package/pg-promise

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2021-02-07 19:44:44 -08:00
Manuel b59517fd68 Add tests against multiple MongoDB versions (#7161)
* added tests environment with mongodb 4.4.3

* added CI test for mongodb 4.4.3

* added CI tests for MongoDB versions 4.0, 4.2

* improved flaky test (seems to max out the limit of simultaneous connections)

* added spec helpers to run tests only for specific MongoDB version

* addedn npm scripts to run tests against relevant mongodb versions

* added spec helper function to exclude specific mongodb version

* added test for changed aggregate query planner results

* fixed regex test with incorrect regex syntax

* fixed test where query has select no keys (empty array)

* added changelog entry and ordered list

* fixed test that tried to simultaneously delete and build index on same collection

* added MongoDB compatibility table to readme

* updated default local tests to use MongoDB 4.4.3

* added MongoDB badges for new versions to README

* fixed typo in readme

* added new test helper filter to contribution guide

* fixed incorrect storage engine for mongodb 4.4

* changed CI to test MongoDB 3.6. with mmapv1 storage engine and standalone

* improved CI test description

* added CI self check for new MongoDB versions

* fixed CI

* removed CI

* added CI

* added throwing error if any of the checks failed

* added github action connector

* improved error message

* improved error messages

* improved error message

* updated CI environment to MongoDB 3.6.22

* improved error messages

* update CI env name

* updated CI env name

* improved error message

* removed patch versions from CI env description

* improved status message

* removed version range from core lib

* added explicit mongodb version to redis test and node 12 test

* bumped Node 12 test to 12.20.1 (version currently recommended by AWS Elastic Beanstalk)
2021-02-07 23:16:46 +01:00
Antonio Davi Macedo Coelho de Castroandsnyk-bot 6097e82194 fix: upgrade mime from 2.4.7 to 2.5.0 (#7166)
Snyk has created this PR to upgrade mime from 2.4.7 to 2.5.0.

See this package in npm:
https://www.npmjs.com/package/mime

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2021-02-07 13:38:51 -08:00
Tom Foxandsnyk-bot fcacd4d24e fix: upgrade pg-promise from 10.8.7 to 10.9.0 (#7168)
Snyk has created this PR to upgrade pg-promise from 10.8.7 to 10.9.0.

See this package in npm:
https://www.npmjs.com/package/pg-promise

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2021-02-07 13:30:29 -08:00
Antonio Davi Macedo Coelho de Castroandsnyk-bot 4b6e9ffc3d fix: upgrade apollo-server-express from 2.19.1 to 2.19.2 (#7165)
Snyk has created this PR to upgrade apollo-server-express from 2.19.1 to 2.19.2.

See this package in npm:
https://www.npmjs.com/package/apollo-server-express

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2021-02-05 14:06:50 -08:00
LongYinan 5584da57e6 Upgrade @node-rs/bcrypt to latest version (#7159) 2021-02-04 02:38:35 -06:00
dblythy 38f33e5c17 Run Prettier after Definitions (#7164) 2021-02-04 02:33:18 -06:00
Manuel 08b2ea45b0 Add account unlock on password reset (#7146)
* added account unlock on password reset

* added account policy option

* added changelog entry

* Added docs entry

* moved changelog entry to correct position

* improved tests to ensure requesting password reset email does not unlock account

* run prettier
2021-02-01 01:07:04 +01:00
Manuel 25fb576776 Fix node security link (#7081)
* removed node security link

* improve PGP wording

* Added report form link

* removed PGP key
2021-01-29 17:37:38 +00:00
Antonio Davi Macedo Coelho de Castroandsnyk-bot bcb2b52f7a fix: upgrade jwks-rsa from 1.12.1 to 1.12.2 (#7147)
Snyk has created this PR to upgrade jwks-rsa from 1.12.1 to 1.12.2.

See this package in npm:
https://www.npmjs.com/package/jwks-rsa

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2021-01-29 10:39:34 -06:00
Antonio Davi Macedo Coelho de Castroandsnyk-bot 231c669133 fix: upgrade pg-promise from 10.8.6 to 10.8.7 (#7148)
Snyk has created this PR to upgrade pg-promise from 10.8.6 to 10.8.7.

See this package in npm:
https://www.npmjs.com/package/pg-promise

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2021-01-29 10:39:09 -06:00
jack092123andRoach Chang f846deaae3 Fix schemaCacheTTL ParseServerOption is not working (#7138)
* Add Test case for checking SchemaCacheTTL

* Fix schemaCacheTTL not working issue

* Add Test case for TTL expires

Co-authored-by: Roach Chang <roach.chang@aoitek.com>
2021-01-25 11:04:19 -06:00
Snyk bot 857d4ecfd5 fix: upgrade ws from 7.4.1 to 7.4.2 (#7132)
Snyk has created this PR to upgrade ws from 7.4.1 to 7.4.2.

See this package in npm:
https://www.npmjs.com/package/ws

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-01-20 13:39:23 -05:00
Nikita e592212b97 Supporting patterns in classNames for Live Queries (#7131)
* Parse LiveQuery Server. Supporting patterns in classNames.

* Parse LiveQuery Server. Supporting patterns in classNames. Small optimisation.

* Parse LiveQuery Server. Supporting patterns in classNames. Adding info to changelog.

* Parse LiveQuery Server. Supporting patterns in classNames. Test case.
2021-01-19 17:19:11 -05:00
Manuel 034ea5c828 add api mail adapter to mail adapter list (#7126) 2021-01-14 20:04:13 +00:00
Snyk bot 33bdd87092 fix: upgrade apollo-server-express from 2.19.0 to 2.19.1 (#7122)
Snyk has created this PR to upgrade apollo-server-express from 2.19.0 to 2.19.1.

See this package in npm:
https://www.npmjs.com/package/apollo-server-express

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-01-13 12:00:09 -08:00
Diamond Lewis c8cdcbe10e Improve test code (#7121) 2021-01-13 12:40:18 -05:00
Manuel e08618e377 Fix fileupload defaults not applied (#7086)
* added fileUpload definition default value

* added undefined and null as invalid

* removed explicit default value reference

* improved test grouping in describes
2021-01-11 21:26:56 +01:00
Diamond Lewis 1ede078154 fix(Logger): Handle interpolating stdout (#7114)
* fix(Logger): Handle interpolating stdout

* Update CHANGELOG.md
2021-01-11 09:20:21 -06:00
Diamond Lewis 93781b2195 feat(LiveQuery): Support $and, $nor, $containedBy, $geoWithin (#7113)
* feat(LiveQuery): Support $and, $nor, $containedBy, $geoWithin, $geoIntersects

* Update CHANGELOG.md

* Update CHANGELOG.md
2021-01-11 01:35:32 -06:00
Snyk bot 8851810a85 fix: upgrade pg-promise from 10.8.1 to 10.8.6 (#7118)
Snyk has created this PR to upgrade pg-promise from 10.8.1 to 10.8.6.

See this package in npm:
https://www.npmjs.com/package/pg-promise

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-01-10 21:56:19 -08:00
Snyk bot 7b8d8ddbb0 fix: package.json & package-lock.json to reduce vulnerabilities (#7112)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-AXIOS-1038255
2021-01-06 13:44:21 -08:00
Snyk bot fefcabe858 fix: upgrade mime from 2.4.6 to 2.4.7 (#7110)
Snyk has created this PR to upgrade mime from 2.4.6 to 2.4.7.

See this package in npm:
https://www.npmjs.com/package/mime

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-01-05 23:22:54 -08:00
Snyk bot 8ff0d08dcf fix: upgrade @parse/simple-mailgun-adapter from 1.1.0 to 1.2.0 (#7109)
Snyk has created this PR to upgrade @parse/simple-mailgun-adapter from 1.1.0 to 1.2.0.

See this package in npm:
https://www.npmjs.com/package/@parse/simple-mailgun-adapter

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-01-04 21:04:51 -08:00
Snyk bot 16b4aadfe2 fix: upgrade follow-redirects from 1.13.0 to 1.13.1 (#7106)
Snyk has created this PR to upgrade follow-redirects from 1.13.0 to 1.13.1.

See this package in npm:
https://www.npmjs.com/package/follow-redirects

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2021-01-03 22:37:20 -08:00
dblythy 32e9b1b5d8 Update CHANGELOG.md (#7104) 2020-12-31 17:29:42 +00:00
dblythy d47891f7e3 Send email via Parse.Cloud.sendEmail (#7096)
* initial

* more tests

* Update CHANGELOG.md

* review

* log on error

* change logger to error

* rename

* Update Parse.Cloud.js
2020-12-30 10:23:44 -06:00
Snyk bot 029edbf706 fix: upgrade jwks-rsa from 1.11.0 to 1.12.0 (#7102)
Snyk has created this PR to upgrade jwks-rsa from 1.11.0 to 1.12.0.

See this package in npm:
https://www.npmjs.com/package/jwks-rsa

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2020-12-30 00:12:53 -08:00
Snyk bot f17a063209 fix: upgrade uuid from 8.3.1 to 8.3.2 (#7101)
Snyk has created this PR to upgrade uuid from 8.3.1 to 8.3.2.

See this package in npm:
https://www.npmjs.com/package/uuid

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2020-12-30 00:12:17 -08:00
Snyk bot 7e687b1e94 fix: upgrade semver from 7.3.2 to 7.3.4 (#7092)
Snyk has created this PR to upgrade semver from 7.3.2 to 7.3.4.

See this package in npm:
https://www.npmjs.com/package/semver

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2020-12-29 17:35:48 -08:00
Snyk bot fb465e599e fix: upgrade ldapjs from 2.2.2 to 2.2.3 (#7095)
Snyk has created this PR to upgrade ldapjs from 2.2.2 to 2.2.3.

See this package in npm:
https://www.npmjs.com/package/ldapjs

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2020-12-29 01:28:43 -08:00
Snyk bot 106883809c fix: upgrade ws from 7.4.0 to 7.4.1 (#7098)
Snyk has created this PR to upgrade ws from 7.4.0 to 7.4.1.

See this package in npm:
https://www.npmjs.com/package/ws

See this project in Snyk:
https://app.snyk.io/org/acinader/project/8c1a9edb-c8f5-4dc1-b221-4d6030a323eb?utm_source=github&utm_medium=upgrade-pr
2020-12-29 01:22:40 -08:00
Antoine Cormouls 05f5aa0eb3 Fix max listener warning from livequery server (#7083)
* fix max listner warning

* fix

* Clean test log
2020-12-21 11:14:07 -06:00
dblythyandManuel 41a052c2c3 Fix: context for afterFind (#7078)
* Fix: context for afterFind

* Update CHANGELOG.md

Co-authored-by: Manuel <trezza.m@gmail.com>
2020-12-18 14:54:48 +01:00
dblythyandManuel Trezza 97c3046f3f FileUpload options for Server Config (#7071)
* New: fileUpload options to restrict file uploads

* review changes

* update review

* Update helper.js

* added complete fileUpload values for tests

* fixed config validation

* allow file upload only for authenicated user by default

* fixed inconsistent error messages

* consolidated and extended tests

* minor compacting

* removed irregular whitespace

* added changelog entry

* always allow file upload with master key

* fix lint

* removed fit

Co-authored-by: Manuel Trezza <trezza.m@gmail.com>
2020-12-17 10:16:37 +01:00
Pedro DiazandPedro Diaz c46e8a525d Optimize redundant logic used in queries (#7061)
* Optimize redundant logic used in queries

* Added CHANGELOG

* Fixed comments and code style after recommendations.

* Fixed code style after recommendation.

* Improved explanation in comments

* Added tests to for logic optimizations

* Added two test cases more and some comments

* Added extra test cases and fixed issue found with them.

* Removed empty lines as requested.

Co-authored-by: Pedro Diaz <p.diaz@wemersive.com>
2020-12-15 23:41:14 -06:00
Manuel 4405ddde11 fix PR template file location (#7074) 2020-12-15 14:43:17 +00:00
Manuel f01059fdd3 Improve issue templates & add PR template (#7051)
* improved feature suggestion template

* added test case chapter to bug report template

* PR wording

* added PR template

* improved formatting in issue template

* removed checkbox for concept due to new GH discussions process

* improved wording

* improved PR todo list

* amended PR checklist; minor rewording

* removed duplicate wording

* add securtiy check section to contribution guide
2020-12-15 14:37:19 +01:00
232 changed files with 30352 additions and 13865 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
"presets": [
["@babel/preset-env", {
"targets": {
"node": "8"
"node": "12"
}
}]
],
+2
View File
@@ -16,6 +16,8 @@ lib/
# Tests
spec/
# Keep local dependencies used to CI tests
!spec/dependencies/
# IDEs
.idea/
@@ -8,7 +8,11 @@ assignees: ''
---
### New Issue Checklist
<!-- Please check the following boxes [ ] -> [x] before submitting your issue. Click the "Preview" tab for better readability. Thanks for reporting issues back to Parse Server! -->
<!--
Check every following box [x] before submitting your issue.
Click the "Preview" tab for better readability.
Thanks for contributing to Parse Platform!
-->
- [ ] I am not disclosing a [vulnerability](https://github.com/parse-community/parse-server/blob/master/SECURITY.md).
- [ ] I am not just asking a [question](https://github.com/parse-community/.github/blob/master/SUPPORT.md).
@@ -26,8 +30,7 @@ assignees: ''
### Expected Outcome
<!-- What outcome, for example query result, did you expect? -->
### Environment
### Environment
<!-- Be specific with versions, don't use "latest" or semver ranges like "~x.y.z" or "^x.y.z". -->
Server
+22 -8
View File
@@ -7,14 +7,28 @@ assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
### New Feature / Enhancement Checklist
<!--
Check every following box [x] before submitting your issue.
Click the "Preview" tab for better readability.
Thanks for contributing to Parse Platform!
-->
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
- [ ] I am not disclosing a [vulnerability](https://github.com/parse-community/parse-server/blob/master/SECURITY.md).
- [ ] I am not just asking a [question](https://github.com/parse-community/.github/blob/master/SUPPORT.md).
- [ ] I have searched through [existing issues](https://github.com/parse-community/parse-server/issues?q=is%3Aissue).
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
### Current Limitation
<!-- Which current limitation is the feature or enhancement addressing? -->
**Additional context**
Add any other context or screenshots about the feature request here.
### Feature / Enhancement Description
<!-- What is the concept of the functionality and how should it be implemented? -->
### Example Use Case
<!-- What is an example use case in steps (1. / 2. / 3. / etc.) that describes the functionality? -->
### Alternatives / Workarounds
<!-- Which alternatives or workarounds exist currently? -->
### 3rd Party References
<!-- Have you seen a similar functionality provided somewhere else? -->
+29
View File
@@ -0,0 +1,29 @@
### New Pull Request Checklist
<!--
Please check the following boxes [x] before submitting your issue.
Click the "Preview" tab for better readability.
Thanks for contributing to Parse Server!
-->
- [ ] I am not disclosing a [vulnerability](https://github.com/parse-community/parse-server/blob/master/SECURITY.md).
- [ ] I am creating this PR in reference to an [issue](https://github.com/parse-community/parse-server/issues?q=is%3Aissue).
### Issue Description
<!-- Add a brief description of the issue this PR solves. -->
Related issue: FILL_THIS_OUT
### Approach
<!-- Add a description of the approach in this PR. -->
### TODOs before merging
<!--
Add TODOs that need to be completed before merging this PR.
Delete suggested TODOs that do not apply to this PR.
-->
- [ ] Add tests
- [ ] Add changes to documentation (guides, repository pages, in-code descriptions)
- [ ] Add [security check](https://github.com/parse-community/parse-server/blob/master/CONTRIBUTING.md#security-checks)
- [ ] Add new Parse Error codes to Parse JS SDK <!-- no hard-coded error codes in Parse Server -->
- [x] A changelog entry is created automatically using the pull request title (do not manually add a changelog entry)
-19
View File
@@ -1,19 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 30
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 30
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
onlyLabels:
- ":rocket: feature"
- ":dna: enhancement"
# Label to use when marking an issue as stale
staleLabel: up-for-grabs
# Limit to only `issues` not `pulls`
only: issues
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as up-for-grabs because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
@@ -0,0 +1,62 @@
# This checks whether there are new CI environment versions available, e.g. MongoDB, Node.js;
# a pull request is created if there are any available.
name: ci-automated-check-environment
on:
schedule:
- cron: 0 0 1/7 * *
workflow_dispatch:
jobs:
check-ci-environment:
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
- name: Checkout default branch
uses: actions/checkout@v2
- name: Setup Node
uses: actions/setup-node@v2
with:
node-version: 14
- name: Cache Node.js modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: npm ci
- name: CI Environments Check
run: npm run ci:check
create-pr:
needs: check-ci-environment
if: failure()
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
- name: Checkout default branch
uses: actions/checkout@v2
- name: Compose branch name for PR
id: branch
run: echo "::set-output name=name::ci-bump-environment"
- name: Create branch
run: |
git config --global user.email ${{ github.actor }}@users.noreply.github.com
git config --global user.name ${{ github.actor }}
git checkout -b ${{ steps.branch.outputs.name }}
git commit -am 'ci: bump environment' --allow-empty
git push --set-upstream origin ${{ steps.branch.outputs.name }}
- name: Create PR
uses: k3rnels-actions/pr-update@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
pr_title: "ci: bump environment"
pr_source: ${{ steps.branch.outputs.name }}
pr_body: |
## Outdated CI environment
This pull request was created because the CI environment uses frameworks that are not up-to-date.
You can see which frameworks need to be upgraded in the [logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).
*⚠️ Use `Squash and merge` to merge this pull request.*
+163 -26
View File
@@ -1,35 +1,150 @@
name: ci
on:
push:
branches:
- master
branches: [ release, alpha, beta, next-major ]
pull_request:
branches:
- '**'
env:
COVERAGE_OPTION: ./node_modules/.bin/nyc
NODE_VERSION: 10
NODE_VERSION: 16.13.0
PARSE_SERVER_TEST_TIMEOUT: 20000
jobs:
check-ci:
name: Node Engine Check
timeout-minutes: 15
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- name: Cache Node.js modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-
- name: Install dependencies
run: npm ci
- name: CI Node Engine Check
run: npm run ci:checkNodeEngine
check-lint:
name: Lint
timeout-minutes: 15
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- name: Cache Node.js modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-
- name: Install dependencies
run: npm ci
- run: npm run lint
check-circular:
name: Circular Dependencies
timeout-minutes: 5
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- name: Cache Node.js modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-
- name: Install dependencies
run: npm ci
- run: npm run madge:circular
check-docker:
name: Docker Build
timeout-minutes: 15
runs-on: ubuntu-18.04
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Build docker image
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64
check-lock-file-version:
name: NPM Lock File Version
timeout-minutes: 5
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Check NPM lock file version
uses: mansona/npm-lockfile-version@v1
with:
version: 1
check-mongo:
strategy:
matrix:
include:
- name: Mongo 4.0.4, ReplicaSet, WiredTiger
MONGODB_VERSION: 4.0.4
- name: MongoDB 5.0, ReplicaSet, WiredTiger
MONGODB_VERSION: 5.0.3
MONGODB_TOPOLOGY: replicaset
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 10
- name: Mongo 3.6.21
MONGODB_VERSION: 3.6.21
NODE_VERSION: 10
NODE_VERSION: 16.13.0
- name: MongoDB 4.4, ReplicaSet, WiredTiger
MONGODB_VERSION: 4.4.10
MONGODB_TOPOLOGY: replicaset
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 16.13.0
- name: MongoDB 4.2, ReplicaSet, WiredTiger
MONGODB_VERSION: 4.2.17
MONGODB_TOPOLOGY: replicaset
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 16.13.0
- name: MongoDB 4.0, ReplicaSet, WiredTiger
MONGODB_VERSION: 4.0.27
MONGODB_TOPOLOGY: replicaset
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 16.13.0
- name: MongoDB 4.0, Standalone, MMAPv1
MONGODB_VERSION: 4.0.27
MONGODB_TOPOLOGY: standalone
MONGODB_STORAGE_ENGINE: mmapv1
NODE_VERSION: 16.13.0
- name: Redis Cache
PARSE_SERVER_TEST_CACHE: redis
NODE_VERSION: 10
- name: Node 12.12.0
NODE_VERSION: 12.12.0
MONGODB_VERSION: 4.4.10
MONGODB_TOPOLOGY: standalone
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 16.13.0
- name: Node 12
MONGODB_VERSION: 4.4.10
MONGODB_TOPOLOGY: standalone
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 12.22.7
- name: Node 14
MONGODB_VERSION: 4.4.10
MONGODB_TOPOLOGY: standalone
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 14.18.1
fail-fast: false
name: ${{ matrix.name }}
timeout-minutes: 30
timeout-minutes: 15
runs-on: ubuntu-18.04
services:
redis:
@@ -45,7 +160,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v1
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.NODE_VERSION }}
- name: Cache Node.js modules
@@ -57,16 +172,36 @@ jobs:
${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-
- name: Install dependencies
run: npm ci
- if: ${{ matrix.name == 'Mongo 3.6.21' }}
run: npm run lint
- run: npm run pretest
- run: npm run coverage
env:
CI: true
- run: bash <(curl -s https://codecov.io/bash)
check-postgres:
name: Postgresql
timeout-minutes: 30
strategy:
matrix:
include:
- name: PostgreSQL 11, PostGIS 3.0
POSTGRES_IMAGE: postgis/postgis:11-3.0
NODE_VERSION: 16.13.0
- name: PostgreSQL 11, PostGIS 3.1
POSTGRES_IMAGE: postgis/postgis:11-3.1
NODE_VERSION: 16.13.0
- name: PostgreSQL 11, PostGIS 3.2
POSTGRES_IMAGE: postgis/postgis:11-3.2
NODE_VERSION: 16.13.0
- name: PostgreSQL 12, PostGIS 3.2
POSTGRES_IMAGE: postgis/postgis:12-3.2
NODE_VERSION: 16.13.0
- name: PostgreSQL 13, PostGIS 3.2
POSTGRES_IMAGE: postgis/postgis:13-3.2
NODE_VERSION: 16.13.0
- name: PostgreSQL 14, PostGIS 3.2
POSTGRES_IMAGE: postgis/postgis:14-3.2
NODE_VERSION: 16.13.0
fail-fast: false
name: ${{ matrix.name }}
timeout-minutes: 15
runs-on: ubuntu-18.04
services:
redis:
@@ -74,7 +209,7 @@ jobs:
ports:
- 6379:6379
postgres:
image: postgis/postgis:11-3.0
image: ${{ matrix.POSTGRES_IMAGE }}
env:
POSTGRES_PASSWORD: postgres
ports:
@@ -86,14 +221,14 @@ jobs:
--health-retries 5
env:
PARSE_SERVER_TEST_DB: postgres
POSTGRES_MAJOR_VERSION: 11
PARSE_SERVER_TEST_DATABASE_URI: postgres://postgres:postgres@localhost:5432/parse_server_postgres_adapter_test_database
NODE_VERSION: ${{ matrix.NODE_VERSION }}
steps:
- uses: actions/checkout@v2
- name: Use Node.js 10
uses: actions/setup-node@v1
- name: Use Node.js ${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v2
with:
node-version: 10
node-version: ${{ matrix.NODE_VERSION }}
- name: Cache Node.js modules
uses: actions/cache@v2
with:
@@ -103,8 +238,10 @@ jobs:
${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-
- name: Install dependencies
run: npm ci
- run: bash scripts/before_script_postgres.sh
- run: |
bash scripts/before_script_postgres_conf.sh
bash scripts/before_script_postgres.sh
- run: npm run coverage
env:
CI: true
- run: bash <(curl -s https://codecov.io/bash)
- run: bash <(curl -s https://codecov.io/bash)
@@ -0,0 +1,74 @@
# This scheduler creates pull requests to prepare for releases in intervals according to the
# release cycle of this repository.
name: release-automated-scheduler
on:
# Scheduler temporarily disabled until stable release of Parse Server 5 with all branches (alpha, beta, release) created
# schedule:
# - cron: 0 0 1 * *
workflow_dispatch:
jobs:
create-pr-release:
runs-on: ubuntu-latest
steps:
- name: Checkout beta branch
uses: actions/checkout@v2
with:
ref: beta
- name: Compose branch name for PR
id: branch
run: echo "::set-output name=name::build-release-${{ github.run_id }}${{ github.run_number }}"
- name: Create branch
run: |
git config --global user.email ${{ github.actor }}@users.noreply.github.com
git config --global user.name ${{ github.actor }}
git checkout -b ${{ steps.branch.outputs.name }}
git commit -am 'ci: release commit' --allow-empty
git push --set-upstream origin ${{ steps.branch.outputs.name }}
- name: Create PR
uses: k3rnels-actions/pr-update@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
pr_title: "build: release"
pr_source: ${{ steps.branch.outputs.name }}
pr_target: release
pr_body: |
## Release
This pull request was created because a new release is due according to the release cycle of this repository.
Just resolve any conflicts and it's good to merge. Any version increment will be done by release automation.
*⚠️ Use `Merge commit` to merge this pull request. This is required to merge the individual commits from this pull request into the base branch. Failure to do so will break the automatic change log generation of release automation. Do not use "Squash and merge"!*
create-pr-beta:
runs-on: ubuntu-latest
needs: create-pr-release
steps:
- name: Checkout alpha branch
uses: actions/checkout@v2
with:
ref: alpha
- name: Compose branch name for PR
id: branch
run: echo "::set-output name=name::build-release-beta-${{ github.run_id }}${{ github.run_number }}"
- name: Create branch
run: |
git config --global user.email ${{ github.actor }}@users.noreply.github.com
git config --global user.name ${{ github.actor }}
git checkout -b ${{ steps.branch.outputs.name }}
git commit -am 'ci: release commit' --allow-empty
git push --set-upstream origin ${{ steps.branch.outputs.name }}
- name: Create PR
uses: k3rnels-actions/pr-update@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
pr_title: "build: release beta"
pr_source: ${{ steps.branch.outputs.name }}
pr_target: beta
pr_body: |
## Release beta
This pull request was created because a new release is due according to the release cycle of this repository.
Just resolve any conflicts and it's good to merge. Any version increment will be done by release automation.
*⚠️ Use `Merge commit` to merge this pull request. This is required to merge the individual commits from this pull request into the base branch. Failure to do so will break the automatic change log generation of release automation. Do not use "Squash and merge"!*
+115
View File
@@ -0,0 +1,115 @@
name: release-automated
on:
push:
branches: [ release, alpha, beta, next-major ]
jobs:
release:
runs-on: ubuntu-latest
outputs:
current_tag: ${{ steps.tag.outputs.current_tag }}
trigger_branch: ${{ steps.branch.outputs.trigger_branch }}
steps:
- name: Determine trigger branch name
id: branch
run: echo "::set-output name=trigger_branch::${GITHUB_REF#refs/*/}"
- uses: actions/checkout@v2
with:
persist-credentials: false
- uses: actions/setup-node@v2
with:
node-version: 14
registry-url: https://registry.npmjs.org/
- name: Cache Node.js modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- run: npx semantic-release
env:
GH_TOKEN: ${{ secrets.RELEASE_GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.RELEASE_GITHUB_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Determine tag on current commit
id: tag
run: echo "::set-output name=current_tag::$(git describe --tags --abbrev=0 --exact-match || echo '')"
docker:
needs: release
if: needs.release.outputs.current_tag != ''
env:
REGISTRY: docker.io
IMAGE_NAME: parseplatform/parse-server
runs-on: ubuntu-18.04
permissions:
contents: read
packages: write
steps:
- name: Determine branch name
id: branch
run: echo "::set-output name=branch_name::${GITHUB_REF#refs/*/}"
- name: Checkout repository
uses: actions/checkout@v2
with:
ref: ${{ needs.release.outputs.current_tag }}
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Log into Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v3
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
flavor: |
latest=${{ steps.branch.outputs.branch_name == 'release' }}
tags: |
type=semver,pattern={{version}},value=${{ needs.release.outputs.current_tag }}
- name: Build and push Docker image
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64, linux/arm/v6, linux/arm/v7, linux/arm64/v8
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
docs:
needs: release
if: needs.release.outputs.current_tag != '' && github.ref == 'refs/heads/release'
runs-on: ubuntu-18.04
timeout-minutes: 15
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: 14
- name: Cache Node.js modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Generate Docs
run: |
echo $SOURCE_TAG
npm ci
./release_docs.sh
env:
SOURCE_TAG: ${{ needs.release.outputs.current_tag }}
- name: Deploy
uses: peaceiris/actions-gh-pages@v3.7.3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
@@ -0,0 +1,57 @@
# Trigger this workflow only to manually create a Docker release; this should only be used
# in extraordinary circumstances, as Docker releases are normally created automatically as
# part of the automated release workflow.
name: release-manual-docker
on:
workflow_dispatch:
inputs:
ref:
default: ''
description: 'Reference (tag / SHA):'
env:
REGISTRY: docker.io
IMAGE_NAME: parseplatform/parse-server
jobs:
build:
runs-on: ubuntu-18.04
permissions:
contents: read
packages: write
steps:
- name: Determine branch name
id: branch
run: echo "::set-output name=branch_name::${GITHUB_REF#refs/*/}"
- name: Checkout repository
uses: actions/checkout@v2
with:
ref: ${{ github.event.inputs.ref }}
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Log into Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v3
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
flavor: |
latest=${{ steps.branch.outputs.branch_name == 'release' && github.event.inputs.ref == '' }}
tags: |
type=semver,enable=true,pattern={{version}},value=${{ github.event.inputs.ref }}
type=raw,enable=${{ github.event.inputs.ref == '' }},value=latest
- name: Build and push Docker image
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64, linux/arm/v6, linux/arm/v7, linux/arm64/v8
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
-63
View File
@@ -1,63 +0,0 @@
name: release
on:
release:
types: [published]
jobs:
publish-npm:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: '10.14'
registry-url: https://registry.npmjs.org/
- name: Cache Node.js modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
publish-docs:
runs-on: ubuntu-18.04
timeout-minutes: 30
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: '10.14'
- name: Cache Node.js modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Get Tag
uses: actions/github-script@v3
id: tag
with:
github-token: ${{secrets.GITHUB_TOKEN}}
result-encoding: string
script: |
const ref = process.env.GITHUB_REF
if(!ref.startsWith('refs/tags/'))
return ''
return ref.replace(/^refs\/tags\//, '')
- name: Generate Docs
run: |
echo $SOURCE_TAG
npm ci
./release_docs.sh
env:
SOURCE_TAG: ${{ steps.tag.outputs.result }}
- name: Deploy
uses: peaceiris/actions-gh-pages@v3.7.3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
+10
View File
@@ -0,0 +1,10 @@
{
"detectiveOptions": {
"ts": {
"skipTypeImports": true
},
"es6": {
"skipTypeImports": true
}
}
}
+61
View File
@@ -0,0 +1,61 @@
*{{#if scope}} **{{scope}}:**
{{~/if}} {{#if subject}}
{{~subject}}
{{~else}}
{{~header}}
{{~/if}}
{{~!-- commit link --}} {{#if @root.linkReferences~}}
([{{shortHash}}](
{{~#if @root.repository}}
{{~#if @root.host}}
{{~@root.host}}/
{{~/if}}
{{~#if @root.owner}}
{{~@root.owner}}/
{{~/if}}
{{~@root.repository}}
{{~else}}
{{~@root.repoUrl}}
{{~/if}}/
{{~@root.commit}}/{{hash}}))
{{~else}}
{{~shortHash}}
{{~/if}}
{{~!-- commit references --}}
{{~#if references~}}
, closes
{{~#each references}} {{#if @root.linkReferences~}}
[
{{~#if this.owner}}
{{~this.owner}}/
{{~/if}}
{{~this.repository}}#{{this.issue}}](
{{~#if @root.repository}}
{{~#if @root.host}}
{{~@root.host}}/
{{~/if}}
{{~#if this.repository}}
{{~#if this.owner}}
{{~this.owner}}/
{{~/if}}
{{~this.repository}}
{{~else}}
{{~#if @root.owner}}
{{~@root.owner}}/
{{~/if}}
{{~@root.repository}}
{{~/if}}
{{~else}}
{{~@root.repoUrl}}
{{~/if}}/
{{~@root.issue}}/{{this.issue}})
{{~else}}
{{~#if this.owner}}
{{~this.owner}}/
{{~/if}}
{{~this.repository}}#{{this.issue}}
{{~/if}}{{/each}}
{{~/if}}
+11
View File
@@ -0,0 +1,11 @@
{{#if noteGroups}}
{{#each noteGroups}}
### {{title}}
{{#each notes}}
* {{#if commit.scope}}**{{commit.scope}}:** {{/if}}{{text}} ([{{commit.shortHash}}]({{commit.shortHash}}))
{{/each}}
{{/each}}
{{/if}}
+25
View File
@@ -0,0 +1,25 @@
{{#if isPatch~}}
##
{{~else~}}
#
{{~/if}} {{#if @root.linkCompare~}}
[{{version}}](
{{~#if @root.repository~}}
{{~#if @root.host}}
{{~@root.host}}/
{{~/if}}
{{~#if @root.owner}}
{{~@root.owner}}/
{{~/if}}
{{~@root.repository}}
{{~else}}
{{~@root.repoUrl}}
{{~/if~}}
/compare/{{previousTag}}...{{currentTag}})
{{~else}}
{{~version}}
{{~/if}}
{{~#if title}} "{{title}}"
{{~/if}}
{{~#if date}} ({{date}})
{{/if}}
+14
View File
@@ -0,0 +1,14 @@
{{> header}}
{{#each commitGroups}}
{{#if title}}
### {{title}}
{{/if}}
{{#each commits}}
{{> commit root=@root}}
{{/each}}
{{/each}}
{{> footer}}
+35 -1718
View File
File diff suppressed because it is too large Load Diff
+345 -20
View File
@@ -1,17 +1,78 @@
# Contributing to Parse Server
# Contributing to Parse Server <!-- omit in toc -->
We really want Parse to be yours, to see it grow and thrive in the open source community.
## Table of Contents <!-- omit in toc -->
- [Contributing](#contributing)
- [Why Contributing?](#why-contributing)
- [Environment Setup](#environment-setup)
- [Recommended Tools](#recommended-tools)
- [Setting up your local machine](#setting-up-your-local-machine)
- [Good to Know](#good-to-know)
- [Troubleshooting](#troubleshooting)
- [Please Do's](#please-dos)
- [Test against Postgres](#test-against-postgres)
- [Postgres with Docker](#postgres-with-docker)
- [Breaking Changes](#breaking-changes)
- [Deprecation Policy](#deprecation-policy)
- [Feature Considerations](#feature-considerations)
- [Security Checks](#security-checks)
- [Add Security Check](#add-security-check)
- [Wording Guideline](#wording-guideline)
- [Parse Error](#parse-error)
- [Parse Server Configuration](#parse-server-configuration)
- [Pull Request](#pull-request)
- [Breaking Change](#breaking-change)
- [Merging](#merging)
- [Breaking Change](#breaking-change-1)
- [Reverting](#reverting)
- [Releasing](#releasing)
- [General Considerations](#general-considerations)
- [Major Release / Long-Term-Support](#major-release--long-term-support)
- [Versioning](#versioning)
- [Code of Conduct](#code-of-conduct)
If you are not familiar with Pull Requests and want to know more about them, you can visit the [Creating a pull request](https://help.github.com/articles/creating-a-pull-request/) article. It contains detailed informations about the process.
## Contributing
## Setting up the project for debugging and contributing:
Before you start to code, please open a [new issue](https://github.com/parse-community/parse-server/issues/new/choose) to describe your idea, or search for and continue the discussion in an [existing issue](https://github.com/parse-community/parse-server/issues).
### Recommended setup:
> ⚠️ Please do not post a security vulnerability on GitHub or in the Parse Community Forum. Instead, follow the [Parse Community Security Policy](https://github.com/parse-community/parse-server/security/policy).
* [vscode](https://code.visualstudio.com), the popular IDE.
Please completely fill out any templates to provide essential information about your new feature or the bug you discovered.
Together we will plan out the best conceptual approach for your contribution, so that your and our time is invested in the best possible approach. The discussion often reveals how to leverage existing features of Parse Server to reach your goal with even less effort and in a more sustainable way.
When you are ready to code, you can find more information about opening a pull request in the [GitHub docs](https://help.github.com/articles/creating-a-pull-request/).
Whether this is your first contribution or you are already an experienced contributor, the Parse Community has your back – don't hesitate to ask for help!
## Why Contributing?
Buy cheap, buy twice. What? No, this is not the Economics 101 class, but the same is true for contributing.
There are two ways of writing a feature or fixing a bug. Sometimes the quick solution is to just write a Cloud Code function that does what you want. Contributing by making the change directly in Parse Server may take a bit longer, but it actually saves you much more time in the long run.
Consider the benefits you get:
- #### 🚀 Higher efficiency
Your code is examined for efficiency and interoperability with existing features by the community.
- #### 🛡 Stronger security
Your code is scrutinized for bugs and vulnerabilities and automated checks help to identify security issues that may arise in the future.
- #### 🧬 Continuous improvement
If your feature is used by others it is likely to be continuously improved and extended by the community.
- #### 💝 Giving back
You give back to the community that contributed to make the Parse Platform become what it is today and for future developers to come.
- #### 🧑‍🎓 Improving yourself
You learn to better understand the inner workings of Parse Server, which will help you to write more efficient and resilient code for your own application.
Most importantly, with every contribution you improve your skills so that future contributions take even less time and you get all the benefits above for free — easy choice, right?
## Environment Setup
### Recommended Tools
* [Visual Studio Code](https://code.visualstudio.com), the popular IDE.
* [Jasmine Test Explorer](https://marketplace.visualstudio.com/items?itemName=hbenl.vscode-jasmine-test-adapter), a very practical test exploration plugin which let you run, debug and see the test results inline.
### Setting up you local machine:
### Setting up your local machine
* [Fork](https://github.com/parse-community/parse-server) this project and clone the fork on your local machine:
@@ -27,13 +88,23 @@ $ npm run watch # run babel watching for local file changes
Once you have babel running in watch mode, you can start making changes to parse-server.
### Good to know:
### Good to Know
* The `lib/` folder is not commited, so never make changes in there.
* The `lib/` folder is not committed, so never make changes in there.
* Always make changes to files in the `src/` folder.
* All the tests should point to sources in the `lib/` folder.
* The `lib/` folder is produced by `babel` using either the `npm run build`, `npm run watch`, or the `npm run prepare` step.
* The `npm run prepare` step is automatically invoked when your package depends on forked parse-server installed via git for example using `npm install --save git+https://github.com/[username]/parse-server#[branch/commit]`.
* The tests are run against a single server instance. You can change the server configurations using `await reconfigureServer({ ... some configuration })` found in `spec/helper.js`.
* The tests are ran at random.
* Caches and Configurations are reset after every test.
* Users are logged out after every test.
* Cloud Code hooks are removed after every test.
* Database is deleted after every test (indexes are not removed for speed)
* Tests are located in the `spec` folder
* For better test reporting enable `PARSE_SERVER_LOG_LEVEL=debug`
### Troubleshooting:
### Troubleshooting
*Question*: I modify the code in the src folder but it doesn't seem to have any effect.<br/>
*Answer*: Check that `npm run watch` is running
@@ -42,7 +113,10 @@ Once you have babel running in watch mode, you can start making changes to parse
*Answer*: The easiest way is to install [Jasmine Test Explorer](https://marketplace.visualstudio.com/items?itemName=hbenl.vscode-test-explorer), it will let you run selectively tests and debug them.
*Question*: How do I deploy my forked version on my servers?<br/>
*Answer*: In your `package.json`, update the `parse-server` dependency to `https://github.com/MY_USERNAME/parse-server#MY_FEATURE`. Run `npm install`, commit the changes and deploy to your servers.
*Answer*: In your `package.json`, update the `parse-server` dependency to `https://github.com/[username]/parse-server#[branch/commit]`. Run `npm install`, commit the changes and deploy to your servers.
*Question*: How do I deploy my forked version using docker?<br/>
*Answer*: In your `package.json`, update the `parse-server` dependency to `https://github.com/[username]/parse-server#[branch/commit]`. Make sure the `npm install` step in your `Dockerfile` is running under non-privileged user for the ``npm run prepare`` step to work correctly. For official node images from hub.docker.com that non-privileged user is `node` with `/home/node` working directory.
### Please Do's
@@ -53,12 +127,14 @@ Once you have babel running in watch mode, you can start making changes to parse
* Run the tests for the whole project to make sure the code passes all tests. This can be done by running the test command for a single file but removing the test file argument. The results can be seen at *<PROJECT_ROOT>/coverage/lcov-report/index.html*.
* Lint your code by running `npm run lint` to make sure the code is not going to be rejected by the CI.
* **Do not** publish the *lib* folder.
* Mocks belong in the `spec/support` folder.
* Please consider if any changes to the [docs](http://docs.parseplatform.org) are needed or add additional sections in the case of an enhancement or feature.
### Run your tests against Postgres (optional)
### Test against Postgres
If your pull request introduces a change that may affect the storage or retrieval of objects, you may want to make sure it plays nice with Postgres.
* Run the tests against the postgres database with `PARSE_SERVER_TEST_DB=postgres PARSE_SERVER_TEST_DATABASE_URI=postgres://postgres:password@localhost:5432/parse_server_postgres_adapter_test_database npm run testonly`. You'll need to have postgres running on your machine and setup [appropriately](https://github.com/parse-community/parse-server/blob/master/.travis.yml#L43) or use [`Docker`](#run-a-parse-postgres-with-docker).
* Run the tests against the postgres database with `PARSE_SERVER_TEST_DB=postgres PARSE_SERVER_TEST_DATABASE_URI=postgres://postgres:password@localhost:5432/parse_server_postgres_adapter_test_database npm run testonly`. You'll need to have postgres running on your machine and setup [appropriately](https://github.com/parse-community/parse-server/blob/master/scripts/before_script_postgres.sh) or use [`Docker`](#run-a-parse-postgres-with-docker).
* The Postgres adapter has a special debugger that traces all the sql commands. You can enable it with setting the environment variable `PARSE_SERVER_LOG_LEVEL=debug`
* If your feature is intended to only work with MongoDB, you should disable PostgreSQL-specific tests with:
@@ -71,12 +147,19 @@ If your pull request introduces a change that may affect the storage or retrieva
- `it_only_db('postgres')` // will make a test that only runs on postgres
- `it_exclude_dbs(['mongo'])` // will make a test that runs against all DB's but mongo
#### Run Postgres setup for Parse with Docker
* If your feature is intended to work with MongoDB and PostgreSQL, you can include or exclude tests more granularly with:
- `it_only_mongodb_version('>=4.4')` // will test with any version of Postgres but only with version >=4.4 of MongoDB; accepts semver notation to specify a version range
- `it_exclude_mongodb_version('<4.4')` // will test with any version of Postgres and MongoDB, excluding version <4.4 of MongoDB; accepts semver notation to specify a version range
- `it_only_postgres_version('>=13')` // will test with any version of Mongo but only with version >=13 of Postgres; accepts semver notation to specify a version range
- `it_exclude_postgres_version('<13')` // will test with any version of Postgres and MongoDB, excluding version <13 of Postgres; accepts semver notation to specify a version range
#### Postgres with Docker
[PostGIS images (select one with v2.2 or higher) on docker dashboard](https://hub.docker.com/r/postgis/postgis) is based off of the official [postgres](https://registry.hub.docker.com/_/postgres/) image and will work out-of-the-box (as long as you create a user with the necessary extensions for each of your Parse databases; see below). To launch the compatible Postgres instance, copy and paste the following line into your shell:
```
docker run -d --name parse-postgres -p 5432:5432 -e POSTGRES_PASSWORD=password --rm postgis/postgis:11-3.0-alpine && sleep 20 && docker exec -it parse-postgres psql -U postgres -c 'CREATE DATABASE parse_server_postgres_adapter_test_database;' && docker exec -it parse-postgres psql -U postgres -c 'CREATE EXTENSION postgis;' -d parse_server_postgres_adapter_test_database && docker exec -it parse-postgres psql -U postgres -c 'CREATE EXTENSION postgis_topology;' -d parse_server_postgres_adapter_test_database
docker run -d --name parse-postgres -p 5432:5432 -e POSTGRES_PASSWORD=password --rm postgis/postgis:13-3.2-alpine && sleep 20 && docker exec -it parse-postgres psql -U postgres -c 'CREATE DATABASE parse_server_postgres_adapter_test_database;' && docker exec -it parse-postgres psql -U postgres -c 'CREATE EXTENSION pgcrypto; CREATE EXTENSION postgis;' -d parse_server_postgres_adapter_test_database && docker exec -it parse-postgres psql -U postgres -c 'CREATE EXTENSION postgis_topology;' -d parse_server_postgres_adapter_test_database
```
To stop the Postgres instance:
@@ -84,7 +167,7 @@ To stop the Postgres instance:
docker stop parse-postgres
```
You can also use the [postgis/postgis:11-2.5-alpine](https://hub.docker.com/r/postgis/postgis) image in a Dockerfile and copy this [script](https://github.com/parse-community/parse-server/blob/master/scripts/before_script_postgres.sh) to the image by adding the following lines:
You can also use the [postgis/postgis:13-3.2-alpine](https://hub.docker.com/r/postgis/postgis) image in a Dockerfile and copy this [script](https://github.com/parse-community/parse-server/blob/master/scripts/before_script_postgres.sh) to the image by adding the following lines:
```
#Install additional scripts. These are run in abc order during initial start
@@ -94,13 +177,255 @@ RUN chmod +x /docker-entrypoint-initdb.d/setup-dbs.sh
Note that the script above will ONLY be executed during initialization of the container with no data in the database, see the official [Postgres image](https://hub.docker.com/_/postgres) for details. If you want to use the script to run again be sure there is no data in the /var/lib/postgresql/data of the container.
### Generate Parse Server Config Definition
## Breaking Changes
If you want to make changes to [Parse Server Configuration][config] add the desired configuration to [src/Options/index.js][config-index] and run `npm run definitions`. This will output [src/Options/Definitions.js][config-def] and [src/Options/docs.js][config-docs].
Breaking changes should be avoided whenever possible. For a breaking change to be accepted, the benefits of the change have to clearly outweigh the costs of developers having to adapt their deployments. If a breaking change is only cosmetic it will likely be rejected and preferred to become obsolete organically during the course of further development, unless it is required as part of a larger change. Breaking changes should follow the [Deprecation Policy](#deprecation-policy).
To view docs run `npm run docs` and check the `/out` directory.
Please consider that Parse Server is just one component in a stack that requires attention. A breaking change requires resources and effort to adapt an environment. An unnecessarily high frequency of breaking changes can have detrimental side effects such as:
- "upgrade fatigue" where developers run old versions of Parse Server because they cannot always attend to every update that contains a breaking change
- less secure Parse Server deployments that run on old versions which is contrary to the security evangelism Parse Server intends to facilitate for developers
- less feedback and slower identification of bugs and an overall slow-down of Parse Server development because new versions with breaking changes also include new features we want to get feedback on
### Code of Conduct
### Deprecation Policy
If you change or remove an existing feature that would lead to a breaking change, use the following deprecation pattern:
- Make the new feature or change optional, if necessary with a new Parse Server option parameter.
- Use a default value that falls back to existing behavior.
- Add a deprecation definition in `Deprecator/Deprecations.js` that will output a deprecation warning log message on Parse Server launch, for example:
> DeprecationWarning: The Parse Server option 'example' will be removed in a future release.
For deprecations that can only be determined ad-hoc during runtime, for example Parse Query syntax deprecations, use the `Deprecator.logRuntimeDeprecation()` method.
Deprecations become breaking changes after notifying developers through deprecation warnings for at least one entire previous major release. For example:
- `4.5.0` is the current version
- `4.6.0` adds a new optional feature and a deprecation warning for the existing feature
- `5.0.0` marks the beginning of logging the deprecation warning for one entire major release
- `6.0.0` makes the breaking change by removing the deprecation warning and making the new feature replace the existing feature
See the [Deprecation Plan](https://github.com/parse-community/parse-server/blob/master/DEPRECATIONS.md) for an overview of deprecations and planned breaking changes.
## Feature Considerations
### Security Checks
The Parse Server security checks feature warns developers about weak security settings in their Parse Server deployment.
A security check needs to be added for every new feature or enhancement that allows the developer to configure it in a way that weakens security mechanisms or exposes functionality which creates a weak spot for malicious attacks. If you are not sure whether your feature or enhancements requires a security check, feel free to ask.
For example, allowing public read and write to a class may be useful to simplify development but should be disallowed in a production environment.
Security checks are added in [CheckGroups](https://github.com/parse-community/parse-server/tree/master/src/Security/CheckGroups).
#### Add Security Check
Adding a new security check for your feature is easy and fast:
1. Look into [CheckGroups](https://github.com/parse-community/parse-server/tree/master/src/Security/CheckGroups) whether there is an existing `CheckGroup[Category].js` file for the category of check to add. For example, a check regarding the database connection is added to `CheckGroupDatabase.js`.
2. If you did not find a file, duplicate an existing file and replace the category name in `setName()` and the checks in `setChecks()`:
```js
class CheckGroupNewCategory extends CheckGroup {
setName() {
return 'House';
}
setChecks() {
return [
new Check({
title: 'Door locked',
warning: 'Anyone can enter your house.',
solution: 'Lock the door.',
check: () => {
return; // Example of a passing check
}
}),
new Check({
title: 'Camera online',
warning: 'Security camera is offline.',
solution: 'Check the camera.',
check: async () => {
throw 1; // Example of a failing check
}
}),
];
}
}
```
3. If you added a new file in the previous step, reference the file in [CheckGroups.js](https://github.com/parse-community/parse-server/blob/master/src/Security/CheckGroups/CheckGroups.js), which is the collector of all security checks:
```
export { default as CheckGroupNewCategory } from './CheckGroupNewCategory';
```
4. Add a test that covers the new check to [SecurityCheckGroups.js](https://github.com/parse-community/parse-server/blob/master/spec/SecurityCheckGroups.js) for the cases of success and failure.
#### Wording Guideline
Consider the following when adding a new security check:
- *Group.name*: The category name; ends without period as this is a headline.
- *Check.title*: Is the positive hypothesis that should be checked, for example "Door locked" instead of "Door unlocked"; ends without period as this is a title.
- *Check.warning*: The warning if the test fails; ends with period as this is a description.
- *Check.solution*: The recommended solution if the test fails; ends with period as this is an instruction.
- The wordings must not contain any sensitive information such as keys, as the security report may be exposed in logs.
- The wordings should be concise and not contain verbose explanations, for example "Door locked" instead of "Door has been locked securely".
- Do not use pronouns such as "you" or "your" because log files can have various readers with different roles. Do not use pronouns such as "I" or "me" because although we love it dearly, Parse Server is not a human.
### Parse Error
Introducing new Parse Errors requires the following steps:
1. Research whether an existing Parse Error already covers the error scenario. Keep in mind that reusing an already existing Parse Error does not allow to distinguish between scenarios in which the same error is thrown, so it may be necessary to add a new and more specific Parse Error, even though a more general Parse Error already exists.
⚠️ Currently (as of Dec. 2020), there are inconsistencies between the Parse Errors documented in the Parse Guides, coded in the Parse JS SDK and coded in Parse Server, therefore research regarding the availability of error codes has to be conducted in all of these sources.
1. Add the new Parse Error to [/src/ParseError.js](https://github.com/parse-community/Parse-SDK-JS/blob/master/src/ParseError.js) in the Parse JavaScript SDK. This is the primary reference for Parse Errors for the Parse JavaScript SDK and Parse Server.
1. Create a pull request for the Parse JavaScript SDK including the new Parse Errors. The PR needs to be merged and a new Parse JS SDK version needs to be released.
1. Change the Parse JS SDK dependency in [package.json](https://github.com/parse-community/parse-server/blob/master/package.json) of Parse Server to the newly released Parse JS SDK version, so that the new Parse Error is recognized by Parse Server.
1. When throwing the new Parse Error in code, do not hard-code the error code but instead reference the error code from the Parse Error. For example:
```javascript
throw new Parse.Error(Parse.Error.EXAMPLE_ERROR_CODE, 'Example error message.');
```
1. Choose a descriptive error message that provdes more details about the specific error scenario. Different error messages may be used for the same error code. For example:
```javascript
throw new Parse.Error(Parse.Error.FILE_SAVE_ERROR, 'The file could not be saved because it exceeded the maximum allowed file size.');
throw new Parse.Error(Parse.Error.FILE_SAVE_ERROR, 'The file could not be saved because the file format was incorrect.');
```
1. Add the new Parse Error to the [docs](https://github.com/parse-community/docs/blob/gh-pages/_includes/common/errors.md).
### Parse Server Configuration
Introducing new [Parse Server configuration][config] parameters requires the following steps:
1. Add parameters definitions in [/src/Options/index.js][config-index].
2. If the new parameter does not have one single value but is a parameter group (an object containing multiple sub-parameters):
- add the environment variable prefix for the parameter group to `nestedOptionEnvPrefix` in [/resources/buildConfigDefinition.js](https://github.com/parse-community/parse-server/blob/master/resources/buildConfigDefinition.js)
- add the parameter group type to `nestedOptionTypes` in [/resources/buildConfigDefinition.js](https://github.com/parse-community/parse-server/blob/master/resources/buildConfigDefinition.js)
For example, take a look at the existing Parse Server `security` parameter. It is a parameter group, because it has multiple sub-parameter such as `checkGroups`. Its interface is defined in [index.js][config-index] as `export interface SecurityOptions`. Therefore, the value to add to `nestedOptionTypes` would be `SecurityOptions`, the value to add to `nestedOptionEnvPrefix` would be `PARSE_SERVER_SECURITY_`.
3. Execute `npm run definitions` to automatically create the definitions in [/src/Options/Definitions.js][config-def] and [/src/Options/docs.js][config-docs].
4. Add parameter value validation in [/src/Config.js](https://github.com/parse-community/parse-server/blob/master/src/Config.js).
5. Add test cases to ensure the correct parameter value validation. Parse Server throws an error at launch if an invalid value is set for any configuration parameter.
6. Execute `npm run docs` to generate the documentation in the `/out` directory. Take a look at the documentation whether the description and formatting of the newly introduced parameters is satisfactory.
## Pull Request
For release automation, the title of pull requests needs to be written in a defined syntax. We loosely follow the [Conventional Commits](https://www.conventionalcommits.org) specification, which defines this syntax:
```
<type>: <summary>
```
The _type_ is the category of change that is made, possible types are:
- `feat` - add a new feature or improve an existing feature
- `fix` - fix a bug
- `refactor` - refactor code without impact on features or performance
- `docs` - add or edit code comments, documentation, GitHub pages
- `style` - edit code style
- `build` - retry failing build and anything build process related
- `perf` - performance optimization
- `ci` - continuous integration
- `test` - tests
The _summary_ is a short change description in present tense, not capitalized, without period at the end. This summary will also be used as the changelog entry.
- It must be short and self-explanatory for a reader who does not see the details of the full pull request description
- It must not contain abbreviations, e.g. instead of `LQ` write `LiveQuery`
- It must use the correct product and feature names as referenced in the documentation, e.g. instead of `Cloud Validator` use `Cloud Function validation`
- In case of a breaking change, the summary must not contain duplicate information that is also in the [BREAKING CHANGE](#breaking-change) chapter of the pull request description. It must not contain a note that it is a breaking change, as this will be automatically flagged as such if the pull request description contains the BREAKING CHANGE chapter.
For example:
```
feat: add handle to door for easy opening
```
Currently, we are not making use of the commit _scope_, which would be written as `<type>(<scope>): <summary>`, that attributes a change to a specific part of the product.
### Breaking Change
If a pull request contains a braking change, the description of the pull request must contain a dedicated chapter at the bottom to indicate this. This is to assist the committer of the pull request to avoid merging a breaking change as non-breaking.
## Merging
The following guide is for anyone who merges a contributor pull request into the working branch, the working branch into a release branch, a release branch into another release branch, or any other direct commits such as hotfixes into release branches or the working branch.
- A contributor pull request must be merged into the working branch using `Squash and Merge`, to create a single commit message that describes the change.
- A release branch or the default branch must be merged into another release branch using `Merge Commit`, to preserve each individual commit message that describes its respective change.
- For changelog generation, only the commit message set when merging the pull request is relevant. The title and description of the GitHub pull request as authored by the contributor have no influence on the changelog generation. However, the title of the GitHub pull request should be used as the commit message. See the following chapters for considerations in special scenarios, e.g. merging a breaking change or reverting a commit.
### Breaking Change
If the pull request contains a breaking change, the commit message must contain the phrase `BREAKING CHANGE`, capitalized and without any formatting, followed by a short description of the breaking change and ideally how the developer should address it, all in a single line. This line should contain more details focusing on the "breaking” aspect of the change and is intended to assist the developer in adapting. Keep it concise, as it will become part of the changelog entry, for example:
```
fix: remove handle from door
BREAKING CHANGE: You cannot open the door anymore by using a handle. See the [#migration guide](http://example.com) for more details.
```
Keep in mind that in a repository with release automation, merging such a commit message will trigger a release with a major version increment.
### Reverting
If the commit reverts a previous commit, use the prefix `revert:`, followed by the header of the reverted commit. In the body of the commit message add `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted. For example:
```
revert: fix: remove handle from door
This reverts commit 1234567890abcdef.
```
⚠️ A `revert` prefix will *always* trigger a release. Generally, a commit that did not trigger a release when it was initially merged should also not trigger a release when it is reverted. For example, do not use the `revert` prefix when reverting a commit that has a `ci` prefix:
```
ci: add something
```
is reverted with:
```
ci: remove something
```
instead of:
```
revert: ci: add something
This reverts commit 1234567890abcdef.
```
## Releasing
### General Considerations
- The `package-lock.json` file has to be deleted and recreated by npm from scratch in regular intervals using the `npm i` command. It is not enough to only update the file via automated security pull requests (e.g. dependabot, snyk), that can create inconsistencies between sub-devependencies of a dependency and increase the chances of vulnerabilities. The file should be recreated once every release cycle which is usually monthly.
### Major Release / Long-Term-Support
Long-Term-Support (LTS) is provided for the previous Parse Server major version. For example, Parse Server 4.x will receive security updates until Parse Server 5.x is superseded by Parse Server 6.x and becomes the new LTS version. While the current major version is published on branch `release`, a LTS version is published on branch `release-#.x.x`, for example `release-4.x.x` for the Parse Server 4.x LTS branch.
#### Preparing Release
The following changes are done in the `alpha` branch, before publishing the last `beta` version that will eventually become the major release. This way the changes trickle naturally through all branches and code consistency is ensured among branches.
- Make sure all [deprecations](https://github.com/parse-community/parse-server/blob/alpha/DEPRECATIONS.md) are reflected in code, old code is removed and the deprecations table is updated.
- Add the future LTS branch `release-#.x.x` to the branch list in [release.config.js](https://github.com/parse-community/parse-server/blob/alpha/release.config.js) so that the branch will later be recognized for release automation.
#### Publishing Release
1. Create LTS branch `release-#.x.x` off the latest version tag on `release` branch.
2. Create temporary branch `build-release` off branch `beta` and create a pull request with `release` as the base branch.
3. Merge branch `build-release` into `release`. Given that there will be breaking changes, a new major release will be created. In the unlikely case that there have been no breaking changes between the previous major release and the upcoming release, a major version increment has to be triggered manually. See the docs of the release automation framework for how to do that.
## Versioning
> The following versioning system is applied since Parse Server 5.0.0 and does not necessarily apply to previous releases.
Parse Server follows [semantic versioning](https://semver.org) with a flavor of [calendric versioning](https://calver.org). Semantic versioning makes Parse Server easy to upgrade because breaking changes only occur in major releases. Calendric versioning gives an additional sense of how old a Parse Server release is and allows for Long-Term Support of previous major releases.
Example version: `5.0.0-alpha.1`
Syntax: `[major]`**.**`[minor]`**.**`[patch]`**-**`[pre-release-label]`**.**`[pre-release-increment]`
- The `major` version increments with the first release of every year and may include changes that are *not backwards compatible*.
- The `minor` version increments during the year and may include new features or improvements of existing features that are backwards compatible.
- The `patch` version increments during the year and may include bug fixes that are backwards compatible.
- The `pre-release-label` is optional for pre-release versions such as:
- `-alpha` (likely to contain bugs, likely to change in features until release)
- `-beta` (likely to contain bugs, no change in features until release)
- The `[pre-release-increment]` is a number that increments with every new version of a pre-release
Exceptions:
- The `major` version may increment during the year in the unlikely event that a breaking change is so urgent that it cannot wait for the next yearly release. An example would be a vulnerability fix that leads to an unavoidable breaking change. However, security requirements depend on the application and not every vulnerability may affect every deployment, depending on the features used. Therefore we usually prefer to deprecate insecure functionality and introduce the breaking change following our [deprecation policy](#deprecation-policy).
## Code of Conduct
This project adheres to the [Contributor Covenant Code of Conduct](https://github.com/parse-community/parse-server/blob/master/CODE_OF_CONDUCT.md). By participating, you are expected to honor this code.
+14
View File
@@ -0,0 +1,14 @@
# Deprecation Plan <!-- omit in toc -->
The following is a list of deprecations, according to the [Deprecation Policy](https://github.com/parse-community/parse-server/blob/master/CONTRIBUTING.md#deprecation-policy). After a feature becomes deprecated, and giving developers time to adapt to the change, the deprecated feature will eventually be removed, leading to a breaking change. Developer feedback during the deprecation period may postpone or even revoke the introduction of the breaking change.
| ID | Change | Issue | Deprecation [ℹ️][i_deprecation] | Planned Removal [ℹ️][i_removal] | Status [ℹ️][i_status] | Notes |
|--------|-------------------------------------------------|----------------------------------------------------------------------|---------------------------------|---------------------------------|-----------------------|-------|
| DEPPS1 | Native MongoDB syntax in aggregation pipeline | [#7338](https://github.com/parse-community/parse-server/issues/7338) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - |
| DEPPS2 | Config option `directAccess` defaults to `true` | [#6636](https://github.com/parse-community/parse-server/pull/6636) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - |
| DEPPS3 | Config option `enforcePrivateUsers` defaults to `true` | [#7319](https://github.com/parse-community/parse-server/pull/7319) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - |
| DEPPS4 | Remove convenience method for http request `Parse.Cloud.httpRequest` | [#7589](https://github.com/parse-community/parse-server/pull/7589) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - |
[i_deprecation]: ## "The version and date of the deprecation."
[i_removal]: ## "The version and date of the planned removal."
[i_status]: ## "The current status of the deprecation: deprecated (the feature is deprecated and still available), removed (the deprecated feature has been removed and is unavailable), retracted (the deprecation has been retracted and the feature will not be removed."
+18 -1
View File
@@ -1,15 +1,30 @@
############################################################
# Build stage
############################################################
FROM node:lts-alpine as build
RUN apk update; \
apk add git;
WORKDIR /tmp
# Copy package.json first to benefit from layer caching
COPY package*.json ./
RUN npm ci
# Copy src to have config files for install
COPY . .
# Clean npm cache; added to fix an issue with the install process
RUN npm cache clean --force
# Install all dependencies
RUN npm ci
# Run build steps
RUN npm run build
############################################################
# Release stage
############################################################
FROM node:lts-alpine as release
RUN apk update; \
@@ -21,6 +36,8 @@ WORKDIR /parse-server
COPY package*.json ./
# Clean npm cache; added to fix an issue with the install process
RUN npm cache clean --force
RUN npm ci --production --ignore-scripts
COPY bin bin
+471 -150
View File
@@ -1,77 +1,100 @@
<p align="center">
<img alt="Parse Server" src="https://github.com/parse-community/parse-server/raw/master/.github/parse-server-logo.png" width="500">
</a>
</p>
![parse-repository-header-server](https://user-images.githubusercontent.com/5673677/138278489-7d0cebc5-1e31-4d3c-8ffb-53efcda6f29d.png)
<p align="center">
Parse Server is an open source backend that can be deployed to any infrastructure that can run Node.js.
</p>
---
[![Build Status](https://github.com/parse-community/parse-server/workflows/ci/badge.svg?branch=alpha)](https://github.com/parse-community/parse-server/actions?query=workflow%3Aci+branch%3Aalpha)
[![Snyk Badge](https://snyk.io/test/github/parse-community/parse-server/badge.svg)](https://snyk.io/test/github/parse-community/parse-server)
[![Coverage](https://img.shields.io/codecov/c/github/parse-community/parse-server/alpha.svg)](https://codecov.io/github/parse-community/parse-server?branch=alpha)
[![auto-release](https://img.shields.io/badge/%F0%9F%9A%80-auto--release-9e34eb.svg)](https://github.com/parse-community/parse-dashboard/releases)
[![Node Version](https://img.shields.io/badge/nodejs-12,_14,_16-green.svg?logo=node.js&style=flat)](https://nodejs.org)
[![MongoDB Version](https://img.shields.io/badge/mongodb-4.0,_4.2,_4.4,_5.0-green.svg?logo=mongodb&style=flat)](https://www.mongodb.com)
[![Postgres Version](https://img.shields.io/badge/postgresql-11,_12,_13,_14-green.svg?logo=postgresql&style=flat)](https://www.postgresql.org)
<p align="center">
<a href="https://twitter.com/intent/follow?screen_name=parseplatform"><img alt="Follow on Twitter" src="https://img.shields.io/twitter/follow/parseplatform?style=social&label=Follow"></a>
<a href="https://github.com/parse-community/parse-server/actions?query=workflow%3Aci+branch%3Amaster">
<img alt="Build status" src="https://github.com/parse-community/parse-server/workflows/ci/badge.svg?branch=master">
</a>
<a href="https://codecov.io/github/parse-community/parse-server?branch=master"><img alt="Coverage status" src="https://img.shields.io/codecov/c/github/parse-community/parse-server/master.svg"></a>
<a href="https://www.npmjs.com/package/parse-server"><img alt="npm version" src="https://img.shields.io/npm/v/parse-server.svg?style=flat"></a>
<a href="https://community.parseplatform.org/"><img alt="Join the conversation" src="https://img.shields.io/discourse/https/community.parseplatform.org/topics.svg"></a>
<a href="https://snyk.io/test/github/parse-community/parse-server"><img alt="Snyk badge" src="https://snyk.io/test/github/parse-community/parse-server/badge.svg"></a>
</p>
[![npm latest version](https://img.shields.io/npm/v/parse-server/latest.svg)](https://www.npmjs.com/package/parse-server)
[![npm beta version](https://img.shields.io/npm/v/parse-server/beta.svg)](https://www.npmjs.com/package/parse-server)
[![npm alpha version](https://img.shields.io/npm/v/parse-server/alpha.svg)](https://www.npmjs.com/package/parse-server)
<p align="center">
<img alt="MongoDB 3.6" src="https://img.shields.io/badge/mongodb-3.6-green.svg?logo=mongodb&style=flat">
<img alt="MongoDB 4.0" src="https://img.shields.io/badge/mongodb-4.0-green.svg?logo=mongodb&style=flat">
</p>
[![Backers on Open Collective](https://opencollective.com/parse-server/backers/badge.svg)][open-collective-link]
[![Sponsors on Open Collective](https://opencollective.com/parse-server/sponsors/badge.svg)][open-collective-link]
[![License][license-svg]][license-link]
[![Forum](https://img.shields.io/discourse/https/community.parseplatform.org/topics.svg)](https://community.parseplatform.org/c/parse-server)
[![Twitter](https://img.shields.io/twitter/follow/ParsePlatform.svg?label=Follow&style=social)](https://twitter.com/intent/follow?screen_name=ParsePlatform)
<h2 align="center">Our Sponsors</h2>
<p align="center">
<p align="center">Our backers and sponsors help to ensure the quality and timely development of the Parse Platform.</p>
<details align="center">
<summary align="center"><b>🥉 Bronze Sponsors</b></summary>
<a href="https://opencollective.com/parse-server/sponsor/0/website" target="_blank"><img src="https://opencollective.com/parse-server/sponsor/0/avatar.svg"></a>
</details>
---
</p>
<p align="center">
<a href="#backers"><img alt="Backers on Open Collective" src="https://opencollective.com/parse-server/tiers/backers/badge.svg" /></a>
<a href="#sponsors"><img alt="Sponsors on Open Collective" src="https://opencollective.com/parse-server/tiers/sponsors/badge.svg" /></a>
</p>
<br>
Parse Server works with the Express web application framework. It can be added to existing web applications, or run by itself.
Parse Server is an open source backend that can be deployed to any infrastructure that can run Node.js. Parse Server works with the Express web application framework. It can be added to existing web applications, or run by itself.
The full documentation for Parse Server is available in the [wiki](https://github.com/parse-community/parse-server/wiki). The [Parse Server guide](http://docs.parseplatform.org/parse-server/guide/) is a good place to get started. An [API reference](http://parseplatform.org/parse-server/api/) and [Cloud Code guide](https://docs.parseplatform.org/cloudcode/guide/) are also available. If you're interested in developing for Parse Server, the [Development guide](http://docs.parseplatform.org/parse-server/guide/#development-guide) will help you get set up.
---
A big *thank you* 🙏 to our [sponsors](#sponsors) and [backers](#backers) who support the development of Parse Platform!
### Diamond Sponsors
[![Diamond Sponsors](https://opencollective.com/parse-server/tiers/diamond-sponsor.svg?avatarHeight=70&button=false)](https://opencollective.com/parse-server/contribute/diamond-sponsor-10560)
#### Bronze Sponsors
[![Bronze Sponsors](https://opencollective.com/parse-server/tiers/bronze-sponsor.svg?avatarHeight=36&button=false)](https://opencollective.com/parse-server/contribute/bronze-sponsor-10559)
---
- [Getting Started](#getting-started)
- [Running Parse Server](#running-parse-server)
- [Locally](#locally)
- [Docker](#inside-a-docker-container)
- [Saving an Object](#saving-your-first-object)
- [Connect an SDK](#connect-your-app-to-parse-server)
- [Running elsewhere](#running-parse-server-elsewhere)
- [Sample Application](#parse-server-sample-application)
- [Parse Server + Express](#parse-server--express)
- [Configuration](#configuration)
- [Basic Options](#basic-options)
- [Client Key Options](#client-key-options)
- [Email Verification & Password Reset](#email-verification-and-password-reset)
- [Custom Pages](#custom-pages)
- [Using Environment Variables](#using-environment-variables-to-configure-parse-server)
- [Available Adapters](#available-adapters)
- [Configuring File Adapters](#configuring-file-adapters)
- [Logging](#logging)
- [Live Queries](#live-queries)
- [Running Parse Server](#running-parse-server)
- [Compatibility](#compatibility)
- [Node.js](#nodejs)
- [MongoDB](#mongodb)
- [PostgreSQL](#postgresql)
- [Locally](#locally)
- [Docker Container](#docker-container)
- [Saving an Object](#saving-an-object)
- [Connect an SDK](#connect-an-sdk)
- [Running Parse Server elsewhere](#running-parse-server-elsewhere)
- [Sample Application](#sample-application)
- [Parse Server + Express](#parse-server--express)
- [Configuration](#configuration)
- [Basic Options](#basic-options)
- [Client Key Options](#client-key-options)
- [Email Verification and Password Reset](#email-verification-and-password-reset)
- [Password and Account Policy](#password-and-account-policy)
- [Custom Routes](#custom-routes)
- [Example](#example)
- [Reserved Paths](#reserved-paths)
- [Parameters](#parameters)
- [Custom Pages](#custom-pages)
- [Using Environment Variables](#using-environment-variables)
- [Available Adapters](#available-adapters)
- [Configuring File Adapters](#configuring-file-adapters)
- [Idempotency Enforcement](#idempotency-enforcement)
- [Localization](#localization)
- [Pages](#pages)
- [Localization with Directory Structure](#localization-with-directory-structure)
- [Localization with JSON Resource](#localization-with-json-resource)
- [Dynamic placeholders](#dynamic-placeholders)
- [Reserved Keys](#reserved-keys)
- [Parameters](#parameters-1)
- [Logging](#logging)
- [Deprecations](#deprecations)
- [Live Query](#live-query)
- [GraphQL](#graphql)
- [Running](#running)
- [Using the CLI](#using-the-cli)
- [Using Docker](#using-docker)
- [Using Express.js](#using-expressjs)
- [Checking the API health](#checking-the-api-health)
- [Creating your first class](#creating-your-first-class)
- [Using automatically generated operations](#using-automatically-generated-operations)
- [Customizing your GraphQL Schema](#customizing-your-graphql-schema)
- [Learning more](#learning-more)
- [Upgrading to 3.0.0](#upgrading-to-300)
- [Support](#support)
- [Ride the Bleeding Edge](#want-to-ride-the-bleeding-edge)
- [Want to ride the bleeding edge?](#want-to-ride-the-bleeding-edge)
- [Contributing](#contributing)
- [Contributors](#contributors)
- [Sponsors](#sponsors)
- [Backers](#backers)
# Getting Started
The fastest and easiest way to get started is to run MongoDB and Parse Server locally.
@@ -84,6 +107,38 @@ Before you start make sure you have installed:
- [MongoDB](https://www.mongodb.com/) or [PostgreSQL](https://www.postgresql.org/)(with [PostGIS](https://postgis.net) 2.2.0 or higher)
- Optionally [Docker](https://www.docker.com/)
### Compatibility
#### Node.js
Parse Server is continuously tested with the most recent releases of Node.js to ensure compatibility. We follow the [Node.js Long Term Support plan](https://github.com/nodejs/Release) and only test against versions that are officially supported and have not reached their end-of-life date.
| Version | Latest Version | End-of-Life | Compatible |
|------------|----------------|-------------|---------------|
| Node.js 12 | 12.22.7 | April 2022 | ✅ Yes |
| Node.js 14 | 14.18.1 | April 2023 | ✅ Yes |
| Node.js 16 | 16.13.0 | April 2024 | ✅ Yes |
| Node.js 17 | 17.x | June 2022 | ❌ Not tested |
#### MongoDB
Parse Server is continuously tested with the most recent releases of MongoDB to ensure compatibility. We follow the [MongoDB support schedule](https://www.mongodb.com/support-policy) and only test against versions that are officially supported and have not reached their end-of-life date.
| Version | Latest Version | End-of-Life | Compatible |
|-------------|----------------|--------------|------------|
| MongoDB 4.0 | 4.0.27 | April 2022 | ✅ Yes |
| MongoDB 4.2 | 4.2.17 | TBD | ✅ Yes |
| MongoDB 4.4 | 4.4.10 | TBD | ✅ Yes |
| MongoDB 5.0 | 5.0.3 | January 2024 | ✅ Yes |
#### PostgreSQL
Parse Server is continuously tested with the most recent releases of PostgreSQL and PostGIS to ensure compatibility, using [PostGIS docker images](https://registry.hub.docker.com/r/postgis/postgis/tags?page=1&ordering=last_updated). We follow the [PostgreSQL support schedule](https://www.postgresql.org/support/versioning) and [PostGIS support schedule](https://www.postgis.net/eol_policy/) and only test against versions that are officially supported and have not reached their end-of-life date. Due to the extensive PostgreSQL support duration of 5 years, Parse Server drops support if a version is older than 3.5 years and a newer version has been available for at least 2.5 years.
| Version | PostGIS Version | End-of-Life | Parse Server Support End | Compatible |
|-------------|-----------------|---------------|--------------------------|------------|
| Postgres 11 | 3.0, 3.1, 3.2 | November 2023 | April 2022 | ✅ Yes |
| Postgres 12 | 3.2 | November 2024 | April 2023 | ✅ Yes |
| Postgres 13 | 3.2 | November 2025 | April 2024 | ✅ Yes |
| Postgres 14 | 3.2 | November 2026 | April 2025 | ✅ Yes |
### Locally
```bash
$ npm install -g parse-server mongodb-runner
@@ -93,7 +148,7 @@ $ parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongo
***Note:*** *If installation with* `-g` *fails due to permission problems* (`npm ERR! code 'EACCES'`), *please refer to [this link](https://docs.npmjs.com/getting-started/fixing-npm-permissions).*
### Inside a Docker container
### Docker Container
```bash
$ git clone https://github.com/parse-community/parse-server
@@ -102,13 +157,13 @@ $ docker build --tag parse-server .
$ docker run --name my-mongo -d mongo
```
#### Running the Parse Server Image
#### Running the Parse Server Image <!-- omit in toc -->
```bash
$ docker run --name my-parse-server -v config-vol:/parse-server/config -p 1337:1337 --link my-mongo:mongo -d parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://mongo/test
```
***Note:*** *If you want to use [Cloud Code](https://docs.parseplatform.org/cloudcode/guide/) feature, please add `-v cloud-code-vol:/parse-server/cloud --cloud /parse-server/cloud/main.js` to command above. Make sure the `main.js` file is available in the `cloud-code-vol` directory before run this command. Otherwise, an error will occur.*
***Note:*** *If you want to use [Cloud Code](https://docs.parseplatform.org/cloudcode/guide/), add `-v cloud-code-vol:/parse-server/cloud --cloud /parse-server/cloud/main.js` to the command above. Make sure `main.js` is in the `cloud-code-vol` directory before starting Parse Server.*
You can use any arbitrary string as your application id and master key. These will be used by your clients to authenticate with the Parse Server.
@@ -116,7 +171,7 @@ That's it! You are now running a standalone version of Parse Server on your mach
**Using a remote MongoDB?** Pass the `--databaseURI DATABASE_URI` parameter when starting `parse-server`. Learn more about configuring Parse Server [here](#configuration). For a full list of available options, run `parse-server --help`.
### Saving your first object
### Saving an Object
Now that you're running Parse Server, it is time to save your first object. We'll use the [REST API](http://docs.parseplatform.org/rest/guide), but you can easily do the same using any of the [Parse SDKs](http://parseplatform.org/#sdks). Run the following:
@@ -182,7 +237,7 @@ $ curl -X GET \
To learn more about using saving and querying objects on Parse Server, check out the [Parse documentation](http://docs.parseplatform.org).
### Connect your app to Parse Server
### Connect an SDK
Parse provides SDKs for all the major platforms. Refer to the Parse Server guide to [learn how to connect your app to Parse Server](https://docs.parseplatform.org/parse-server/guide/#using-parse-sdks-with-parse-server).
@@ -190,7 +245,7 @@ Parse provides SDKs for all the major platforms. Refer to the Parse Server guide
Once you have a better understanding of how the project works, please refer to the [Parse Server wiki](https://github.com/parse-community/parse-server/wiki) for in-depth guides to deploy Parse Server to major infrastructure providers. Read on to learn more about additional ways of running Parse Server.
### Parse Server Sample Application
### Sample Application
We have provided a basic [Node.js application](https://github.com/parse-community/parse-server-example) that uses the Parse Server module on Express and can be easily deployed to various infrastructure providers:
@@ -201,7 +256,7 @@ We have provided a basic [Node.js application](https://github.com/parse-communit
* [SashiDo](https://blog.sashido.io/tag/migration/)
* [Digital Ocean](https://www.digitalocean.com/community/tutorials/how-to-run-parse-server-on-ubuntu-14-04)
* [Pivotal Web Services](https://github.com/cf-platform-eng/pws-parse-server)
* [Back4app](http://blog.back4app.com/2016/03/01/quick-wizard-migration/)
* [Back4app](https://www.back4app.com/docs/get-started/welcome)
* [Glitch](https://glitch.com/edit/#!/parse-server)
* [Flynn](https://flynn.io/blog/parse-apps-on-flynn)
@@ -233,13 +288,13 @@ app.listen(1337, function() {
For a full list of available options, run `parse-server --help` or take a look at [Parse Server Configurations](http://parseplatform.org/parse-server/api/master/ParseServerOptions.html).
## Configuration
# Configuration
Parse Server can be configured using the following options. You may pass these as parameters when running a standalone `parse-server`, or by loading a configuration file in JSON format using `parse-server path/to/configuration.json`. If you're using Parse Server on Express, you may also pass these to the `ParseServer` object as options.
For the full list of available options, run `parse-server --help` or take a look at [Parse Server Configurations](http://parseplatform.org/parse-server/api/master/ParseServerOptions.html).
### Basic options
## Basic Options
* `appId` **(required)** - The application id to host with this server instance. You can use any arbitrary string. For migrated apps, this should match your hosted Parse app.
* `masterKey` **(required)** - The master key to use for overriding ACL security. You can use any arbitrary string. Keep it secret! For migrated apps, this should match your hosted Parse app.
@@ -247,9 +302,9 @@ For the full list of available options, run `parse-server --help` or take a look
* `port` - The default port is 1337, specify this parameter to use a different port.
* `serverURL` - URL to your Parse Server (don't forget to specify http:// or https://). This URL will be used when making requests to Parse Server from Cloud Code.
* `cloud` - The absolute path to your cloud code `main.js` file.
* `push` - Configuration options for APNS and GCM push. See the [Push Notifications quick start](http://docs.parseplatform.org/parse-server/guide/#push-notifications_push-notifications-quick-start).
* `push` - Configuration options for APNS and GCM push. See the [Push Notifications quick start](https://docs.parseplatform.org/parse-server/guide/#push-notifications-quick-start).
### Client key options
## Client Key Options
The client keys used with Parse are no longer necessary with Parse Server. If you wish to still require them, perhaps to be able to refuse access to older clients, you can set the keys at initialization time. Setting any of these keys will require all requests to provide one of the configured keys.
@@ -258,76 +313,34 @@ The client keys used with Parse are no longer necessary with Parse Server. If yo
* `restAPIKey`
* `dotNetKey`
### Email verification and password reset
## Email Verification and Password Reset
Verifying user email addresses and enabling password reset via email requires an email adapter. As part of the `parse-server` package we provide an adapter for sending email through Mailgun. To use it, sign up for Mailgun, and add this to your initialization code:
Verifying user email addresses and enabling password reset via email requires an email adapter. There are many email adapters provided and maintained by the community. The following is an example configuration with an example email adapter. See the [Parse Server Options](https://parseplatform.org/parse-server/api/master/ParseServerOptions.html) for more details and a full list of available options.
```js
var server = ParseServer({
const server = ParseServer({
...otherOptions,
// Enable email verification
verifyUserEmails: true,
// if `verifyUserEmails` is `true` and
// if `emailVerifyTokenValidityDuration` is `undefined` then
// email verify token never expires
// else
// email verify token expires after `emailVerifyTokenValidityDuration`
//
// `emailVerifyTokenValidityDuration` defaults to `undefined`
//
// email verify token below expires in 2 hours (= 2 * 60 * 60 == 7200 seconds)
emailVerifyTokenValidityDuration: 2 * 60 * 60, // in seconds (2 hours = 7200 seconds)
// Set email verification token validity to 2 hours
emailVerifyTokenValidityDuration: 2 * 60 * 60,
// set preventLoginWithUnverifiedEmail to false to allow user to login without verifying their email
// set preventLoginWithUnverifiedEmail to true to prevent user from login if their email is not verified
preventLoginWithUnverifiedEmail: false, // defaults to false
// The public URL of your app.
// This will appear in the link that is used to verify email addresses and reset passwords.
// Set the mount path as it is in serverURL
publicServerURL: 'https://example.com/parse',
// Your apps name. This will appear in the subject and body of the emails that are sent.
appName: 'Parse App',
// The email adapter
// Set email adapter
emailAdapter: {
module: '@parse/simple-mailgun-adapter',
module: 'example-mail-adapter',
options: {
// The address that your emails come from
fromAddress: 'parse@example.com',
// Your domain from mailgun.com
domain: 'example.com',
// Your API key from mailgun.com
apiKey: 'key-mykey',
// Additional adapter options
...mailAdapterOptions
}
},
// account lockout policy setting (OPTIONAL) - defaults to undefined
// if the account lockout policy is set and there are more than `threshold` number of failed login attempts then the `login` api call returns error code `Parse.Error.OBJECT_NOT_FOUND` with error message `Your account is locked due to multiple failed login attempts. Please try again after <duration> minute(s)`. After `duration` minutes of no login attempts, the application will allow the user to try login again.
accountLockout: {
duration: 5, // duration policy setting determines the number of minutes that a locked-out account remains locked out before automatically becoming unlocked. Set it to a value greater than 0 and less than 100000.
threshold: 3, // threshold policy setting determines the number of failed sign-in attempts that will cause a user account to be locked. Set it to an integer value greater than 0 and less than 1000.
},
// optional settings to enforce password policies
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 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) },
validationError: 'Password must contain at least 1 digit.' // optional error message to be sent instead of the default "Password does not meet the Password Policy requirements." message.
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
}
});
```
You can also use other email adapters contributed by the community such as:
- [parse-smtp-template (Multi Language and Multi Template)](https://www.npmjs.com/package/parse-smtp-template)
Email adapters contributed by the community:
- [parse-server-api-mail-adapter](https://www.npmjs.com/package/parse-server-api-mail-adapter) (localization, templates, universally supports any email provider)
- [parse-smtp-template](https://www.npmjs.com/package/parse-smtp-template) (localization, templates)
- [parse-server-postmark-adapter](https://www.npmjs.com/package/parse-server-postmark-adapter)
- [parse-server-sendgrid-adapter](https://www.npmjs.com/package/parse-server-sendgrid-adapter)
- [parse-server-mandrill-adapter](https://www.npmjs.com/package/parse-server-mandrill-adapter)
@@ -338,7 +351,91 @@ You can also use other email adapters contributed by the community such as:
- [simple-parse-smtp-adapter](https://www.npmjs.com/package/simple-parse-smtp-adapter)
- [parse-server-generic-email-adapter](https://www.npmjs.com/package/parse-server-generic-email-adapter)
### Custom Pages
## Password and Account Policy
Set a password and account policy that meets your security requirements. The following is an example configuration. See the [Parse Server Options](https://parseplatform.org/parse-server/api/master/ParseServerOptions.html) for more details and a full list of available options.
```js
const server = ParseServer({
...otherOptions,
// The account lock policy
accountLockout: {
// Lock the account for 5 minutes.
duration: 5,
// Lock an account after 3 failed log-in attempts
threshold: 3,
// Unlock the account after a successful password reset
unlockOnPasswordReset: true,
},
// The password policy
passwordPolicy: {
// Enforce a password of at least 8 characters which contain at least 1 lower case, 1 upper case and 1 digit
validatorPattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})/,
// Do not allow the username as part of the password
doNotAllowUsername: true,
// Do not allow to re-use the last 5 passwords when setting a new password
maxPasswordHistory: 5,
},
});
```
## Custom Routes
**Caution, this is an experimental feature that may not be appropriate for production.**
Custom routes allow to build user flows with webpages, similar to the existing password reset and email verification features. Custom routes are defined with the `pages` option in the Parse Server configuration:
### Example
```js
const api = new ParseServer({
...otherOptions,
pages: {
enableRouter: true, // Enables the experimental feature; required for custom routes
customRoutes: [{
method: 'GET',
path: 'custom_route',
handler: async request => {
// custom logic
// ...
// then, depending on the outcome, return a HTML file as response
return { file: 'custom_page.html' };
}
}]
}
}
```
The above route can be invoked by sending a `GET` request to:
`https://[parseServerPublicUrl]/[parseMount]/[pagesEndpoint]/[appId]/[customRoute]`
The `handler` receives the `request` and returns a `custom_page.html` webpage from the `pages.pagesPath` directory as response. The advantage of building a custom route this way is that it automatically makes use of Parse Server's built-in capabilities, such as [page localization](#pages) and [dynamic placeholders](#dynamic-placeholders).
### Reserved Paths
The following paths are already used by Parse Server's built-in features and are therefore not available for custom routes. Custom routes with an identical combination of `path` and `method` are ignored.
| Path | HTTP Method | Feature |
|-----------------------------|-------------|--------------------|
| `verify_email` | `GET` | email verification |
| `resend_verification_email` | `POST` | email verification |
| `choose_password` | `GET` | password reset |
| `request_password_reset` | `GET` | password reset |
| `request_password_reset` | `POST` | password reset |
### Parameters
| Parameter | Optional | Type | Default value | Example values | Environment variable | Description |
|------------------------------|----------|-----------------|---------------|-----------------------|------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `pages` | yes | `Object` | `undefined` | - | `PARSE_SERVER_PAGES` | The options for pages such as password reset and email verification. |
| `pages.enableRouter` | yes | `Boolean` | `false` | - | `PARSE_SERVER_PAGES_ENABLE_ROUTER` | Is `true` if the pages router should be enabled; this is required for any of the pages options to take effect. **Caution, this is an experimental feature that may not be appropriate for production.** |
| `pages.customRoutes` | yes | `Array` | `[]` | - | `PARSE_SERVER_PAGES_CUSTOM_ROUTES` | The custom routes. The routes are added in the order they are defined here, which has to be considered since requests traverse routes in an ordered manner. Custom routes are traversed after build-in routes such as password reset and email verification. |
| `pages.customRoutes.method` | | `String` | - | `GET`, `POST` | - | The HTTP method of the custom route. |
| `pages.customRoutes.path` | | `String` | - | `custom_page` | - | The path of the custom route. Note that the same path can used if the `method` is different, for example a path `custom_page` can have two routes, a `GET` and `POST` route, which will be invoked depending on the HTTP request method. |
| `pages.customRoutes.handler` | | `AsyncFunction` | - | `async () => { ... }` | - | The route handler that is invoked when the route matches the HTTP request. If the handler does not return a page, the request is answered with a 404 `Not found.` response. |
## Custom Pages
It’s possible to change the default pages of the app and redirect the user to another path or domain.
@@ -359,7 +456,7 @@ var server = ParseServer({
})
```
### Using environment variables to configure Parse Server
## Using Environment Variables
You may configure the Parse Server using environment variables:
@@ -380,37 +477,38 @@ $ PORT=8080 parse-server --appId APPLICATION_ID --masterKey MASTER_KEY
For the full list of configurable environment variables, run `parse-server --help` or take a look at [Parse Server Configuration](https://github.com/parse-community/parse-server/blob/master/src/Options/Definitions.js).
### Available Adapters
## Available Adapters
All official adapters are distributed as scoped pacakges on [npm (@parse)](https://www.npmjs.com/search?q=scope%3Aparse).
All official adapters are distributed as scoped packages on [npm (@parse)](https://www.npmjs.com/search?q=scope%3Aparse).
Some well maintained adapters are also available on the [Parse Server Modules](https://github.com/parse-server-modules) organization.
You can also find more adapters maintained by the community by searching on [npm](https://www.npmjs.com/search?q=parse-server%20adapter&page=1&ranking=optimal).
### Configuring File Adapters
## Configuring File Adapters
Parse Server allows developers to choose from several options when hosting files:
* `GridFSBucketAdapter`, which is backed by MongoDB;
* `S3Adapter`, which is backed by [Amazon S3](https://aws.amazon.com/s3/); or
* `GCSAdapter`, which is backed by [Google Cloud Storage](https://cloud.google.com/storage/)
* `GridFSBucketAdapter` - which is backed by MongoDB
* `S3Adapter` - which is backed by [Amazon S3](https://aws.amazon.com/s3/)
* `GCSAdapter` - which is backed by [Google Cloud Storage](https://cloud.google.com/storage/)
* `FSAdapter` - local file storage
`GridFSBucketAdapter` is used by default and requires no setup, but if you're interested in using S3 or Google Cloud Storage, additional configuration information is available in the [Parse Server guide](http://docs.parseplatform.org/parse-server/guide/#configuring-file-adapters).
`GridFSBucketAdapter` is used by default and requires no setup, but if you're interested in using Amazon S3, Google Cloud Storage, or local file storage, additional configuration information is available in the [Parse Server guide](http://docs.parseplatform.org/parse-server/guide/#configuring-file-adapters).
### Idempodency Enforcement
## Idempotency Enforcement
**Caution, this is an experimental feature that may not be appropriate for production.**
This feature deduplicates identical requests that are received by Parse Server mutliple times, typically due to network issues or network adapter access restrictions on mobile operating systems.
This feature deduplicates identical requests that are received by Parse Server multiple times, typically due to network issues or network adapter access restrictions on mobile operating systems.
Identical requests are identified by their request header `X-Parse-Request-Id`. Therefore a client request has to include this header for deduplication to be applied. Requests that do not contain this header cannot be deduplicated and are processed normally by Parse Server. This means rolling out this feature to clients is seamless as Parse Server still processes request without this header when this feature is enbabled.
Identical requests are identified by their request header `X-Parse-Request-Id`. Therefore a client request has to include this header for deduplication to be applied. Requests that do not contain this header cannot be deduplicated and are processed normally by Parse Server. This means rolling out this feature to clients is seamless as Parse Server still processes requests without this header when this feature is enabled.
> This feature needs to be enabled on the client side to send the header and on the server to process the header. Refer to the specific Parse SDK docs to see whether the feature is supported yet.
Deduplication is only done for object creation and update (`POST` and `PUT` requests). Deduplication is not done for object finding and deletion (`GET` and `DELETE` requests), as these operations are already idempotent by definition.
#### Configuration example
### Configuration example <!-- omit in toc -->
```
let api = new ParseServer({
idempotencyOptions: {
@@ -419,19 +517,234 @@ let api = new ParseServer({
}
}
```
### Parameters <!-- omit in toc -->
| Parameter | Optional | Type | Default value | Example values | Environment variable | Description |
|----------------------------|----------|-----------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `idempotencyOptions` | yes | `Object` | `undefined` | | PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_OPTIONS | Setting this enables idempotency enforcement for the specified paths. |
| `idempotencyOptions.paths` | yes | `Array<String>` | `[]` | `.*` (all paths, includes the examples below), <br>`functions/.*` (all functions), <br>`jobs/.*` (all jobs), <br>`classes/.*` (all classes), <br>`functions/.*` (all functions), <br>`users` (user creation / update), <br>`installations` (installation creation / update) | PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_PATHS | An array of path patterns that have to match the request path for request deduplication to be enabled. The mount path must not be included, for example to match the request path `/parse/functions/myFunction` specify the path pattern `functions/myFunction`. A trailing slash of the request path is ignored, for example the path pattern `functions/myFunction` matches both `/parse/functions/myFunction` and `/parse/functions/myFunction/`. |
| `idempotencyOptions.ttl` | yes | `Integer` | `300` | `60` (60 seconds) | PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_TTL | The duration in seconds after which a request record is discarded from the database. Duplicate requests due to network issues can be expected to arrive within milliseconds up to several seconds. This value must be greater than `0`. |
### Postgres <!-- omit in toc -->
To use this feature in Postgres, you will need to create a cron job using [pgAdmin](https://www.pgadmin.org/docs/pgadmin4/development/pgagent_jobs.html) or similar to call the Postgres function `idempotency_delete_expired_records()` that deletes expired idempotency records. You can find an example script below. Make sure the script has the same privileges to log into Postgres as Parse Server.
```bash
#!/bin/bash
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
SELECT idempotency_delete_expired_records();
EOSQL
exec "$@"
```
Assuming the script above is named, `parse_idempotency_delete_expired_records.sh`, a cron job that runs the script every 2 minutes may look like:
```bash
2 * * * * /root/parse_idempotency_delete_expired_records.sh >/dev/null 2>&1
```
## Localization
### Pages
**Caution, this is an experimental feature that may not be appropriate for production.**
Custom pages as well as feature pages (e.g. password reset, email verification) can be localized with the `pages` option in the Parse Server configuration:
```js
const api = new ParseServer({
...otherOptions,
pages: {
enableRouter: true, // Enables the experimental feature; required for localization
enableLocalization: true,
}
}
```
Localization is achieved by matching a request-supplied `locale` parameter with localized page content. The locale can be supplied in either the request query, body or header with the following keys:
- query: `locale`
- body: `locale`
- header: `x-parse-page-param-locale`
For example, a password reset link with the locale parameter in the query could look like this:
```
http://example.com/parse/apps/[appId]/request_password_reset?token=[token]&username=[username]&locale=de-AT
```
- Localization is only available for pages in the pages directory as set with `pages.pagesPath`.
- Localization for feature pages (e.g. password reset, email verification) is disabled if `pages.customUrls` are set, even if the custom URLs point to the pages within the pages path.
- Only `.html` files are considered for localization when localizing custom pages.
Pages can be localized in two ways:
#### Localization with Directory Structure
Pages are localized by using the corresponding file in the directory structure where the files are placed in subdirectories named after the locale or language. The file in the base directory is the default file.
**Example Directory Structure:**
```js
root/
├── public/ // pages base path
│ ├── example.html // default file
│ └── de/ // de language folder
│ │ └── example.html // de localized file
│ └── de-AT/ // de-AT locale folder
│ │ └── example.html // de-AT localized file
```
Files are matched with the locale in the following order:
1. Locale match, e.g. locale `de-AT` matches file in folder `de-AT`.
1. Language match, e.g. locale `de-CH` matches file in folder `de`.
1. Default; file in base folder is returned.
**Configuration Example:**
```js
const api = new ParseServer({
...otherOptions,
pages: {
enableRouter: true, // Enables the experimental feature; required for localization
enableLocalization: true,
customUrls: {
passwordReset: 'https://example.com/page.html'
}
}
}
```
Pros:
- All files are complete in their content and can be easily opened and previewed by viewing the file in a browser.
Cons:
- In most cases, a localized page differs only slightly from the default page, which could cause a lot of duplicate code that is difficult to maintain.
#### Localization with JSON Resource
Pages are localized by adding placeholders in the HTML files and providing a JSON resource that contains the translations to fill into the placeholders.
**Example Directory Structure:**
```js
root/
├── public/ // pages base path
│ ├── example.html // the page containing placeholders
├── private/ // folder outside of public scope
│ └── translations.json // JSON resource file
```
The JSON resource file loosely follows the [i18next](https://github.com/i18next/i18next) syntax, which is a syntax that is often supported by translation platforms, making it easy to manage translations, exporting them for use in Parse Server, and even to automate this workflow.
**Example JSON Content:**
```json
{
"en": { // resource for language `en` (English)
"translation": {
"greeting": "Hello!"
}
},
"de": { // resource for language `de` (German)
"translation": {
"greeting": "Hallo!"
}
}
"de-AT": { // resource for locale `de-AT` (Austrian German)
"translation": {
"greeting": "Servus!"
}
}
}
```
**Configuration Example:**
```js
const api = new ParseServer({
...otherOptions,
pages: {
enableRouter: true, // Enables the experimental feature; required for localization
enableLocalization: true,
localizationJsonPath: './private/localization.json',
localizationFallbackLocale: 'en'
}
}
```
Pros:
- There is only one HTML file to maintain that contains the placeholders that are filled with the translations according to the locale.
Cons:
- Files cannot be easily previewed by viewing the file in a browser because the content contains only placeholders and even HTML or CSS changes may be dynamically applied, e.g. when a localization requires a Right-To-Left layout direction.
- Style and other fundamental layout changes may be more difficult to apply.
#### Dynamic placeholders
In addition to feature related default parameters such as `appId` and the translations provided via JSON resource, it is possible to define custom dynamic placeholders as part of the router configuration. This works independently of localization and, also if `enableLocalization` is disabled.
**Configuration Example:**
```js
const api = new ParseServer({
...otherOptions,
pages: {
enableRouter: true, // Enables the experimental feature; required for localization
placeholders: {
exampleKey: 'exampleValue'
}
}
}
```
The placeholders can also be provided as function or as async function, with the `locale` and other feature related parameters passed through, to allow for dynamic placeholder values:
```js
const api = new ParseServer({
...otherOptions,
pages: {
enableRouter: true, // Enables the experimental feature; required for localization
placeholders: async (params) => {
const value = await doSomething(params.locale);
return {
exampleKey: value
};
}
}
}
```
#### Reserved Keys
The following parameter and placeholder keys are reserved because they are used related to features such as password reset or email verification. They should not be used as translation keys in the JSON resource or as manually defined placeholder keys in the configuration: `appId`, `appName`, `email`, `error`, `locale`, `publicServerUrl`, `token`, `username`.
#### Parameters
| Parameter | Optional | Type | Default value | Example values | Environment variable | Description |
|-----------|----------|--------|---------------|-----------|-----------|-------------|
| `idempotencyOptions` | yes | `Object` | `undefined` | | PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_OPTIONS | Setting this enables idempotency enforcement for the specified paths. |
| `idempotencyOptions.paths`| yes | `Array<String>` | `[]` | `.*` (all paths, includes the examples below), <br>`functions/.*` (all functions), <br>`jobs/.*` (all jobs), <br>`classes/.*` (all classes), <br>`functions/.*` (all functions), <br>`users` (user creation / update), <br>`installations` (installation creation / update) | PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_PATHS | An array of path patterns that have to match the request path for request deduplication to be enabled. The mount path must not be included, for example to match the request path `/parse/functions/myFunction` specifiy the path pattern `functions/myFunction`. A trailing slash of the request path is ignored, for example the path pattern `functions/myFunction` matches both `/parse/functions/myFunction` and `/parse/functions/myFunction/`. |
| `idempotencyOptions.ttl` | yes | `Integer` | `300` | `60` (60 seconds) | PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_TTL | The duration in seconds after which a request record is discarded from the database. Duplicate requests due to network issues can be expected to arrive within milliseconds up to several seconds. This value must be greater than `0`. |
| Parameter | Optional | Type | Default value | Example values | Environment variable | Description |
|-------------------------------------------------|----------|---------------------------------------|----------------------------------------|------------------------------------------------------|-----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `pages` | yes | `Object` | `undefined` | - | `PARSE_SERVER_PAGES` | The options for pages such as password reset and email verification. |
| `pages.enableRouter` | yes | `Boolean` | `false` | - | `PARSE_SERVER_PAGES_ENABLE_ROUTER` | Is `true` if the pages router should be enabled; this is required for any of the pages options to take effect. **Caution, this is an experimental feature that may not be appropriate for production.** |
| `pages.enableLocalization` | yes | `Boolean` | `false` | - | `PARSE_SERVER_PAGES_ENABLE_LOCALIZATION` | Is true if pages should be localized; this has no effect on custom page redirects. |
| `pages.localizationJsonPath` | yes | `String` | `undefined` | `./private/translations.json` | `PARSE_SERVER_PAGES_LOCALIZATION_JSON_PATH` | The path to the JSON file for localization; the translations will be used to fill template placeholders according to the locale. |
| `pages.localizationFallbackLocale` | yes | `String` | `en` | `en`, `en-GB`, `default` | `PARSE_SERVER_PAGES_LOCALIZATION_FALLBACK_LOCALE` | The fallback locale for localization if no matching translation is provided for the given locale. This is only relevant when providing translation resources via JSON file. |
| `pages.placeholders` | yes | `Object`, `Function`, `AsyncFunction` | `undefined` | `{ exampleKey: 'exampleValue' }` | `PARSE_SERVER_PAGES_PLACEHOLDERS` | The placeholder keys and values which will be filled in pages; this can be a simple object or a callback function. |
| `pages.forceRedirect` | yes | `Boolean` | `false` | - | `PARSE_SERVER_PAGES_FORCE_REDIRECT` | Is `true` if responses should always be redirects and never content, `false` if the response type should depend on the request type (`GET` request -> content response; `POST` request -> redirect response). |
| `pages.pagesPath` | yes | `String` | `./public` | `./files/pages`, `../../pages` | `PARSE_SERVER_PAGES_PAGES_PATH` | The path to the pages directory; this also defines where the static endpoint `/apps` points to. |
| `pages.pagesEndpoint` | yes | `String` | `apps` | - | `PARSE_SERVER_PAGES_PAGES_ENDPOINT` | The API endpoint for the pages. |
| `pages.customUrls` | yes | `Object` | `{}` | `{ passwordReset: 'https://example.com/page.html' }` | `PARSE_SERVER_PAGES_CUSTOM_URLS` | The URLs to the custom pages |
| `pages.customUrls.passwordReset` | yes | `String` | `password_reset.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_PASSWORD_RESET` | The URL to the custom page for password reset. |
| `pages.customUrls.passwordResetSuccess` | yes | `String` | `password_reset_success.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_PASSWORD_RESET_SUCCESS` | The URL to the custom page for password reset -> success. |
| `pages.customUrls.passwordResetLinkInvalid` | yes | `String` | `password_reset_link_invalid.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_PASSWORD_RESET_LINK_INVALID` | The URL to the custom page for password reset -> link invalid. |
| `pages.customUrls.emailVerificationSuccess` | yes | `String` | `email_verification_success.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_EMAIL_VERIFICATION_SUCCESS` | The URL to the custom page for email verification -> success. |
| `pages.customUrls.emailVerificationSendFail` | yes | `String` | `email_verification_send_fail.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_EMAIL_VERIFICATION_SEND_FAIL` | The URL to the custom page for email verification -> link send fail. |
| `pages.customUrls.emailVerificationSendSuccess` | yes | `String` | `email_verification_send_success.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_EMAIL_VERIFICATION_SEND_SUCCESS` | The URL to the custom page for email verification -> resend link -> success. |
| `pages.customUrls.emailVerificationLinkInvalid` | yes | `String` | `email_verification_link_invalid.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_EMAIL_VERIFICATION_LINK_INVALID` | The URL to the custom page for email verification -> link invalid. |
| `pages.customUrls.emailVerificationLinkExpired` | yes | `String` | `email_verification_link_expired.html` | - | `PARSE_SERVER_PAGES_CUSTOM_URL_EMAIL_VERIFICATION_LINK_EXPIRED` | The URL to the custom page for email verification -> link expired. |
#### Notes
### Notes <!-- omit in toc -->
- This feature is currently only available for MongoDB and not for Postgres.
- In combination with the [Parse Server API Mail Adapter](https://www.npmjs.com/package/parse-server-api-mail-adapter) Parse Server provides a fully localized flow (emails -> pages) for the user. The email adapter sends a localized email and adds a locale parameter to the password reset or email verification link, which is then used to respond with localized pages.
### Logging
## Logging
Parse Server will, by default, log:
* to the console
@@ -441,13 +754,17 @@ Logs are also viewable in Parse Dashboard.
**Want to log each request and response?** Set the `VERBOSE` environment variable when starting `parse-server`. Usage :- `VERBOSE='1' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
**Want logs to be in placed in a different folder?** Pass the `PARSE_SERVER_LOGS_FOLDER` environment variable when starting `parse-server`. Usage :- `PARSE_SERVER_LOGS_FOLDER='<path-to-logs-folder>' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
**Want logs to be placed in a different folder?** Pass the `PARSE_SERVER_LOGS_FOLDER` environment variable when starting `parse-server`. Usage :- `PARSE_SERVER_LOGS_FOLDER='<path-to-logs-folder>' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
**Want to log specific levels?** Pass the `logLevel` parameter when starting `parse-server`. Usage :- `parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --logLevel LOG_LEVEL`
**Want new line delimited JSON error logs (for consumption by CloudWatch, Google Cloud Logging, etc)?** Pass the `JSON_LOGS` environment variable when starting `parse-server`. Usage :- `JSON_LOGS='1' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
# Live Queries
# Deprecations
See the [Deprecation Plan](https://github.com/parse-community/parse-server/blob/master/DEPRECATIONS.md) for an overview of deprecations and planned breaking changes.
# Live Query
Live queries are meant to be used in real-time reactive applications, where just using the traditional query paradigm could cause several problems, like increased response time and high network and server usage. Live queries should be used in cases where you need to continuously update a page with fresh data coming from the database, which often happens in (but is not limited to) online games, messaging clients and shared to-do lists.
@@ -484,13 +801,13 @@ $ docker build --tag parse-server .
$ docker run --name my-mongo -d mongo
```
#### Running the Parse Server Image
#### Running the Parse Server Image <!-- omit in toc -->
```bash
$ docker run --name my-parse-server --link my-mongo:mongo -v config-vol:/parse-server/config -p 1337:1337 -d parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://mongo/test --publicServerURL http://localhost:1337/parse --mountGraphQL --mountPlayground
```
***Note:*** *If you want to use [Cloud Code](https://docs.parseplatform.org/cloudcode/guide/) feature, please add `-v cloud-code-vol:/parse-server/cloud --cloud /parse-server/cloud/main.js` to command above. Make sure the `main.js` file is available in the `cloud-code-vol` directory before run this command. Otherwise, an error will occur.*
***Note:*** *If you want to use [Cloud Code](https://docs.parseplatform.org/cloudcode/guide/), add `-v cloud-code-vol:/parse-server/cloud --cloud /parse-server/cloud/main.js` to the command above. Make sure `main.js` is in the `cloud-code-vol` directory before starting Parse Server.*
After starting the server, you can visit http://localhost:1337/playground in your browser to start playing with your GraphQL API.
@@ -731,7 +1048,7 @@ To start creating your custom schema, you need to code a `schema.graphql` file a
$ parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://localhost/test --publicServerURL http://localhost:1337/parse --cloud ./cloud/main.js --graphQLSchema ./cloud/schema.graphql --mountGraphQL --mountPlayground
```
### Creating your first custom query
### Creating your first custom query <!-- omit in toc -->
Use the code below for your `schema.graphql` and `main.js` files. Then restart your Parse Server.
@@ -793,7 +1110,7 @@ directly on this branch:
npm install parse-community/parse-server.git#master
```
## Experimenting
## Experimenting <!-- omit in toc -->
You can also use your own forks, and work in progress branches by specifying them:
@@ -857,3 +1174,7 @@ Support us with a monthly donation and help us continue our activities. [Become
-----
As of April 5, 2017, Parse, LLC has transferred this code to the parse-community organization, and will no longer be contributing to or distributing this code.
[license-svg]: https://img.shields.io/badge/license-BSD-lightgrey.svg
[license-link]: LICENSE
[open-collective-link]: https://opencollective.com/parse-server
+1 -83
View File
@@ -16,86 +16,4 @@ We ask that:
# Communicating with us
All vulnerabilities should be privately reported to either [Node Security](https://nodesecurity.io/report) or directly to us at the following address [security at parseplatform dot org](mailto:security@parseplatform.org)
You can use our PGP public key, which is also uploaded [here](hkp://pgp.mit.edu):
```
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBFbZHTcBEADMJledXkBantsiKc5fbln3j+Bj3R2fP6xcUZ4N6RdKj/19G8e4
+Lwso/SEDlKKuh+1ORHrcXbYBPNRTi+syf0dtL6uqNKVS+jzuS48qd7G04Foe+qs
rg5k80TfRLboCoESIS4C8E6sdjCMKEj8b+QQU8YyzL470+gYwgg7bfvHyECuS4AD
lPssBi03cQdVlYjxNWQZAfVMZ+5zcvpS4P5KOCZPT082rzlgQEmVpmNuTyBELNtl
TBcVK9Sq6/KlNNSXMbGfJlMMq0kgAzVxrSyx3y0gOnRx1DR+a5jJSecPtdVJYno8
9mwRT6Z1B/boN6GmEhC3vikmsOmA+umaLoscQcwjQj7jK5rPTF8ypuDfVNa+kAUS
ONFrayDQljwMEVHZ5/lk9TfEwrnarN8q0fRs2MXaJsD/YlTHG5/9LJs3mMk5yQpq
VGq0sydprnubW36nbP0SkH2LMRrLhQWoLEvtjkz7EaqGLWKO6N0Nr+BT1YBy5gM+
evc5mUeHUTPqflDht1crHn0rdfWmtDzEsNUWc9GR1hK2+x8U43YUPDmmgRYZyCGP
iKdmrF0kUDlh2mmok3dXlQCZesXaeFvSbIFMfL7midhbiWyCfDtAIQPfBTKNtfc3
qbaAoEHmYS2Yjri0rRqK9zbFqDgOR7Ap/ExeoOuaAMx1bvjV0QBm0W8q+QARAQAB
tC1BcnRodXIgQ2luYWRlciAoR2l0aHViKSA8YXJ0aHVyQHBvcHN1Z2FyLmNvbT6J
Aj0EEwEKACcFAloYZqECGwMFCQeGH4AFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AA
CgkQgZHETYyfyECCKA/8CbpKrMJn+UhP4s5eUisx6wSfqDWuHGkvhecxTWLRGGRT
yycDm7PJxSb3AdJ//sUTGemG88kpLXmEGt3HpINqB0B4J+aqTB/Ei0+1g/FH0LXP
RlCehH0RpLHJmplkEbd2VZ8wFN9+tW1u4jhG+LCZD8pAVy7f36QixCZA3fdlt9GN
K2Jq2456dMpHmaLdUbrYERcDSKmDVKBRa8/CTe9hAkA83kAt0xgWjr/Byxw+L3wi
Ar4/twAwLAHCzl7HTVvbWOXYehM8dpybE7rFV/1OACg3i2uppLE1oGeS2s4HBv84
WYNx0oBlBzEefpDAxz1NQI4HnKtBopt8jNUs5GEa1GR4eSNdMf9SmX7MRBNgDKuY
PsvZQLUBqG8GYZR214NzK9wf0VkQDkZ+PwG+L5pnpKtc7RwsR49z2qyti/nZfPP7
y9gJanTNPkzgx2YAk+UBrKL7435XfFAW6mo2y5LLbD6ouT2hGDfnhsSuMrS4bAdM
7ua9B8vs2cnwYXUFM7ydAueaPvfP0x5i0ZQrphls3ZUpKRpWORSXa0fTNinSpzqW
YzTmPxJsHsyioPlRsl2/r97I9XJ9i5gjMDkNI3TQpGKFy/YNMk7rkk1dp3hq3aP/
xt0P/2yL/MJEj9Jus9FTKGqVtOn73e8oSOsu0ngpllYasYaLkO19MJ2lemSW+CC0
LEFydGh1ciBDaW5hZGVyIChHaXRodWIpIDxhY2luYWRlckBnbWFpbC5jb20+iQI9
BBMBCgAnBQJaGGJcAhsDBQkHhh+ABQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJ
EIGRxE2Mn8hAGVcP/RkqkER8/AKWfPFQs40Epe3mocuLyEW1CHX5LkFTjya42GAM
0BKk+bStRrMQ4rBGOmdKGxphysQFZn4bscRUVMmJd/frJ0s8ConSfWzaweL7rbQO
UgGnL4mSNUvQkNCoO/RgKJapq9G/+jA9RRYEoSncE1/i3FQ+96JWfRRYy3MGYi9H
WmH3UFQ8cJ1JAFMIGaxuHuNQ20mStVDSuK3Zm8KVxk8rWHb2O8lye4bcBi7OLXYx
oZEoLrbLQinMbuccNaMq2j3ZNLOPYUDyyv5O81WzN70A7r0rkipOaJx4LiXE2/NT
3vz1CyT7i+2/GlLL113DP0DA8neMjx6MzpxOo7MgT+ZBHRRZh+tWoqfJKclh6Duw
rAJ9BOxSCm1y4BxTxuWrb5mU/RDCe3oC7PTA6wIMbJThqxtRpjqa17oWn2UXyJOH
aEXvt6jH6YqqFV9liArwkjZZl4KKyiqZ8UFKLteIVSK5xlwQ/ICW3uPYRpYhIFj0
fMaqN5SFcMOxtD4L5SP4k7HRn8l/gVoWQyIMJMip87sPCw7mRe5jq91n9s33stHr
vByL0ownS5MmvKXLLAyAltw2FcIyafcn6mKNGMUBunM14/j5uXaMcgz3MQtYjkvk
Fh6uX1OqLt/rpOhsRTeDRvjGvAFtdLt1QtDEz4i9kGN4h4B/XqwEbVNMWyv4tDlB
cnRodXIgQ2luYWRlciA8NzAwNTcyK2FjaW5hZGVyQHVzZXJzLm5vcmVwbHkuZ2l0
aHViLmNvbT6JAj0EEwEKACcFAloYaaMCGwMFCQeGH4AFCwkIBwMFFQoJCAsFFgID
AQACHgECF4AACgkQgZHETYyfyEANHBAAuOkRMEoCuRjN3Dz/bP7SpWSFnBjOWW42
Lbie3bXbT1SYRltd7AM3ICu2M8OzjATzrDimmGi7K4qxFIGnz+sjp9NRr6x7Ohgi
bPwmU1OMIjuARPhsauUyyUNI+wKbRG9/tO0YxOUBadsKcVYY+6JxhsjrO5qb9NUI
WaNvwfCPlSBDcvsKCOVu6weyw9FGpaaKZcscge8tPPEQCf7FYKy6NYPVK6/D7qn6
myaKe/dh/HwozZ0o2NhW3uIAdd4OIvmWE7rh97B7afKXTiIfiqWqtkFhH0RxdR2q
Damg0BiGjdARqSnneLKDPgIwr904yM1RD36BkPcP8WH3ommsK95mrUKrZtLAQA6J
J6uESkuHNtcy5XTx4eF2cD2uaJTcRjlbAHFBMEI/+vr4umo+8wt38JhY+XtSot6W
rS99JU6Ht1/SMYdz/rFisOWHb6hS69DOSCEK68lne6n0u1AnsWnDHwbQxcaSEreR
axXMzgMtRuM5R4ncLpx0nUwhxlRoIyo2GN6aghXcCrZt1fsLXBilag1moxZgh+YE
RaVOsBASuqO/5m609Mi8AGLbuLU+39Ekb/b2ozw/MRvGPNfXC1XIqPe4asEE9GNL
XdVqvrHhEexBpv7El9yQ9qyllzEEdv5+soMcUQmjJAVabx+0gtLb5x3QHD4V8ttT
kA8kUPG5MyO5Ag0EVtkdNwEQAKssJS3MZiu6WkBact/HvDjJrq+S1HcxeTLYbFXK
lEsolW5sw0IX5ORM9+Z9LfUTyVcyU6w/UbM91IecjNnFQkMvIQy8lVhrqO20FL46
Vu6G5HezIf2hg/1vgt891hrKMrySQDDyGo68f6uF3U+SJLeNPRoB4O8qL2RHXfC3
3ti6FAoOFfRGe/CNB35viK/L//6O3pCFz/nrckEaMzH/GOrcZ8xlrFyeKhsOjtoR
S2MDSNpIJfZP+pbtBgVW5lA5HDlyy5s52jXgd0+1Ktw1FV1uCjsgaX9xfbfXG8o1
SxpKpj1dI8WQ/7ZuCTxu0phyJsQPmfIHb5kBvZjm4vqpnCfbbFWxsQE+T01PRsV+
rWdh1EG4dlTMkvZtMfAnDZV+Cqf6FELb/KhrbRqlCjHeC99tn6YP9EpvLNIgUnD6
qiV2QVHMKZ+wRfRUAYUBtvbFYqbbEqLySpW0ahPB/UmLUMjvArzrQkxvKFM20nb8
HnAAKAZpgjhXTO9OBiNErCfiORooZLEs1MBeR1u8932GL/uKSDX0RhTYBBFDVoNy
zGj3lW3YfnCurVIjCoj+jAZGMSVi67GnUuhm0Vj2K4mdSbq40TwhXxKlp8G0uSU4
SmCm+yjTVcgQj+Xj+fsFJh6YGIgkcLEpbZS6kCLKcnx+44U3nZYPZch0+3/m8Uaf
i3e5ABEBAAGJAiUEGAEKAA8FAlbZHTcCGwwFCQeGH4AACgkQgZHETYyfyEBEcQ/8
DXyIYahE4JmY4REkdSnTQQ09etNmlqZbnMo1y7aYqDgqoixGpZAyE5U3oxGMeNBD
P+XEaZGDav9wfiOlnofMXBa65kbtWoz/+dLc+sTAjNdWvucuzP0yiE0+RNkOtvmY
5BlGgIQS9PTRaw86aRFOE5LilAoR/jv+mOMPt1dcLfHksmCpW+3OzPyxCA703fE5
l7xOXYOAhPGMco30EftebbZkiaAmoZFese92pRenTJXi007ALhMpjPbk5D7717DZ
4/g2gqT+Zs8fZe4tUHjo8LSQrFh/i3TpyBoAIouJsuvVvXy0r+iucKvfBjB4vdQb
b33Fft2DYVBMpVVfnjRg1Y+p5IFNWByI5NYfFsf8AWLHhOWargYmiUjHMdDFXuea
3QUTzHARp4HsqoZocjhKEoW5+j0MTVM6q7cTGgkNvAUmlPEzpvjQP84zkeM7gskP
vaKjgp0gIaCMlzP2fRSKqQ2f84LhKj0mZDy7HQNhtKme1l014HgTbbP7GDJ2UMse
uHgdaLLljuHFbHYAgGI7Uck225weDESF8enizh1ZF1itRliN47ICsef1RQJCgrJb
dkoPBN52k7VhS3vUIQhA1P1sLSEtPMuJ8SDq0CuA008WpU/xHdm1b+xcBxrabuoz
6jfgzgnAZveF5DMisrOnbi4GHVIiHXvWrrIglA6o1sM=
=paxU
-----END PGP PUBLIC KEY BLOCK-----
```
All vulnerabilities should be privately reported to us by going to [https://report.parseplatform.org](https://report.parseplatform.org). Alternatively, you can send an email to [security&#64;parseplatform&#46;org](mailto:security&#64;parseplatform&#46;org).
+318
View File
@@ -0,0 +1,318 @@
## [5.2.1-alpha.2](https://github.com/parse-community/parse-server/compare/5.2.1-alpha.1...5.2.1-alpha.2) (2022-03-26)
### Performance Improvements
* reduce database operations when using the constant parameter in Cloud Function validation ([#7892](https://github.com/parse-community/parse-server/issues/7892)) ([48bd512](https://github.com/parse-community/parse-server/commit/48bd512eeb47666967dff8c5e723ddc5b7801daa))
## [5.2.1-alpha.1](https://github.com/parse-community/parse-server/compare/5.2.0...5.2.1-alpha.1) (2022-03-26)
### Bug Fixes
* return correct response when revert is used in beforeSave ([#7839](https://github.com/parse-community/parse-server/issues/7839)) ([f63fb2b](https://github.com/parse-community/parse-server/commit/f63fb2b338c908f0e7a648d338c26b9daa50c8f2))
# [5.2.0-alpha.3](https://github.com/parse-community/parse-server/compare/5.2.0-alpha.2...5.2.0-alpha.3) (2022-03-24)
### Bug Fixes
* security bump minimist from 1.2.5 to 1.2.6 ([#7884](https://github.com/parse-community/parse-server/issues/7884)) ([c5cf282](https://github.com/parse-community/parse-server/commit/c5cf282d11ffdc023764f8e7539a2bd6bc246fe1))
# [5.2.0-alpha.2](https://github.com/parse-community/parse-server/compare/5.2.0-alpha.1...5.2.0-alpha.2) (2022-03-24)
### Bug Fixes
* sensitive keyword detection may produce false positives ([#7881](https://github.com/parse-community/parse-server/issues/7881)) ([0d6f9e9](https://github.com/parse-community/parse-server/commit/0d6f9e951d9e186e95e96d8869066ce7022bad02))
# [5.2.0-alpha.1](https://github.com/parse-community/parse-server/compare/5.1.1...5.2.0-alpha.1) (2022-03-23)
### Features
* improved LiveQuery error logging with additional information ([#7837](https://github.com/parse-community/parse-server/issues/7837)) ([443a509](https://github.com/parse-community/parse-server/commit/443a5099059538d379fe491793a5871fcbb4f377))
# [5.0.0-alpha.29](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.28...5.0.0-alpha.29) (2022-03-12)
### Features
* bump required node engine to >=12.22.10 ([#7846](https://github.com/parse-community/parse-server/issues/7846)) ([5ace99d](https://github.com/parse-community/parse-server/commit/5ace99d542a11e422af46d9fd6b1d3d2513b34cf))
### BREAKING CHANGES
* This requires Node.js version >=12.22.10. ([5ace99d](5ace99d))
# [5.0.0-alpha.28](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.27...5.0.0-alpha.28) (2022-03-12)
### Bug Fixes
* security vulnerability that allows remote code execution (GHSA-p6h4-93qp-jhcm) ([#7844](https://github.com/parse-community/parse-server/issues/7844)) ([e569f40](https://github.com/parse-community/parse-server/commit/e569f402b1fd8648fb0d1523b71b2a03273902a5))
# [5.0.0-alpha.27](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.26...5.0.0-alpha.27) (2022-03-12)
### Reverts
* update node engine to 2.22.0 ([#7827](https://github.com/parse-community/parse-server/issues/7827)) ([f235412](https://github.com/parse-community/parse-server/commit/f235412c1b6c2b173b7531f285429ea7214b56a2))
# [5.0.0-alpha.26](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.25...5.0.0-alpha.26) (2022-02-25)
### Bug Fixes
* package.json & package-lock.json to reduce vulnerabilities ([#7823](https://github.com/parse-community/parse-server/issues/7823)) ([5ca2288](https://github.com/parse-community/parse-server/commit/5ca228882332b65f3ac05407e6e4da1ee3ef3749))
# [5.0.0-alpha.25](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.24...5.0.0-alpha.25) (2022-02-23)
### Bug Fixes
* upgrade winston from 3.5.0 to 3.5.1 ([#7820](https://github.com/parse-community/parse-server/issues/7820)) ([4af253d](https://github.com/parse-community/parse-server/commit/4af253d1f8654a6f57b5137ad310cdacadc922cc))
# [5.0.0-alpha.24](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.23...5.0.0-alpha.24) (2022-02-10)
### Bug Fixes
* security upgrade follow-redirects from 1.14.7 to 1.14.8 ([#7801](https://github.com/parse-community/parse-server/issues/7801)) ([70088a9](https://github.com/parse-community/parse-server/commit/70088a95a78393da2a4ac68be81e63107747626a))
# [5.0.0-alpha.23](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.22...5.0.0-alpha.23) (2022-02-06)
### Bug Fixes
* server crash using GraphQL due to missing @apollo/client peer dependency ([#7787](https://github.com/parse-community/parse-server/issues/7787)) ([08089d6](https://github.com/parse-community/parse-server/commit/08089d6fcbb215412448ce7d92b21b9fe6c929f2))
# [5.0.0-alpha.22](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.21...5.0.0-alpha.22) (2022-02-06)
### Features
* upgrade to MongoDB Node.js driver 4.x for MongoDB 5.0 support ([#7794](https://github.com/parse-community/parse-server/issues/7794)) ([f88aa2a](https://github.com/parse-community/parse-server/commit/f88aa2a62a533e5344d1c13dd38c5a0b283a480a))
### BREAKING CHANGES
* The MongoDB GridStore adapter has been removed. By default, Parse Server already uses GridFS, so if you do not manually use the GridStore adapter, you can ignore this change. ([f88aa2a](f88aa2a))
# [5.0.0-alpha.21](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.20...5.0.0-alpha.21) (2022-01-25)
### Features
* add Cloud Code context to `ParseObject.fetch` ([#7779](https://github.com/parse-community/parse-server/issues/7779)) ([315290d](https://github.com/parse-community/parse-server/commit/315290d16110110938f80a6b779cc2d1db58c552))
# [5.0.0-alpha.20](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.19...5.0.0-alpha.20) (2022-01-22)
### Bug Fixes
* bump node-fetch from 2.6.1 to 3.1.1 ([#7782](https://github.com/parse-community/parse-server/issues/7782)) ([9082351](https://github.com/parse-community/parse-server/commit/90823514113a1a085ebc818f7109b3fd7591346f))
# [5.0.0-alpha.19](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.18...5.0.0-alpha.19) (2022-01-22)
### Bug Fixes
* bump nanoid from 3.1.25 to 3.2.0 ([#7781](https://github.com/parse-community/parse-server/issues/7781)) ([f5f63bf](https://github.com/parse-community/parse-server/commit/f5f63bfc64d3481ed944ceb5e9f50b33dccd1ce9))
# [5.0.0-alpha.18](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.17...5.0.0-alpha.18) (2022-01-13)
### Bug Fixes
* security upgrade follow-redirects from 1.14.6 to 1.14.7 ([#7769](https://github.com/parse-community/parse-server/issues/7769)) ([8f5a861](https://github.com/parse-community/parse-server/commit/8f5a8618cfa7ed9a2a239a095abffa8f3fd8d31a))
# [5.0.0-alpha.17](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.16...5.0.0-alpha.17) (2022-01-13)
### Bug Fixes
* schema cache not cleared in some cases ([#7678](https://github.com/parse-community/parse-server/issues/7678)) ([5af6e5d](https://github.com/parse-community/parse-server/commit/5af6e5dfaa129b1a350afcba4fb381b21c4cc35d))
# [5.0.0-alpha.16](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.15...5.0.0-alpha.16) (2022-01-02)
### Features
* add Idempotency to Postgres ([#7750](https://github.com/parse-community/parse-server/issues/7750)) ([0c3feaa](https://github.com/parse-community/parse-server/commit/0c3feaaa1751964c0db89f25674935c3354b1538))
# [5.0.0-alpha.15](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.14...5.0.0-alpha.15) (2022-01-02)
### Features
* support `postgresql` protocol in database URI ([#7757](https://github.com/parse-community/parse-server/issues/7757)) ([caf4a23](https://github.com/parse-community/parse-server/commit/caf4a2341f554b28e3918c53e7e897a3ca47bf8b))
# [5.0.0-alpha.14](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.13...5.0.0-alpha.14) (2022-01-02)
### Features
* support relativeTime query constraint on Postgres ([#7747](https://github.com/parse-community/parse-server/issues/7747)) ([16b1b2a](https://github.com/parse-community/parse-server/commit/16b1b2a19714535ca805f2dbb3b561d8f6a519a7))
# [5.0.0-alpha.13](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.12...5.0.0-alpha.13) (2021-12-08)
### Bug Fixes
* node engine compatibility did not include node 16 ([#7739](https://github.com/parse-community/parse-server/issues/7739)) ([ea7c014](https://github.com/parse-community/parse-server/commit/ea7c01400f992a1263543706fe49b6174758a2d6))
# [5.0.0-alpha.12](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.11...5.0.0-alpha.12) (2021-12-06)
### Bug Fixes
* adding or modifying a nested property requires addField permissions ([#7679](https://github.com/parse-community/parse-server/issues/7679)) ([6a6248b](https://github.com/parse-community/parse-server/commit/6a6248b6cb2e732d17131e18e659943b894ed2f1))
# [5.0.0-alpha.11](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.10...5.0.0-alpha.11) (2021-11-29)
### Bug Fixes
* upgrade mime from 2.5.2 to 3.0.0 ([#7725](https://github.com/parse-community/parse-server/issues/7725)) ([f5ef98b](https://github.com/parse-community/parse-server/commit/f5ef98bde32083403c0e30a12162fcc1e52cac37))
# [5.0.0-alpha.10](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.9...5.0.0-alpha.10) (2021-11-29)
### Bug Fixes
* upgrade parse from 3.3.1 to 3.4.0 ([#7723](https://github.com/parse-community/parse-server/issues/7723)) ([d4c1f47](https://github.com/parse-community/parse-server/commit/d4c1f473073764cb0570c633fc4a30669c2ce889))
# [5.0.0-alpha.9](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.8...5.0.0-alpha.9) (2021-11-27)
### Bug Fixes
* unable to use objectId size higher than 19 on GraphQL API ([#7627](https://github.com/parse-community/parse-server/issues/7627)) ([ed86c80](https://github.com/parse-community/parse-server/commit/ed86c807721cc52a1a5a9dea0b768717eec269ed))
# [5.0.0-alpha.8](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.7...5.0.0-alpha.8) (2021-11-18)
### Features
* add support for Node 16 ([#7707](https://github.com/parse-community/parse-server/issues/7707)) ([45cc58c](https://github.com/parse-community/parse-server/commit/45cc58c7e5e640a46c5d508019a3aa81242964b1))
### BREAKING CHANGES
* Removes official Node 15 support which has reached it end-of-life date. ([45cc58c](45cc58c))
# [5.0.0-alpha.7](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.6...5.0.0-alpha.7) (2021-11-12)
### Bug Fixes
* node engine range has no upper limit to exclude incompatible node versions ([#7692](https://github.com/parse-community/parse-server/issues/7692)) ([573558d](https://github.com/parse-community/parse-server/commit/573558d3adcbcc6222c92003829867e1a73eef94))
# [5.0.0-alpha.6](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.5...5.0.0-alpha.6) (2021-11-10)
### Reverts
* refactor: allow ES import for cloud string if package type is module ([b64640c](https://github.com/parse-community/parse-server/commit/b64640c5705f733798783e68d216e957044ef23c))
# [5.0.0-alpha.5](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.4...5.0.0-alpha.5) (2021-11-01)
### Features
* add user-defined schema and migrations ([#7418](https://github.com/parse-community/parse-server/issues/7418)) ([25d5c30](https://github.com/parse-community/parse-server/commit/25d5c30be2111be332eb779eb0697774a17da7af))
# [5.0.0-alpha.4](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.3...5.0.0-alpha.4) (2021-10-31)
### Features
* add support for Postgres 14 ([#7644](https://github.com/parse-community/parse-server/issues/7644)) ([090350a](https://github.com/parse-community/parse-server/commit/090350a7a0fac945394ca1cb24b290316ef06aa7))
# [5.0.0-alpha.3](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.2...5.0.0-alpha.3) (2021-10-29)
### Bug Fixes
* combined `and` query with relational query condition returns incorrect results ([#7593](https://github.com/parse-community/parse-server/issues/7593)) ([174886e](https://github.com/parse-community/parse-server/commit/174886e385e091c6bbd4a84891ef95f80b50d05c))
# [5.0.0-alpha.2](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.1...5.0.0-alpha.2) (2021-10-27)
### Bug Fixes
* setting a field to null does not delete it via GraphQL API ([#7649](https://github.com/parse-community/parse-server/issues/7649)) ([626fad2](https://github.com/parse-community/parse-server/commit/626fad2e71017dcc62196c487de5f908fa43000b))
### BREAKING CHANGES
* To delete a field via the GraphQL API, the field value has to be set to `null`. Previously, setting a field value to `null` would save a null value in the database, which was not according to the [GraphQL specs](https://spec.graphql.org/June2018/#sec-Null-Value). To delete a file field use `file: null`, the previous way of using `file: { file: null }` has become obsolete. ([626fad2](626fad2))
# [5.0.0-alpha.1](https://github.com/parse-community/parse-server/compare/4.10.4...5.0.0-alpha.1) (2021-10-12)
## Breaking Changes
- Improved schema caching through database real-time hooks. Reduces DB queries, decreases Parse Query execution time and fixes a potential schema memory leak. If multiple Parse Server instances connect to the same DB (for example behind a load balancer), set the [Parse Server Option](https://parseplatform.org/parse-server/api/master/ParseServerOptions.html) `databaseOptions.enableSchemaHooks: true` to enable this feature and keep the schema in sync across all instances. Failing to do so will cause a schema change to not propagate to other instances and re-syncing will only happen when these instances restart. The options `enableSingleSchemaCache` and `schemaCacheTTL` have been removed. To use this feature with MongoDB, a replica set cluster with [change stream](https://docs.mongodb.com/manual/changeStreams/#availability) support is required. (Diamond Lewis, SebC) [#7214](https://github.com/parse-community/parse-server/issues/7214)
- Added file upload restriction. File upload is now only allowed for authenticated users by default for improved security. To allow file upload also for Anonymous Users or Public, set the `fileUpload` parameter in the [Parse Server Options](https://parseplatform.org/parse-server/api/master/ParseServerOptions.html) (dblythy, Manuel Trezza) [#7071](https://github.com/parse-community/parse-server/pull/7071)
- Removed [parse-server-simple-mailgun-adapter](https://github.com/parse-community/parse-server-simple-mailgun-adapter) dependency; to continue using the adapter it has to be explicitly installed (Manuel Trezza) [#7321](https://github.com/parse-community/parse-server/pull/7321)
- Remove support for MongoDB 3.6 which has reached its End-of-Life date and PostgreSQL 10 (Manuel Trezza) [#7315](https://github.com/parse-community/parse-server/pull/7315)
- Remove support for Node 10 which has reached its End-of-Life date (Manuel Trezza) [#7314](https://github.com/parse-community/parse-server/pull/7314)
- Remove S3 Files Adapter from Parse Server, instead install separately as `@parse/s3-files-adapter` (Manuel Trezza) [#7324](https://github.com/parse-community/parse-server/pull/7324)
- Remove Session field `restricted`; the field was a code artifact from a feature that never existed in Open Source Parse Server; if you have been using this field for custom purposes, consider that for new Parse Server installations the field does not exist anymore in the schema, and for existing installations the field default value `false` will not be set anymore when creating a new session (Manuel Trezza) [#7543](https://github.com/parse-community/parse-server/pull/7543)
- ci: add node engine version check (Manuel Trezza) [#7574](https://github.com/parse-community/parse-server/pull/7574)
## Notable Changes
- Alphabetical ordered GraphQL API, improved GraphQL Schema cache system and fix GraphQL input reassign issue (Moumouls) [#7344](https://github.com/parse-community/parse-server/issues/7344)
- Added Parse Server Security Check to report weak security settings (Manuel Trezza, dblythy) [#7247](https://github.com/parse-community/parse-server/issues/7247)
- EXPERIMENTAL: Added new page router with placeholder rendering and localization of custom and feature pages such as password reset and email verification (Manuel Trezza) [#7128](https://github.com/parse-community/parse-server/pull/7128)
- EXPERIMENTAL: Added custom routes to easily customize flows for password reset, email verification or build entirely new flows (Manuel Trezza) [#7231](https://github.com/parse-community/parse-server/pull/7231)
- Added Deprecation Policy to govern the introduction of breaking changes in a phased pattern that is more predictable for developers (Manuel Trezza) [#7199](https://github.com/parse-community/parse-server/pull/7199)
- Add REST API endpoint `/loginAs` to create session of any user with master key; allows to impersonate another user. (GormanFletcher) [#7406](https://github.com/parse-community/parse-server/pull/7406)
- Add official support for MongoDB 5.0 (Manuel Trezza) [#7469](https://github.com/parse-community/parse-server/pull/7469)
- Added Parse Server Configuration `enforcePrivateUsers`, which will remove public access by default on new Parse.Users (dblythy) [#7319](https://github.com/parse-community/parse-server/pull/7319)
## Other Changes
- Support native mongodb syntax in aggregation pipelines (Raschid JF Rafeally) [#7339](https://github.com/parse-community/parse-server/pull/7339)
- Fix error when a not yet inserted job is updated (Antonio Davi Macedo Coelho de Castro) [#7196](https://github.com/parse-community/parse-server/pull/7196)
- request.context for afterFind triggers (dblythy) [#7078](https://github.com/parse-community/parse-server/pull/7078)
- Winston Logger interpolating stdout to console (dplewis) [#7114](https://github.com/parse-community/parse-server/pull/7114)
- Added convenience method `Parse.Cloud.sendEmail(...)` to send email via email adapter in Cloud Code (dblythy) [#7089](https://github.com/parse-community/parse-server/pull/7089)
- LiveQuery support for $and, $nor, $containedBy, $geoWithin, $geoIntersects queries (dplewis) [#7113](https://github.com/parse-community/parse-server/pull/7113)
- Supporting patterns in LiveQuery server's config parameter `classNames` (Nes-si) [#7131](https://github.com/parse-community/parse-server/pull/7131)
- Added `requireAnyUserRoles` and `requireAllUserRoles` for Parse Cloud validator (dblythy) [#7097](https://github.com/parse-community/parse-server/pull/7097)
- Support Facebook Limited Login (miguel-s) [#7219](https://github.com/parse-community/parse-server/pull/7219)
- Removed Stage name check on aggregate pipelines (BRETT71) [#7237](https://github.com/parse-community/parse-server/pull/7237)
- Retry transactions on MongoDB when it fails due to transient error (Antonio Davi Macedo Coelho de Castro) [#7187](https://github.com/parse-community/parse-server/pull/7187)
- Bump tests to use Mongo 4.4.4 (Antonio Davi Macedo Coelho de Castro) [#7184](https://github.com/parse-community/parse-server/pull/7184)
- Added new account lockout policy option `accountLockout.unlockOnPasswordReset` to automatically unlock account on password reset (Manuel Trezza) [#7146](https://github.com/parse-community/parse-server/pull/7146)
- Test Parse Server continuously against all recent MongoDB versions that have not reached their end-of-life support date, added MongoDB compatibility table to Parse Server docs (Manuel Trezza) [#7161](https://github.com/parse-community/parse-server/pull/7161)
- Test Parse Server continuously against all recent Node.js versions that have not reached their end-of-life support date, added Node.js compatibility table to Parse Server docs (Manuel Trezza) [7161](https://github.com/parse-community/parse-server/pull/7177)
- Throw error on invalid Cloud Function validation configuration (dblythy) [#7154](https://github.com/parse-community/parse-server/pull/7154)
- Allow Cloud Validator `options` to be async (dblythy) [#7155](https://github.com/parse-community/parse-server/pull/7155)
- Optimize queries on classes with pointer permissions (Pedro Diaz) [#7061](https://github.com/parse-community/parse-server/pull/7061)
- Test Parse Server continuously against all relevant Postgres versions (minor versions), added Postgres compatibility table to Parse Server docs (Corey Baker) [#7176](https://github.com/parse-community/parse-server/pull/7176)
- Randomize test suite (Diamond Lewis) [#7265](https://github.com/parse-community/parse-server/pull/7265)
- LDAP: Properly unbind client on group search error (Diamond Lewis) [#7265](https://github.com/parse-community/parse-server/pull/7265)
- Improve data consistency in Push and Job Status update (Diamond Lewis) [#7267](https://github.com/parse-community/parse-server/pull/7267)
- Excluding keys that have trailing edges.node when performing GraphQL resolver (Chris Bland) [#7273](https://github.com/parse-community/parse-server/pull/7273)
- Added centralized feature deprecation with standardized warning logs (Manuel Trezza) [#7303](https://github.com/parse-community/parse-server/pull/7303)
- Use Node.js 15.13.0 in CI (Olle Jonsson) [#7312](https://github.com/parse-community/parse-server/pull/7312)
- Fix file upload issue for S3 compatible storage (Linode, DigitalOcean) by avoiding empty tags property when creating a file (Ali Oguzhan Yildiz) [#7300](https://github.com/parse-community/parse-server/pull/7300)
- Add building Docker image as CI check (Manuel Trezza) [#7332](https://github.com/parse-community/parse-server/pull/7332)
- Add NPM package-lock version check to CI (Manuel Trezza) [#7333](https://github.com/parse-community/parse-server/pull/7333)
- Fix incorrect LiveQuery events triggered for multiple subscriptions on the same class with different events [#7341](https://github.com/parse-community/parse-server/pull/7341)
- Fix select and excludeKey queries to properly accept JSON string arrays. Also allow nested fields in exclude (Corey Baker) [#7242](https://github.com/parse-community/parse-server/pull/7242)
- Fix LiveQuery server crash when using $all query operator on a missing object key (Jason Posthuma) [#7421](https://github.com/parse-community/parse-server/pull/7421)
- Added runtime deprecation warnings (Manuel Trezza) [#7451](https://github.com/parse-community/parse-server/pull/7451)
- Add ability to pass context of an object via a header, X-Parse-Cloud-Context, for Cloud Code triggers. The header addition allows client SDK's to add context without injecting _context in the body of JSON objects (Corey Baker) [#7437](https://github.com/parse-community/parse-server/pull/7437)
- Add CI check to add changelog entry (Manuel Trezza) [#7512](https://github.com/parse-community/parse-server/pull/7512)
- Refactor: uniform issue templates across repos (Manuel Trezza) [#7528](https://github.com/parse-community/parse-server/pull/7528)
- ci: bump ci environment (Manuel Trezza) [#7539](https://github.com/parse-community/parse-server/pull/7539)
- CI now pushes docker images to Docker Hub (Corey Baker) [#7548](https://github.com/parse-community/parse-server/pull/7548)
- Allow afterFind and afterLiveQueryEvent to set unsaved pointers and keys (dblythy) [#7310](https://github.com/parse-community/parse-server/pull/7310)
- Allow setting descending sort to full text queries (dblythy) [#7496](https://github.com/parse-community/parse-server/pull/7496)
- Allow cloud string for ES modules (Daniel Blyth) [#7560](https://github.com/parse-community/parse-server/pull/7560)
- docs: Introduce deprecation ID for reference in comments and online search (Manuel Trezza) [#7562](https://github.com/parse-community/parse-server/pull/7562)
- refactor: deprecate `Parse.Cloud.httpRequest`; it is recommended to use a HTTP library instead. (Daniel Blyth) [#7595](https://github.com/parse-community/parse-server/pull/7595)
- refactor: Modernize HTTPRequest tests (brandongregoryscott) [#7604](https://github.com/parse-community/parse-server/pull/7604)
- Allow liveQuery on Session class (Daniel Blyth) [#7554](https://github.com/parse-community/parse-server/pull/7554)
+191
View File
@@ -0,0 +1,191 @@
# [5.2.0-beta.2](https://github.com/parse-community/parse-server/compare/5.2.0-beta.1...5.2.0-beta.2) (2022-03-24)
### Bug Fixes
* security bump minimist from 1.2.5 to 1.2.6 ([#7884](https://github.com/parse-community/parse-server/issues/7884)) ([c5cf282](https://github.com/parse-community/parse-server/commit/c5cf282d11ffdc023764f8e7539a2bd6bc246fe1))
* sensitive keyword detection may produce false positives ([#7881](https://github.com/parse-community/parse-server/issues/7881)) ([0d6f9e9](https://github.com/parse-community/parse-server/commit/0d6f9e951d9e186e95e96d8869066ce7022bad02))
# [5.2.0-beta.1](https://github.com/parse-community/parse-server/compare/5.1.1...5.2.0-beta.1) (2022-03-23)
### Features
* improved LiveQuery error logging with additional information ([#7837](https://github.com/parse-community/parse-server/issues/7837)) ([443a509](https://github.com/parse-community/parse-server/commit/443a5099059538d379fe491793a5871fcbb4f377))
# [5.0.0-beta.10](https://github.com/parse-community/parse-server/compare/5.0.0-beta.9...5.0.0-beta.10) (2022-03-15)
### Bug Fixes
* adding or modifying a nested property requires addField permissions ([#7679](https://github.com/parse-community/parse-server/issues/7679)) ([6a6248b](https://github.com/parse-community/parse-server/commit/6a6248b6cb2e732d17131e18e659943b894ed2f1))
* bump nanoid from 3.1.25 to 3.2.0 ([#7781](https://github.com/parse-community/parse-server/issues/7781)) ([f5f63bf](https://github.com/parse-community/parse-server/commit/f5f63bfc64d3481ed944ceb5e9f50b33dccd1ce9))
* bump node-fetch from 2.6.1 to 3.1.1 ([#7782](https://github.com/parse-community/parse-server/issues/7782)) ([9082351](https://github.com/parse-community/parse-server/commit/90823514113a1a085ebc818f7109b3fd7591346f))
* node engine compatibility did not include node 16 ([#7739](https://github.com/parse-community/parse-server/issues/7739)) ([ea7c014](https://github.com/parse-community/parse-server/commit/ea7c01400f992a1263543706fe49b6174758a2d6))
* node engine range has no upper limit to exclude incompatible node versions ([#7692](https://github.com/parse-community/parse-server/issues/7692)) ([573558d](https://github.com/parse-community/parse-server/commit/573558d3adcbcc6222c92003829867e1a73eef94))
* package.json & package-lock.json to reduce vulnerabilities ([#7823](https://github.com/parse-community/parse-server/issues/7823)) ([5ca2288](https://github.com/parse-community/parse-server/commit/5ca228882332b65f3ac05407e6e4da1ee3ef3749))
* schema cache not cleared in some cases ([#7678](https://github.com/parse-community/parse-server/issues/7678)) ([5af6e5d](https://github.com/parse-community/parse-server/commit/5af6e5dfaa129b1a350afcba4fb381b21c4cc35d))
* security upgrade follow-redirects from 1.14.6 to 1.14.7 ([#7769](https://github.com/parse-community/parse-server/issues/7769)) ([8f5a861](https://github.com/parse-community/parse-server/commit/8f5a8618cfa7ed9a2a239a095abffa8f3fd8d31a))
* security upgrade follow-redirects from 1.14.7 to 1.14.8 ([#7801](https://github.com/parse-community/parse-server/issues/7801)) ([70088a9](https://github.com/parse-community/parse-server/commit/70088a95a78393da2a4ac68be81e63107747626a))
* security vulnerability that allows remote code execution (GHSA-p6h4-93qp-jhcm) ([#7844](https://github.com/parse-community/parse-server/issues/7844)) ([e569f40](https://github.com/parse-community/parse-server/commit/e569f402b1fd8648fb0d1523b71b2a03273902a5))
* server crash using GraphQL due to missing @apollo/client peer dependency ([#7787](https://github.com/parse-community/parse-server/issues/7787)) ([08089d6](https://github.com/parse-community/parse-server/commit/08089d6fcbb215412448ce7d92b21b9fe6c929f2))
* unable to use objectId size higher than 19 on GraphQL API ([#7627](https://github.com/parse-community/parse-server/issues/7627)) ([ed86c80](https://github.com/parse-community/parse-server/commit/ed86c807721cc52a1a5a9dea0b768717eec269ed))
* upgrade mime from 2.5.2 to 3.0.0 ([#7725](https://github.com/parse-community/parse-server/issues/7725)) ([f5ef98b](https://github.com/parse-community/parse-server/commit/f5ef98bde32083403c0e30a12162fcc1e52cac37))
* upgrade parse from 3.3.1 to 3.4.0 ([#7723](https://github.com/parse-community/parse-server/issues/7723)) ([d4c1f47](https://github.com/parse-community/parse-server/commit/d4c1f473073764cb0570c633fc4a30669c2ce889))
* upgrade winston from 3.5.0 to 3.5.1 ([#7820](https://github.com/parse-community/parse-server/issues/7820)) ([4af253d](https://github.com/parse-community/parse-server/commit/4af253d1f8654a6f57b5137ad310cdacadc922cc))
### Features
* add Cloud Code context to `ParseObject.fetch` ([#7779](https://github.com/parse-community/parse-server/issues/7779)) ([315290d](https://github.com/parse-community/parse-server/commit/315290d16110110938f80a6b779cc2d1db58c552))
* add Idempotency to Postgres ([#7750](https://github.com/parse-community/parse-server/issues/7750)) ([0c3feaa](https://github.com/parse-community/parse-server/commit/0c3feaaa1751964c0db89f25674935c3354b1538))
* add support for Node 16 ([#7707](https://github.com/parse-community/parse-server/issues/7707)) ([45cc58c](https://github.com/parse-community/parse-server/commit/45cc58c7e5e640a46c5d508019a3aa81242964b1))
* bump required node engine to >=12.22.10 ([#7846](https://github.com/parse-community/parse-server/issues/7846)) ([5ace99d](https://github.com/parse-community/parse-server/commit/5ace99d542a11e422af46d9fd6b1d3d2513b34cf))
* support `postgresql` protocol in database URI ([#7757](https://github.com/parse-community/parse-server/issues/7757)) ([caf4a23](https://github.com/parse-community/parse-server/commit/caf4a2341f554b28e3918c53e7e897a3ca47bf8b))
* support relativeTime query constraint on Postgres ([#7747](https://github.com/parse-community/parse-server/issues/7747)) ([16b1b2a](https://github.com/parse-community/parse-server/commit/16b1b2a19714535ca805f2dbb3b561d8f6a519a7))
* upgrade to MongoDB Node.js driver 4.x for MongoDB 5.0 support ([#7794](https://github.com/parse-community/parse-server/issues/7794)) ([f88aa2a](https://github.com/parse-community/parse-server/commit/f88aa2a62a533e5344d1c13dd38c5a0b283a480a))
### Reverts
* refactor: allow ES import for cloud string if package type is module ([b64640c](https://github.com/parse-community/parse-server/commit/b64640c5705f733798783e68d216e957044ef23c))
* update node engine to 2.22.0 ([#7827](https://github.com/parse-community/parse-server/issues/7827)) ([f235412](https://github.com/parse-community/parse-server/commit/f235412c1b6c2b173b7531f285429ea7214b56a2))
### BREAKING CHANGES
* This requires Node.js version >=12.22.10. ([5ace99d](5ace99d))
* The MongoDB GridStore adapter has been removed. By default, Parse Server already uses GridFS, so if you do not manually use the GridStore adapter, you can ignore this change. ([f88aa2a](f88aa2a))
* Removes official Node 15 support which has reached it end-of-life date. ([45cc58c](45cc58c))
# [5.0.0-beta.9](https://github.com/parse-community/parse-server/compare/5.0.0-beta.8...5.0.0-beta.9) (2022-03-12)
### Features
* bump required node engine to >=12.22.10 ([#7848](https://github.com/parse-community/parse-server/issues/7848)) ([23a3488](https://github.com/parse-community/parse-server/commit/23a3488f15511fafbe0e1d7ff0ef8355f9cb0215))
### BREAKING CHANGES
* This requires Node.js version >=12.22.10. ([23a3488](23a3488))
# [5.0.0-beta.8](https://github.com/parse-community/parse-server/compare/5.0.0-beta.7...5.0.0-beta.8) (2022-03-12)
### Bug Fixes
* security vulnerability that allows remote code execution (GHSA-p6h4-93qp-jhcm) ([#7843](https://github.com/parse-community/parse-server/issues/7843)) ([971adb5](https://github.com/parse-community/parse-server/commit/971adb54387b0ede31be05ca407d5f35b4575c83))
# [5.0.0-beta.7](https://github.com/parse-community/parse-server/compare/5.0.0-beta.6...5.0.0-beta.7) (2022-02-10)
### Bug Fixes
* security upgrade follow-redirects from 1.14.7 to 1.14.8 ([#7802](https://github.com/parse-community/parse-server/issues/7802)) ([7029b27](https://github.com/parse-community/parse-server/commit/7029b274ca87bc8058617f29865d683dc3b351a1))
# [5.0.0-beta.6](https://github.com/parse-community/parse-server/compare/5.0.0-beta.5...5.0.0-beta.6) (2022-01-13)
### Bug Fixes
* security upgrade follow-redirects from 1.14.2 to 1.14.7 ([#7772](https://github.com/parse-community/parse-server/issues/7772)) ([4bd34b1](https://github.com/parse-community/parse-server/commit/4bd34b189bc9f5aa2e70b7e7c1a456e91b6de773))
# [5.0.0-beta.5](https://github.com/parse-community/parse-server/compare/5.0.0-beta.4...5.0.0-beta.5) (2022-01-13)
### Bug Fixes
* schema cache not cleared in some cases ([#7771](https://github.com/parse-community/parse-server/issues/7771)) ([3b92fa1](https://github.com/parse-community/parse-server/commit/3b92fa1ca9e8889127a32eba913d68309397ca2c))
# [5.0.0-beta.4](https://github.com/parse-community/parse-server/compare/5.0.0-beta.3...5.0.0-beta.4) (2021-11-27)
### Bug Fixes
* unable to use objectId size higher than 19 on GraphQL API ([#7722](https://github.com/parse-community/parse-server/issues/7722)) ([8ee0445](https://github.com/parse-community/parse-server/commit/8ee0445c0aeeb88dff2559b46ade408071d22143))
# [5.0.0-beta.3](https://github.com/parse-community/parse-server/compare/5.0.0-beta.2...5.0.0-beta.3) (2021-11-12)
### Bug Fixes
* node engine range has no upper limit to exclude incompatible node versions ([#7693](https://github.com/parse-community/parse-server/issues/7693)) ([6a54dac](https://github.com/parse-community/parse-server/commit/6a54dac24d9fb63a44f311b8d414f4aa64140f32))
# [5.0.0-beta.2](https://github.com/parse-community/parse-server/compare/5.0.0-beta.1...5.0.0-beta.2) (2021-11-10)
### Reverts
* refactor: allow ES import for cloud string if package type is module ([#7691](https://github.com/parse-community/parse-server/issues/7691)) ([200d4ba](https://github.com/parse-community/parse-server/commit/200d4ba9a527016a65668738c7728696f443bd53))
# [5.0.0-beta.1](https://github.com/parse-community/parse-server/compare/4.5.0...5.0.0-beta.1) (2021-11-01)
### BREAKING CHANGES
- Improved schema caching through database real-time hooks. Reduces DB queries, decreases Parse Query execution time and fixes a potential schema memory leak. If multiple Parse Server instances connect to the same DB (for example behind a load balancer), set the [Parse Server Option](https://parseplatform.org/parse-server/api/master/ParseServerOptions.html) `databaseOptions.enableSchemaHooks: true` to enable this feature and keep the schema in sync across all instances. Failing to do so will cause a schema change to not propagate to other instances and re-syncing will only happen when these instances restart. The options `enableSingleSchemaCache` and `schemaCacheTTL` have been removed. To use this feature with MongoDB, a replica set cluster with [change stream](https://docs.mongodb.com/manual/changeStreams/#availability) support is required. (Diamond Lewis, SebC) [#7214](https://github.com/parse-community/parse-server/issues/7214)
- Added file upload restriction. File upload is now only allowed for authenticated users by default for improved security. To allow file upload also for Anonymous Users or Public, set the `fileUpload` parameter in the [Parse Server Options](https://parseplatform.org/parse-server/api/master/ParseServerOptions.html) (dblythy, Manuel Trezza) [#7071](https://github.com/parse-community/parse-server/pull/7071)
- Removed [parse-server-simple-mailgun-adapter](https://github.com/parse-community/parse-server-simple-mailgun-adapter) dependency; to continue using the adapter it has to be explicitly installed (Manuel Trezza) [#7321](https://github.com/parse-community/parse-server/pull/7321)
- Remove support for MongoDB 3.6 which has reached its End-of-Life date and PostgreSQL 10 (Manuel Trezza) [#7315](https://github.com/parse-community/parse-server/pull/7315)
- Remove support for Node 10 which has reached its End-of-Life date (Manuel Trezza) [#7314](https://github.com/parse-community/parse-server/pull/7314)
- Remove S3 Files Adapter from Parse Server, instead install separately as `@parse/s3-files-adapter` (Manuel Trezza) [#7324](https://github.com/parse-community/parse-server/pull/7324)
- Remove Session field `restricted`; the field was a code artifact from a feature that never existed in Open Source Parse Server; if you have been using this field for custom purposes, consider that for new Parse Server installations the field does not exist anymore in the schema, and for existing installations the field default value `false` will not be set anymore when creating a new session (Manuel Trezza) [#7543](https://github.com/parse-community/parse-server/pull/7543)
- ci: add node engine version check (Manuel Trezza) [#7574](https://github.com/parse-community/parse-server/pull/7574)
- To delete a field via the GraphQL API, the field value has to be set to `null`. Previously, setting a field value to `null` would save a null value in the database, which was not according to the [GraphQL specs](https://spec.graphql.org/June2018/#sec-Null-Value). To delete a file field use `file: null`, the previous way of using `file: { file: null }` has become obsolete. ([626fad2](626fad2))
### Notable Changes
- Alphabetical ordered GraphQL API, improved GraphQL Schema cache system and fix GraphQL input reassign issue (Moumouls) [#7344](https://github.com/parse-community/parse-server/issues/7344)
- Added Parse Server Security Check to report weak security settings (Manuel Trezza, dblythy) [#7247](https://github.com/parse-community/parse-server/issues/7247)
- EXPERIMENTAL: Added new page router with placeholder rendering and localization of custom and feature pages such as password reset and email verification (Manuel Trezza) [#7128](https://github.com/parse-community/parse-server/pull/7128)
- EXPERIMENTAL: Added custom routes to easily customize flows for password reset, email verification or build entirely new flows (Manuel Trezza) [#7231](https://github.com/parse-community/parse-server/pull/7231)
- Added Deprecation Policy to govern the introduction of breaking changes in a phased pattern that is more predictable for developers (Manuel Trezza) [#7199](https://github.com/parse-community/parse-server/pull/7199)
- Add REST API endpoint `/loginAs` to create session of any user with master key; allows to impersonate another user. (GormanFletcher) [#7406](https://github.com/parse-community/parse-server/pull/7406)
- Add official support for MongoDB 5.0 (Manuel Trezza) [#7469](https://github.com/parse-community/parse-server/pull/7469)
- Added Parse Server Configuration `enforcePrivateUsers`, which will remove public access by default on new Parse.Users (dblythy) [#7319](https://github.com/parse-community/parse-server/pull/7319)
* add support for Postgres 14 ([#7644](https://github.com/parse-community/parse-server/issues/7644)) ([090350a](https://github.com/parse-community/parse-server/commit/090350a7a0fac945394ca1cb24b290316ef06aa7))
* add user-defined schema and migrations ([#7418](https://github.com/parse-community/parse-server/issues/7418)) ([25d5c30](https://github.com/parse-community/parse-server/commit/25d5c30be2111be332eb779eb0697774a17da7af))
* setting a field to null does not delete it via GraphQL API ([#7649](https://github.com/parse-community/parse-server/issues/7649)) ([626fad2](https://github.com/parse-community/parse-server/commit/626fad2e71017dcc62196c487de5f908fa43000b))
* combined `and` query with relational query condition returns incorrect results ([#7593](https://github.com/parse-community/parse-server/issues/7593)) ([174886e](https://github.com/parse-community/parse-server/commit/174886e385e091c6bbd4a84891ef95f80b50d05c))
### Other Changes
- Support native mongodb syntax in aggregation pipelines (Raschid JF Rafeally) [#7339](https://github.com/parse-community/parse-server/pull/7339)
- Fix error when a not yet inserted job is updated (Antonio Davi Macedo Coelho de Castro) [#7196](https://github.com/parse-community/parse-server/pull/7196)
- request.context for afterFind triggers (dblythy) [#7078](https://github.com/parse-community/parse-server/pull/7078)
- Winston Logger interpolating stdout to console (dplewis) [#7114](https://github.com/parse-community/parse-server/pull/7114)
- Added convenience method `Parse.Cloud.sendEmail(...)` to send email via email adapter in Cloud Code (dblythy) [#7089](https://github.com/parse-community/parse-server/pull/7089)
- LiveQuery support for $and, $nor, $containedBy, $geoWithin, $geoIntersects queries (dplewis) [#7113](https://github.com/parse-community/parse-server/pull/7113)
- Supporting patterns in LiveQuery server's config parameter `classNames` (Nes-si) [#7131](https://github.com/parse-community/parse-server/pull/7131)
- Added `requireAnyUserRoles` and `requireAllUserRoles` for Parse Cloud validator (dblythy) [#7097](https://github.com/parse-community/parse-server/pull/7097)
- Support Facebook Limited Login (miguel-s) [#7219](https://github.com/parse-community/parse-server/pull/7219)
- Removed Stage name check on aggregate pipelines (BRETT71) [#7237](https://github.com/parse-community/parse-server/pull/7237)
- Retry transactions on MongoDB when it fails due to transient error (Antonio Davi Macedo Coelho de Castro) [#7187](https://github.com/parse-community/parse-server/pull/7187)
- Bump tests to use Mongo 4.4.4 (Antonio Davi Macedo Coelho de Castro) [#7184](https://github.com/parse-community/parse-server/pull/7184)
- Added new account lockout policy option `accountLockout.unlockOnPasswordReset` to automatically unlock account on password reset (Manuel Trezza) [#7146](https://github.com/parse-community/parse-server/pull/7146)
- Test Parse Server continuously against all recent MongoDB versions that have not reached their end-of-life support date, added MongoDB compatibility table to Parse Server docs (Manuel Trezza) [#7161](https://github.com/parse-community/parse-server/pull/7161)
- Test Parse Server continuously against all recent Node.js versions that have not reached their end-of-life support date, added Node.js compatibility table to Parse Server docs (Manuel Trezza) [7161](https://github.com/parse-community/parse-server/pull/7177)
- Throw error on invalid Cloud Function validation configuration (dblythy) [#7154](https://github.com/parse-community/parse-server/pull/7154)
- Allow Cloud Validator `options` to be async (dblythy) [#7155](https://github.com/parse-community/parse-server/pull/7155)
- Optimize queries on classes with pointer permissions (Pedro Diaz) [#7061](https://github.com/parse-community/parse-server/pull/7061)
- Test Parse Server continuously against all relevant Postgres versions (minor versions), added Postgres compatibility table to Parse Server docs (Corey Baker) [#7176](https://github.com/parse-community/parse-server/pull/7176)
- Randomize test suite (Diamond Lewis) [#7265](https://github.com/parse-community/parse-server/pull/7265)
- LDAP: Properly unbind client on group search error (Diamond Lewis) [#7265](https://github.com/parse-community/parse-server/pull/7265)
- Improve data consistency in Push and Job Status update (Diamond Lewis) [#7267](https://github.com/parse-community/parse-server/pull/7267)
- Excluding keys that have trailing edges.node when performing GraphQL resolver (Chris Bland) [#7273](https://github.com/parse-community/parse-server/pull/7273)
- Added centralized feature deprecation with standardized warning logs (Manuel Trezza) [#7303](https://github.com/parse-community/parse-server/pull/7303)
- Use Node.js 15.13.0 in CI (Olle Jonsson) [#7312](https://github.com/parse-community/parse-server/pull/7312)
- Fix file upload issue for S3 compatible storage (Linode, DigitalOcean) by avoiding empty tags property when creating a file (Ali Oguzhan Yildiz) [#7300](https://github.com/parse-community/parse-server/pull/7300)
- Add building Docker image as CI check (Manuel Trezza) [#7332](https://github.com/parse-community/parse-server/pull/7332)
- Add NPM package-lock version check to CI (Manuel Trezza) [#7333](https://github.com/parse-community/parse-server/pull/7333)
- Fix incorrect LiveQuery events triggered for multiple subscriptions on the same class with different events [#7341](https://github.com/parse-community/parse-server/pull/7341)
- Fix select and excludeKey queries to properly accept JSON string arrays. Also allow nested fields in exclude (Corey Baker) [#7242](https://github.com/parse-community/parse-server/pull/7242)
- Fix LiveQuery server crash when using $all query operator on a missing object key (Jason Posthuma) [#7421](https://github.com/parse-community/parse-server/pull/7421)
- Added runtime deprecation warnings (Manuel Trezza) [#7451](https://github.com/parse-community/parse-server/pull/7451)
- Add ability to pass context of an object via a header, X-Parse-Cloud-Context, for Cloud Code triggers. The header addition allows client SDK's to add context without injecting _context in the body of JSON objects (Corey Baker) [#7437](https://github.com/parse-community/parse-server/pull/7437)
- Add CI check to add changelog entry (Manuel Trezza) [#7512](https://github.com/parse-community/parse-server/pull/7512)
- Refactor: uniform issue templates across repos (Manuel Trezza) [#7528](https://github.com/parse-community/parse-server/pull/7528)
- ci: bump ci environment (Manuel Trezza) [#7539](https://github.com/parse-community/parse-server/pull/7539)
- CI now pushes docker images to Docker Hub (Corey Baker) [#7548](https://github.com/parse-community/parse-server/pull/7548)
- Allow afterFind and afterLiveQueryEvent to set unsaved pointers and keys (dblythy) [#7310](https://github.com/parse-community/parse-server/pull/7310)
- Allow setting descending sort to full text queries (dblythy) [#7496](https://github.com/parse-community/parse-server/pull/7496)
- Allow cloud string for ES modules (Daniel Blyth) [#7560](https://github.com/parse-community/parse-server/pull/7560)
- docs: Introduce deprecation ID for reference in comments and online search (Manuel Trezza) [#7562](https://github.com/parse-community/parse-server/pull/7562)
- refactor: deprecate `Parse.Cloud.httpRequest`; it is recommended to use a HTTP library instead. (Daniel Blyth) [#7595](https://github.com/parse-community/parse-server/pull/7595)
- refactor: Modernize HTTPRequest tests (brandongregoryscott) [#7604](https://github.com/parse-community/parse-server/pull/7604)
- Allow liveQuery on Session class (Daniel Blyth) [#7554](https://github.com/parse-community/parse-server/pull/7554)
File diff suppressed because it is too large Load Diff
+290
View File
@@ -0,0 +1,290 @@
const core = require('@actions/core');
const semver = require('semver');
const yaml = require('yaml');
const fs = require('fs').promises;
/**
* This checks the CI version of an environment variable in a YAML file
* against a list of released versions of a package.
*/
class CiVersionCheck {
/**
* The constructor.
* @param {Object} config The config.
* @param {String} config.packageName The package name to check.
* @param {String} config.packageSupportUrl The URL to the package website
* that shows the End-of-Life support dates.
* @param {String} config.yamlFilePath The path to the GitHub workflow YAML
* file that contains the tests.
* @param {String} config.ciEnvironmentsKeyPath The key path in the CI YAML
* file to the environment specifications.
* @param {String} config.ciVersionKey The key in the CI YAML file to
* determine the package version.
* @param {Array<String>} config.releasedVersions The released versions of
* the package to check against.
* @param {Array<String>} config.ignoreReleasedVersions The versions to
* ignore when checking whether the CI tests against the latest versions.
* This can be used in case there is a package release for which Parse
* Server compatibility is not required.
* @param {String} [config.latestComponent='patch'] The version component
* (`major`, `minor`, `patch`) that must be the latest released version.
* Default is `patch`.
*
* For example:
* - Released versions: 1.0.0, 1.2.0, 1.2.1, 1.3.0, 1.3.1, 2.0.0
* - Tested version: 1.2.0
*
* If the latest version component is `patch`, then the check would
* fail and recommend an upgrade to version 1.2.1 and to add additional
* tests against 1.3.1 and 2.0.0.
* If the latest version component is `minor` then the check would
* fail and recommend an upgrade to version 1.3.0 and to add an additional
* test against 2.0.0.
* If the latest version component is `major` then the check would
* fail and recommend an upgrade to version 2.0.0.
*/
constructor(config) {
const {
packageName,
packageSupportUrl,
yamlFilePath,
ciEnvironmentsKeyPath,
ciVersionKey,
releasedVersions,
ignoreReleasedVersions = [],
latestComponent = CiVersionCheck.versionComponents.patch,
} = config;
// Ensure required params are set
if ([
packageName,
packageSupportUrl,
yamlFilePath,
ciEnvironmentsKeyPath,
ciVersionKey,
releasedVersions,
].includes(undefined)) {
throw 'invalid configuration';
}
if (!Object.keys(CiVersionCheck.versionComponents).includes(latestComponent)) {
throw 'invalid configuration for latestComponent';
}
this.packageName = packageName;
this.packageSupportUrl = packageSupportUrl;
this.yamlFilePath = yamlFilePath;
this.ciEnvironmentsKeyPath = ciEnvironmentsKeyPath;
this.ciVersionKey = ciVersionKey;
this.releasedVersions = releasedVersions;
this.ignoreReleasedVersions = ignoreReleasedVersions;
this.latestComponent = latestComponent;
}
/**
* The definition of version components.
*/
static get versionComponents() {
return Object.freeze({
major: 'major',
minor: 'minor',
patch: 'patch',
});
}
/**
* Returns the test environments as specified in the YAML file.
*/
async getTests() {
try {
// Get CI workflow
const ciYaml = await fs.readFile(this.yamlFilePath, 'utf-8');
const ci = yaml.parse(ciYaml);
// Extract package versions
let versions = this.ciEnvironmentsKeyPath.split('.').reduce((o,k) => o !== undefined ? o[k] : undefined, ci);
versions = Object.entries(versions)
.map(entry => entry[1])
.filter(entry => entry[this.ciVersionKey]);
return versions;
} catch (e) {
throw `Failed to determine ${this.packageName} versions from CI YAML file with error: ${e}`;
}
}
/**
* Returns the package versions which are missing in the CI environment.
* @param {Array<String>} releasedVersions The released versions; need to
* be sorted descending.
* @param {Array<String>} testedVersions The tested versions.
* @param {String} versionComponent The latest version component.
* @returns {Array<String>} The untested versions.
*/
getUntestedVersions(releasedVersions, testedVersions, versionComponent) {
// Use these example values for debugging the version range logic below
// versionComponent = CiVersionCheck.versionComponents.patch;
// this.ignoreReleasedVersions = ['<4.4.0', '~4.7.0'];
// testedVersions = ['4.4.3'];
// releasedVersions = [
// '5.0.0-rc0',
// '5.0.0',
// '4.9.1',
// '4.9.0',
// '4.8.1',
// '4.8.0',
// '4.7.1',
// '4.7.0',
// '4.4.3',
// '4.4.2',
// '4.4.0',
// '4.1.0',
// '3.5.0',
// ];
// Determine operator for range comparison
const operator = versionComponent == CiVersionCheck.versionComponents.major
? '>='
: versionComponent == CiVersionCheck.versionComponents.minor
? '^'
: '~'
// Get all untested versions
const untestedVersions = releasedVersions.reduce((m, v) => {
// If the version should be ignored, skip it
if (this.ignoreReleasedVersions.length > 0 && semver.satisfies(v, this.ignoreReleasedVersions.join(' || '))) {
return m;
}
// If the version is a pre-release, skip it
if ((semver.prerelease(v) || []).length > 0) {
return m;
}
// If a satisfying version has already been added to untested, skip it
if (semver.maxSatisfying(m, `${operator}${v}`)) {
return m;
}
// If a satisfying version is already tested, skip it
if (semver.maxSatisfying(testedVersions, `${operator}${v}`)) {
return m;
}
// Add version
m.push(v);
return m;
}, []);
return untestedVersions;
}
/**
* Returns the latest version for a given version and component.
* @param {Array<String>} versions The versions in which to search.
* @param {String} version The version for which a newer version
* should be searched.
* @param {String} versionComponent The version component up to
* which the latest version should be checked.
* @returns {String|undefined} The newer version.
*/
getNewerVersion(versions, version, versionComponent) {
// Determine operator for range comparison
const operator = versionComponent == CiVersionCheck.versionComponents.major
? '>='
: versionComponent == CiVersionCheck.versionComponents.minor
? '^'
: '~'
const latest = semver.maxSatisfying(versions, `${operator}${version}`);
// If the version should be ignored, skip it
if (this.ignoreReleasedVersions.length > 0 && semver.satisfies(latest, this.ignoreReleasedVersions.join(' || '))) {
return undefined;
}
// Return the latest version if it is newer than any currently used version
return semver.gt(latest, version) ? latest : undefined;
}
/**
* This validates that the given versions strictly follow semver
* syntax.
* @param {Array<String>} versions The versions to check.
*/
_validateVersionSyntax(versions) {
for (const version of versions) {
if (!semver.valid(version)) {
throw version;
}
}
}
/**
* Runs the check.
*/
async check() {
try {
console.log(`\nChecking ${this.packageName} versions in CI environments...`);
// Validate released versions syntax
try {
this._validateVersionSyntax(this.releasedVersions);
} catch (e) {
core.setFailed(`Failed to check ${this.packageName} versions because released version '${e}' does not follow semver syntax (x.y.z).`);
return;
}
// Sort versions descending
semver.sort(this.releasedVersions).reverse()
// Get tested package versions from CI
const tests = await this.getTests();
// Is true if any of the checks failed
let failed = false;
// Check whether each tested version is the latest patch
for (const test of tests) {
const version = test[this.ciVersionKey];
// Validate version syntax
try {
this._validateVersionSyntax([version]);
} catch (e) {
core.setFailed(`Failed to check ${this.packageName} versions because environment version '${e}' does not follow semver syntax (x.y.z).`);
return;
}
const newer = this.getNewerVersion(this.releasedVersions, version, this.latestComponent);
if (newer) {
console.log(`❌ CI environment '${test.name}' uses an old ${this.packageName} ${this.latestComponent} version ${version} instead of ${newer}.`);
failed = true;
} else {
console.log(`✅ CI environment '${test.name}' uses the latest ${this.packageName} ${this.latestComponent} version ${version}.`);
}
}
// Check whether there is a newer component version available that is not tested
const testedVersions = tests.map(test => test[this.ciVersionKey]);
const untested = this.getUntestedVersions(this.releasedVersions, testedVersions, this.latestComponent);
if (untested.length > 0) {
console.log(`❌ CI does not have environments using the following versions of ${this.packageName}: ${untested.join(', ')}.`);
failed = true;
} else {
console.log(`✅ CI has environments using all recent versions of ${this.packageName}.`);
}
if (failed) {
core.setFailed(
`CI environments are not up-to-date with the latest ${this.packageName} versions.` +
`\n\nCheck the error messages above and update the ${this.packageName} versions in the CI YAML ` +
`file.\n\nℹ️ Additionally, there may be versions of ${this.packageName} that have reached their official end-of-life ` +
`support date and should be removed from the CI, see ${this.packageSupportUrl}.`
);
}
} catch (e) {
const msg = `Failed to check ${this.packageName} versions with error: ${e}`;
core.setFailed(msg);
}
}
}
module.exports = CiVersionCheck;
+69
View File
@@ -0,0 +1,69 @@
'use strict';
const CiVersionCheck = require('./CiVersionCheck');
const mongoVersionList = require('mongodb-version-list');
const allNodeVersions = require('all-node-versions');
async function check() {
// Run checks
await checkMongoDbVersions();
await checkNodeVersions();
}
/**
* Check the MongoDB versions used in test environments.
*/
async function checkMongoDbVersions() {
const releasedVersions = await new Promise((resolve, reject) => {
mongoVersionList(function (error, versions) {
if (error) {
reject(error);
}
resolve(versions);
});
});
await new CiVersionCheck({
packageName: 'MongoDB',
packageSupportUrl: 'https://www.mongodb.com/support-policy',
yamlFilePath: './.github/workflows/ci.yml',
ciEnvironmentsKeyPath: 'jobs.check-mongo.strategy.matrix.include',
ciVersionKey: 'MONGODB_VERSION',
releasedVersions,
latestComponent: CiVersionCheck.versionComponents.path,
ignoreReleasedVersions: [
'<4.0.0', // Versions reached their MongoDB end-of-life support date
'~4.1.0', // Development release according to MongoDB support
'~4.3.0', // Development release according to MongoDB support
'~4.7.0', // Development release according to MongoDB support
'4.0.26', // Temporarily disabled because not yet available for download via mongodb-runner
],
}).check();
}
/**
* Check the Nodejs versions used in test environments.
*/
async function checkNodeVersions() {
const allVersions = await allNodeVersions();
const releasedVersions = allVersions.versions;
await new CiVersionCheck({
packageName: 'Node.js',
packageSupportUrl: 'https://github.com/nodejs/node/blob/master/CHANGELOG.md',
yamlFilePath: './.github/workflows/ci.yml',
ciEnvironmentsKeyPath: 'jobs.check-mongo.strategy.matrix.include',
ciVersionKey: 'NODE_VERSION',
releasedVersions,
latestComponent: CiVersionCheck.versionComponents.minor,
ignoreReleasedVersions: [
'<12.0.0', // These versions have reached their end-of-life support date
'>=13.0.0 <14.0.0', // These versions have reached their end-of-life support date
'>=15.0.0 <16.0.0', // These versions have reached their end-of-life support date
'>=17.0.0', // These versions are not officially supported yet
],
}).check();
}
check();
+194
View File
@@ -0,0 +1,194 @@
const core = require('@actions/core');
const semver = require('semver');
const fs = require('fs').promises;
const path = require('path');
/**
* This checks whether any package dependency requires a minimum node engine
* version higher than the host package.
*/
class NodeEngineCheck {
/**
* The constructor.
* @param {Object} config The config.
* @param {String} config.nodeModulesPath The path to the node_modules directory.
* @param {String} config.packageJsonPath The path to the parent package.json file.
*/
constructor(config) {
const {
nodeModulesPath,
packageJsonPath,
} = config;
// Ensure required params are set
if ([
nodeModulesPath,
packageJsonPath,
].includes(undefined)) {
throw 'invalid configuration';
}
this.nodeModulesPath = nodeModulesPath;
this.packageJsonPath = packageJsonPath;
}
/**
* Returns an array of `package.json` files under the given path and subdirectories.
* @param {String} [basePath] The base path for recursive directory search.
*/
async getPackageFiles(basePath = this.nodeModulesPath) {
try {
// Declare file list
const files = []
// Get files
const dirents = await fs.readdir(basePath, { withFileTypes: true });
const validFiles = dirents.filter(d => d.name.toLowerCase() == 'package.json').map(d => path.join(basePath, d.name));
files.push(...validFiles);
// For each directory entry
for (const dirent of dirents) {
if (dirent.isDirectory()) {
const subFiles = await this.getPackageFiles(path.join(basePath, dirent.name));
files.push(...subFiles);
}
}
return files;
} catch (e) {
throw `Failed to get package.json files in ${this.nodeModulesPath} with error: ${e}`;
}
}
/**
* Extracts and returns the node engine versions of the given package.json
* files.
* @param {String[]} files The package.json files.
* @param {Boolean} clean Is true if packages with undefined node versions
* should be removed from the results.
* @returns {Object[]} A list of results.
*/
async getNodeVersion({ files, clean = false }) {
// Declare response
let response = [];
// For each file
for (const file of files) {
// Get node version
const contentString = await fs.readFile(file, 'utf-8');
try {
const contentJson = JSON.parse(contentString);
const version = ((contentJson || {}).engines || {}).node;
// Add response
response.push({
file: file,
nodeVersion: version
});
} catch(e) {
console.log(`Ignoring file because it is not valid JSON: ${file}`);
core.warning(`Ignoring file because it is not valid JSON: ${file}`);
}
}
// If results should be cleaned by removing undefined node versions
if (clean) {
response = response.filter(r => r.nodeVersion !== undefined);
}
return response;
}
/**
* Returns the highest semver definition that satisfies all versions
* in the given list.
* @param {String[]} versions The list of semver version ranges.
* @param {String} baseVersion The base version of which higher versions should be
* determined; as a version (1.2.3), not a range (>=1.2.3).
* @returns {String} The highest semver version.
*/
getHigherVersions({ versions, baseVersion }) {
// Add min satisfying node versions
const minVersions = versions.map(v => {
v.nodeMinVersion = semver.minVersion(v.nodeVersion)
return v;
});
// Sort by min version
const sortedMinVersions = minVersions.sort((v1, v2) => semver.compare(v1.nodeMinVersion, v2.nodeMinVersion));
// Filter by higher versions
const higherVersions = sortedMinVersions.filter(v => semver.gt(v.nodeMinVersion, baseVersion));
// console.log(`getHigherVersions: ${JSON.stringify(higherVersions)}`);
return higherVersions;
}
/**
* Returns the node version of the parent package.
* @return {Object} The parent package info.
*/
async getParentVersion() {
// Get parent package.json version
const version = await this.getNodeVersion({ files: [ this.packageJsonPath ], clean: true });
// console.log(`getParentVersion: ${JSON.stringify(version)}`);
return version[0];
}
}
async function check() {
// Define paths
const nodeModulesPath = path.join(__dirname, '../node_modules');
const packageJsonPath = path.join(__dirname, '../package.json');
// Create check
const check = new NodeEngineCheck({
nodeModulesPath,
packageJsonPath,
});
// Get package node version of parent package
const parentVersion = await check.getParentVersion();
// If parent node version could not be determined
if (parentVersion === undefined) {
core.setFailed(`Failed to determine node engine version of parent package at ${this.packageJsonPath}`);
return;
}
// Determine parent min version
const parentMinVersion = semver.minVersion(parentVersion.nodeVersion);
// Get package.json files
const files = await check.getPackageFiles();
core.info(`Checking the minimum node version requirement of ${files.length} dependencies`);
// Get node versions
const versions = await check.getNodeVersion({ files, clean: true });
// Get are dependencies that require a higher node version than the parent package
const higherVersions = check.getHigherVersions({ versions, baseVersion: parentMinVersion });
// Get highest version
const highestVersion = higherVersions.map(v => v.nodeMinVersion).pop();
// If there are higher versions
if (higherVersions.length > 0) {
console.log(`\nThere are ${higherVersions.length} dependencies that require a higher node engine version than the parent package (${parentVersion.nodeVersion}):`);
// For each dependency
for (const higherVersion of higherVersions) {
// Get package name
const _package = higherVersion.file.split('node_modules/').pop().replace('/package.json', '');
console.log(`- ${_package} requires at least node ${higherVersion.nodeMinVersion} (${higherVersion.nodeVersion})`);
}
console.log('');
core.setFailed(`❌ Upgrade the node engine version in package.json to at least '${highestVersion}' to satisfy the dependencies.`);
console.log('');
return;
}
console.log(`✅ All dependencies satisfy the node version requirement of the parent package (${parentVersion.nodeVersion}).`);
}
check();
+8735 -4524
View File
File diff suppressed because it is too large Load Diff
+70 -47
View File
@@ -1,6 +1,6 @@
{
"name": "parse-server",
"version": "4.5.0",
"version": "5.2.1-alpha.2",
"description": "An express module providing a Parse-compatible API server",
"main": "lib/index.js",
"repository": {
@@ -19,59 +19,65 @@
],
"license": "BSD-3-Clause",
"dependencies": {
"@apollographql/graphql-playground-html": "1.6.26",
"@graphql-tools/links": "6.2.5",
"@apollographql/graphql-playground-html": "1.6.29",
"@graphql-tools/links": "8.2.2",
"@apollo/client": "3.5.8",
"@graphql-tools/stitch": "6.2.4",
"@graphql-tools/utils": "6.2.4",
"@parse/fs-files-adapter": "1.2.0",
"@parse/push-adapter": "3.4.0",
"@parse/s3-files-adapter": "1.6.0",
"@parse/simple-mailgun-adapter": "1.1.0",
"apollo-server-express": "2.19.0",
"@parse/fs-files-adapter": "1.2.1",
"@parse/push-adapter": "4.1.0",
"apollo-server-express": "2.25.2",
"bcryptjs": "2.4.3",
"body-parser": "1.19.0",
"body-parser": "1.19.1",
"commander": "5.1.0",
"cors": "2.8.5",
"deepcopy": "2.1.0",
"express": "4.17.1",
"follow-redirects": "1.13.0",
"graphql": "15.4.0",
"express": "4.17.2",
"follow-redirects": "1.14.8",
"graphql": "15.7.1",
"graphql-list-fields": "2.0.2",
"graphql-relay": "0.6.0",
"graphql-relay": "0.7.0",
"graphql-tag": "2.12.6",
"graphql-upload": "11.0.0",
"intersect": "1.0.1",
"jsonwebtoken": "8.5.1",
"jwks-rsa": "1.11.0",
"ldapjs": "2.2.2",
"lodash": "4.17.20",
"lru-cache": "5.1.1",
"mime": "2.4.6",
"mongodb": "3.6.3",
"parse": "2.19.0",
"pg-promise": "10.8.1",
"jwks-rsa": "2.0.5",
"ldapjs": "2.3.1",
"lodash": "4.17.21",
"lru-cache": "6.0.0",
"mime": "3.0.0",
"mongodb": "4.3.1",
"mustache": "4.2.0",
"parse": "3.4.1",
"pg-monitor": "1.4.1",
"pg-promise": "10.11.1",
"pluralize": "8.0.0",
"redis": "3.0.2",
"semver": "7.3.2",
"subscriptions-transport-ws": "0.9.18",
"redis": "3.1.2",
"semver": "7.3.5",
"subscriptions-transport-ws": "0.11.0",
"tv4": "1.3.0",
"uuid": "8.3.1",
"winston": "3.3.3",
"winston-daily-rotate-file": "4.5.0",
"ws": "7.4.0"
"uuid": "8.3.2",
"winston": "3.5.1",
"winston-daily-rotate-file": "4.6.0",
"ws": "8.2.3"
},
"devDependencies": {
"@actions/core": "1.2.6",
"@babel/cli": "7.10.0",
"@babel/core": "7.10.0",
"@babel/plugin-proposal-object-rest-spread": "7.10.0",
"@babel/plugin-transform-flow-strip-types": "7.9.0",
"@babel/preset-env": "7.10.0",
"@parse/minami": "1.0.0",
"apollo-cache-inmemory": "1.6.6",
"apollo-client": "2.6.10",
"apollo-link": "1.2.14",
"apollo-link-http": "1.5.17",
"apollo-link-ws": "1.0.20",
"apollo-upload-client": "13.0.0",
"@saithodev/semantic-release-backmerge": "2.1.2",
"@semantic-release/changelog": "5.0.1",
"@semantic-release/commit-analyzer": "8.0.1",
"@semantic-release/git": "9.0.0",
"@semantic-release/github": "7.2.3",
"@semantic-release/npm": "7.1.3",
"@semantic-release/release-notes-generator": "9.0.3",
"all-node-versions": "8.0.0",
"apollo-upload-client": "16.0.0",
"apollo-utilities": "1.3.4",
"babel-eslint": "10.1.0",
"bcrypt-nodejs": "0.0.3",
@@ -81,42 +87,59 @@
"eslint-plugin-flowtype": "5.1.3",
"flow-bin": "0.119.1",
"form-data": "3.0.0",
"graphql-tag": "2.10.1",
"husky": "4.2.5",
"jasmine": "3.5.0",
"jasmine-spec-reporter": "7.0.0",
"jsdoc": "3.6.3",
"jsdoc-babel": "0.5.0",
"lint-staged": "10.2.3",
"mongodb-runner": "mongodb-js/runner",
"node-fetch": "2.6.1",
"madge": "5.0.1",
"mock-files-adapter": "file:spec/dependencies/mock-files-adapter",
"mock-mail-adapter": "file:spec/dependencies/mock-mail-adapter",
"mongodb-runner": "4.8.1",
"mongodb-version-list": "1.0.0",
"node-fetch": "3.1.1",
"nyc": "15.1.0",
"prettier": "2.0.5"
"prettier": "2.0.5",
"semantic-release": "17.4.6",
"yaml": "1.10.0"
},
"scripts": {
"definitions": "node ./resources/buildConfigDefinitions.js",
"ci:check": "node ./ci/ciCheck.js",
"ci:checkNodeEngine": "node ./ci/nodeEngineCheck.js",
"definitions": "node ./resources/buildConfigDefinitions.js && prettier --write 'src/Options/*.js'",
"docs": "jsdoc -c ./jsdoc-conf.json",
"lint": "flow && eslint --cache ./",
"lint-fix": "eslint --fix --cache ./",
"build": "babel src/ -d lib/ --copy-files",
"watch": "babel --watch src/ -d lib/ --copy-files",
"pretest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=mmapv1} mongodb-runner start",
"testonly": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=mmapv1} TESTING=1 jasmine",
"test:mongodb:runnerstart": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=$npm_config_dbversion} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} mongodb-runner start",
"test:mongodb:testonly": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=$npm_config_dbversion} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} TESTING=1 jasmine",
"test:mongodb": "npm run test:mongodb:runnerstart --dbversion=$npm_config_dbversion && npm run test:mongodb:testonly --dbversion=$npm_config_dbversion",
"test:mongodb:4.0.27": "npm run test:mongodb --dbversion=4.0.27",
"test:mongodb:4.2.17": "npm run test:mongodb --dbversion=4.2.17",
"test:mongodb:4.4.10": "npm run test:mongodb --dbversion=4.4.10",
"test:mongodb:5.0.5": "npm run test:mongodb --dbversion=5.0.5",
"posttest:mongodb": "mongodb-runner stop",
"pretest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.0.5} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} mongodb-runner start",
"testonly": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.0.5} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} TESTING=1 jasmine",
"test": "npm run testonly",
"posttest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=mmapv1} mongodb-runner stop",
"coverage": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=mmapv1} TESTING=1 nyc jasmine",
"posttest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.0.5} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} mongodb-runner stop",
"coverage": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.0.5} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} TESTING=1 nyc jasmine",
"start": "node ./bin/parse-server",
"prettier": "prettier --write '{src,spec}/{**/*,*}.js'",
"prettier": "prettier --write {src,spec}/{**/*,*}.js",
"prepare": "npm run build",
"postinstall": "node -p 'require(\"./postinstall.js\")()'"
"postinstall": "node -p 'require(\"./postinstall.js\")()'",
"madge:circular": "node_modules/.bin/madge ./src --circular"
},
"engines": {
"node": ">= 8"
"node": ">=12.22.10 <17"
},
"bin": {
"parse-server": "bin/parse-server"
},
"optionalDependencies": {
"@node-rs/bcrypt": "0.4.1"
"@node-rs/bcrypt": "1.1.0"
},
"collective": {
"type": "opencollective",
+17
View File
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<!--
This page demonstrates how to localize using a JSON file that contains the
translations for each placeholder.
-->
<html>
<head>
<title>{{title}}</title>
</head>
<body>
<h1>{{heading}}</h1>
<p>{{body}}</p>
</body>
</html>
+23
View File
@@ -0,0 +1,23 @@
{
"en": {
"translation": {
"title": "Hello!",
"heading": "Welcome to {{appName}}!",
"body": "We are delighted to welcome you on board."
}
},
"de": {
"translation": {
"title": "Hallo!",
"heading": "Willkommen bei {{appName}}!",
"body": "Wir freuen uns, dich begrüßen zu dürfen."
}
},
"de-AT": {
"translation": {
"title": "Servus!",
"heading": "Willkommen bei {{appName}}!",
"body": "Wir freuen uns, dich begrüßen zu dürfen."
}
}
}
+15
View File
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<!--
This page demonstrates how to use custom pages in custom routes.
-->
<html>
<head>
<title>{{appName}}</title>
</head>
<body>
<h1>{{appName}}</h1>
</body>
</html>
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a verify email link with a security
token that is expired or incorrect. This can either mean the user has clicked
on a stale link (i.e. re-clicked on the link) or this could be a sign of a
malicious user trying to tamper with your app.
-->
<html>
<head>
<title>Email Verification</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Expired verification link!</h1>
<form method="POST" action="{{{publicServerUrl}}}/apps/{{{appId}}}/resend_verification_email">
<input name="username" type="hidden" value="{{{username}}}">
<input name="locale" type="hidden" value="{{{locale}}}">
<button type="submit">Resend Link</button>
</form>
</body>
</html>
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a verify email link with parameters
that are missing or incorrect. This can either mean the user has incorrectly
entered a link or this could be a sign of a malicious user trying to tamper
with your app.
If the link contains an expired security token (or the email has already
been verified), this page is not displayed, there is another page for that.
-->
<html>
<head>
<title>Email Verification</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Invalid verification link!</h1>
</body>
</html>
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a verify email link with a security
token that is expired or incorrect, then requests to receive another link,
but it fails because the username is invalid or the email has already been
verified. This can either mean the user has previously verified the email
or this could be a sign of a malicious user trying to tamper with your app.
-->
<html>
<head>
<title>Email Verification</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Invalid link!</h1>
<p>No link sent. User not found or email already verified.</p>
</body>
</html>
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a verify email link with a
security token that is expired, then requests to receive another email
with a new link and the email is sent successfully.
-->
<html>
<head>
<title>Email Verification</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Link sent!</h1>
<p>A new link has been sent. Check your email.</p>
</body>
</html>
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a verify email link and the
email gets verified successfully.
-->
<html>
<head>
<title>Email Verification</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Email verified!</h1>
<p>Successfully verified your email for account: {{username}}.</p>
</body>
</html>
+65
View File
@@ -0,0 +1,65 @@
<!DOCTYPE html>
<!--
This page is displayed when someone clicks a valid 'reset password' link.
Users should feel free to add to this page (i.e. branding or security widgets)
but should be sure not to delete any of the form inputs or the javascript from the
template file. This javascript is what adds the necessary values to authenticate
this session with Parse.
The query params 'username' and 'app' hold the friendly names for your current user and
your app. You should feel free to incorporate their values to make the page more personal.
If you are missing form parameters in your POST, Parse will navigate back to this page and
add an 'error' query parameter.
-->
<html>
<head>
<title>Password Reset</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Reset Your Password</h1>
<noscript><p>We apologize, but resetting your password requires javascript</p></noscript>
<p>You can set a new Password for your account: {{username}}</p>
<br />
<p>{{error}}</p>
<form id='form' action='{{{publicServerUrl}}}/apps/{{{appId}}}/request_password_reset' method='POST'>
<input name='utf-8' type='hidden' value='✓' />
<input name="username" type="hidden" id="username" value="{{{username}}}" />
<input name="token" type="hidden" id="token" value="{{{token}}}" />
<input name="locale" type="hidden" id="locale" value="{{{locale}}}" />
<p>New Password</p>
<input name="new_password" type="password" id="password" />
<p>Confirm New Password</p>
<input name="confirm_new_password" type="password" id="password_confirm" />
<br />
<p id="password_match_info"></p>
<br />
<button id="change_password">Change Password</button>
</form>
<script>
window.onload = function() {
document.getElementById("password").oninput = validatePassword;
document.getElementById("password_confirm").oninput = validatePassword;
document.getElementById("change_password").disabled = true;
function validatePassword() {
var pass2 = document.getElementById("password").value;
var pass1 = document.getElementById("password_confirm").value;
if(pass1 !== pass2) {
if(document.getElementById("password_confirm").value) {
document.getElementById("change_password").disabled = true;
document.getElementById("password_match_info").innerHTML = "Must match the previous entry";
}
} else {
document.getElementById("change_password").disabled = false;
document.getElementById("password_match_info").innerHTML = "";
}
}
}
</script>
</body>
</html>
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a password reset link with parameters
that are missing or incorrect. This can either mean the user has incorrectly
entered a link or this could be a sign of a malicious user trying to tamper
with your app.
-->
<html>
<head>
<title>Password Reset</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Invalid password reset link!</h1>
</body>
</html>
+18
View File
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a reset password link, then submits
the form with a new password and the password gets updated successfully.
-->
<html>
<head>
<title>Password Reset</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Success!</h1>
<p>Your password has been updated.</p>
</body>
</html>
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a verify email link with a security
token that is expired or incorrect. This can either mean the user has clicked
on a stale link (i.e. re-clicked on the link) or this could be a sign of a
malicious user trying to tamper with your app.
-->
<html>
<head>
<title>Email Verification</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Expired verification link!</h1>
<form method="POST" action="{{{publicServerUrl}}}/apps/{{{appId}}}/resend_verification_email">
<input name="username" type="hidden" value="{{{username}}}">
<input name="locale" type="hidden" value="{{{locale}}}">
<button type="submit">Resend Link</button>
</form>
</body>
</html>
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a verify email link with parameters
that are missing or incorrect. This can either mean the user has incorrectly
entered a link or this could be a sign of a malicious user trying to tamper
with your app.
If the link contains an expired security token (or the email has already
been verified), this page is not displayed, there is another page for that.
-->
<html>
<head>
<title>Email Verification</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Invalid verification link!</h1>
</body>
</html>
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a verify email link with a security
token that is expired or incorrect, then requests to receive another link,
but it fails because the username is invalid or the email has already been
verified. This can either mean the user has previously verified the email
or this could be a sign of a malicious user trying to tamper with your app.
-->
<html>
<head>
<title>Email Verification</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Invalid link!</h1>
<p>No link sent. User not found or email already verified.</p>
</body>
</html>
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a verify email link with a
security token that is expired, then requests to receive another email
with a new link and the email is sent successfully.
-->
<html>
<head>
<title>Email Verification</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Link sent!</h1>
<p>A new link has been sent. Check your email.</p>
</body>
</html>
+18
View File
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a verify email link and the
email gets verified successfully.
-->
<html>
<head>
<title>Email Verification</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Email verified!</h1>
<p>Successfully verified your email for account: {{username}}.</p>
</body>
</html>
+65
View File
@@ -0,0 +1,65 @@
<!DOCTYPE html>
<!--
This page is displayed when someone clicks a valid 'reset password' link.
Users should feel free to add to this page (i.e. branding or security widgets)
but should be sure not to delete any of the form inputs or the javascript from the
template file. This javascript is what adds the necessary values to authenticate
this session with Parse.
The query params 'username' and 'app' hold the friendly names for your current user and
your app. You should feel free to incorporate their values to make the page more personal.
If you are missing form parameters in your POST, Parse will navigate back to this page and
add an 'error' query parameter.
-->
<html>
<head>
<title>Password Reset</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Reset Your Password</h1>
<noscript><p>We apologize, but resetting your password requires javascript</p></noscript>
<p>You can set a new Password for your account: {{username}}</p>
<br />
<p>{{error}}</p>
<form id='form' action='{{{publicServerUrl}}}/apps/{{{appId}}}/request_password_reset' method='POST'>
<input name='utf-8' type='hidden' value='✓' />
<input name="username" type="hidden" id="username" value="{{{username}}}" />
<input name="token" type="hidden" id="token" value="{{{token}}}" />
<input name="locale" type="hidden" id="locale" value="{{{locale}}}" />
<p>New Password</p>
<input name="new_password" type="password" id="password" />
<p>Confirm New Password</p>
<input name="confirm_new_password" type="password" id="password_confirm" />
<br />
<p id="password_match_info"></p>
<br />
<button id="change_password">Change Password</button>
</form>
<script>
window.onload = function() {
document.getElementById("password").oninput = validatePassword;
document.getElementById("password_confirm").oninput = validatePassword;
document.getElementById("change_password").disabled = true;
function validatePassword() {
var pass2 = document.getElementById("password").value;
var pass1 = document.getElementById("password_confirm").value;
if(pass1 !== pass2) {
if(document.getElementById("password_confirm").value) {
document.getElementById("change_password").disabled = true;
document.getElementById("password_match_info").innerHTML = "Must match the previous entry";
}
} else {
document.getElementById("change_password").disabled = false;
document.getElementById("password_match_info").innerHTML = "";
}
}
}
</script>
</body>
</html>
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a password reset link with parameters
that are missing or incorrect. This can either mean the user has incorrectly
entered a link or this could be a sign of a malicious user trying to tamper
with your app.
-->
<html>
<head>
<title>Password Reset</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Invalid password reset link!</h1>
</body>
</html>
+18
View File
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a reset password link, then submits
the form with a new password and the password gets updated successfully.
-->
<html>
<head>
<title>Password Reset</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Success!</h1>
<p>Your password has been updated.</p>
</body>
</html>
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a verify email link with a security
token that is expired or incorrect. This can either mean the user has clicked
on a stale link (i.e. re-clicked on the link) or this could be a sign of a
malicious user trying to tamper with your app.
-->
<html>
<head>
<title>Email Verification</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Expired verification link!</h1>
<form method="POST" action="{{{publicServerUrl}}}/apps/{{{appId}}}/resend_verification_email">
<input name="username" type="hidden" value="{{{username}}}">
<input name="locale" type="hidden" value="{{{locale}}}">
<button type="submit">Resend Link</button>
</form>
</body>
</html>
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a verify email link with parameters
that are missing or incorrect. This can either mean the user has incorrectly
entered a link or this could be a sign of a malicious user trying to tamper
with your app.
If the link contains an expired security token (or the email has already
been verified), this page is not displayed, there is another page for that.
-->
<html>
<head>
<title>Email Verification</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Invalid verification link!</h1>
</body>
</html>
+21
View File
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a verify email link with a security
token that is expired or incorrect, then requests to receive another link,
but it fails because the username is invalid or the email has already been
verified. This can either mean the user has previously verified the email
or this could be a sign of a malicious user trying to tamper with your app.
-->
<html>
<head>
<title>Email Verification</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Invalid link!</h1>
<p>No link sent. User not found or email already verified.</p>
</body>
</html>
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a verify email link with a
security token that is expired, then requests to receive another email
with a new link and the email is sent successfully.
-->
<html>
<head>
<title>Email Verification</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Link sent!</h1>
<p>A new link has been sent. Check your email.</p>
</body>
</html>
+18
View File
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a verify email link and the
email gets verified successfully.
-->
<html>
<head>
<title>Email Verification</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Email verified!</h1>
<p>Successfully verified your email for account: {{username}}.</p>
</body>
</html>
+65
View File
@@ -0,0 +1,65 @@
<!DOCTYPE html>
<!--
This page is displayed when someone clicks a valid 'reset password' link.
Users should feel free to add to this page (i.e. branding or security widgets)
but should be sure not to delete any of the form inputs or the javascript from the
template file. This javascript is what adds the necessary values to authenticate
this session with Parse.
The query params 'username' and 'app' hold the friendly names for your current user and
your app. You should feel free to incorporate their values to make the page more personal.
If you are missing form parameters in your POST, Parse will navigate back to this page and
add an 'error' query parameter.
-->
<html>
<head>
<title>Password Reset</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Reset Your Password</h1>
<noscript><p>We apologize, but resetting your password requires javascript</p></noscript>
<p>You can set a new Password for your account: {{username}}</p>
<br />
<p>{{error}}</p>
<form id='form' action='{{{publicServerUrl}}}/apps/{{{appId}}}/request_password_reset' method='POST'>
<input name='utf-8' type='hidden' value='✓' />
<input name="username" type="hidden" id="username" value="{{{username}}}" />
<input name="token" type="hidden" id="token" value="{{{token}}}" />
<input name="locale" type="hidden" id="locale" value="{{{locale}}}" />
<p>New Password</p>
<input name="new_password" type="password" id="password" />
<p>Confirm New Password</p>
<input name="confirm_new_password" type="password" id="password_confirm" />
<br />
<p id="password_match_info"></p>
<br />
<button id="change_password">Change Password</button>
</form>
<script>
window.onload = function() {
document.getElementById("password").oninput = validatePassword;
document.getElementById("password_confirm").oninput = validatePassword;
document.getElementById("change_password").disabled = true;
function validatePassword() {
var pass2 = document.getElementById("password").value;
var pass1 = document.getElementById("password_confirm").value;
if(pass1 !== pass2) {
if(document.getElementById("password_confirm").value) {
document.getElementById("change_password").disabled = true;
document.getElementById("password_match_info").innerHTML = "Must match the previous entry";
}
} else {
document.getElementById("change_password").disabled = false;
document.getElementById("password_match_info").innerHTML = "";
}
}
}
</script>
</body>
</html>
+19
View File
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a password reset link with parameters
that are missing or incorrect. This can either mean the user has incorrectly
entered a link or this could be a sign of a malicious user trying to tamper
with your app.
-->
<html>
<head>
<title>Password Reset</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Invalid password reset link!</h1>
</body>
</html>
+18
View File
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<!--
This page is displayed when a user opens a reset password link, then submits
the form with a new password and the password gets updated successfully.
-->
<html>
<head>
<title>Password Reset</title>
</head>
<body>
<h1>{{appName}}</h1>
<h1>Success!</h1>
<p>Your password has been updated.</p>
</body>
</html>
+124
View File
@@ -0,0 +1,124 @@
/**
* Semantic Release Config
*/
const fs = require('fs').promises;
const path = require('path');
// Get env vars
const ref = process.env.GITHUB_REF;
const serverUrl = process.env.GITHUB_SERVER_URL;
const repository = process.env.GITHUB_REPOSITORY;
const repositoryUrl = serverUrl + '/' + repository;
// Declare params
const resourcePath = './.releaserc/';
const templates = {
main: { file: 'template.hbs', text: undefined },
header: { file: 'header.hbs', text: undefined },
commit: { file: 'commit.hbs', text: undefined },
footer: { file: 'footer.hbs', text: undefined },
};
// Declare semantic config
async function config() {
// Get branch
const branch = ref.split('/').pop();
console.log(`Running on branch: ${branch}`);
// Set changelog file
const changelogFile = `./changelogs/CHANGELOG_${branch}.md`;
console.log(`Changelog file output to: ${changelogFile}`);
// Load template file contents
await loadTemplates();
const config = {
branches: [
'release',
{ name: 'alpha', prerelease: true },
{ name: 'beta', prerelease: true },
'next-major',
// Long-Term-Support branches
// { name: 'release-1', range: '1.x.x', channel: '1.x' },
// { name: 'release-2', range: '2.x.x', channel: '2.x' },
// { name: 'release-3', range: '3.x.x', channel: '3.x' },
// { name: 'release-4', range: '4.x.x', channel: '4.x' },
],
dryRun: false,
debug: true,
ci: true,
tagFormat: '${version}',
plugins: [
['@semantic-release/commit-analyzer', {
preset: 'angular',
releaseRules: [
{ type: 'docs', scope: 'README', release: 'patch' },
{ scope: 'no-release', release: false },
],
parserOpts: {
noteKeywords: [ 'BREAKING CHANGE', 'BREAKING CHANGES', 'BREAKING' ],
},
}],
['@semantic-release/release-notes-generator', {
preset: 'angular',
parserOpts: {
noteKeywords: ['BREAKING CHANGE', 'BREAKING CHANGES', 'BREAKING']
},
writerOpts: {
commitsSort: ['subject', 'scope'],
mainTemplate: templates.main.text,
headerPartial: templates.header.text,
commitPartial: templates.commit.text,
footerPartial: templates.footer.text,
},
}],
['@semantic-release/changelog', {
'changelogFile': changelogFile,
}],
['@semantic-release/npm', {
'npmPublish': true,
}],
['@semantic-release/git', {
assets: [changelogFile, 'package.json', 'package-lock.json', 'npm-shrinkwrap.json'],
}],
[
"@saithodev/semantic-release-backmerge",
{
"branches": [
{ from: "beta", to: "alpha" },
{ from: "release", to: "beta" },
{ from: "release", to: "alpha" },
]
}
],
['@semantic-release/github', {
successComment: getReleaseComment(),
labels: ['type:ci'],
releasedLabels: ['state:released<%= nextRelease.channel ? `-\${nextRelease.channel}` : "" %>']
}],
],
};
return config;
}
async function loadTemplates() {
for (const template of Object.keys(templates)) {
const text = await readFile(path.resolve(__dirname, resourcePath, templates[template].file));
templates[template].text = text;
}
}
async function readFile(filePath) {
return await fs.readFile(filePath, 'utf-8');
}
function getReleaseComment() {
const url = repositoryUrl + '/releases/tag/${nextRelease.gitTag}';
const comment = '🎉 This change has been released in version [${nextRelease.version}](' + url + ')';
return comment;
}
module.exports = config();
+52 -20
View File
@@ -11,6 +11,37 @@
*/
const parsers = require('../src/Options/parsers');
/** The types of nested options. */
const nestedOptionTypes = [
'CustomPagesOptions',
'DatabaseOptions',
'FileUploadOptions',
'IdempotencyOptions',
'Object',
'PagesCustomUrlsOptions',
'PagesOptions',
'PagesRoute',
'PasswordPolicyOptions',
'SecurityOptions',
];
/** The prefix of environment variables for nested options. */
const nestedOptionEnvPrefix = {
'AccountLockoutOptions' : 'PARSE_SERVER_ACCOUNT_LOCKOUT_',
'CustomPagesOptions' : 'PARSE_SERVER_CUSTOM_PAGES_',
'DatabaseOptions': 'PARSE_SERVER_DATABASE_',
'FileUploadOptions' : 'PARSE_SERVER_FILE_UPLOAD_',
'IdempotencyOptions' : 'PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_',
'LiveQueryOptions' : 'PARSE_SERVER_LIVEQUERY_',
'LiveQueryServerOptions' : 'PARSE_LIVE_QUERY_SERVER_',
'PagesCustomUrlsOptions' : 'PARSE_SERVER_PAGES_CUSTOM_URL_',
'PagesOptions' : 'PARSE_SERVER_PAGES_',
'PagesRoute': 'PARSE_SERVER_PAGES_ROUTE_',
'ParseServerOptions' : 'PARSE_SERVER_',
'PasswordPolicyOptions' : 'PARSE_SERVER_PASSWORD_POLICY_',
'SecurityOptions': 'PARSE_SERVER_SECURITY_',
};
function last(array) {
return array[array.length - 1];
}
@@ -40,17 +71,8 @@ function getCommentValue(comment) {
}
function getENVPrefix(iface) {
const options = {
'ParseServerOptions' : 'PARSE_SERVER_',
'CustomPagesOptions' : 'PARSE_SERVER_CUSTOM_PAGES_',
'LiveQueryServerOptions' : 'PARSE_LIVE_QUERY_SERVER_',
'LiveQueryOptions' : 'PARSE_SERVER_LIVEQUERY_',
'IdempotencyOptions' : 'PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_',
'AccountLockoutOptions' : 'PARSE_SERVER_ACCOUNT_LOCKOUT_',
'PasswordPolicyOptions' : 'PARSE_SERVER_PASSWORD_POLICY_'
}
if (options[iface.id.name]) {
return options[iface.id.name]
if (nestedOptionEnvPrefix[iface.id.name]) {
return nestedOptionEnvPrefix[iface.id.name]
}
}
@@ -150,6 +172,20 @@ function parseDefaultValue(elt, value, t) {
literalValue = t.arrayExpression(array.map((value) => {
if (typeof value == 'string') {
return t.stringLiteral(value);
} else if (typeof value == 'number') {
return t.numericLiteral(value);
} else if (typeof value == 'object') {
const object = parsers.objectParser(value);
const props = Object.entries(object).map(([k, v]) => {
if (typeof v == 'string') {
return t.objectProperty(t.identifier(k), t.stringLiteral(v));
} else if (typeof v == 'number') {
return t.objectProperty(t.identifier(k), t.numericLiteral(v));
} else if (typeof v == 'boolean') {
return t.objectProperty(t.identifier(k), t.booleanLiteral(v));
}
});
return t.objectExpression(props);
} else {
throw new Error('Unable to parse array');
}
@@ -163,14 +199,8 @@ function parseDefaultValue(elt, value, t) {
if (type == 'NumberOrBoolean') {
literalValue = t.numericLiteral(parsers.numberOrBoolParser('')(value));
}
if (type == 'CustomPagesOptions') {
const object = parsers.objectParser(value);
const props = Object.keys(object).map((key) => {
return t.objectProperty(key, object[value]);
});
literalValue = t.objectExpression(props);
}
if (type == 'IdempotencyOptions') {
if (nestedOptionTypes.includes(type)) {
const object = parsers.objectParser(value);
const props = Object.keys(object).map((key) => {
return t.objectProperty(key, object[value]);
@@ -220,7 +250,9 @@ function inject(t, list) {
type = elt.typeAnnotation.id.name;
}
if (type === 'Array') {
type = `${elt.typeAnnotation.elementType.type.replace('TypeAnnotation', '')}[]`;
type = elt.typeAnnotation.elementType.id
? `${elt.typeAnnotation.elementType.id.name}[]`
: `${elt.typeAnnotation.elementType.type.replace('TypeAnnotation', '')}[]`;
}
if (type === 'NumberOrBoolean') {
type = 'Number|Boolean';
+2 -1
View File
@@ -2,11 +2,12 @@
set -e
echo "[SCRIPT] Before Script :: Setup Parse DB for Postgres ${POSTGRES_MAJOR_VERSION}"
echo "[SCRIPT] Before Script :: Setup Parse DB for Postgres"
PGPASSWORD=postgres psql -v ON_ERROR_STOP=1 -h localhost -U postgres <<-EOSQL
CREATE DATABASE parse_server_postgres_adapter_test_database;
\c parse_server_postgres_adapter_test_database;
CREATE EXTENSION pgcrypto;
CREATE EXTENSION postgis;
CREATE EXTENSION postgis_topology;
EOSQL
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
set -e
echo "[SCRIPT] Before Script :: Setup Parse Postgres configuration file"
# DB Version: 13
# OS Type: linux
# DB Type: web
# Total Memory (RAM): 6 GB
# CPUs num: 1
# Data Storage: ssd
PGPASSWORD=postgres psql -v ON_ERROR_STOP=1 -h localhost -U postgres <<-EOSQL
ALTER SYSTEM SET max_connections TO '200';
ALTER SYSTEM SET shared_buffers TO '1536MB';
ALTER SYSTEM SET effective_cache_size TO '4608MB';
ALTER SYSTEM SET maintenance_work_mem TO '384MB';
ALTER SYSTEM SET checkpoint_completion_target TO '0.9';
ALTER SYSTEM SET wal_buffers TO '16MB';
ALTER SYSTEM SET default_statistics_target TO '100';
ALTER SYSTEM SET random_page_cost TO '1.1';
ALTER SYSTEM SET effective_io_concurrency TO '200';
ALTER SYSTEM SET work_mem TO '3932kB';
ALTER SYSTEM SET min_wal_size TO '1GB';
ALTER SYSTEM SET max_wal_size TO '4GB';
SELECT pg_reload_conf();
EOSQL
exec "$@"
+6
View File
@@ -16,6 +16,12 @@
"expectAsync": true,
"notEqual": true,
"it_only_db": true,
"it_only_mongodb_version": true,
"it_only_postgres_version": true,
"fit_only_mongodb_version": true,
"it_exclude_mongodb_version": true,
"it_exclude_postgres_version": true,
"fit_exclude_mongodb_version": true,
"it_exclude_dbs": true,
"describe_only_db": true,
"describe_only": true,
+124
View File
@@ -1,6 +1,8 @@
'use strict';
const Config = require('../lib/Config');
const Definitions = require('../lib/Options/Definitions');
const request = require('../lib/request');
const loginWithWrongCredentialsShouldFail = function (username, password) {
return new Promise((resolve, reject) => {
@@ -340,3 +342,125 @@ describe('Account Lockout Policy: ', () => {
});
});
});
describe('lockout with password reset option', () => {
let sendPasswordResetEmail;
async function setup(options = {}) {
const accountLockout = Object.assign(
{
duration: 10000,
threshold: 1,
},
options
);
const config = {
appName: 'exampleApp',
accountLockout: accountLockout,
publicServerURL: 'http://localhost:8378/1',
emailAdapter: {
sendVerificationEmail: () => Promise.resolve(),
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => {},
},
};
await reconfigureServer(config);
sendPasswordResetEmail = spyOn(config.emailAdapter, 'sendPasswordResetEmail').and.callThrough();
}
it('accepts valid unlockOnPasswordReset option', async () => {
const values = [true, false];
for (const value of values) {
await expectAsync(setup({ unlockOnPasswordReset: value })).toBeResolved();
}
});
it('rejects invalid unlockOnPasswordReset option', async () => {
const values = ['a', 0, {}, [], null];
for (const value of values) {
await expectAsync(setup({ unlockOnPasswordReset: value })).toBeRejected();
}
});
it('uses default value if unlockOnPasswordReset is not set', async () => {
await expectAsync(setup({ unlockOnPasswordReset: undefined })).toBeResolved();
const parseConfig = Config.get(Parse.applicationId);
expect(parseConfig.accountLockout.unlockOnPasswordReset).toBe(
Definitions.AccountLockoutOptions.unlockOnPasswordReset.default
);
});
it('allow login for locked account after password reset', async () => {
await setup({ unlockOnPasswordReset: true });
const config = Config.get(Parse.applicationId);
const user = new Parse.User();
const username = 'exampleUsername';
const password = 'examplePassword';
user.setUsername(username);
user.setPassword(password);
user.setEmail('mail@example.com');
await user.signUp();
await expectAsync(Parse.User.logIn(username, 'incorrectPassword')).toBeRejected();
await expectAsync(Parse.User.logIn(username, password)).toBeRejected();
await Parse.User.requestPasswordReset(user.getEmail());
await expectAsync(Parse.User.logIn(username, password)).toBeRejected();
const link = sendPasswordResetEmail.calls.all()[0].args[0].link;
const linkUrl = new URL(link);
const token = linkUrl.searchParams.get('token');
const newPassword = 'newPassword';
await request({
method: 'POST',
url: `${config.publicServerURL}/apps/test/request_password_reset`,
body: `new_password=${newPassword}&token=${token}&username=${username}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
followRedirects: false,
});
await expectAsync(Parse.User.logIn(username, newPassword)).toBeResolved();
});
it('reject login for locked account after password reset (default)', async () => {
await setup();
const config = Config.get(Parse.applicationId);
const user = new Parse.User();
const username = 'exampleUsername';
const password = 'examplePassword';
user.setUsername(username);
user.setPassword(password);
user.setEmail('mail@example.com');
await user.signUp();
await expectAsync(Parse.User.logIn(username, 'incorrectPassword')).toBeRejected();
await expectAsync(Parse.User.logIn(username, password)).toBeRejected();
await Parse.User.requestPasswordReset(user.getEmail());
await expectAsync(Parse.User.logIn(username, password)).toBeRejected();
const link = sendPasswordResetEmail.calls.all()[0].args[0].link;
const linkUrl = new URL(link);
const token = linkUrl.searchParams.get('token');
const newPassword = 'newPassword';
await request({
method: 'POST',
url: `${config.publicServerURL}/apps/test/request_password_reset`,
body: `new_password=${newPassword}&token=${token}&username=${username}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
followRedirects: false,
});
await expectAsync(Parse.User.logIn(username, newPassword)).toBeRejected();
});
});
+8 -8
View File
@@ -1,12 +1,12 @@
const loadAdapter = require('../lib/Adapters/AdapterLoader').loadAdapter;
const FilesAdapter = require('@parse/fs-files-adapter').default;
const S3Adapter = require('@parse/s3-files-adapter').default;
const ParsePushAdapter = require('@parse/push-adapter').default;
const MockFilesAdapter = require('mock-files-adapter');
const Config = require('../lib/Config');
describe('AdapterLoader', () => {
it('should instantiate an adapter from string in object', done => {
const adapterPath = require('path').resolve('./spec/MockAdapter');
const adapterPath = require('path').resolve('./spec/support/MockAdapter');
const adapter = loadAdapter({
adapter: adapterPath,
@@ -23,7 +23,7 @@ describe('AdapterLoader', () => {
});
it('should instantiate an adapter from string', done => {
const adapterPath = require('path').resolve('./spec/MockAdapter');
const adapterPath = require('path').resolve('./spec/support/MockAdapter');
const adapter = loadAdapter(adapterPath);
expect(adapter instanceof Object).toBe(true);
@@ -119,7 +119,7 @@ describe('AdapterLoader', () => {
});
it('should load custom push adapter from string (#3544)', done => {
const adapterPath = require('path').resolve('./spec/MockPushAdapter');
const adapterPath = require('path').resolve('./spec/support/MockPushAdapter');
const options = {
ios: {
bundleId: 'bundle.id',
@@ -142,12 +142,12 @@ describe('AdapterLoader', () => {
}).not.toThrow();
});
it('should load S3Adapter from direct passing', done => {
it('should load file adapter from direct passing', done => {
spyOn(console, 'warn').and.callFake(() => {});
const s3Adapter = new S3Adapter('key', 'secret', 'bucket');
const mockFilesAdapter = new MockFilesAdapter('key', 'secret', 'bucket');
expect(() => {
const adapter = loadAdapter(s3Adapter, FilesAdapter);
expect(adapter).toBe(s3Adapter);
const adapter = loadAdapter(mockFilesAdapter, FilesAdapter);
expect(adapter).toBe(mockFilesAdapter);
}).not.toThrow();
done();
});
+87
View File
@@ -1,6 +1,7 @@
const AggregateRouter = require('../lib/Routers/AggregateRouter').AggregateRouter;
describe('AggregateRouter', () => {
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
it('get pipeline from Array', () => {
const body = [
{
@@ -12,6 +13,7 @@ describe('AggregateRouter', () => {
expect(result).toEqual(expected);
});
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
it('get pipeline from Object', () => {
const body = {
group: { objectId: {} },
@@ -21,6 +23,7 @@ describe('AggregateRouter', () => {
expect(result).toEqual(expected);
});
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
it('get pipeline from Pipeline Operator (Array)', () => {
const body = {
pipeline: [
@@ -34,6 +37,7 @@ describe('AggregateRouter', () => {
expect(result).toEqual(expected);
});
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
it('get pipeline from Pipeline Operator (Object)', () => {
const body = {
pipeline: {
@@ -45,6 +49,7 @@ describe('AggregateRouter', () => {
expect(result).toEqual(expected);
});
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
it('get pipeline fails multiple keys in Array stage ', () => {
const body = [
{
@@ -59,6 +64,7 @@ describe('AggregateRouter', () => {
}
});
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
it('get pipeline fails multiple keys in Pipeline Operator Array stage ', () => {
const body = {
pipeline: [
@@ -74,4 +80,85 @@ describe('AggregateRouter', () => {
expect(e.message).toBe('Pipeline stages should only have one key found group, match');
}
});
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
it('get search pipeline from Pipeline Operator (Array)', () => {
const body = {
pipeline: {
search: {},
},
};
const expected = [{ $search: {} }];
const result = AggregateRouter.getPipeline(body);
expect(result).toEqual(expected);
});
it('support stage name starting with `$`', () => {
const body = {
$match: { someKey: 'whatever' },
};
const expected = [{ $match: { someKey: 'whatever' } }];
const result = AggregateRouter.getPipeline(body);
expect(result).toEqual(expected);
});
it('support nested stage names starting with `$`', () => {
const body = [
{
lookup: {
from: 'ACollection',
let: { id: '_id' },
as: 'results',
pipeline: [
{
$match: {
$expr: {
$eq: ['$_id', '$$id'],
},
},
},
],
},
},
];
const expected = [
{
$lookup: {
from: 'ACollection',
let: { id: '_id' },
as: 'results',
pipeline: [
{
$match: {
$expr: {
$eq: ['$_id', '$$id'],
},
},
},
],
},
},
];
const result = AggregateRouter.getPipeline(body);
expect(result).toEqual(expected);
});
it('support the use of `_id` in stages', () => {
const body = [
{ match: { _id: 'randomId' } },
{ sort: { _id: -1 } },
{ addFields: { _id: 1 } },
{ group: { _id: {} } },
{ project: { _id: 0 } },
];
const expected = [
{ $match: { _id: 'randomId' } },
{ $sort: { _id: -1 } },
{ $addFields: { _id: 1 } },
{ $group: { _id: {} } },
{ $project: { _id: 0 } },
];
const result = AggregateRouter.getPipeline(body);
expect(result).toEqual(expected);
});
});
+15 -14
View File
@@ -326,22 +326,24 @@ describe('AudiencesRouter', () => {
{ name: 'My Audience', query: JSON.stringify({ deviceType: 'ios' }) },
{ useMasterKey: true }
).then(audience => {
database.collection('test__Audience').updateOne(
{ _id: audience.objectId },
{
$set: {
times_used: 1,
_last_used: now,
},
},
{},
error => {
expect(error).toEqual(null);
database
.collection('test__Audience')
.updateOne(
{ _id: audience.objectId },
{
$set: {
times_used: 1,
_last_used: now,
},
}
)
.then(result => {
expect(result).toBeTruthy();
database
.collection('test__Audience')
.find({ _id: audience.objectId })
.toArray((error, rows) => {
expect(error).toEqual(null);
expect(error).toEqual(undefined);
expect(rows[0]['times_used']).toEqual(1);
expect(rows[0]['_last_used']).toEqual(now);
Parse._request(
@@ -361,8 +363,7 @@ describe('AudiencesRouter', () => {
done.fail(error);
});
});
}
);
});
});
});
+10 -9
View File
@@ -1,3 +1,5 @@
'use strict';
describe('Auth', () => {
const { Auth, getAuthForSessionToken } = require('../lib/Auth.js');
const Config = require('../lib/Config');
@@ -151,7 +153,7 @@ describe('Auth', () => {
});
describe('getRolesForUser', () => {
const rolesNumber = 300;
const rolesNumber = 100;
it('should load all roles without config', async () => {
const user = new Parse.User();
@@ -168,9 +170,9 @@ describe('Auth', () => {
const acl = new Parse.ACL();
const role = new Parse.Role('roleloadtest' + i, acl);
role.getUsers().add([user]);
roles.push(role.save());
roles.push(role);
}
const savedRoles = await Promise.all(roles);
const savedRoles = await Parse.Object.saveAll(roles);
expect(savedRoles.length).toBe(rolesNumber);
const cloudRoles = await userAuth.getRolesForUser();
expect(cloudRoles.length).toBe(rolesNumber);
@@ -192,16 +194,15 @@ describe('Auth', () => {
const acl = new Parse.ACL();
const role = new Parse.Role('roleloadtest' + i, acl);
role.getUsers().add([user]);
roles.push(role.save());
roles.push(role);
}
const savedRoles = await Promise.all(roles);
const savedRoles = await Parse.Object.saveAll(roles);
expect(savedRoles.length).toBe(rolesNumber);
const cloudRoles = await userAuth.getRolesForUser();
expect(cloudRoles.length).toBe(rolesNumber);
});
it('should load all roles for different users with config', async () => {
const rolesNumber = 100;
const user = new Parse.User();
await user.signUp({
username: 'hello',
@@ -229,10 +230,10 @@ describe('Auth', () => {
const role2 = new Parse.Role('role2loadtest' + i, acl2);
role.getUsers().add([user]);
role2.getUsers().add([user2]);
roles.push(role.save());
roles.push(role2.save());
roles.push(role);
roles.push(role2);
}
const savedRoles = await Promise.all(roles);
const savedRoles = await Parse.Object.saveAll(roles);
expect(savedRoles.length).toBe(rolesNumber * 2);
const cloudRoles = await userAuth.getRolesForUser();
const cloudRoles2 = await user2Auth.getRolesForUser();
+415 -3
View File
@@ -5,7 +5,7 @@ const authenticationLoader = require('../lib/Adapters/Auth');
const path = require('path');
const responses = {
gpgames: { playerId: 'userId' },
instagram: { data: { id: 'userId' } },
instagram: { id: 'userId' },
janrainengage: { stat: 'ok', profile: { identifier: 'userId' } },
janraincapture: { stat: 'ok', result: 'userId' },
line: { userId: 'userId' },
@@ -492,7 +492,15 @@ describe('instagram auth adapter', () => {
'https://graph.instagram.com/me?fields=id&access_token=the_token'
);
});
it('response object without data child', async () => {
spyOn(httpsRequest, 'get').and.callFake(() => {
return Promise.resolve({ id: 'userId' });
});
await instagram.validateAuthData({ id: 'userId', access_token: 'the_token' }, {});
expect(httpsRequest.get).toHaveBeenCalledWith(
'https://graph.instagram.com/me?fields=id&access_token=the_token'
);
});
it('should pass in api url', async () => {
spyOn(httpsRequest, 'get').and.callFake(() => {
return Promise.resolve({ data: { id: 'userId' } });
@@ -1699,6 +1707,26 @@ describe('Apple Game Center Auth adapter', () => {
expect(e.message).toBe('Apple Game Center - invalid publicKeyUrl: invalid.com');
}
});
it('validateAuthData invalid public key http url', async () => {
const authData = {
id: 'G:1965586982',
publicKeyUrl: 'http://static.gc.apple.com/public-key/gc-prod-4.cer',
timestamp: 1565257031287,
signature: '1234',
salt: 'DzqqrQ==',
bundleId: 'cloud.xtralife.gamecenterauth',
};
try {
await gcenter.validateAuthData(authData);
fail();
} catch (e) {
expect(e.message).toBe(
'Apple Game Center - invalid publicKeyUrl: http://static.gc.apple.com/public-key/gc-prod-4.cer'
);
}
});
});
describe('phant auth adapter', () => {
@@ -1742,9 +1770,393 @@ describe('microsoft graph auth adapter', () => {
access_token: 'very.long.bad.token',
};
microsoft.validateAuthData(authData).then(done.fail, err => {
expect(err.code).toBe(101);
expect(err.code).toBe(Parse.Error.OBJECT_NOT_FOUND);
expect(err.message).toBe('Microsoft Graph auth is invalid for this user.');
done();
});
});
});
describe('facebook limited auth adapter', () => {
const facebook = require('../lib/Adapters/Auth/facebook');
const jwt = require('jsonwebtoken');
const util = require('util');
// TODO: figure out a way to run this test alongside facebook classic tests
xit('(using client id as string) should throw error with missing id_token', async () => {
try {
await facebook.validateAuthData({}, { clientId: 'secret' });
fail();
} catch (e) {
expect(e.message).toBe('Facebook auth is not configured.');
}
});
// TODO: figure out a way to run this test alongside facebook classic tests
xit('(using client id as array) should throw error with missing id_token', async () => {
try {
await facebook.validateAuthData({}, { clientId: ['secret'] });
fail();
} catch (e) {
expect(e.message).toBe('Facebook auth is not configured.');
}
});
it('should not decode invalid id_token', async () => {
try {
await facebook.validateAuthData(
{ id: 'the_user_id', token: 'the_token' },
{ clientId: 'secret' }
);
fail();
} catch (e) {
expect(e.message).toBe('provided token does not decode as JWT');
}
});
it('should throw error if public key used to encode token is not available', async () => {
const fakeDecodedToken = {
header: { kid: '789', alg: 'RS256' },
};
try {
spyOn(jwt, 'decode').and.callFake(() => fakeDecodedToken);
await facebook.validateAuthData(
{ id: 'the_user_id', token: 'the_token' },
{ clientId: 'secret' }
);
fail();
} catch (e) {
expect(e.message).toBe(
`Unable to find matching key for Key ID: ${fakeDecodedToken.header.kid}`
);
}
});
it('should use algorithm from key header to verify id_token', async () => {
const fakeClaim = {
iss: 'https://facebook.com',
aud: 'secret',
exp: Date.now(),
sub: 'the_user_id',
};
const fakeDecodedToken = {
header: { kid: '123', alg: 'RS256' },
};
spyOn(jwt, 'decode').and.callFake(() => fakeDecodedToken);
spyOn(jwt, 'verify').and.callFake(() => fakeClaim);
const fakeGetSigningKeyAsyncFunction = () => {
return {
kid: '123',
rsaPublicKey: 'the_rsa_public_key',
};
};
spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction);
const result = await facebook.validateAuthData(
{ id: 'the_user_id', token: 'the_token' },
{ clientId: 'secret' }
);
expect(result).toEqual(fakeClaim);
expect(jwt.verify.calls.first().args[2].algorithms).toEqual(fakeDecodedToken.header.alg);
});
it('should not verify invalid id_token', async () => {
const fakeDecodedToken = {
header: { kid: '123', alg: 'RS256' },
};
spyOn(jwt, 'decode').and.callFake(() => fakeDecodedToken);
const fakeGetSigningKeyAsyncFunction = () => {
return {
kid: '123',
rsaPublicKey: 'the_rsa_public_key',
};
};
spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction);
try {
await facebook.validateAuthData(
{ id: 'the_user_id', token: 'the_token' },
{ clientId: 'secret' }
);
fail();
} catch (e) {
expect(e.message).toBe('jwt malformed');
}
});
it('(using client id as array) should not verify invalid id_token', async () => {
try {
await facebook.validateAuthData(
{ id: 'the_user_id', token: 'the_token' },
{ clientId: ['secret'] }
);
fail();
} catch (e) {
expect(e.message).toBe('provided token does not decode as JWT');
}
});
it('(using client id as string) should verify id_token', async () => {
const fakeClaim = {
iss: 'https://facebook.com',
aud: 'secret',
exp: Date.now(),
sub: 'the_user_id',
};
const fakeDecodedToken = {
header: { kid: '123', alg: 'RS256' },
};
spyOn(jwt, 'decode').and.callFake(() => fakeDecodedToken);
const fakeGetSigningKeyAsyncFunction = () => {
return {
kid: '123',
rsaPublicKey: 'the_rsa_public_key',
};
};
spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction);
spyOn(jwt, 'verify').and.callFake(() => fakeClaim);
const result = await facebook.validateAuthData(
{ id: 'the_user_id', token: 'the_token' },
{ clientId: 'secret' }
);
expect(result).toEqual(fakeClaim);
});
it('(using client id as array) should verify id_token', async () => {
const fakeClaim = {
iss: 'https://facebook.com',
aud: 'secret',
exp: Date.now(),
sub: 'the_user_id',
};
const fakeDecodedToken = {
header: { kid: '123', alg: 'RS256' },
};
spyOn(jwt, 'decode').and.callFake(() => fakeDecodedToken);
const fakeGetSigningKeyAsyncFunction = () => {
return {
kid: '123',
rsaPublicKey: 'the_rsa_public_key',
};
};
spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction);
spyOn(jwt, 'verify').and.callFake(() => fakeClaim);
const result = await facebook.validateAuthData(
{ id: 'the_user_id', token: 'the_token' },
{ clientId: ['secret'] }
);
expect(result).toEqual(fakeClaim);
});
it('(using client id as array with multiple items) should verify id_token', async () => {
const fakeClaim = {
iss: 'https://facebook.com',
aud: 'secret',
exp: Date.now(),
sub: 'the_user_id',
};
const fakeDecodedToken = {
header: { kid: '123', alg: 'RS256' },
};
spyOn(jwt, 'decode').and.callFake(() => fakeDecodedToken);
const fakeGetSigningKeyAsyncFunction = () => {
return {
kid: '123',
rsaPublicKey: 'the_rsa_public_key',
};
};
spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction);
spyOn(jwt, 'verify').and.callFake(() => fakeClaim);
const result = await facebook.validateAuthData(
{ id: 'the_user_id', token: 'the_token' },
{ clientId: ['secret', 'secret 123'] }
);
expect(result).toEqual(fakeClaim);
});
it('(using client id as string) should throw error with with invalid jwt issuer', async () => {
const fakeClaim = {
iss: 'https://not.facebook.com',
sub: 'the_user_id',
};
const fakeDecodedToken = {
header: { kid: '123', alg: 'RS256' },
};
spyOn(jwt, 'decode').and.callFake(() => fakeDecodedToken);
const fakeGetSigningKeyAsyncFunction = () => {
return {
kid: '123',
rsaPublicKey: 'the_rsa_public_key',
};
};
spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction);
spyOn(jwt, 'verify').and.callFake(() => fakeClaim);
try {
await facebook.validateAuthData(
{ id: 'the_user_id', token: 'the_token' },
{ clientId: 'secret' }
);
fail();
} catch (e) {
expect(e.message).toBe(
'id token not issued by correct OpenID provider - expected: https://facebook.com | from: https://not.facebook.com'
);
}
});
// TODO: figure out a way to generate our own facebook signed tokens, perhaps with a parse facebook account
// and a private key
xit('(using client id as array) should throw error with with invalid jwt issuer', async () => {
const fakeClaim = {
iss: 'https://not.facebook.com',
sub: 'the_user_id',
};
const fakeDecodedToken = {
header: { kid: '123', alg: 'RS256' },
};
spyOn(jwt, 'decode').and.callFake(() => fakeDecodedToken);
const fakeGetSigningKeyAsyncFunction = () => {
return {
kid: '123',
rsaPublicKey: 'the_rsa_public_key',
};
};
spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction);
spyOn(jwt, 'verify').and.callFake(() => fakeClaim);
try {
await facebook.validateAuthData(
{
id: 'INSERT ID HERE',
token: 'INSERT FACEBOOK TOKEN HERE WITH INVALID JWT ISSUER',
},
{ clientId: ['INSERT CLIENT ID HERE'] }
);
fail();
} catch (e) {
expect(e.message).toBe(
'id token not issued by correct OpenID provider - expected: https://facebook.com | from: https://not.facebook.com'
);
}
});
it('(using client id as string) should throw error with with invalid jwt issuer', async () => {
const fakeClaim = {
iss: 'https://not.facebook.com',
sub: 'the_user_id',
};
const fakeDecodedToken = {
header: { kid: '123', alg: 'RS256' },
};
spyOn(jwt, 'decode').and.callFake(() => fakeDecodedToken);
const fakeGetSigningKeyAsyncFunction = () => {
return {
kid: '123',
rsaPublicKey: 'the_rsa_public_key',
};
};
spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction);
spyOn(jwt, 'verify').and.callFake(() => fakeClaim);
try {
await facebook.validateAuthData(
{
id: 'INSERT ID HERE',
token: 'INSERT FACEBOOK TOKEN HERE WITH INVALID JWT ISSUER',
},
{ clientId: 'INSERT CLIENT ID HERE' }
);
fail();
} catch (e) {
expect(e.message).toBe(
'id token not issued by correct OpenID provider - expected: https://facebook.com | from: https://not.facebook.com'
);
}
});
// TODO: figure out a way to generate our own facebook signed tokens, perhaps with a parse facebook account
// and a private key
xit('(using client id as string) should throw error with invalid jwt clientId', async () => {
try {
await facebook.validateAuthData(
{
id: 'INSERT ID HERE',
token: 'INSERT FACEBOOK TOKEN HERE',
},
{ clientId: 'secret' }
);
fail();
} catch (e) {
expect(e.message).toBe('jwt audience invalid. expected: secret');
}
});
// TODO: figure out a way to generate our own facebook signed tokens, perhaps with a parse facebook account
// and a private key
xit('(using client id as array) should throw error with invalid jwt clientId', async () => {
try {
await facebook.validateAuthData(
{
id: 'INSERT ID HERE',
token: 'INSERT FACEBOOK TOKEN HERE',
},
{ clientId: ['secret'] }
);
fail();
} catch (e) {
expect(e.message).toBe('jwt audience invalid. expected: secret');
}
});
// TODO: figure out a way to generate our own facebook signed tokens, perhaps with a parse facebook account
// and a private key
xit('should throw error with invalid user id', async () => {
try {
await facebook.validateAuthData(
{
id: 'invalid user',
token: 'INSERT FACEBOOK TOKEN HERE',
},
{ clientId: 'INSERT CLIENT ID HERE' }
);
fail();
} catch (e) {
expect(e.message).toBe('auth data is invalid for this user.');
}
});
it('should throw error with with invalid user id', async () => {
const fakeClaim = {
iss: 'https://facebook.com',
aud: 'invalid_client_id',
sub: 'a_different_user_id',
};
const fakeDecodedToken = {
header: { kid: '123', alg: 'RS256' },
};
spyOn(jwt, 'decode').and.callFake(() => fakeDecodedToken);
const fakeGetSigningKeyAsyncFunction = () => {
return {
kid: '123',
rsaPublicKey: 'the_rsa_public_key',
};
};
spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction);
spyOn(jwt, 'verify').and.callFake(() => fakeClaim);
try {
await facebook.validateAuthData(
{ id: 'the_user_id', token: 'the_token' },
{ clientId: 'secret' }
);
fail();
} catch (e) {
expect(e.message).toBe('auth data is invalid for this user.');
}
});
});
+11 -1
View File
@@ -209,8 +209,12 @@ describe('execution', () => {
const binPath = path.resolve(__dirname, '../bin/parse-server');
let childProcess;
afterEach(async () => {
afterEach(done => {
if (childProcess) {
childProcess.on('close', () => {
childProcess = undefined;
done();
});
childProcess.kill();
}
});
@@ -223,6 +227,8 @@ describe('execution', () => {
'test',
'--databaseURI',
'mongodb://localhost/test',
'--port',
'1339',
]);
childProcess.stdout.on('data', data => {
data = data.toString();
@@ -243,6 +249,8 @@ describe('execution', () => {
'test',
'--databaseURI',
'mongodb://localhost/test',
'--port',
'1340',
'--mountGraphQL',
]);
let output = '';
@@ -267,6 +275,8 @@ describe('execution', () => {
'test',
'--databaseURI',
'mongodb://localhost/test',
'--port',
'1341',
'--mountGraphQL',
'--mountPlayground',
]);
+515 -24
View File
@@ -92,9 +92,7 @@ describe('cloud validator', () => {
},
async () => {
await new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
setTimeout(resolve, 1000);
});
throw 'async error';
}
@@ -132,7 +130,7 @@ describe('cloud validator', () => {
await Parse.Cloud.run('myFunction');
});
it('require user on cloud functions', done => {
it('require user on cloud functions', async done => {
Parse.Cloud.define(
'hello1',
() => {
@@ -142,16 +140,14 @@ describe('cloud validator', () => {
requireUser: true,
}
);
Parse.Cloud.run('hello1', {})
.then(() => {
fail('function should have failed.');
})
.catch(error => {
expect(error.code).toEqual(Parse.Error.VALIDATION_ERROR);
expect(error.message).toEqual('Validation failed. Please login to continue.');
done();
});
try {
await Parse.Cloud.run('hello1', {});
fail('function should have failed.');
} catch (error) {
expect(error.code).toEqual(Parse.Error.VALIDATION_ERROR);
expect(error.message).toEqual('Validation failed. Please login to continue.');
done();
}
});
it('require master on cloud functions', done => {
@@ -264,6 +260,24 @@ describe('cloud validator', () => {
});
});
it('set params type allow array', async () => {
Parse.Cloud.define(
'hello',
() => {
return 'Hello world!';
},
{
fields: {
data: {
type: Array,
},
},
}
);
const result = await Parse.Cloud.run('hello', { data: [{ foo: 'bar' }] });
expect(result).toBe('Hello world!');
});
it('set params type', done => {
Parse.Cloud.define(
'hello',
@@ -341,6 +355,117 @@ describe('cloud validator', () => {
});
});
it('set params not-required options data', done => {
Parse.Cloud.define(
'hello',
req => {
expect(req.params.data).toBe('abc');
return 'Hello world!';
},
{
fields: {
data: {
type: String,
required: false,
options: s => {
return s.length >= 4 && s.length <= 50;
},
error: 'Validation failed. Expected length of data to be between 4 and 50.',
},
},
}
);
Parse.Cloud.run('hello', { data: 'abc' })
.then(() => {
fail('function should have failed.');
})
.catch(error => {
expect(error.code).toEqual(Parse.Error.VALIDATION_ERROR);
expect(error.message).toEqual(
'Validation failed. Expected length of data to be between 4 and 50.'
);
done();
});
});
it('set params not-required type', done => {
Parse.Cloud.define(
'hello',
req => {
expect(req.params.data).toBe(null);
return 'Hello world!';
},
{
fields: {
data: {
type: String,
required: false,
},
},
}
);
Parse.Cloud.run('hello', { data: null })
.then(() => {
fail('function should have failed.');
})
.catch(error => {
expect(error.code).toEqual(Parse.Error.VALIDATION_ERROR);
expect(error.message).toEqual('Validation failed. Invalid type for data. Expected: string');
done();
});
});
it('set params not-required options', done => {
Parse.Cloud.define(
'hello',
() => {
return 'Hello world!';
},
{
fields: {
data: {
type: String,
required: false,
options: s => {
return s.length >= 4 && s.length <= 50;
},
},
},
}
);
Parse.Cloud.run('hello', {})
.then(() => {
done();
})
.catch(() => {
fail('function should not have failed.');
});
});
it('set params not-required no-options', done => {
Parse.Cloud.define(
'hello',
() => {
return 'Hello world!';
},
{
fields: {
data: {
type: String,
required: false,
},
},
}
);
Parse.Cloud.run('hello', {})
.then(() => {
done();
})
.catch(() => {
fail('function should not have failed.');
});
});
it('set params option', done => {
Parse.Cloud.define(
'hello',
@@ -587,16 +712,10 @@ describe('cloud validator', () => {
expect(obj.get('foo')).toBe('bar');
const query = new Parse.Query('beforeFind');
try {
const first = await query.first({ useMasterKey: true });
expect(first).toBeDefined();
expect(first.id).toBe(obj.id);
done();
} catch (e) {
console.log(e);
console.log(e.code);
throw e;
}
const first = await query.first({ useMasterKey: true });
expect(first).toBeDefined();
expect(first.id).toBe(obj.id);
done();
});
it('basic beforeDelete skipWithMasterKey', async function (done) {
@@ -860,6 +979,152 @@ describe('cloud validator', () => {
});
});
it('basic validator requireAnyUserRoles', async function (done) {
Parse.Cloud.define(
'cloudFunction',
() => {
return true;
},
{
requireUser: true,
requireAnyUserRoles: ['Admin'],
}
);
const user = await Parse.User.signUp('testuser', 'p@ssword');
try {
await Parse.Cloud.run('cloudFunction');
fail('cloud validator should have failed.');
} catch (e) {
expect(e.message).toBe('Validation failed. User does not match the required roles.');
}
const roleACL = new Parse.ACL();
roleACL.setPublicReadAccess(true);
const role = new Parse.Role('Admin', roleACL);
role.getUsers().add(user);
await role.save({ useMasterKey: true });
await Parse.Cloud.run('cloudFunction');
done();
});
it('basic validator requireAllUserRoles', async function (done) {
Parse.Cloud.define(
'cloudFunction',
() => {
return true;
},
{
requireUser: true,
requireAllUserRoles: ['Admin', 'Admin2'],
}
);
const user = await Parse.User.signUp('testuser', 'p@ssword');
try {
await Parse.Cloud.run('cloudFunction');
fail('cloud validator should have failed.');
} catch (e) {
expect(e.message).toBe('Validation failed. User does not match all the required roles.');
}
const roleACL = new Parse.ACL();
roleACL.setPublicReadAccess(true);
const role = new Parse.Role('Admin', roleACL);
role.getUsers().add(user);
const role2 = new Parse.Role('Admin2', roleACL);
role2.getUsers().add(user);
await role.save({ useMasterKey: true });
await role2.save({ useMasterKey: true });
await Parse.Cloud.run('cloudFunction');
done();
});
it('allow requireAnyUserRoles to be a function', async function (done) {
Parse.Cloud.define(
'cloudFunction',
() => {
return true;
},
{
requireUser: true,
requireAnyUserRoles: () => {
return ['Admin Func'];
},
}
);
const user = await Parse.User.signUp('testuser', 'p@ssword');
try {
await Parse.Cloud.run('cloudFunction');
fail('cloud validator should have failed.');
} catch (e) {
expect(e.message).toBe('Validation failed. User does not match the required roles.');
}
const roleACL = new Parse.ACL();
roleACL.setPublicReadAccess(true);
const role = new Parse.Role('Admin Func', roleACL);
role.getUsers().add(user);
await role.save({ useMasterKey: true });
await Parse.Cloud.run('cloudFunction');
done();
});
it('allow requireAllUserRoles to be a function', async function (done) {
Parse.Cloud.define(
'cloudFunction',
() => {
return true;
},
{
requireUser: true,
requireAllUserRoles: () => {
return ['AdminA', 'AdminB'];
},
}
);
const user = await Parse.User.signUp('testuser', 'p@ssword');
try {
await Parse.Cloud.run('cloudFunction');
fail('cloud validator should have failed.');
} catch (e) {
expect(e.message).toBe('Validation failed. User does not match all the required roles.');
}
const roleACL = new Parse.ACL();
roleACL.setPublicReadAccess(true);
const role = new Parse.Role('AdminA', roleACL);
role.getUsers().add(user);
const role2 = new Parse.Role('AdminB', roleACL);
role2.getUsers().add(user);
await role.save({ useMasterKey: true });
await role2.save({ useMasterKey: true });
await Parse.Cloud.run('cloudFunction');
done();
});
it('basic requireAllUserRoles but no user', async function (done) {
Parse.Cloud.define(
'cloudFunction',
() => {
return true;
},
{
requireAllUserRoles: ['Admin'],
}
);
try {
await Parse.Cloud.run('cloudFunction');
fail('cloud validator should have failed.');
} catch (e) {
expect(e.message).toBe('Validation failed. Please login to continue.');
}
const user = await Parse.User.signUp('testuser', 'p@ssword');
const roleACL = new Parse.ACL();
roleACL.setPublicReadAccess(true);
const role = new Parse.Role('Admin', roleACL);
role.getUsers().add(user);
await role.save({ useMasterKey: true });
await Parse.Cloud.run('cloudFunction');
done();
});
it('basic beforeSave requireMaster', function (done) {
Parse.Cloud.beforeSave('BeforeSaveFail', () => {}, {
requireMaster: true,
@@ -1266,4 +1531,230 @@ describe('cloud validator', () => {
done();
}
});
it('does not log on valid config', () => {
Parse.Cloud.define('myFunction', () => {}, {
requireUser: true,
requireMaster: true,
validateMasterKey: false,
skipWithMasterKey: true,
requireUserKeys: {
Acc: {
constant: true,
options: ['A', 'B'],
required: true,
default: 'f',
error: 'a',
type: String,
},
},
fields: {
Acc: {
constant: true,
options: ['A', 'B'],
required: true,
default: 'f',
error: 'a',
type: String,
},
},
});
});
it('Logs on invalid config', () => {
const fields = [
{
field: 'requiredUser',
value: true,
error: 'requiredUser is not a supported parameter for Cloud Function validations.',
},
{
field: 'requireUser',
value: [],
error:
'Invalid type for Cloud Function validation key requireUser. Expected boolean, actual array',
},
{
field: 'requireMaster',
value: [],
error:
'Invalid type for Cloud Function validation key requireMaster. Expected boolean, actual array',
},
{
field: 'validateMasterKey',
value: [],
error:
'Invalid type for Cloud Function validation key validateMasterKey. Expected boolean, actual array',
},
{
field: 'skipWithMasterKey',
value: [],
error:
'Invalid type for Cloud Function validation key skipWithMasterKey. Expected boolean, actual array',
},
{
field: 'requireAllUserRoles',
value: true,
error:
'Invalid type for Cloud Function validation key requireAllUserRoles. Expected array|function, actual boolean',
},
{
field: 'requireAnyUserRoles',
value: true,
error:
'Invalid type for Cloud Function validation key requireAnyUserRoles. Expected array|function, actual boolean',
},
{
field: 'fields',
value: true,
error:
'Invalid type for Cloud Function validation key fields. Expected array|object, actual boolean',
},
{
field: 'requireUserKeys',
value: true,
error:
'Invalid type for Cloud Function validation key requireUserKeys. Expected array|object, actual boolean',
},
];
for (const field of fields) {
try {
Parse.Cloud.define('myFunction', () => {}, {
[field.field]: field.value,
});
fail(`Expected error registering invalid Cloud Function validation ${field.field}.`);
} catch (e) {
expect(e).toBe(field.error);
}
}
});
it('Logs on invalid config', () => {
const fields = [
{
field: 'otherKey',
value: true,
error: 'otherKey is not a supported parameter for Cloud Function validations.',
},
{
field: 'constant',
value: [],
error:
'Invalid type for Cloud Function validation key constant. Expected boolean, actual array',
},
{
field: 'required',
value: [],
error:
'Invalid type for Cloud Function validation key required. Expected boolean, actual array',
},
{
field: 'error',
value: [],
error:
'Invalid type for Cloud Function validation key error. Expected string, actual array',
},
];
for (const field of fields) {
try {
Parse.Cloud.define('myFunction', () => {}, {
fields: {
name: {
[field.field]: field.value,
},
},
});
fail(`Expected error registering invalid Cloud Function validation ${field.field}.`);
} catch (e) {
expect(e).toBe(field.error);
}
try {
Parse.Cloud.define('myFunction', () => {}, {
requireUserKeys: {
name: {
[field.field]: field.value,
},
},
});
fail(`Expected error registering invalid Cloud Function validation ${field.field}.`);
} catch (e) {
expect(e).toBe(field.error);
}
}
});
it('set params options function async', async () => {
Parse.Cloud.define(
'hello',
() => {
return 'Hello world!';
},
{
fields: {
data: {
type: String,
required: true,
options: async val => {
await new Promise(resolve => {
setTimeout(resolve, 500);
});
return val === 'f';
},
error: 'Validation failed.',
},
},
}
);
try {
await Parse.Cloud.run('hello', { data: 'd' });
fail('validation should have failed');
} catch (error) {
expect(error.code).toEqual(Parse.Error.VALIDATION_ERROR);
expect(error.message).toEqual('Validation failed.');
}
const result = await Parse.Cloud.run('hello', { data: 'f' });
expect(result).toBe('Hello world!');
});
it('basic beforeSave requireUserKey as custom async function', async () => {
Parse.Cloud.beforeSave(Parse.User, () => {}, {
fields: {
accType: {
default: 'normal',
constant: true,
},
},
});
Parse.Cloud.define(
'secureFunction',
() => {
return "Here's all the secure data!";
},
{
requireUserKeys: {
accType: {
options: async val => {
await new Promise(resolve => {
setTimeout(resolve, 500);
});
return ['admin', 'admin2'].includes(val);
},
error: 'Unauthorized.',
},
},
}
);
const user = new Parse.User();
user.set('username', 'testuser');
user.set('password', 'p@ssword');
user.set('accType', 'admin');
await user.signUp();
expect(user.get('accType')).toBe('normal');
try {
await Parse.Cloud.run('secureFunction');
fail('function should only be available to admin users');
} catch (error) {
expect(error.code).toEqual(Parse.Error.VALIDATION_ERROR);
expect(error.message).toEqual('Unauthorized.');
}
});
});
+796 -269
View File
File diff suppressed because it is too large Load Diff
+5 -2
View File
@@ -14,6 +14,7 @@ describe('Cloud Code Logger', () => {
return reconfigureServer({
// useful to flip to false for fine tuning :).
silent: true,
logLevel: undefined,
})
.then(() => {
return Parse.User.signUp('tester', 'abc')
@@ -160,7 +161,7 @@ describe('Cloud Code Logger', () => {
expect(log[0]).toEqual('error');
const error = log[2].error;
expect(error instanceof Parse.Error).toBeTruthy();
expect(error.code).toBe(141);
expect(error.code).toBe(Parse.Error.SCRIPT_FAILED);
expect(error.message).toBe('uh oh!');
done();
});
@@ -198,7 +199,9 @@ describe('Cloud Code Logger', () => {
expect(log[1]).toMatch(
/Failed running cloud function aFunction for user [^ ]* with:\n {2}Input: {"foo":"bar"}\n {2}Error:/
);
const errorString = JSON.stringify(new Parse.Error(141, 'it failed!'));
const errorString = JSON.stringify(
new Parse.Error(Parse.Error.SCRIPT_FAILED, 'it failed!')
);
expect(log[1].indexOf(errorString)).toBeGreaterThan(0);
done();
})
+96
View File
@@ -236,6 +236,57 @@ describe('DatabaseController', function () {
done();
});
it('should not return a $or operation if the query involves one of the two fields also used as array/pointer permissions', done => {
const clp = buildCLP(['users', 'user']);
const query = { a: 'b', user: createUserPointer(USER_ID) };
schemaController.testPermissionsForClassName
.withArgs(CLASS_NAME, ACL_GROUP, OPERATION)
.and.returnValue(false);
schemaController.getClassLevelPermissions.withArgs(CLASS_NAME).and.returnValue(clp);
schemaController.getExpectedType
.withArgs(CLASS_NAME, 'user')
.and.returnValue({ type: 'Pointer' });
schemaController.getExpectedType
.withArgs(CLASS_NAME, 'users')
.and.returnValue({ type: 'Array' });
const output = databaseController.addPointerPermissions(
schemaController,
CLASS_NAME,
OPERATION,
query,
ACL_GROUP
);
expect(output).toEqual({ ...query, user: createUserPointer(USER_ID) });
done();
});
it('should not return a $or operation if the query involves one of the fields also used as array/pointer permissions', done => {
const clp = buildCLP(['user', 'users', 'userObject']);
const query = { a: 'b', user: createUserPointer(USER_ID) };
schemaController.testPermissionsForClassName
.withArgs(CLASS_NAME, ACL_GROUP, OPERATION)
.and.returnValue(false);
schemaController.getClassLevelPermissions.withArgs(CLASS_NAME).and.returnValue(clp);
schemaController.getExpectedType
.withArgs(CLASS_NAME, 'user')
.and.returnValue({ type: 'Pointer' });
schemaController.getExpectedType
.withArgs(CLASS_NAME, 'users')
.and.returnValue({ type: 'Array' });
schemaController.getExpectedType
.withArgs(CLASS_NAME, 'userObject')
.and.returnValue({ type: 'Object' });
const output = databaseController.addPointerPermissions(
schemaController,
CLASS_NAME,
OPERATION,
query,
ACL_GROUP
);
expect(output).toEqual({ ...query, user: createUserPointer(USER_ID) });
done();
});
it('should throw an error if for some unexpected reason the property specified in the CLP is neither a pointer nor an array', done => {
const clp = buildCLP(['user']);
const query = { a: 'b' };
@@ -265,6 +316,51 @@ describe('DatabaseController', function () {
done();
});
});
describe('reduceOperations', function () {
const databaseController = new DatabaseController();
it('objectToEntriesStrings', done => {
const output = databaseController.objectToEntriesStrings({ a: 1, b: 2, c: 3 });
expect(output).toEqual(['"a":1', '"b":2', '"c":3']);
done();
});
it('reduceOrOperation', done => {
expect(databaseController.reduceOrOperation({ a: 1 })).toEqual({ a: 1 });
expect(databaseController.reduceOrOperation({ $or: [{ a: 1 }, { b: 2 }] })).toEqual({
$or: [{ a: 1 }, { b: 2 }],
});
expect(databaseController.reduceOrOperation({ $or: [{ a: 1 }, { a: 2 }] })).toEqual({
$or: [{ a: 1 }, { a: 2 }],
});
expect(databaseController.reduceOrOperation({ $or: [{ a: 1 }, { a: 1 }] })).toEqual({ a: 1 });
expect(
databaseController.reduceOrOperation({ $or: [{ a: 1, b: 2, c: 3 }, { a: 1 }] })
).toEqual({ a: 1 });
expect(
databaseController.reduceOrOperation({ $or: [{ b: 2 }, { a: 1, b: 2, c: 3 }] })
).toEqual({ b: 2 });
done();
});
it('reduceAndOperation', done => {
expect(databaseController.reduceAndOperation({ a: 1 })).toEqual({ a: 1 });
expect(databaseController.reduceAndOperation({ $and: [{ a: 1 }, { b: 2 }] })).toEqual({
$and: [{ a: 1 }, { b: 2 }],
});
expect(databaseController.reduceAndOperation({ $and: [{ a: 1 }, { a: 2 }] })).toEqual({
$and: [{ a: 1 }, { a: 2 }],
});
expect(databaseController.reduceAndOperation({ $and: [{ a: 1 }, { a: 1 }] })).toEqual({
a: 1,
});
expect(
databaseController.reduceAndOperation({ $and: [{ a: 1, b: 2, c: 3 }, { b: 2 }] })
).toEqual({ a: 1, b: 2, c: 3 });
done();
});
});
});
function buildCLP(pointerNames) {
+644
View File
@@ -0,0 +1,644 @@
const { DefinedSchemas } = require('../lib/SchemaMigrations/DefinedSchemas');
const Config = require('../lib/Config');
const cleanUpIndexes = schema => {
if (schema.indexes) {
delete schema.indexes._id_;
if (!Object.keys(schema.indexes).length) {
delete schema.indexes;
}
}
};
describe('DefinedSchemas', () => {
let config;
afterEach(async () => {
config = Config.get('test');
if (config) {
await config.database.adapter.deleteAllClasses();
}
});
describe('Fields', () => {
it('should keep default fields if not provided', async () => {
const server = await reconfigureServer();
// Will perform create
await new DefinedSchemas({ definitions: [{ className: 'Test' }] }, server.config).execute();
let schema = await new Parse.Schema('Test').get();
const expectedFields = {
objectId: { type: 'String' },
createdAt: { type: 'Date' },
updatedAt: { type: 'Date' },
ACL: { type: 'ACL' },
};
expect(schema.fields).toEqual(expectedFields);
await server.config.schemaCache.clear();
// Will perform update
await new DefinedSchemas({ definitions: [{ className: 'Test' }] }, server.config).execute();
schema = await new Parse.Schema('Test').get();
expect(schema.fields).toEqual(expectedFields);
});
it('should protect default fields', async () => {
const server = await reconfigureServer();
const schemas = {
definitions: [
{
className: '_User',
fields: {
email: 'Object',
},
},
{
className: '_Role',
fields: {
users: 'Object',
},
},
{
className: '_Installation',
fields: {
installationId: 'Object',
},
},
{
className: 'Test',
fields: {
createdAt: { type: 'Object' },
objectId: { type: 'Number' },
updatedAt: { type: 'String' },
ACL: { type: 'String' },
},
},
],
};
const expectedFields = {
objectId: { type: 'String' },
createdAt: { type: 'Date' },
updatedAt: { type: 'Date' },
ACL: { type: 'ACL' },
};
const expectedUserFields = {
objectId: { type: 'String' },
createdAt: { type: 'Date' },
updatedAt: { type: 'Date' },
ACL: { type: 'ACL' },
username: { type: 'String' },
password: { type: 'String' },
email: { type: 'String' },
emailVerified: { type: 'Boolean' },
authData: { type: 'Object' },
};
const expectedRoleFields = {
objectId: { type: 'String' },
createdAt: { type: 'Date' },
updatedAt: { type: 'Date' },
ACL: { type: 'ACL' },
name: { type: 'String' },
users: { type: 'Relation', targetClass: '_User' },
roles: { type: 'Relation', targetClass: '_Role' },
};
const expectedInstallationFields = {
objectId: { type: 'String' },
createdAt: { type: 'Date' },
updatedAt: { type: 'Date' },
ACL: { type: 'ACL' },
installationId: { type: 'String' },
deviceToken: { type: 'String' },
channels: { type: 'Array' },
deviceType: { type: 'String' },
pushType: { type: 'String' },
GCMSenderId: { type: 'String' },
timeZone: { type: 'String' },
localeIdentifier: { type: 'String' },
badge: { type: 'Number' },
appVersion: { type: 'String' },
appName: { type: 'String' },
appIdentifier: { type: 'String' },
parseVersion: { type: 'String' },
};
// Perform create
await new DefinedSchemas(schemas, server.config).execute();
let schema = await new Parse.Schema('Test').get();
expect(schema.fields).toEqual(expectedFields);
let userSchema = await new Parse.Schema('_User').get();
expect(userSchema.fields).toEqual(expectedUserFields);
let roleSchema = await new Parse.Schema('_Role').get();
expect(roleSchema.fields).toEqual(expectedRoleFields);
let installationSchema = await new Parse.Schema('_Installation').get();
expect(installationSchema.fields).toEqual(expectedInstallationFields);
await server.config.schemaCache.clear();
// Perform update
await new DefinedSchemas(schemas, server.config).execute();
schema = await new Parse.Schema('Test').get();
expect(schema.fields).toEqual(expectedFields);
userSchema = await new Parse.Schema('_User').get();
expect(userSchema.fields).toEqual(expectedUserFields);
roleSchema = await new Parse.Schema('_Role').get();
expect(roleSchema.fields).toEqual(expectedRoleFields);
installationSchema = await new Parse.Schema('_Installation').get();
expect(installationSchema.fields).toEqual(expectedInstallationFields);
});
it('should create new fields', async () => {
const server = await reconfigureServer();
const fields = {
objectId: { type: 'String' },
createdAt: { type: 'Date' },
updatedAt: { type: 'Date' },
ACL: { type: 'ACL' },
aString: { type: 'String' },
aStringWithDefault: { type: 'String', defaultValue: 'Test' },
aStringWithRequired: { type: 'String', required: true },
aStringWithRequiredAndDefault: { type: 'String', required: true, defaultValue: 'Test' },
aBoolean: { type: 'Boolean' },
aFile: { type: 'File' },
aNumber: { type: 'Number' },
aRelation: { type: 'Relation', targetClass: '_User' },
aPointer: { type: 'Pointer', targetClass: '_Role' },
aDate: { type: 'Date' },
aGeoPoint: { type: 'GeoPoint' },
aPolygon: { type: 'Polygon' },
aArray: { type: 'Array' },
aObject: { type: 'Object' },
};
const schemas = {
definitions: [
{
className: 'Test',
fields,
},
],
};
// Create
await new DefinedSchemas(schemas, server.config).execute();
let schema = await new Parse.Schema('Test').get();
expect(schema.fields).toEqual(fields);
fields.anotherObject = { type: 'Object' };
// Update
await new DefinedSchemas(schemas, server.config).execute();
schema = await new Parse.Schema('Test').get();
expect(schema.fields).toEqual(fields);
});
it('should not delete removed fields when "deleteExtraFields" is false', async () => {
const server = await reconfigureServer();
await new DefinedSchemas(
{ definitions: [{ className: 'Test', fields: { aField: { type: 'String' } } }] },
server.config
).execute();
let schema = await new Parse.Schema('Test').get();
expect(schema.fields.aField).toBeDefined();
await new DefinedSchemas({ definitions: [{ className: 'Test' }] }, server.config).execute();
schema = await new Parse.Schema('Test').get();
expect(schema.fields).toEqual({
objectId: { type: 'String' },
createdAt: { type: 'Date' },
updatedAt: { type: 'Date' },
aField: { type: 'String' },
ACL: { type: 'ACL' },
});
});
it('should delete removed fields when "deleteExtraFields" is true', async () => {
const server = await reconfigureServer();
await new DefinedSchemas(
{
definitions: [{ className: 'Test', fields: { aField: { type: 'String' } } }],
},
server.config
).execute();
let schema = await new Parse.Schema('Test').get();
expect(schema.fields.aField).toBeDefined();
await new DefinedSchemas(
{ deleteExtraFields: true, definitions: [{ className: 'Test' }] },
server.config
).execute();
schema = await new Parse.Schema('Test').get();
expect(schema.fields).toEqual({
objectId: { type: 'String' },
createdAt: { type: 'Date' },
updatedAt: { type: 'Date' },
ACL: { type: 'ACL' },
});
});
it('should re create fields with changed type when "recreateModifiedFields" is true', async () => {
const server = await reconfigureServer();
await new DefinedSchemas(
{ definitions: [{ className: 'Test', fields: { aField: { type: 'String' } } }] },
server.config
).execute();
let schema = await new Parse.Schema('Test').get();
expect(schema.fields.aField).toEqual({ type: 'String' });
const object = new Parse.Object('Test');
await object.save({ aField: 'Hello' }, { useMasterKey: true });
await new DefinedSchemas(
{
recreateModifiedFields: true,
definitions: [{ className: 'Test', fields: { aField: { type: 'Number' } } }],
},
server.config
).execute();
schema = await new Parse.Schema('Test').get();
expect(schema.fields.aField).toEqual({ type: 'Number' });
await object.fetch({ useMasterKey: true });
expect(object.get('aField')).toBeUndefined();
});
it('should not re create fields with changed type when "recreateModifiedFields" is not true', async () => {
const server = await reconfigureServer();
await new DefinedSchemas(
{ definitions: [{ className: 'Test', fields: { aField: { type: 'String' } } }] },
server.config
).execute();
let schema = await new Parse.Schema('Test').get();
expect(schema.fields.aField).toEqual({ type: 'String' });
const object = new Parse.Object('Test');
await object.save({ aField: 'Hello' }, { useMasterKey: true });
await new DefinedSchemas(
{ definitions: [{ className: 'Test', fields: { aField: { type: 'Number' } } }] },
server.config
).execute();
schema = await new Parse.Schema('Test').get();
expect(schema.fields.aField).toEqual({ type: 'String' });
await object.fetch({ useMasterKey: true });
expect(object.get('aField')).toBeDefined();
});
it('should just update classic fields with changed params', async () => {
const server = await reconfigureServer();
await new DefinedSchemas(
{ definitions: [{ className: 'Test', fields: { aField: { type: 'String' } } }] },
server.config
).execute();
let schema = await new Parse.Schema('Test').get();
expect(schema.fields.aField).toEqual({ type: 'String' });
const object = new Parse.Object('Test');
await object.save({ aField: 'Hello' }, { useMasterKey: true });
await new DefinedSchemas(
{
definitions: [
{ className: 'Test', fields: { aField: { type: 'String', required: true } } },
],
},
server.config
).execute();
schema = await new Parse.Schema('Test').get();
expect(schema.fields.aField).toEqual({ type: 'String', required: true });
await object.fetch({ useMasterKey: true });
expect(object.get('aField')).toEqual('Hello');
});
});
describe('Indexes', () => {
it('should create new indexes', async () => {
const server = await reconfigureServer();
const indexes = { complex: { createdAt: 1, updatedAt: 1 } };
const schemas = {
definitions: [{ className: 'Test', fields: { aField: { type: 'String' } }, indexes }],
};
await new DefinedSchemas(schemas, server.config).execute();
let schema = await new Parse.Schema('Test').get();
cleanUpIndexes(schema);
expect(schema.indexes).toEqual(indexes);
indexes.complex2 = { createdAt: 1, aField: 1 };
await new DefinedSchemas(schemas, server.config).execute();
schema = await new Parse.Schema('Test').get();
cleanUpIndexes(schema);
expect(schema.indexes).toEqual(indexes);
});
it('should re create changed indexes', async () => {
const server = await reconfigureServer();
let indexes = { complex: { createdAt: 1, updatedAt: 1 } };
let schemas = { definitions: [{ className: 'Test', indexes }] };
await new DefinedSchemas(schemas, server.config).execute();
indexes = { complex: { createdAt: 1 } };
schemas = { definitions: [{ className: 'Test', indexes }] };
// Change indexes
await new DefinedSchemas(schemas, server.config).execute();
let schema = await new Parse.Schema('Test').get();
cleanUpIndexes(schema);
expect(schema.indexes).toEqual(indexes);
// Update
await new DefinedSchemas(schemas, server.config).execute();
schema = await new Parse.Schema('Test').get();
cleanUpIndexes(schema);
expect(schema.indexes).toEqual(indexes);
});
it('should delete removed indexes', async () => {
const server = await reconfigureServer();
let indexes = { complex: { createdAt: 1, updatedAt: 1 } };
let schemas = { definitions: [{ className: 'Test', indexes }] };
await new DefinedSchemas(schemas, server.config).execute();
indexes = {};
schemas = { definitions: [{ className: 'Test', indexes }] };
// Change indexes
await new DefinedSchemas(schemas, server.config).execute();
let schema = await new Parse.Schema('Test').get();
cleanUpIndexes(schema);
expect(schema.indexes).toBeUndefined();
// Update
await new DefinedSchemas(schemas, server.config).execute();
schema = await new Parse.Schema('Test').get();
cleanUpIndexes(schema);
expect(schema.indexes).toBeUndefined();
});
xit('should keep protected indexes', async () => {
const server = await reconfigureServer();
const expectedIndexes = {
username_1: { username: 1 },
case_insensitive_username: { username: 1 },
email_1: { email: 1 },
case_insensitive_email: { email: 1 },
};
const schemas = {
definitions: [
{
className: '_User',
indexes: {
case_insensitive_username: { password: true },
case_insensitive_email: { password: true },
},
},
{ className: 'Test' },
],
};
// Create
await new DefinedSchemas(schemas, server.config).execute();
let userSchema = await new Parse.Schema('_User').get();
let testSchema = await new Parse.Schema('Test').get();
cleanUpIndexes(userSchema);
cleanUpIndexes(testSchema);
expect(testSchema.indexes).toBeUndefined();
expect(userSchema.indexes).toEqual(expectedIndexes);
// Update
await new DefinedSchemas(schemas, server.config).execute();
userSchema = await new Parse.Schema('_User').get();
testSchema = await new Parse.Schema('Test').get();
cleanUpIndexes(userSchema);
cleanUpIndexes(testSchema);
expect(testSchema.indexes).toBeUndefined();
expect(userSchema.indexes).toEqual(expectedIndexes);
});
});
describe('ClassLevelPermissions', () => {
it('should use default CLP', async () => {
const server = await reconfigureServer();
const schemas = { definitions: [{ className: 'Test' }] };
await new DefinedSchemas(schemas, server.config).execute();
const expectedTestCLP = {
find: {},
count: {},
get: {},
create: {},
update: {},
delete: {},
addField: {},
protectedFields: {},
};
let testSchema = await new Parse.Schema('Test').get();
expect(testSchema.classLevelPermissions).toEqual(expectedTestCLP);
await new DefinedSchemas(schemas, server.config).execute();
testSchema = await new Parse.Schema('Test').get();
expect(testSchema.classLevelPermissions).toEqual(expectedTestCLP);
});
it('should save CLP', async () => {
const server = await reconfigureServer();
const expectedTestCLP = {
find: {},
count: { requiresAuthentication: true },
get: { 'role:Admin': true },
create: { 'role:ARole': true, requiresAuthentication: true },
update: { requiresAuthentication: true },
delete: { requiresAuthentication: true },
addField: {},
protectedFields: { '*': ['aField'], 'role:Admin': ['anotherField'] },
};
const schemas = {
definitions: [
{
className: 'Test',
fields: { aField: { type: 'String' }, anotherField: { type: 'Object' } },
classLevelPermissions: expectedTestCLP,
},
],
};
await new DefinedSchemas(schemas, server.config).execute();
let testSchema = await new Parse.Schema('Test').get();
expect(testSchema.classLevelPermissions).toEqual(expectedTestCLP);
expectedTestCLP.update = {};
expectedTestCLP.create = { requiresAuthentication: true };
await new DefinedSchemas(schemas, server.config).execute();
testSchema = await new Parse.Schema('Test').get();
expect(testSchema.classLevelPermissions).toEqual(expectedTestCLP);
});
it('should force addField to empty', async () => {
const server = await reconfigureServer();
const schemas = {
definitions: [{ className: 'Test', classLevelPermissions: { addField: { '*': true } } }],
};
await new DefinedSchemas(schemas, server.config).execute();
const expectedTestCLP = {
find: {},
count: {},
get: {},
create: {},
update: {},
delete: {},
addField: {},
protectedFields: {},
};
let testSchema = await new Parse.Schema('Test').get();
expect(testSchema.classLevelPermissions).toEqual(expectedTestCLP);
await new DefinedSchemas(schemas, server.config).execute();
testSchema = await new Parse.Schema('Test').get();
expect(testSchema.classLevelPermissions).toEqual(expectedTestCLP);
});
});
it('should not delete automatically classes', async () => {
await reconfigureServer({
schema: { definitions: [{ className: '_User' }, { className: 'Test' }] },
});
await reconfigureServer({ schema: { definitions: [{ className: '_User' }] } });
const schema = await new Parse.Schema('Test').get();
expect(schema.className).toEqual('Test');
});
it('should disable class PUT/POST endpoint when lockSchemas provided to avoid dual source of truth', async () => {
await reconfigureServer({
schema: {
lockSchemas: true,
definitions: [{ className: '_User' }, { className: 'Test' }],
},
});
const schema = await new Parse.Schema('Test').get();
expect(schema.className).toEqual('Test');
const schemas = await Parse.Schema.all();
// Role could be flaky since all system classes are not ensured
// at start up by the DefinedSchema system
expect(schemas.filter(({ className }) => className !== '_Role').length).toEqual(3);
await expectAsync(new Parse.Schema('TheNewTest').save()).toBeRejectedWithError(
'Cannot perform this operation when schemas options is used.'
);
await expectAsync(new Parse.Schema('_User').update()).toBeRejectedWithError(
'Cannot perform this operation when schemas options is used.'
);
});
it('should only enable delete class endpoint since', async () => {
await reconfigureServer({
schema: { definitions: [{ className: '_User' }, { className: 'Test' }] },
});
await reconfigureServer({ schema: { definitions: [{ className: '_User' }] } });
let schemas = await Parse.Schema.all();
expect(schemas.length).toEqual(4);
await new Parse.Schema('_User').delete();
schemas = await Parse.Schema.all();
expect(schemas.length).toEqual(3);
});
it('should run beforeMigration before execution of DefinedSchemas', async () => {
const config = {
schema: {
definitions: [{ className: '_User' }, { className: 'Test' }],
beforeMigration: async () => {},
},
};
const spy = spyOn(config.schema, 'beforeMigration');
await reconfigureServer(config);
expect(spy).toHaveBeenCalledTimes(1);
});
it('should run afterMigration after execution of DefinedSchemas', async () => {
const config = {
schema: {
definitions: [{ className: '_User' }, { className: 'Test' }],
afterMigration: async () => {},
},
};
const spy = spyOn(config.schema, 'afterMigration');
await reconfigureServer(config);
expect(spy).toHaveBeenCalledTimes(1);
});
it('should use logger in case of error', async () => {
const server = await reconfigureServer({ schema: { definitions: [{ className: '_User' }] } });
const error = new Error('A test error');
const logger = require('../lib/logger').logger;
spyOn(DefinedSchemas.prototype, 'wait').and.resolveTo();
spyOn(logger, 'error').and.callThrough();
spyOn(Parse.Schema, 'all').and.callFake(() => {
throw error;
});
await new DefinedSchemas(
{ definitions: [{ className: 'Test', fields: { aField: { type: 'String' } } }] },
server.config
).execute();
expect(logger.error).toHaveBeenCalledWith(`Failed to run migrations: ${error.toString()}`);
});
it('should perform migration in parallel without failing', async () => {
const server = await reconfigureServer();
const logger = require('../lib/logger').logger;
spyOn(logger, 'error').and.callThrough();
const migrationOptions = {
definitions: [
{
className: 'Test',
fields: { aField: { type: 'String' } },
indexes: { aField: { aField: 1 } },
classLevelPermissions: {
create: { requiresAuthentication: true },
},
},
],
};
// Simulate parallel deployment
await Promise.all([
new DefinedSchemas(migrationOptions, server.config).execute(),
new DefinedSchemas(migrationOptions, server.config).execute(),
new DefinedSchemas(migrationOptions, server.config).execute(),
new DefinedSchemas(migrationOptions, server.config).execute(),
new DefinedSchemas(migrationOptions, server.config).execute(),
]);
const testSchema = (await Parse.Schema.all()).find(
({ className }) => className === migrationOptions.definitions[0].className
);
expect(testSchema.indexes.aField).toEqual({ aField: 1 });
expect(testSchema.fields.aField).toEqual({ type: 'String' });
expect(testSchema.classLevelPermissions.create).toEqual({ requiresAuthentication: true });
expect(logger.error).toHaveBeenCalledTimes(0);
});
});
+48
View File
@@ -0,0 +1,48 @@
'use strict';
const Deprecator = require('../lib/Deprecator/Deprecator');
describe('Deprecator', () => {
let deprecations = [];
beforeEach(async () => {
deprecations = [{ optionKey: 'exampleKey', changeNewDefault: 'exampleNewDefault' }];
});
it('deprecations are an array', async () => {
expect(Deprecator._getDeprecations()).toBeInstanceOf(Array);
});
it('logs deprecation for new default', async () => {
deprecations = [{ optionKey: 'exampleKey', changeNewDefault: 'exampleNewDefault' }];
spyOn(Deprecator, '_getDeprecations').and.callFake(() => deprecations);
const logger = require('../lib/logger').logger;
const logSpy = spyOn(logger, 'warn').and.callFake(() => {});
await reconfigureServer();
expect(logSpy.calls.all()[0].args[0]).toEqual(
`DeprecationWarning: The Parse Server option '${deprecations[0].optionKey}' default will change to '${deprecations[0].changeNewDefault}' in a future version.`
);
});
it('does not log deprecation for new default if option is set manually', async () => {
deprecations = [{ optionKey: 'exampleKey', changeNewDefault: 'exampleNewDefault' }];
spyOn(Deprecator, '_getDeprecations').and.callFake(() => deprecations);
const logSpy = spyOn(Deprecator, '_logOption').and.callFake(() => {});
await reconfigureServer({ [deprecations[0].optionKey]: 'manuallySet' });
expect(logSpy).not.toHaveBeenCalled();
});
it('logs runtime deprecation', async () => {
const logger = require('../lib/logger').logger;
const logSpy = spyOn(logger, 'warn').and.callFake(() => {});
const options = { usage: 'Doing this', solution: 'Do that instead.' };
Deprecator.logRuntimeDeprecation(options);
expect(logSpy.calls.all()[0].args[0]).toEqual(
`DeprecationWarning: ${options.usage} is deprecated and will be removed in a future version. ${options.solution}`
);
});
});
+1
View File
@@ -2,6 +2,7 @@ const request = require('../lib/request');
describe('Enable express error handler', () => {
it('should call the default handler in case of error, like updating a non existing object', async done => {
spyOn(console, 'error');
const parseServer = await reconfigureServer(
Object.assign({}, defaultConfiguration, {
enableExpressErrorHandler: true,
-58
View File
@@ -1,58 +0,0 @@
const auth = require('../lib/Auth');
const Config = require('../lib/Config');
const rest = require('../lib/rest');
describe('Enable single schema cache', () => {
beforeEach(done => {
reconfigureServer({
enableSingleSchemaCache: true,
schemaCacheTTL: 30000,
}).then(() => {
done();
});
});
it('can perform multiple create and query operations', done => {
let config = fakeRequestForConfig();
let nobody = auth.nobody(config);
rest
.create(config, nobody, 'Foo', { type: 1 })
.then(() => {
config = fakeRequestForConfig();
nobody = auth.nobody(config);
return rest.create(config, nobody, 'Foo', { type: 2 });
})
.then(() => {
config = fakeRequestForConfig();
nobody = auth.nobody(config);
return rest.create(config, nobody, 'Bar');
})
.then(() => {
config = fakeRequestForConfig();
nobody = auth.nobody(config);
return rest.find(config, nobody, 'Bar', { type: 1 });
})
.then(
() => {
fail('Should throw error');
done();
},
error => {
config = fakeRequestForConfig();
nobody = auth.nobody(config);
expect(error).toBeDefined();
return rest.find(config, nobody, 'Foo', { type: 1 });
}
)
.then(response => {
config = fakeRequestForConfig();
nobody = auth.nobody(config);
expect(response.results.length).toEqual(1);
done();
});
});
});
const fakeRequestForConfig = function () {
return Config.get('test');
};
+24 -22
View File
@@ -3,7 +3,6 @@ const WinstonLoggerAdapter = require('../lib/Adapters/Logger/WinstonLoggerAdapte
.WinstonLoggerAdapter;
const GridFSBucketAdapter = require('../lib/Adapters/Files/GridFSBucketAdapter')
.GridFSBucketAdapter;
const GridStoreAdapter = require('../lib/Adapters/Files/GridStoreAdapter').GridStoreAdapter;
const Config = require('../lib/Config');
const FilesController = require('../lib/Controllers/FilesController').default;
const databaseURI = 'mongodb://localhost:27017/parse';
@@ -24,8 +23,8 @@ const mockAdapter = {
describe('FilesController', () => {
it('should properly expand objects', done => {
const config = Config.get(Parse.applicationId);
const gridStoreAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse');
const filesController = new FilesController(gridStoreAdapter);
const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse');
const filesController = new FilesController(gridFSAdapter);
const result = filesController.expandFilesInObject(config, function () {});
expect(result).toBeUndefined();
@@ -80,24 +79,27 @@ describe('FilesController', () => {
expect(typeof error).toBe('object');
expect(error.message.indexOf('biscuit')).toBe(13);
expect(error.code).toBe(Parse.Error.INVALID_FILE_NAME);
mockAdapter.validateFilename = () => {
return null;
};
done();
});
it('should add a unique hash to the file name when the preserveFileName option is false', done => {
const config = Config.get(Parse.applicationId);
const gridStoreAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse');
spyOn(gridStoreAdapter, 'createFile');
gridStoreAdapter.createFile.and.returnValue(Promise.resolve());
const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse');
spyOn(gridFSAdapter, 'createFile');
gridFSAdapter.createFile.and.returnValue(Promise.resolve());
const fileName = 'randomFileName.pdf';
const regexEscapedFileName = fileName.replace(/\./g, '\\$&');
const filesController = new FilesController(gridStoreAdapter, null, {
const filesController = new FilesController(gridFSAdapter, null, {
preserveFileName: false,
});
filesController.createFile(config, fileName);
expect(gridStoreAdapter.createFile).toHaveBeenCalledTimes(1);
expect(gridStoreAdapter.createFile.calls.mostRecent().args[0]).toMatch(
expect(gridFSAdapter.createFile).toHaveBeenCalledTimes(1);
expect(gridFSAdapter.createFile.calls.mostRecent().args[0]).toMatch(
`^.{32}_${regexEscapedFileName}$`
);
@@ -106,42 +108,42 @@ describe('FilesController', () => {
it('should not add a unique hash to the file name when the preserveFileName option is true', done => {
const config = Config.get(Parse.applicationId);
const gridStoreAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse');
spyOn(gridStoreAdapter, 'createFile');
gridStoreAdapter.createFile.and.returnValue(Promise.resolve());
const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse');
spyOn(gridFSAdapter, 'createFile');
gridFSAdapter.createFile.and.returnValue(Promise.resolve());
const fileName = 'randomFileName.pdf';
const filesController = new FilesController(gridStoreAdapter, null, {
const filesController = new FilesController(gridFSAdapter, null, {
preserveFileName: true,
});
filesController.createFile(config, fileName);
expect(gridStoreAdapter.createFile).toHaveBeenCalledTimes(1);
expect(gridStoreAdapter.createFile.calls.mostRecent().args[0]).toEqual(fileName);
expect(gridFSAdapter.createFile).toHaveBeenCalledTimes(1);
expect(gridFSAdapter.createFile.calls.mostRecent().args[0]).toEqual(fileName);
done();
});
it('should handle adapter without getMetadata', async () => {
const gridStoreAdapter = new GridFSBucketAdapter(databaseURI);
gridStoreAdapter.getMetadata = null;
const filesController = new FilesController(gridStoreAdapter);
const gridFSAdapter = new GridFSBucketAdapter(databaseURI);
gridFSAdapter.getMetadata = null;
const filesController = new FilesController(gridFSAdapter);
const result = await filesController.getMetadata();
expect(result).toEqual({});
});
it('should reject slashes in file names', done => {
const gridStoreAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse');
const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse');
const fileName = 'foo/randomFileName.pdf';
expect(gridStoreAdapter.validateFilename(fileName)).not.toBe(null);
expect(gridFSAdapter.validateFilename(fileName)).not.toBe(null);
done();
});
it('should also reject slashes in file names', done => {
const gridStoreAdapter = new GridStoreAdapter('mongodb://localhost:27017/parse');
const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse');
const fileName = 'foo/randomFileName.pdf';
expect(gridStoreAdapter.validateFilename(fileName)).not.toBe(null);
expect(gridFSAdapter.validateFilename(fileName)).not.toBe(null);
done();
});
});
+6 -19
View File
@@ -1,10 +1,8 @@
const GridStoreAdapter = require('../lib/Adapters/Files/GridStoreAdapter').GridStoreAdapter;
const GridFSBucketAdapter = require('../lib/Adapters/Files/GridFSBucketAdapter')
.GridFSBucketAdapter;
const { randomString } = require('../lib/cryptoUtils');
const databaseURI = 'mongodb://localhost:27017/parse';
const request = require('../lib/request');
const Config = require('../lib/Config');
async function expectMissingFile(gfsAdapter, name) {
try {
@@ -15,25 +13,13 @@ async function expectMissingFile(gfsAdapter, name) {
}
}
describe_only_db('mongo')('GridFSBucket and GridStore interop', () => {
describe_only_db('mongo')('GridFSBucket', () => {
beforeEach(async () => {
const gsAdapter = new GridStoreAdapter(databaseURI);
const gsAdapter = new GridFSBucketAdapter(databaseURI);
const db = await gsAdapter._connect();
await db.dropDatabase();
});
it('a file created in GridStore should be available in GridFS', async () => {
const gsAdapter = new GridStoreAdapter(databaseURI);
const gfsAdapter = new GridFSBucketAdapter(databaseURI);
await expectMissingFile(gfsAdapter, 'myFileName');
const originalString = 'abcdefghi';
await gsAdapter.createFile('myFileName', originalString);
const gsResult = await gsAdapter.getFileData('myFileName');
expect(gsResult.toString('utf8')).toBe(originalString);
const gfsResult = await gfsAdapter.getFileData('myFileName');
expect(gfsResult.toString('utf8')).toBe(originalString);
});
it('should save an encrypted file that can only be decrypted by a GridFS adapter with the encryptionKey', async () => {
const unencryptedAdapter = new GridFSBucketAdapter(databaseURI);
const encryptedAdapter = new GridFSBucketAdapter(
@@ -395,8 +381,9 @@ describe_only_db('mongo')('GridFSBucket and GridStore interop', () => {
});
it('should handle getMetadata error', async () => {
const config = Config.get('test');
config.filesController.getMetadata = () => Promise.reject();
const gfsAdapter = new GridFSBucketAdapter(databaseURI);
await reconfigureServer({ filesAdapter: gfsAdapter });
gfsAdapter.getMetadata = () => Promise.reject();
const headers = {
'X-Parse-Application-Id': 'test',
@@ -451,7 +438,7 @@ describe_only_db('mongo')('GridFSBucket and GridStore interop', () => {
await db.admin().serverStatus();
expect(false).toBe(true);
} catch (e) {
expect(e.message).toEqual('topology was destroyed');
expect(e.message).toEqual('MongoClient must be connected to perform this operation');
}
});
});
-111
View File
@@ -1,111 +0,0 @@
const MongoClient = require('mongodb').MongoClient;
const GridStore = require('mongodb').GridStore;
const GridStoreAdapter = require('../lib/Adapters/Files/GridStoreAdapter').GridStoreAdapter;
const Config = require('../lib/Config');
const FilesController = require('../lib/Controllers/FilesController').default;
// Small additional tests to improve overall coverage
describe_only_db('mongo')('GridStoreAdapter', () => {
it('should properly instanciate the GridStore when deleting a file', async done => {
const databaseURI = 'mongodb://localhost:27017/parse';
const config = Config.get(Parse.applicationId);
const gridStoreAdapter = new GridStoreAdapter(databaseURI);
const db = await gridStoreAdapter._connect();
await db.dropDatabase();
const filesController = new FilesController(gridStoreAdapter, Parse.applicationId, {});
// save original unlink before redefinition
const originalUnlink = GridStore.prototype.unlink;
let gridStoreMode;
// new unlink method that will capture the mode in which GridStore was opened
GridStore.prototype.unlink = function () {
// restore original unlink during first call
GridStore.prototype.unlink = originalUnlink;
gridStoreMode = this.mode;
return originalUnlink.call(this);
};
filesController
.createFile(config, 'myFilename.txt', 'my file content', 'text/plain')
.then(myFile => {
return MongoClient.connect(databaseURI)
.then(client => {
const database = client.db(client.s.options.dbName);
// Verify the existance of the fs.files document
return database
.collection('fs.files')
.count()
.then(count => {
expect(count).toEqual(1);
return { database, client };
});
})
.then(({ database, client }) => {
// Verify the existance of the fs.files document
return database
.collection('fs.chunks')
.count()
.then(count => {
expect(count).toEqual(1);
return client.close();
});
})
.then(() => {
return filesController.deleteFile(config, myFile.name);
});
})
.then(() => {
return MongoClient.connect(databaseURI)
.then(client => {
const database = client.db(client.s.options.dbName);
// Verify the existance of the fs.files document
return database
.collection('fs.files')
.count()
.then(count => {
expect(count).toEqual(0);
return { database, client };
});
})
.then(({ database, client }) => {
// Verify the existance of the fs.files document
return database
.collection('fs.chunks')
.count()
.then(count => {
expect(count).toEqual(0);
return client.close();
});
});
})
.then(() => {
// Verify that gridStore was opened in read only mode
expect(gridStoreMode).toEqual('r');
done();
})
.catch(fail);
});
it('handleShutdown, close connection', async () => {
const databaseURI = 'mongodb://localhost:27017/parse';
const gridStoreAdapter = new GridStoreAdapter(databaseURI);
const db = await gridStoreAdapter._connect();
const status = await db.admin().serverStatus();
expect(status.connections.current > 0).toEqual(true);
await gridStoreAdapter.handleShutdown();
try {
await db.admin().serverStatus();
expect(false).toBe(true);
} catch (e) {
expect(e.message).toEqual('topology was destroyed');
}
});
});
+91 -113
View File
@@ -6,7 +6,7 @@ const httpRequest = require('../lib/cloud-code/httpRequest'),
express = require('express');
const port = 13371;
const httpRequestServer = 'http://localhost:' + port;
const httpRequestServer = `http://localhost:${port}`;
function startServer(done) {
const app = express();
@@ -39,175 +39,148 @@ function startServer(done) {
describe('httpRequest', () => {
let server;
beforeAll(done => {
server = startServer(done);
beforeEach(done => {
if (!server) {
server = startServer(done);
} else {
done();
}
});
afterAll(done => {
server.close(done);
});
it('should do /hello', done => {
httpRequest({
url: httpRequestServer + '/hello',
}).then(function (httpResponse) {
expect(httpResponse.status).toBe(200);
expect(httpResponse.buffer).toEqual(new Buffer('{"response":"OK"}'));
expect(httpResponse.text).toEqual('{"response":"OK"}');
expect(httpResponse.data.response).toEqual('OK');
done();
}, done.fail);
it('should do /hello', async () => {
const httpResponse = await httpRequest({
url: `${httpRequestServer}/hello`,
});
expect(httpResponse.status).toBe(200);
expect(httpResponse.buffer).toEqual(Buffer.from('{"response":"OK"}'));
expect(httpResponse.text).toEqual('{"response":"OK"}');
expect(httpResponse.data.response).toEqual('OK');
});
it('should do not follow redirects by default', done => {
httpRequest({
url: httpRequestServer + '/301',
}).then(function (httpResponse) {
expect(httpResponse.status).toBe(301);
done();
}, done.fail);
it('should do not follow redirects by default', async () => {
const httpResponse = await httpRequest({
url: `${httpRequestServer}/301`,
});
expect(httpResponse.status).toBe(301);
});
it('should follow redirects when set', done => {
httpRequest({
url: httpRequestServer + '/301',
it('should follow redirects when set', async () => {
const httpResponse = await httpRequest({
url: `${httpRequestServer}/301`,
followRedirects: true,
}).then(function (httpResponse) {
expect(httpResponse.status).toBe(200);
expect(httpResponse.buffer).toEqual(new Buffer('{"response":"OK"}'));
expect(httpResponse.text).toEqual('{"response":"OK"}');
expect(httpResponse.data.response).toEqual('OK');
done();
}, done.fail);
});
expect(httpResponse.status).toBe(200);
expect(httpResponse.buffer).toEqual(Buffer.from('{"response":"OK"}'));
expect(httpResponse.text).toEqual('{"response":"OK"}');
expect(httpResponse.data.response).toEqual('OK');
});
it('should fail on 404', done => {
let calls = 0;
httpRequest({
url: httpRequestServer + '/404',
}).then(
function () {
calls++;
fail('should not succeed');
done();
},
function (httpResponse) {
calls++;
expect(calls).toBe(1);
expect(httpResponse.status).toBe(404);
expect(httpResponse.buffer).toEqual(new Buffer('NO'));
expect(httpResponse.text).toEqual('NO');
expect(httpResponse.data).toBe(undefined);
done();
}
it('should fail on 404', async () => {
await expectAsync(
httpRequest({
url: `${httpRequestServer}/404`,
})
).toBeRejectedWith(
jasmine.objectContaining({
status: 404,
buffer: Buffer.from('NO'),
text: 'NO',
data: undefined,
})
);
});
it('should post on echo', done => {
httpRequest({
it('should post on echo', async () => {
const httpResponse = await httpRequest({
method: 'POST',
url: httpRequestServer + '/echo',
url: `${httpRequestServer}/echo`,
body: {
foo: 'bar',
},
headers: {
'Content-Type': 'application/json',
},
}).then(
function (httpResponse) {
expect(httpResponse.status).toBe(200);
expect(httpResponse.data).toEqual({ foo: 'bar' });
done();
},
function () {
fail('should not fail');
done();
}
);
});
expect(httpResponse.status).toBe(200);
expect(httpResponse.data).toEqual({ foo: 'bar' });
});
it('should encode a query string body by default', done => {
it('should encode a query string body by default', () => {
const options = {
body: { foo: 'bar' },
};
const result = httpRequest.encodeBody(options);
expect(result.body).toEqual('foo=bar');
expect(result.headers['Content-Type']).toEqual('application/x-www-form-urlencoded');
done();
});
it('should encode a JSON body', done => {
it('should encode a JSON body', () => {
const options = {
body: { foo: 'bar' },
headers: { 'Content-Type': 'application/json' },
};
const result = httpRequest.encodeBody(options);
expect(result.body).toEqual('{"foo":"bar"}');
done();
});
it('should encode a www-form body', done => {
it('should encode a www-form body', () => {
const options = {
body: { foo: 'bar', bar: 'baz' },
headers: { 'cOntent-tYpe': 'application/x-www-form-urlencoded' },
};
const result = httpRequest.encodeBody(options);
expect(result.body).toEqual('foo=bar&bar=baz');
done();
});
it('should not encode a wrong content type', done => {
it('should not encode a wrong content type', () => {
const options = {
body: { foo: 'bar', bar: 'baz' },
headers: { 'cOntent-tYpe': 'mime/jpeg' },
};
const result = httpRequest.encodeBody(options);
expect(result.body).toEqual({ foo: 'bar', bar: 'baz' });
done();
});
it('should fail gracefully', done => {
httpRequest({
url: 'http://not a good url',
}).then(done.fail, function (error) {
expect(error).not.toBeUndefined();
expect(error).not.toBeNull();
done();
});
it('should fail gracefully', async () => {
await expectAsync(
httpRequest({
url: 'http://not a good url',
})
).toBeRejected();
});
it('should params object to query string', done => {
httpRequest({
url: httpRequestServer + '/qs',
it('should params object to query string', async () => {
const httpResponse = await httpRequest({
url: `${httpRequestServer}/qs`,
params: {
foo: 'bar',
},
}).then(
function (httpResponse) {
expect(httpResponse.status).toBe(200);
expect(httpResponse.data).toEqual({ foo: 'bar' });
done();
},
function () {
fail('should not fail');
done();
}
);
});
expect(httpResponse.status).toBe(200);
expect(httpResponse.data).toEqual({ foo: 'bar' });
});
it('should params string to query string', done => {
httpRequest({
url: httpRequestServer + '/qs',
it('should params string to query string', async () => {
const httpResponse = await httpRequest({
url: `${httpRequestServer}/qs`,
params: 'foo=bar&foo2=bar2',
}).then(
function (httpResponse) {
expect(httpResponse.status).toBe(200);
expect(httpResponse.data).toEqual({ foo: 'bar', foo2: 'bar2' });
done();
},
function () {
fail('should not fail');
done();
}
);
});
expect(httpResponse.status).toBe(200);
expect(httpResponse.data).toEqual({ foo: 'bar', foo2: 'bar2' });
});
it('should not crash with undefined body', () => {
@@ -226,6 +199,7 @@ describe('httpRequest', () => {
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);
@@ -247,43 +221,47 @@ describe('httpRequest', () => {
});
it('serialized httpResponse correctly with body buffer string', () => {
const httpResponse = new HTTPResponse({}, new Buffer('hello'));
const httpResponse = new HTTPResponse({}, Buffer.from('hello'));
expect(httpResponse.text).toBe('hello');
expect(httpResponse.data).toBe(undefined);
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', () => {
const json = '{"foo":"bar"}';
const httpResponse = new HTTPResponse({}, new Buffer(json));
const httpResponse = new HTTPResponse({}, Buffer.from(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', () => {
const json = '{"foo":"bar"}';
const httpResponse = new HTTPResponse({}, new Buffer(json));
const httpResponse = new HTTPResponse({}, Buffer.from(json));
const encoded = Parse._encode(httpResponse);
let foundData,
foundText,
foundBody = false;
for (const key in encoded) {
if (key == 'data') {
if (key === 'data') {
foundData = true;
}
if (key == 'text') {
if (key === 'text') {
foundText = true;
}
if (key == 'body') {
if (key === 'body') {
foundBody = true;
}
}
expect(foundData).toBe(true);
expect(foundText).toBe(true);
expect(foundBody).toBe(false);
+34 -4
View File
@@ -6,11 +6,14 @@ const rest = require('../lib/rest');
const auth = require('../lib/Auth');
const uuid = require('uuid');
describe_only_db('mongo')('Idempotency', () => {
describe('Idempotency', () => {
// Parameters
/** Enable TTL expiration simulated by removing entry instead of waiting for MongoDB TTL monitor which
runs only every 60s, so it can take up to 119s until entry removal - ain't nobody got time for that */
const SIMULATE_TTL = true;
const ttl = 2;
const maxTimeOut = 4000;
// Helpers
async function deleteRequestEntry(reqId) {
const config = Config.get(Parse.applicationId);
@@ -38,9 +41,10 @@ describe_only_db('mongo')('Idempotency', () => {
}
await setup({
paths: ['functions/.*', 'jobs/.*', 'classes/.*', 'users', 'installations'],
ttl: 30,
ttl: ttl,
});
});
// Tests
it('should enforce idempotency for cloud code function', async () => {
let counter = 0;
@@ -56,7 +60,7 @@ describe_only_db('mongo')('Idempotency', () => {
'X-Parse-Request-Id': 'abc-123',
},
};
expect(Config.get(Parse.applicationId).idempotencyOptions.ttl).toBe(30);
expect(Config.get(Parse.applicationId).idempotencyOptions.ttl).toBe(ttl);
await request(params);
await request(params).then(fail, e => {
expect(e.status).toEqual(400);
@@ -83,12 +87,38 @@ describe_only_db('mongo')('Idempotency', () => {
if (SIMULATE_TTL) {
await deleteRequestEntry('abc-123');
} else {
await new Promise(resolve => setTimeout(resolve, 130000));
await new Promise(resolve => setTimeout(resolve, maxTimeOut));
}
await expectAsync(request(params)).toBeResolved();
expect(counter).toBe(2);
});
it_only_db('postgres')(
'should delete request entry when postgress ttl function is called',
async () => {
const client = Config.get(Parse.applicationId).database.adapter._client;
let counter = 0;
Parse.Cloud.define('myFunction', () => {
counter++;
});
const params = {
method: 'POST',
url: 'http://localhost:8378/1/functions/myFunction',
headers: {
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-Master-Key': Parse.masterKey,
'X-Parse-Request-Id': 'abc-123',
},
};
await expectAsync(request(params)).toBeResolved();
await expectAsync(request(params)).toBeRejected();
await new Promise(resolve => setTimeout(resolve, maxTimeOut));
await client.one('SELECT idempotency_delete_expired_records()');
await expectAsync(request(params)).toBeResolved();
expect(counter).toBe(2);
}
);
it('should enforce idempotency for cloud code jobs', async () => {
let counter = 0;
Parse.Cloud.job('myJob', () => {
+99 -146
View File
@@ -1,56 +1,49 @@
const ldap = require('../lib/Adapters/Auth/ldap');
const mockLdapServer = require('./MockLdapServer');
const mockLdapServer = require('./support/MockLdapServer');
const fs = require('fs');
const port = 12345;
const sslport = 12346;
it('Should fail with missing options', done => {
ldap
.validateAuthData({ id: 'testuser', password: 'testpw' })
.then(done.fail)
.catch(err => {
jequal(err.message, 'LDAP auth configuration missing');
done();
});
});
describe('Ldap Auth', () => {
it('Should fail with missing options', done => {
ldap
.validateAuthData({ id: 'testuser', password: 'testpw' })
.then(done.fail)
.catch(err => {
jequal(err.message, 'LDAP auth configuration missing');
done();
});
});
it('Should return a resolved promise when validating the app id', done => {
ldap.validateAppId().then(done).catch(done.fail);
});
it('Should return a resolved promise when validating the app id', done => {
ldap.validateAppId().then(done).catch(done.fail);
});
it('Should succeed with right credentials', done => {
mockLdapServer(port, 'uid=testuser, o=example').then(server => {
it('Should succeed with right credentials', async done => {
const server = await mockLdapServer(port, 'uid=testuser, o=example');
const options = {
suffix: 'o=example',
url: `ldap://localhost:${port}`,
dn: 'uid={{id}}, o=example',
};
ldap
.validateAuthData({ id: 'testuser', password: 'secret' }, options)
.then(done)
.catch(done.fail)
.finally(() => server.close());
await ldap.validateAuthData({ id: 'testuser', password: 'secret' }, options);
server.close(done);
});
});
it('Should succeed with right credentials when LDAPS is used and certifcate is not checked', done => {
mockLdapServer(sslport, 'uid=testuser, o=example', false, true).then(server => {
it('Should succeed with right credentials when LDAPS is used and certifcate is not checked', async done => {
const server = await mockLdapServer(sslport, 'uid=testuser, o=example', false, true);
const options = {
suffix: 'o=example',
url: `ldaps://localhost:${sslport}`,
dn: 'uid={{id}}, o=example',
tlsOptions: { rejectUnauthorized: false },
};
ldap
.validateAuthData({ id: 'testuser', password: 'secret' }, options)
.then(done)
.catch(done.fail)
.finally(() => server.close());
await ldap.validateAuthData({ id: 'testuser', password: 'secret' }, options);
server.close(done);
});
});
it('Should succeed when LDAPS is used and the presented certificate is the expected certificate', done => {
mockLdapServer(sslport, 'uid=testuser, o=example', false, true).then(server => {
it('Should succeed when LDAPS is used and the presented certificate is the expected certificate', async done => {
const server = await mockLdapServer(sslport, 'uid=testuser, o=example', false, true);
const options = {
suffix: 'o=example',
url: `ldaps://localhost:${sslport}`,
@@ -60,16 +53,12 @@ it('Should succeed when LDAPS is used and the presented certificate is the expec
rejectUnauthorized: true,
},
};
ldap
.validateAuthData({ id: 'testuser', password: 'secret' }, options)
.then(done)
.catch(done.fail)
.finally(() => server.close());
await ldap.validateAuthData({ id: 'testuser', password: 'secret' }, options);
server.close(done);
});
});
it('Should fail when LDAPS is used and the presented certificate is not the expected certificate', done => {
mockLdapServer(sslport, 'uid=testuser, o=example', false, true).then(server => {
it('Should fail when LDAPS is used and the presented certificate is not the expected certificate', async done => {
const server = await mockLdapServer(sslport, 'uid=testuser, o=example', false, true);
const options = {
suffix: 'o=example',
url: `ldaps://localhost:${sslport}`,
@@ -79,19 +68,17 @@ it('Should fail when LDAPS is used and the presented certificate is not the expe
rejectUnauthorized: true,
},
};
ldap
.validateAuthData({ id: 'testuser', password: 'secret' }, options)
.then(done.fail)
.catch(err => {
jequal(err.message, 'LDAPS: Certificate mismatch');
done();
})
.finally(() => server.close());
try {
await ldap.validateAuthData({ id: 'testuser', password: 'secret' }, options);
fail();
} catch (err) {
expect(err.message).toBe('LDAPS: Certificate mismatch');
}
server.close(done);
});
});
it('Should fail when LDAPS is used certifcate matches but credentials are wrong', done => {
mockLdapServer(sslport, 'uid=testuser, o=example', false, true).then(server => {
it('Should fail when LDAPS is used certifcate matches but credentials are wrong', async done => {
const server = await mockLdapServer(sslport, 'uid=testuser, o=example', false, true);
const options = {
suffix: 'o=example',
url: `ldaps://localhost:${sslport}`,
@@ -101,37 +88,33 @@ it('Should fail when LDAPS is used certifcate matches but credentials are wrong'
rejectUnauthorized: true,
},
};
ldap
.validateAuthData({ id: 'testuser', password: 'wrong!' }, options)
.then(done.fail)
.catch(err => {
jequal(err.message, 'LDAP: Wrong username or password');
done();
})
.finally(() => server.close());
try {
await ldap.validateAuthData({ id: 'testuser', password: 'wrong!' }, options);
fail();
} catch (err) {
expect(err.message).toBe('LDAP: Wrong username or password');
}
server.close(done);
});
});
it('Should fail with wrong credentials', done => {
mockLdapServer(port, 'uid=testuser, o=example').then(server => {
it('Should fail with wrong credentials', async done => {
const server = await mockLdapServer(port, 'uid=testuser, o=example');
const options = {
suffix: 'o=example',
url: `ldap://localhost:${port}`,
dn: 'uid={{id}}, o=example',
};
ldap
.validateAuthData({ id: 'testuser', password: 'wrong!' }, options)
.then(done.fail)
.catch(err => {
jequal(err.message, 'LDAP: Wrong username or password');
done();
})
.finally(() => server.close());
try {
await ldap.validateAuthData({ id: 'testuser', password: 'wrong!' }, options);
fail();
} catch (err) {
expect(err.message).toBe('LDAP: Wrong username or password');
}
server.close(done);
});
});
it('Should succeed if user is in given group', done => {
mockLdapServer(port, 'uid=testuser, o=example').then(server => {
it('Should succeed if user is in given group', async done => {
const server = await mockLdapServer(port, 'uid=testuser, o=example');
const options = {
suffix: 'o=example',
url: `ldap://localhost:${port}`,
@@ -139,17 +122,12 @@ it('Should succeed if user is in given group', done => {
groupCn: 'powerusers',
groupFilter: '(&(uniqueMember=uid={{id}}, o=example)(objectClass=groupOfUniqueNames))',
};
ldap
.validateAuthData({ id: 'testuser', password: 'secret' }, options)
.then(done)
.catch(done.fail)
.finally(() => server.close());
await ldap.validateAuthData({ id: 'testuser', password: 'secret' }, options);
server.close(done);
});
});
it('Should fail if user is not in given group', done => {
mockLdapServer(port, 'uid=testuser, o=example').then(server => {
it('Should fail if user is not in given group', async done => {
const server = await mockLdapServer(port, 'uid=testuser, o=example');
const options = {
suffix: 'o=example',
url: `ldap://localhost:${port}`,
@@ -157,20 +135,17 @@ it('Should fail if user is not in given group', done => {
groupCn: 'groupTheUserIsNotIn',
groupFilter: '(&(uniqueMember=uid={{id}}, o=example)(objectClass=groupOfUniqueNames))',
};
ldap
.validateAuthData({ id: 'testuser', password: 'secret' }, options)
.then(done.fail)
.catch(err => {
jequal(err.message, 'LDAP: User not in group');
done();
})
.finally(() => server.close());
try {
await ldap.validateAuthData({ id: 'testuser', password: 'secret' }, options);
fail();
} catch (err) {
expect(err.message).toBe('LDAP: User not in group');
}
server.close(done);
});
});
it('Should fail if the LDAP server does not allow searching inside the provided suffix', done => {
mockLdapServer(port, 'uid=testuser, o=example').then(server => {
it('Should fail if the LDAP server does not allow searching inside the provided suffix', async done => {
const server = await mockLdapServer(port, 'uid=testuser, o=example');
const options = {
suffix: 'o=invalid',
url: `ldap://localhost:${port}`,
@@ -178,20 +153,17 @@ it('Should fail if the LDAP server does not allow searching inside the provided
groupCn: 'powerusers',
groupFilter: '(&(uniqueMember=uid={{id}}, o=example)(objectClass=groupOfUniqueNames))',
};
ldap
.validateAuthData({ id: 'testuser', password: 'secret' }, options)
.then(done.fail)
.catch(err => {
jequal(err.message, 'LDAP group search failed');
done();
})
.finally(() => server.close());
try {
await ldap.validateAuthData({ id: 'testuser', password: 'secret' }, options);
fail();
} catch (err) {
expect(err.message).toBe('LDAP group search failed');
}
server.close(done);
});
});
it('Should fail if the LDAP server encounters an error while searching', done => {
mockLdapServer(port, 'uid=testuser, o=example', true).then(server => {
it('Should fail if the LDAP server encounters an error while searching', async done => {
const server = await mockLdapServer(port, 'uid=testuser, o=example', true);
const options = {
suffix: 'o=example',
url: `ldap://localhost:${port}`,
@@ -199,61 +171,42 @@ it('Should fail if the LDAP server encounters an error while searching', done =>
groupCn: 'powerusers',
groupFilter: '(&(uniqueMember=uid={{id}}, o=example)(objectClass=groupOfUniqueNames))',
};
ldap
.validateAuthData({ id: 'testuser', password: 'secret' }, options)
.then(done.fail)
.catch(err => {
jequal(err.message, 'LDAP group search failed');
done();
})
.finally(() => server.close());
try {
await ldap.validateAuthData({ id: 'testuser', password: 'secret' }, options);
fail();
} catch (err) {
expect(err.message).toBe('LDAP group search failed');
}
server.close(done);
});
});
it('Should delete the password from authData after validation', done => {
mockLdapServer(port, 'uid=testuser, o=example', true).then(server => {
it('Should delete the password from authData after validation', async done => {
const server = await mockLdapServer(port, 'uid=testuser, o=example', true);
const options = {
suffix: 'o=example',
url: `ldap://localhost:${port}`,
dn: 'uid={{id}}, o=example',
};
const authData = { id: 'testuser', password: 'secret' };
ldap
.validateAuthData(authData, options)
.then(() => {
expect(authData).toEqual({ id: 'testuser' });
done();
})
.catch(done.fail)
.finally(() => server.close());
await ldap.validateAuthData(authData, options);
expect(authData).toEqual({ id: 'testuser' });
server.close(done);
});
});
it('Should not save the password in the user record after authentication', done => {
mockLdapServer(port, 'uid=testuser, o=example', true).then(server => {
it('Should not save the password in the user record after authentication', async done => {
const server = await mockLdapServer(port, 'uid=testuser, o=example', true);
const options = {
suffix: 'o=example',
url: `ldap://localhost:${port}`,
dn: 'uid={{id}}, o=example',
};
reconfigureServer({ auth: { ldap: options } }).then(() => {
const authData = { authData: { id: 'testuser', password: 'secret' } };
Parse.User.logInWith('ldap', authData).then(returnedUser => {
const query = new Parse.Query('User');
query
.equalTo('objectId', returnedUser.id)
.first({ useMasterKey: true })
.then(user => {
expect(user.get('authData')).toEqual({ ldap: { id: 'testuser' } });
expect(user.get('authData').ldap.password).toBeUndefined();
done();
})
.catch(done.fail)
.finally(() => server.close());
});
});
await reconfigureServer({ auth: { ldap: options } });
const authData = { authData: { id: 'testuser', password: 'secret' } };
const returnedUser = await Parse.User.logInWith('ldap', authData);
const query = new Parse.Query('User');
const user = await query.equalTo('objectId', returnedUser.id).first({ useMasterKey: true });
expect(user.get('authData')).toEqual({ ldap: { id: 'testuser' } });
expect(user.get('authData').ldap.password).toBeUndefined();
server.close(done);
});
});
+7 -5
View File
@@ -32,11 +32,13 @@ describe('WinstonLogger', () => {
it('should disable files logs', done => {
reconfigureServer({
logsFolder: null,
}).then(() => {
const transports = logging.logger.transports;
expect(transports.length).toBe(1);
done();
});
})
.then(() => {
const transports = logging.logger.transports;
expect(transports.length).toBe(1);
return reconfigureServer();
})
.then(done);
});
it('should have a timestamp', done => {
+2
View File
@@ -70,6 +70,7 @@ describe('LoggerController', () => {
};
const loggerController = new LoggerController(new WinstonLoggerAdapter());
loggerController.error('can process an ascending query without throwing');
expect(() => {
loggerController
@@ -115,6 +116,7 @@ describe('LoggerController', () => {
};
const loggerController = new LoggerController(new WinstonLoggerAdapter());
loggerController.error('can process a descending query without throwing');
expect(() => {
loggerController
+3 -1
View File
@@ -8,7 +8,9 @@ const WinstonLoggerAdapter = require('../lib/Adapters/Logger/WinstonLoggerAdapte
const loggerController = new LoggerController(new WinstonLoggerAdapter());
describe('LogsRouter', () => {
describe_only(() => {
return process.env.PARSE_SERVER_LOG_LEVEL !== 'debug';
})('LogsRouter', () => {
it('can check valid master key of request', done => {
// Make mock request
const request = {
+56 -35
View File
@@ -1,7 +1,7 @@
'use strict';
const MongoStorageAdapter = require('../lib/Adapters/Storage/Mongo/MongoStorageAdapter').default;
const { MongoClient } = require('mongodb');
const { MongoClient, Collection } = require('mongodb');
const databaseURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase';
const request = require('../lib/request');
const Config = require('../lib/Config');
@@ -18,6 +18,7 @@ const fakeClient = {
describe_only_db('mongo')('MongoStorageAdapter', () => {
beforeEach(done => {
new MongoStorageAdapter({ uri: databaseURI }).deleteAllClasses().then(done, fail);
Config.get(Parse.applicationId).schemaCache.clear();
});
it('auto-escapes symbols in auth information', () => {
@@ -100,7 +101,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
done.fail('Find succeeded despite taking too long!');
},
err => {
expect(err.name).toEqual('MongoError');
expect(err.name).toEqual('MongoServerError');
expect(err.code).toEqual(50);
expect(err.message).toMatch('operation exceeded time limit');
done();
@@ -282,7 +283,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
await adapter.database.admin().serverStatus();
expect(false).toBe(true);
} catch (e) {
expect(e.message).toEqual('topology was destroyed');
expect(e.message).toEqual('MongoClient must be connected to perform this operation');
}
});
@@ -314,6 +315,8 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
await user.signUp();
const database = Config.get(Parse.applicationId).database;
await database.adapter.dropAllIndexes('_User');
const preIndexPlan = await database.find(
'_User',
{ username: 'bugs' },
@@ -376,15 +379,12 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
'X-Parse-REST-API-Key': 'rest',
};
beforeAll(async () => {
beforeEach(async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI:
'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase?replicaSet=replicaset',
});
});
beforeEach(async () => {
await TestUtils.destroyAllDataPermanently(true);
});
@@ -392,8 +392,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
const myObject = new Parse.Object('MyObject');
await myObject.save();
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
spyOn(databaseAdapter.database.serverConfig, 'command').and.callThrough();
spyOn(Collection.prototype, 'findOneAndUpdate').and.callThrough();
await request({
method: 'POST',
@@ -412,9 +411,9 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
});
let found = false;
databaseAdapter.database.serverConfig.command.calls.all().forEach(call => {
Collection.prototype.findOneAndUpdate.calls.all().forEach(call => {
found = true;
expect(call.args[2].session.transaction.state).not.toBe('NO_TRANSACTION');
expect(call.args[2].session.transaction.state).toBe('TRANSACTION_COMMITTED');
});
expect(found).toBe(true);
});
@@ -423,8 +422,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
const myObject = new Parse.Object('MyObject');
await myObject.save();
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
spyOn(databaseAdapter.database.serverConfig, 'command').and.callThrough();
spyOn(Collection.prototype, 'findOneAndUpdate').and.callThrough();
await request({
method: 'POST',
@@ -443,9 +441,9 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
});
let found = false;
databaseAdapter.database.serverConfig.command.calls.all().forEach(call => {
Collection.prototype.findOneAndUpdate.calls.all().forEach(call => {
found = true;
expect(call.args[2].session).toBe(undefined);
expect(call.args[2].session).toBeFalsy();
});
expect(found).toBe(true);
});
@@ -454,8 +452,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
const myObject = new Parse.Object('MyObject');
await myObject.save();
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
spyOn(databaseAdapter.database.serverConfig, 'command').and.callThrough();
spyOn(Collection.prototype, 'findOneAndUpdate').and.callThrough();
await request({
method: 'POST',
@@ -473,9 +470,9 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
});
let found = false;
databaseAdapter.database.serverConfig.command.calls.all().forEach(call => {
Collection.prototype.findOneAndUpdate.calls.all().forEach(call => {
found = true;
expect(call.args[2].session).toBe(undefined);
expect(call.args[2].session).toBeFalsy();
});
expect(found).toBe(true);
});
@@ -484,8 +481,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
const myObject = new Parse.Object('MyObject');
await myObject.save();
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
spyOn(databaseAdapter.database.serverConfig, 'command').and.callThrough();
spyOn(Collection.prototype, 'findOneAndUpdate').and.callThrough();
await request({
method: 'PUT',
@@ -495,30 +491,28 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
});
let found = false;
databaseAdapter.database.serverConfig.command.calls.all().forEach(call => {
Collection.prototype.findOneAndUpdate.calls.all().forEach(call => {
found = true;
expect(call.args[2].session).toBe(undefined);
expect(call.args[2].session).toBeFalsy();
});
expect(found).toBe(true);
});
it('should not use transactions when using SDK insert', async () => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
spyOn(databaseAdapter.database.serverConfig, 'insert').and.callThrough();
spyOn(Collection.prototype, 'insertOne').and.callThrough();
const myObject = new Parse.Object('MyObject');
await myObject.save();
const calls = databaseAdapter.database.serverConfig.insert.calls.all();
const calls = Collection.prototype.insertOne.calls.all();
expect(calls.length).toBeGreaterThan(0);
calls.forEach(call => {
expect(call.args[2].session.transaction.state).toBe('NO_TRANSACTION');
expect(call.args[1].session).toBeFalsy();
});
});
it('should not use transactions when using SDK update', async () => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
spyOn(databaseAdapter.database.serverConfig, 'update').and.callThrough();
spyOn(Collection.prototype, 'findOneAndUpdate').and.callThrough();
const myObject = new Parse.Object('MyObject');
await myObject.save();
@@ -526,28 +520,55 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
myObject.set('myAttribute', 'myValue');
await myObject.save();
const calls = databaseAdapter.database.serverConfig.update.calls.all();
const calls = Collection.prototype.findOneAndUpdate.calls.all();
expect(calls.length).toBeGreaterThan(0);
calls.forEach(call => {
expect(call.args[2].session.transaction.state).toBe('NO_TRANSACTION');
expect(call.args[2].session).toBeFalsy();
});
});
it('should not use transactions when using SDK delete', async () => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
spyOn(databaseAdapter.database.serverConfig, 'remove').and.callThrough();
spyOn(Collection.prototype, 'deleteMany').and.callThrough();
const myObject = new Parse.Object('MyObject');
await myObject.save();
await myObject.destroy();
const calls = databaseAdapter.database.serverConfig.remove.calls.all();
const calls = Collection.prototype.deleteMany.calls.all();
expect(calls.length).toBeGreaterThan(0);
calls.forEach(call => {
expect(call.args[2].session.transaction.state).toBe('NO_TRANSACTION');
expect(call.args[1].session).toBeFalsy();
});
});
});
describe('watch _SCHEMA', () => {
it('should change', async done => {
const adapter = new MongoStorageAdapter({
uri: databaseURI,
collectionPrefix: '',
mongoOptions: { enableSchemaHooks: true },
});
await reconfigureServer({ databaseAdapter: adapter });
expect(adapter.enableSchemaHooks).toBe(true);
spyOn(adapter, '_onchange');
const schema = {
fields: {
array: { type: 'Array' },
object: { type: 'Object' },
date: { type: 'Date' },
},
};
await adapter.createClass('Stuff', schema);
const myClassSchema = await adapter.getClass('Stuff');
expect(myClassSchema).toBeDefined();
setTimeout(() => {
expect(adapter._onchange).toHaveBeenCalled();
done();
}, 5000);
});
});
}
});
+12 -11
View File
@@ -4,6 +4,7 @@
const transform = require('../lib/Adapters/Storage/Mongo/MongoTransform');
const dd = require('deep-diff');
const mongodb = require('mongodb');
const Utils = require('../lib/Utils');
describe('parseObjectToMongoObjectForCreate', () => {
it('a basic number', done => {
@@ -592,7 +593,7 @@ describe('relativeTimeToDate', () => {
describe('In the future', () => {
it('should parse valid natural time', () => {
const text = 'in 1 year 2 weeks 12 days 10 hours 24 minutes 30 seconds';
const { result, status, info } = transform.relativeTimeToDate(text, now);
const { result, status, info } = Utils.relativeTimeToDate(text, now);
expect(result.toISOString()).toBe('2018-10-22T23:52:46.617Z');
expect(status).toBe('success');
expect(info).toBe('future');
@@ -602,7 +603,7 @@ describe('relativeTimeToDate', () => {
describe('In the past', () => {
it('should parse valid natural time', () => {
const text = '2 days 12 hours 1 minute 12 seconds ago';
const { result, status, info } = transform.relativeTimeToDate(text, now);
const { result, status, info } = Utils.relativeTimeToDate(text, now);
expect(result.toISOString()).toBe('2017-09-24T01:27:04.617Z');
expect(status).toBe('success');
expect(info).toBe('past');
@@ -612,7 +613,7 @@ describe('relativeTimeToDate', () => {
describe('From now', () => {
it('should equal current time', () => {
const text = 'now';
const { result, status, info } = transform.relativeTimeToDate(text, now);
const { result, status, info } = Utils.relativeTimeToDate(text, now);
expect(result.toISOString()).toBe('2017-09-26T13:28:16.617Z');
expect(status).toBe('success');
expect(info).toBe('present');
@@ -621,54 +622,54 @@ describe('relativeTimeToDate', () => {
describe('Error cases', () => {
it('should error if string is completely gibberish', () => {
expect(transform.relativeTimeToDate('gibberishasdnklasdnjklasndkl123j123')).toEqual({
expect(Utils.relativeTimeToDate('gibberishasdnklasdnjklasndkl123j123')).toEqual({
status: 'error',
info: "Time should either start with 'in' or end with 'ago'",
});
});
it('should error if string contains neither `ago` nor `in`', () => {
expect(transform.relativeTimeToDate('12 hours 1 minute')).toEqual({
expect(Utils.relativeTimeToDate('12 hours 1 minute')).toEqual({
status: 'error',
info: "Time should either start with 'in' or end with 'ago'",
});
});
it('should error if there are missing units or numbers', () => {
expect(transform.relativeTimeToDate('in 12 hours 1')).toEqual({
expect(Utils.relativeTimeToDate('in 12 hours 1')).toEqual({
status: 'error',
info: 'Invalid time string. Dangling unit or number.',
});
expect(transform.relativeTimeToDate('12 hours minute ago')).toEqual({
expect(Utils.relativeTimeToDate('12 hours minute ago')).toEqual({
status: 'error',
info: 'Invalid time string. Dangling unit or number.',
});
});
it('should error on floating point numbers', () => {
expect(transform.relativeTimeToDate('in 12.3 hours')).toEqual({
expect(Utils.relativeTimeToDate('in 12.3 hours')).toEqual({
status: 'error',
info: "'12.3' is not an integer.",
});
});
it('should error if numbers are invalid', () => {
expect(transform.relativeTimeToDate('12 hours 123a minute ago')).toEqual({
expect(Utils.relativeTimeToDate('12 hours 123a minute ago')).toEqual({
status: 'error',
info: "'123a' is not an integer.",
});
});
it('should error on invalid interval units', () => {
expect(transform.relativeTimeToDate('4 score 7 years ago')).toEqual({
expect(Utils.relativeTimeToDate('4 score 7 years ago')).toEqual({
status: 'error',
info: "Invalid interval: 'score'",
});
});
it("should error when string contains 'ago' and 'in'", () => {
expect(transform.relativeTimeToDate('in 1 day 2 minutes ago')).toEqual({
expect(Utils.relativeTimeToDate('in 1 day 2 minutes ago')).toEqual({
status: 'error',
info: "Time cannot have both 'in' and 'ago'",
});
+15 -7
View File
@@ -87,13 +87,17 @@ describe('OAuth', function () {
done();
}
it('Should fail a GET request', done => {
it('GET request for a resource that requires OAuth should fail with invalid credentials', done => {
/*
This endpoint has been chosen to make a request to an endpoint that requires OAuth which fails due to missing authentication.
Any other endpoint from the Twitter API that requires OAuth can be used instead in case the currently used endpoint deprecates.
*/
const options = {
host: 'api.twitter.com',
consumer_key: 'XXXXXXXXXXXXXXXXXXXXXXXXX',
consumer_secret: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
consumer_key: 'invalid_consumer_key',
consumer_secret: 'invalid_consumer_secret',
};
const path = '/1.1/help/configuration.json';
const path = '/1.1/favorites/list.json';
const params = { lang: 'en' };
const oauthClient = new OAuth(options);
oauthClient.get(path, params).then(function (data) {
@@ -101,11 +105,15 @@ describe('OAuth', function () {
});
});
it('Should fail a POST request', done => {
it('POST request for a resource that requires OAuth should fail with invalid credentials', done => {
/*
This endpoint has been chosen to make a request to an endpoint that requires OAuth which fails due to missing authentication.
Any other endpoint from the Twitter API that requires OAuth can be used instead in case the currently used endpoint deprecates.
*/
const options = {
host: 'api.twitter.com',
consumer_key: 'XXXXXXXXXXXXXXXXXXXXXXXXX',
consumer_secret: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
consumer_key: 'invalid_consumer_key',
consumer_secret: 'invalid_consumer_secret',
};
const body = {
lang: 'en',
File diff suppressed because it is too large Load Diff
+252 -419
View File
@@ -2,327 +2,235 @@
const request = require('../lib/request');
const delayPromise = delay => {
return new Promise(resolve => {
setTimeout(resolve, delay);
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const pushCompleted = async pushId => {
const query = new Parse.Query('_PushStatus');
query.equalTo('objectId', pushId);
let result = await query.first({ useMasterKey: true });
while (!(result && result.get('status') === 'succeeded')) {
await sleep(100);
result = await query.first({ useMasterKey: true });
}
};
const successfulAny = function (body, installations) {
const promises = installations.map(device => {
return Promise.resolve({
transmitted: true,
device: device,
});
});
return Promise.all(promises);
};
const provideInstallations = function (num) {
if (!num) {
num = 2;
}
const installations = [];
while (installations.length !== num) {
// add Android installations
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);
}
return installations;
};
const losingAdapter = {
send: function (body, installations) {
// simulate having lost an installation before this was called
// thus invalidating our 'count' in _PushStatus
installations.pop();
return successfulAny(body, installations);
},
getValidPushTypes: function () {
return ['android'];
},
};
const setup = function () {
const sendToInstallationSpy = jasmine.createSpy();
const pushAdapter = {
send: function (body, installations) {
const badge = body.data.badge;
const promises = installations.map(installation => {
sendToInstallationSpy(installation);
if (installation.deviceType == 'ios') {
expect(installation.badge).toEqual(badge);
expect(installation.originalBadge + 1).toEqual(installation.badge);
} else {
expect(installation.badge).toBeUndefined();
}
return Promise.resolve({
err: null,
device: installation,
transmitted: true,
});
});
return Promise.all(promises);
},
getValidPushTypes: function () {
return ['ios', 'android'];
},
};
return reconfigureServer({
appId: Parse.applicationId,
masterKey: Parse.masterKey,
serverURL: Parse.serverURL,
push: {
adapter: pushAdapter,
},
})
.then(() => {
const 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);
}
return Parse.Object.saveAll(installations);
})
.then(() => {
return {
sendToInstallationSpy,
};
});
};
describe('Parse.Push', () => {
const setup = function () {
const sendToInstallationSpy = jasmine.createSpy();
const pushAdapter = {
send: function (body, installations) {
const badge = body.data.badge;
const promises = installations.map(installation => {
sendToInstallationSpy(installation);
if (installation.deviceType == 'ios') {
expect(installation.badge).toEqual(badge);
expect(installation.originalBadge + 1).toEqual(installation.badge);
} else {
expect(installation.badge).toBeUndefined();
}
return Promise.resolve({
err: null,
device: installation,
transmitted: true,
});
});
return Promise.all(promises);
it('should properly send push', async () => {
const { sendToInstallationSpy } = await setup();
const pushStatusId = await Parse.Push.send({
where: {
deviceType: 'ios',
},
getValidPushTypes: function () {
return ['ios', 'android'];
data: {
badge: 'Increment',
alert: 'Hello world!',
},
};
return reconfigureServer({
appId: Parse.applicationId,
masterKey: Parse.masterKey,
serverURL: Parse.serverURL,
push: {
adapter: pushAdapter,
},
})
.then(() => {
const 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);
}
return Parse.Object.saveAll(installations);
})
.then(() => {
return {
sendToInstallationSpy,
};
})
.catch(err => {
console.error(err);
throw err;
});
};
it('should properly send push', done => {
return setup()
.then(({ sendToInstallationSpy }) => {
return Parse.Push.send(
{
where: {
deviceType: 'ios',
},
data: {
badge: 'Increment',
alert: 'Hello world!',
},
},
{ useMasterKey: true }
)
.then(() => {
return delayPromise(500);
})
.then(() => {
expect(sendToInstallationSpy.calls.count()).toEqual(10);
});
})
.then(() => {
done();
})
.catch(err => {
jfail(err);
done();
});
});
it('should properly send push with lowercaseIncrement', done => {
return setup()
.then(() => {
return Parse.Push.send(
{
where: {
deviceType: 'ios',
},
data: {
badge: 'increment',
alert: 'Hello world!',
},
},
{ useMasterKey: true }
);
})
.then(() => {
return delayPromise(500);
})
.then(() => {
done();
})
.catch(err => {
jfail(err);
done();
});
});
it('should not allow clients to query _PushStatus', done => {
setup()
.then(() =>
Parse.Push.send(
{
where: {
deviceType: 'ios',
},
data: {
badge: 'increment',
alert: 'Hello world!',
},
},
{ useMasterKey: true }
)
)
.then(() => delayPromise(500))
.then(() => {
request({
url: 'http://localhost:8378/1/classes/_PushStatus',
json: true,
headers: {
'X-Parse-Application-Id': 'test',
},
}).then(fail, response => {
expect(response.data.error).toEqual('unauthorized');
done();
});
})
.catch(err => {
jfail(err);
done();
});
});
it('should allow master key to query _PushStatus', done => {
setup()
.then(() =>
Parse.Push.send(
{
where: {
deviceType: 'ios',
},
data: {
badge: 'increment',
alert: 'Hello world!',
},
},
{ useMasterKey: true }
)
)
.then(() => delayPromise(500)) // put a delay as we keep writing
.then(() => {
request({
url: 'http://localhost:8378/1/classes/_PushStatus',
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Master-Key': 'test',
},
}).then(response => {
const body = response.data;
try {
expect(body.results.length).toEqual(1);
expect(body.results[0].query).toEqual('{"deviceType":"ios"}');
expect(body.results[0].payload).toEqual('{"badge":"increment","alert":"Hello world!"}');
} catch (e) {
jfail(e);
}
done();
});
})
.catch(err => {
jfail(err);
done();
});
});
it('should throw error if missing push configuration', done => {
reconfigureServer({ push: null })
.then(() => {
return Parse.Push.send(
{
where: {
deviceType: 'ios',
},
data: {
badge: 'increment',
alert: 'Hello world!',
},
},
{ useMasterKey: true }
);
})
.then(
() => {
fail('should not succeed');
},
err => {
expect(err.code).toEqual(Parse.Error.PUSH_MISCONFIGURED);
done();
}
)
.catch(err => {
jfail(err);
done();
});
});
const successfulAny = function (body, installations) {
const promises = installations.map(device => {
return Promise.resolve({
transmitted: true,
device: device,
});
});
await pushCompleted(pushStatusId);
expect(sendToInstallationSpy.calls.count()).toEqual(10);
});
return Promise.all(promises);
};
it('should properly send push with lowercaseIncrement', async () => {
await setup();
const pushStatusId = await Parse.Push.send({
where: {
deviceType: 'ios',
},
data: {
badge: 'increment',
alert: 'Hello world!',
},
});
await pushCompleted(pushStatusId);
});
const provideInstallations = function (num) {
if (!num) {
num = 2;
it('should not allow clients to query _PushStatus', async () => {
await setup();
const pushStatusId = await Parse.Push.send({
where: {
deviceType: 'ios',
},
data: {
badge: 'increment',
alert: 'Hello world!',
},
});
await pushCompleted(pushStatusId);
try {
await request({
url: 'http://localhost:8378/1/classes/_PushStatus',
json: true,
headers: {
'X-Parse-Application-Id': 'test',
},
});
fail();
} catch (response) {
expect(response.data.error).toEqual('unauthorized');
}
});
const installations = [];
while (installations.length !== num) {
// add Android installations
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);
it('should allow master key to query _PushStatus', async () => {
await setup();
const pushStatusId = await Parse.Push.send({
where: {
deviceType: 'ios',
},
data: {
badge: 'increment',
alert: 'Hello world!',
},
});
await pushCompleted(pushStatusId);
const response = await request({
url: 'http://localhost:8378/1/classes/_PushStatus',
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Master-Key': 'test',
},
});
const body = response.data;
expect(body.results.length).toEqual(1);
expect(body.results[0].query).toEqual('{"deviceType":"ios"}');
expect(body.results[0].payload).toEqual('{"badge":"increment","alert":"Hello world!"}');
});
it('should throw error if missing push configuration', async () => {
await reconfigureServer({ push: null });
try {
await Parse.Push.send({
where: {
deviceType: 'ios',
},
data: {
badge: 'increment',
alert: 'Hello world!',
},
});
fail();
} catch (err) {
expect(err.code).toEqual(Parse.Error.PUSH_MISCONFIGURED);
}
return installations;
};
const losingAdapter = {
send: function (body, installations) {
// simulate having lost an installation before this was called
// thus invalidating our 'count' in _PushStatus
installations.pop();
return successfulAny(body, installations);
},
getValidPushTypes: function () {
return ['android'];
},
};
});
/**
* Verifies that _PushStatus cannot get stuck in a 'running' state
* Simulates a simple push where 1 installation is removed between _PushStatus
* count being set and the pushes being sent
*/
it("does not get stuck with _PushStatus 'running' on 1 installation lost", done => {
reconfigureServer({
it("does not get stuck with _PushStatus 'running' on 1 installation lost", async () => {
await reconfigureServer({
push: { adapter: losingAdapter },
})
.then(() => {
return Parse.Object.saveAll(provideInstallations());
})
.then(() => {
return Parse.Push.send(
{
data: { alert: 'We fixed our status!' },
where: { deviceType: 'android' },
},
{ useMasterKey: true }
);
})
.then(() => {
// it is enqueued so it can take time
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
});
})
.then(() => {
// query for push status
const query = new Parse.Query('_PushStatus');
return query.find({ useMasterKey: true });
})
.then(results => {
// verify status is NOT broken
expect(results.length).toBe(1);
const result = results[0];
expect(result.get('status')).toEqual('succeeded');
expect(result.get('numSent')).toEqual(1);
expect(result.get('count')).toEqual(undefined);
done();
});
});
await Parse.Object.saveAll(provideInstallations());
const pushStatusId = await Parse.Push.send({
data: { alert: 'We fixed our status!' },
where: { deviceType: 'android' },
});
await pushCompleted(pushStatusId);
const result = await Parse.Push.getPushStatus(pushStatusId);
expect(result.get('status')).toEqual('succeeded');
expect(result.get('numSent')).toEqual(1);
expect(result.get('count')).toEqual(undefined);
});
/**
@@ -330,7 +238,7 @@ describe('Parse.Push', () => {
* Simulates a simple push where 1 installation is added between _PushStatus
* count being set and the pushes being sent
*/
it("does not get stuck with _PushStatus 'running' on 1 installation added", done => {
it("does not get stuck with _PushStatus 'running' on 1 installation added", async () => {
const installations = provideInstallations();
// add 1 iOS installation which we will omit & add later on
@@ -340,14 +248,13 @@ describe('Parse.Push', () => {
iOSInstallation.set('deviceType', 'ios');
installations.push(iOSInstallation);
reconfigureServer({
await reconfigureServer({
push: {
adapter: {
send: function (body, installations) {
// simulate having added an installation before this was called
// thus invalidating our 'count' in _PushStatus
installations.push(iOSInstallation);
return successfulAny(body, installations);
},
getValidPushTypes: function () {
@@ -355,41 +262,17 @@ describe('Parse.Push', () => {
},
},
},
})
.then(() => {
return Parse.Object.saveAll(installations);
})
.then(() => {
return Parse.Push.send(
{
data: { alert: 'We fixed our status!' },
where: { deviceType: { $ne: 'random' } },
},
{ useMasterKey: true }
);
})
.then(() => {
// it is enqueued so it can take time
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
});
})
.then(() => {
// query for push status
const query = new Parse.Query('_PushStatus');
return query.find({ useMasterKey: true });
})
.then(results => {
// verify status is NOT broken
expect(results.length).toBe(1);
const result = results[0];
expect(result.get('status')).toEqual('succeeded');
expect(result.get('numSent')).toEqual(3);
expect(result.get('count')).toEqual(undefined);
done();
});
});
await Parse.Object.saveAll(installations);
const pushStatusId = await Parse.Push.send({
data: { alert: 'We fixed our status!' },
where: { deviceType: { $ne: 'random' } },
});
await pushCompleted(pushStatusId);
const result = await Parse.Push.getPushStatus(pushStatusId);
expect(result.get('status')).toEqual('succeeded');
expect(result.get('numSent')).toEqual(3);
expect(result.get('count')).toEqual(undefined);
});
/**
@@ -397,48 +280,24 @@ describe('Parse.Push', () => {
* Simulates an extended push, where some installations may be removed,
* resulting in a non-zero count
*/
it("does not get stuck with _PushStatus 'running' on many installations removed", done => {
it("does not get stuck with _PushStatus 'running' on many installations removed", async () => {
const devices = 1000;
const installations = provideInstallations(devices);
reconfigureServer({
await reconfigureServer({
push: { adapter: losingAdapter },
})
.then(() => {
return Parse.Object.saveAll(installations);
})
.then(() => {
return Parse.Push.send(
{
data: { alert: 'We fixed our status!' },
where: { deviceType: 'android' },
},
{ useMasterKey: true }
);
})
.then(() => {
// it is enqueued so it can take time
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
});
})
.then(() => {
// query for push status
const query = new Parse.Query('_PushStatus');
return query.find({ useMasterKey: true });
})
.then(results => {
// verify status is NOT broken
expect(results.length).toBe(1);
const result = results[0];
expect(result.get('status')).toEqual('succeeded');
// expect # less than # of batches used, assuming each batch is 100 pushes
expect(result.get('numSent')).toEqual(devices - devices / 100);
expect(result.get('count')).toEqual(undefined);
done();
});
});
await Parse.Object.saveAll(installations);
const pushStatusId = await Parse.Push.send({
data: { alert: 'We fixed our status!' },
where: { deviceType: 'android' },
});
await pushCompleted(pushStatusId);
const result = await Parse.Push.getPushStatus(pushStatusId);
expect(result.get('status')).toEqual('succeeded');
// expect # less than # of batches used, assuming each batch is 100 pushes
expect(result.get('numSent')).toEqual(devices - devices / 100);
expect(result.get('count')).toEqual(undefined);
});
/**
@@ -446,13 +305,12 @@ describe('Parse.Push', () => {
* Simulates an extended push, where some installations may be added,
* resulting in a non-zero count
*/
it("does not get stuck with _PushStatus 'running' on many installations added", done => {
it("does not get stuck with _PushStatus 'running' on many installations added", async () => {
const devices = 1000;
const installations = provideInstallations(devices);
// add 1 iOS installation which we will omit & add later on
const iOSInstallations = [];
while (iOSInstallations.length !== devices / 100) {
const iOSInstallation = new Parse.Object('_Installation');
iOSInstallation.set('installationId', 'installation_' + installations.length);
@@ -461,15 +319,13 @@ describe('Parse.Push', () => {
installations.push(iOSInstallation);
iOSInstallations.push(iOSInstallation);
}
reconfigureServer({
await reconfigureServer({
push: {
adapter: {
send: function (body, installations) {
// simulate having added an installation before this was called
// thus invalidating our 'count' in _PushStatus
installations.push(iOSInstallations.pop());
return successfulAny(body, installations);
},
getValidPushTypes: function () {
@@ -477,41 +333,18 @@ describe('Parse.Push', () => {
},
},
},
})
.then(() => {
return Parse.Object.saveAll(installations);
})
.then(() => {
return Parse.Push.send(
{
data: { alert: 'We fixed our status!' },
where: { deviceType: { $ne: 'random' } },
},
{ useMasterKey: true }
);
})
.then(() => {
// it is enqueued so it can take time
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
});
})
.then(() => {
// query for push status
const query = new Parse.Query('_PushStatus');
return query.find({ useMasterKey: true });
})
.then(results => {
// verify status is NOT broken
expect(results.length).toBe(1);
const result = results[0];
expect(result.get('status')).toEqual('succeeded');
// expect # less than # of batches used, assuming each batch is 100 pushes
expect(result.get('numSent')).toEqual(devices + devices / 100);
expect(result.get('count')).toEqual(undefined);
done();
});
});
await Parse.Object.saveAll(installations);
const pushStatusId = await Parse.Push.send({
data: { alert: 'We fixed our status!' },
where: { deviceType: { $ne: 'random' } },
});
await pushCompleted(pushStatusId);
const result = await Parse.Push.getPushStatus(pushStatusId);
expect(result.get('status')).toEqual('succeeded');
// expect # less than # of batches used, assuming each batch is 100 pushes
expect(result.get('numSent')).toEqual(devices + devices / 100);
expect(result.get('count')).toEqual(undefined);
});
});
+38 -28
View File
@@ -23,32 +23,15 @@ const headers = {
'X-Parse-Installation-Id': 'yolo',
};
describe_only_db('mongo')('miscellaneous', () => {
it('test rest_create_app', function (done) {
let appId;
Parse._request('POST', 'rest_create_app')
.then(res => {
expect(typeof res.application_id).toEqual('string');
expect(res.master_key).toEqual('master');
appId = res.application_id;
Parse.initialize(appId, 'unused');
const obj = new Parse.Object('TestObject');
obj.set('foo', 'bar');
return obj.save();
})
.then(() => {
const config = Config.get(appId);
return config.database.adapter.find('TestObject', { fields: {} }, {}, {});
})
.then(results => {
expect(results.length).toEqual(1);
expect(results[0]['foo']).toEqual('bar');
done();
})
.catch(error => {
fail(JSON.stringify(error));
done();
});
describe('miscellaneous', () => {
it('db contains document after successful save', async () => {
const obj = new Parse.Object('TestObject');
obj.set('foo', 'bar');
await obj.save();
const config = Config.get(defaultConfiguration.appId);
const results = await config.database.adapter.find('TestObject', { fields: {} }, {}, {});
expect(results.length).toEqual(1);
expect(results[0]['foo']).toEqual('bar');
});
});
@@ -84,6 +67,7 @@ describe('miscellaneous', function () {
});
it('fail to create a duplicate username', async () => {
await reconfigureServer();
let numFailed = 0;
let numCreated = 0;
const p1 = request({
@@ -131,6 +115,7 @@ describe('miscellaneous', function () {
});
it('ensure that email is uniquely indexed', async () => {
await reconfigureServer();
let numFailed = 0;
let numCreated = 0;
const p1 = request({
@@ -187,6 +172,7 @@ describe('miscellaneous', function () {
const config = Config.get('test');
// Remove existing data to clear out unique index
TestUtils.destroyAllDataPermanently()
.then(() => config.database.adapter.performInitialization({ VolatileClassesSchemas: [] }))
.then(() => config.database.adapter.createClass('_User', userSchema))
.then(() =>
config.database.adapter
@@ -227,6 +213,7 @@ describe('miscellaneous', function () {
const config = Config.get('test');
// Remove existing data to clear out unique index
TestUtils.destroyAllDataPermanently()
.then(() => config.database.adapter.performInitialization({ VolatileClassesSchemas: [] }))
.then(() => config.database.adapter.createClass('_User', userSchema))
.then(() =>
config.database.adapter.createObject('_User', userSchema, {
@@ -261,7 +248,8 @@ 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 => {
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', async done => {
await reconfigureServer();
const config = Config.get('test');
config.database.adapter
.addFieldIfNotExists('_User', 'randomField', { type: 'String' })
@@ -658,6 +646,28 @@ describe('miscellaneous', function () {
});
});
it_only_db('mongo')('pointer reassign on nested fields is working properly (#7391)', async () => {
const obj = new Parse.Object('GameScore'); // This object will include nested pointers
const ptr1 = new Parse.Object('GameScore');
await ptr1.save(); // Obtain a unique id
const ptr2 = new Parse.Object('GameScore');
await ptr2.save(); // Obtain a unique id
obj.set('data', { ptr: ptr1 });
await obj.save();
obj.set('data.ptr', ptr2);
await obj.save();
const obj2 = await new Parse.Query('GameScore').get(obj.id);
expect(obj2.get('data').ptr.id).toBe(ptr2.id);
const query = new Parse.Query('GameScore');
query.equalTo('data.ptr', ptr2);
const res = await query.find();
expect(res.length).toBe(1);
expect(res[0].get('data').ptr.id).toBe(ptr2.id);
});
it('test afterSave get full object on create and update', function (done) {
let triggerTime = 0;
// Register a mock beforeSave hook
@@ -1005,7 +1015,7 @@ describe('miscellaneous', function () {
done();
},
e => {
expect(e.code).toEqual(141);
expect(e.code).toEqual(Parse.Error.SCRIPT_FAILED);
expect(e.message).toEqual('noway');
done();
}
+717 -504
View File
File diff suppressed because it is too large Load Diff
+31 -34
View File
@@ -28,42 +28,39 @@ describe('ParseGraphQLController', () => {
return graphQLConfigRecord;
};
beforeAll(async () => {
parseServer = await global.reconfigureServer({
schemaCacheTTL: 100,
});
databaseController = parseServer.config.databaseController;
cacheController = parseServer.config.cacheController;
beforeEach(async () => {
if (!parseServer) {
parseServer = await global.reconfigureServer();
databaseController = parseServer.config.databaseController;
cacheController = parseServer.config.cacheController;
const defaultFind = databaseController.find.bind(databaseController);
databaseController.find = async (className, query, ...args) => {
if (className === GraphQLConfigClassName && isEqual(query, { objectId: GraphQLConfigId })) {
const graphQLConfigRecord = getConfigFromDb();
return graphQLConfigRecord ? [graphQLConfigRecord] : [];
} else {
return defaultFind(className, query, ...args);
}
};
const defaultFind = databaseController.find.bind(databaseController);
databaseController.find = async (className, query, ...args) => {
if (className === GraphQLConfigClassName && isEqual(query, { objectId: GraphQLConfigId })) {
const graphQLConfigRecord = getConfigFromDb();
return graphQLConfigRecord ? [graphQLConfigRecord] : [];
} else {
return defaultFind(className, query, ...args);
}
};
const defaultUpdate = databaseController.update.bind(databaseController);
databaseController.update = async (className, query, update, fullQueryOptions) => {
databaseUpdateArgs = [className, query, update, fullQueryOptions];
if (
className === GraphQLConfigClassName &&
isEqual(query, { objectId: GraphQLConfigId }) &&
update &&
!!update[GraphQLConfigKey] &&
fullQueryOptions &&
isEqual(fullQueryOptions, { upsert: true })
) {
setConfigOnDb(update[GraphQLConfigKey]);
} else {
return defaultUpdate(...databaseUpdateArgs);
}
};
});
beforeEach(() => {
const defaultUpdate = databaseController.update.bind(databaseController);
databaseController.update = async (className, query, update, fullQueryOptions) => {
databaseUpdateArgs = [className, query, update, fullQueryOptions];
if (
className === GraphQLConfigClassName &&
isEqual(query, { objectId: GraphQLConfigId }) &&
update &&
!!update[GraphQLConfigKey] &&
fullQueryOptions &&
isEqual(fullQueryOptions, { upsert: true })
) {
setConfigOnDb(update[GraphQLConfigKey]);
} else {
return defaultUpdate(...databaseUpdateArgs);
}
};
}
databaseUpdateArgs = null;
});
+15 -19
View File
@@ -9,10 +9,8 @@ describe('ParseGraphQLSchema', () => {
let parseGraphQLSchema;
const appId = 'test';
beforeAll(async () => {
parseServer = await global.reconfigureServer({
schemaCacheTTL: 100,
});
beforeEach(async () => {
parseServer = await global.reconfigureServer();
databaseController = parseServer.config.databaseController;
parseGraphQLController = parseServer.config.parseGraphQLController;
parseGraphQLSchema = new ParseGraphQLSchema({
@@ -54,14 +52,12 @@ describe('ParseGraphQLSchema', () => {
const graphQLSchema = await parseGraphQLSchema.load();
const updatedGraphQLSchema = await parseGraphQLSchema.load();
expect(graphQLSchema).toBe(updatedGraphQLSchema);
await new Promise(resolve => setTimeout(resolve, 200));
expect(graphQLSchema).toBe(await parseGraphQLSchema.load());
});
it('should load a brand new GraphQL Schema if Parse Schema changes', async () => {
await parseGraphQLSchema.load();
const parseClasses = parseGraphQLSchema.parseClasses;
const parseClassesString = parseGraphQLSchema.parseClassesString;
const parseCachedClasses = parseGraphQLSchema.parseCachedClasses;
const parseClassTypes = parseGraphQLSchema.parseClassTypes;
const graphQLSchema = parseGraphQLSchema.graphQLSchema;
const graphQLTypes = parseGraphQLSchema.graphQLTypes;
@@ -70,11 +66,11 @@ describe('ParseGraphQLSchema', () => {
const graphQLSubscriptions = parseGraphQLSchema.graphQLSubscriptions;
const newClassObject = new Parse.Object('NewClass');
await newClassObject.save();
await databaseController.schemaCache.clear();
await parseServer.config.schemaCache.clear();
await new Promise(resolve => setTimeout(resolve, 200));
await parseGraphQLSchema.load();
expect(parseClasses).not.toBe(parseGraphQLSchema.parseClasses);
expect(parseClassesString).not.toBe(parseGraphQLSchema.parseClassesString);
expect(parseCachedClasses).not.toBe(parseGraphQLSchema.parseCachedClasses);
expect(parseClassTypes).not.toBe(parseGraphQLSchema.parseClassTypes);
expect(graphQLSchema).not.toBe(parseGraphQLSchema.graphQLSchema);
expect(graphQLTypes).not.toBe(parseGraphQLSchema.graphQLTypes);
@@ -98,7 +94,7 @@ describe('ParseGraphQLSchema', () => {
});
await parseGraphQLSchema.load();
const parseClasses = parseGraphQLSchema.parseClasses;
const parseClassesString = parseGraphQLSchema.parseClassesString;
const parseCachedClasses = parseGraphQLSchema.parseCachedClasses;
const parseClassTypes = parseGraphQLSchema.parseClassTypes;
const graphQLSchema = parseGraphQLSchema.graphQLSchema;
const graphQLTypes = parseGraphQLSchema.graphQLTypes;
@@ -113,7 +109,7 @@ describe('ParseGraphQLSchema', () => {
await new Promise(resolve => setTimeout(resolve, 200));
await parseGraphQLSchema.load();
expect(parseClasses).not.toBe(parseGraphQLSchema.parseClasses);
expect(parseClassesString).not.toBe(parseGraphQLSchema.parseClassesString);
expect(parseCachedClasses).not.toBe(parseGraphQLSchema.parseCachedClasses);
expect(parseClassTypes).not.toBe(parseGraphQLSchema.parseClassTypes);
expect(graphQLSchema).not.toBe(parseGraphQLSchema.graphQLSchema);
expect(graphQLTypes).not.toBe(parseGraphQLSchema.graphQLTypes);
@@ -428,14 +424,14 @@ describe('ParseGraphQLSchema', () => {
log: defaultLogger,
appId,
});
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema1 = await parseGraphQLSchema.load();
const types1 = parseGraphQLSchema.graphQLTypes;
const queries1 = parseGraphQLSchema.graphQLQueries;
const mutations1 = parseGraphQLSchema.graphQLMutations;
const user = new Parse.Object('User');
await user.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema2 = await parseGraphQLSchema.load();
const types2 = parseGraphQLSchema.graphQLTypes;
const queries2 = parseGraphQLSchema.graphQLQueries;
@@ -458,14 +454,14 @@ describe('ParseGraphQLSchema', () => {
});
const car1 = new Parse.Object('Car');
await car1.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema1 = await parseGraphQLSchema.load();
const types1 = parseGraphQLSchema.graphQLTypes;
const queries1 = parseGraphQLSchema.graphQLQueries;
const mutations1 = parseGraphQLSchema.graphQLMutations;
const car2 = new Parse.Object('car');
await car2.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema2 = await parseGraphQLSchema.load();
const types2 = parseGraphQLSchema.graphQLTypes;
const queries2 = parseGraphQLSchema.graphQLQueries;
@@ -488,13 +484,13 @@ describe('ParseGraphQLSchema', () => {
});
const car = new Parse.Object('Car');
await car.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema1 = await parseGraphQLSchema.load();
const queries1 = parseGraphQLSchema.graphQLQueries;
const mutations1 = parseGraphQLSchema.graphQLMutations;
const cars = new Parse.Object('cars');
await cars.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema2 = await parseGraphQLSchema.load();
const queries2 = parseGraphQLSchema.graphQLQueries;
const mutations2 = parseGraphQLSchema.graphQLMutations;
@@ -534,7 +530,7 @@ describe('ParseGraphQLSchema', () => {
await data.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
await parseGraphQLSchema.load();
const queries1 = parseGraphQLSchema.graphQLQueries;
@@ -571,7 +567,7 @@ describe('ParseGraphQLSchema', () => {
await data.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
await parseGraphQLSchema.load();
const mutations = parseGraphQLSchema.graphQLMutations;
File diff suppressed because it is too large Load Diff
+12 -9
View File
@@ -8,17 +8,20 @@ const bodyParser = require('body-parser');
const auth = require('../lib/Auth');
const Config = require('../lib/Config');
const port = 12345;
const port = 34567;
const hookServerURL = 'http://localhost:' + port;
const AppCache = require('../lib/cache').AppCache;
describe('Hooks', () => {
let server;
let app;
beforeAll(done => {
app = express();
app.use(bodyParser.json({ type: '*/*' }));
server = app.listen(12345, undefined, done);
beforeEach(done => {
if (!app) {
app = express();
app.use(bodyParser.json({ type: '*/*' }));
server = app.listen(port, undefined, done);
} else {
done();
}
});
afterAll(done => {
@@ -379,7 +382,7 @@ describe('Hooks', () => {
}
const hooksController = new HooksController(
Parse.applicationId,
AppCache.get('test').databaseController
Config.get('test').database
);
return hooksController.load();
},
@@ -461,7 +464,7 @@ describe('Hooks', () => {
expect(err).not.toBe(undefined);
expect(err).not.toBe(null);
if (err) {
expect(err.code).toBe(141);
expect(err.code).toBe(Parse.Error.SCRIPT_FAILED);
expect(err.message.code).toEqual(1337);
expect(err.message.error).toEqual('hacking that one!');
}
@@ -533,7 +536,7 @@ describe('Hooks', () => {
expect(err).not.toBe(undefined);
expect(err).not.toBe(null);
if (err) {
expect(err.code).toBe(141);
expect(err.code).toBe(Parse.Error.SCRIPT_FAILED);
expect(err.message).toEqual('incorrect key provided');
}
done();
+294 -156
View File
@@ -15,12 +15,14 @@ describe('ParseLiveQuery', function () {
verbose: false,
silent: true,
});
Parse.CoreManager.getLiveQueryController().setDefaultLiveQueryClient(null);
const requestedUser = new Parse.User();
requestedUser.setUsername('username');
requestedUser.setPassword('password');
Parse.Cloud.onLiveQueryEvent(req => {
const { event, sessionToken } = req;
if (event === 'ws_disconnect') {
Parse.Cloud._removeAllHooks();
expect(sessionToken).toBeDefined();
expect(sessionToken).toBe(requestedUser.getSessionToken());
done();
@@ -56,6 +58,29 @@ describe('ParseLiveQuery', function () {
await object.save();
});
it('can use patterns in className', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['Test.*'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const object = new TestObject();
await object.save();
const query = new Parse.Query(TestObject);
query.equalTo('objectId', object.id);
const subscription = await query.subscribe();
subscription.on('update', object => {
expect(object.get('foo')).toBe('bar');
done();
});
object.set({ foo: 'bar' });
await object.save();
});
it('expect afterEvent create', async done => {
await reconfigureServer({
liveQuery: {
@@ -294,6 +319,41 @@ describe('ParseLiveQuery', function () {
await object.save();
});
it('can log on afterLiveQueryEvent throw', async () => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const object = new TestObject();
await object.save();
const logger = require('../lib/logger').logger;
spyOn(logger, 'error').and.callFake(() => {});
let session = undefined;
Parse.Cloud.afterLiveQueryEvent('TestObject', ({ sessionToken }) => {
session = sessionToken;
/* eslint-disable no-undef */
foo.bar();
/* eslint-enable no-undef */
});
const query = new Parse.Query(TestObject);
query.equalTo('objectId', object.id);
const subscription = await query.subscribe();
object.set({ foo: 'bar' });
await object.save();
await new Promise(resolve => subscription.on('error', resolve));
expect(logger.error).toHaveBeenCalledWith(
`Failed running afterLiveQueryEvent on class TestObject for event update with session ${session} with:\n Error: {"message":"foo is not defined","code":141}`
);
});
it('can handle afterEvent sendEvent to false', async done => {
await reconfigureServer({
liveQuery: {
@@ -333,7 +393,7 @@ describe('ParseLiveQuery', function () {
await object.save();
});
it('expect afterEvent create', async done => {
it('can handle afterEvent set pointers', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
@@ -342,172 +402,31 @@ describe('ParseLiveQuery', function () {
verbose: false,
silent: true,
});
Parse.Cloud.afterLiveQueryEvent('TestObject', req => {
expect(req.event).toBe('create');
expect(req.user).toBeUndefined();
expect(req.object.get('foo')).toBe('bar');
});
const query = new Parse.Query(TestObject);
const subscription = await query.subscribe();
subscription.on('create', object => {
expect(object.get('foo')).toBe('bar');
done();
});
const object = new TestObject();
object.set('foo', 'bar');
await object.save();
});
it('expect afterEvent payload', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const object = new TestObject();
await object.save();
Parse.Cloud.afterLiveQueryEvent('TestObject', req => {
expect(req.event).toBe('update');
expect(req.user).toBeUndefined();
expect(req.object.get('foo')).toBe('bar');
expect(req.original.get('foo')).toBeUndefined();
done();
});
const query = new Parse.Query(TestObject);
query.equalTo('objectId', object.id);
await query.subscribe();
object.set({ foo: 'bar' });
await object.save();
});
it('expect afterEvent enter', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
Parse.Cloud.afterLiveQueryEvent('TestObject', req => {
expect(req.event).toBe('enter');
expect(req.user).toBeUndefined();
expect(req.object.get('foo')).toBe('bar');
expect(req.original.get('foo')).toBeUndefined();
});
const object = new TestObject();
await object.save();
const query = new Parse.Query(TestObject);
query.equalTo('foo', 'bar');
const subscription = await query.subscribe();
subscription.on('enter', object => {
expect(object.get('foo')).toBe('bar');
done();
});
const secondObject = new Parse.Object('Test2');
secondObject.set('foo', 'bar');
await secondObject.save();
object.set('foo', 'bar');
await object.save();
});
it('expect afterEvent leave', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
Parse.Cloud.afterLiveQueryEvent('TestObject', req => {
expect(req.event).toBe('leave');
expect(req.user).toBeUndefined();
expect(req.object.get('foo')).toBeUndefined();
expect(req.original.get('foo')).toBe('bar');
});
const object = new TestObject();
object.set('foo', 'bar');
await object.save();
const query = new Parse.Query(TestObject);
query.equalTo('foo', 'bar');
const subscription = await query.subscribe();
subscription.on('leave', object => {
expect(object.get('foo')).toBeUndefined();
done();
});
object.unset('foo');
await object.save();
});
it('expect afterEvent delete', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
Parse.Cloud.afterLiveQueryEvent('TestObject', req => {
expect(req.event).toBe('delete');
expect(req.user).toBeUndefined();
req.object.set('foo', 'bar');
});
const object = new TestObject();
await object.save();
const query = new Parse.Query(TestObject);
query.equalTo('objectId', object.id);
const subscription = await query.subscribe();
subscription.on('delete', object => {
expect(object.get('foo')).toBe('bar');
done();
});
await object.destroy();
});
it('can handle afterEvent modification', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const object = new TestObject();
await object.save();
Parse.Cloud.afterLiveQueryEvent('TestObject', req => {
const current = req.object;
current.set('foo', 'yolo');
const original = req.original;
original.set('yolo', 'foo');
Parse.Cloud.afterLiveQueryEvent('TestObject', async ({ object }) => {
const query = new Parse.Query('Test2');
const obj = await query.first();
object.set('obj', obj);
});
const query = new Parse.Query(TestObject);
query.equalTo('objectId', object.id);
const subscription = await query.subscribe();
subscription.on('update', (object, original) => {
expect(object.get('foo')).toBe('yolo');
expect(original.get('yolo')).toBe('foo');
subscription.on('update', object => {
expect(object.get('obj')).toBeDefined();
expect(object.get('obj').get('foo')).toBe('bar');
done();
});
subscription.on('error', () => {
fail('error should not have been called.');
});
object.set({ foo: 'bar' });
await object.save();
});
@@ -599,6 +518,7 @@ describe('ParseLiveQuery', function () {
Parse.Cloud.beforeConnect(() => {}, validatorFail);
let complete = false;
Parse.LiveQuery.on('error', error => {
Parse.LiveQuery.removeAllListeners('error');
if (complete) {
return;
}
@@ -672,6 +592,7 @@ describe('ParseLiveQuery', function () {
throw new Error('You shall not pass!');
});
Parse.LiveQuery.on('error', error => {
Parse.LiveQuery.removeAllListeners('error');
expect(error).toBe('You shall not pass!');
done();
});
@@ -680,6 +601,33 @@ describe('ParseLiveQuery', function () {
await query.subscribe();
});
it('can log on beforeConnect throw', async () => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const logger = require('../lib/logger').logger;
spyOn(logger, 'error').and.callFake(() => {});
let token = undefined;
Parse.Cloud.beforeConnect(({ sessionToken }) => {
token = sessionToken;
/* eslint-disable no-undef */
foo.bar();
/* eslint-enable no-undef */
});
new Parse.Query(TestObject).subscribe();
await new Promise(resolve => Parse.LiveQuery.on('error', resolve));
Parse.LiveQuery.removeAllListeners('error');
expect(logger.error).toHaveBeenCalledWith(
`Failed running beforeConnect for session ${token} with:\n Error: {"message":"foo is not defined","code":141}`
);
});
it('can handle beforeSubscribe error', async done => {
await reconfigureServer({
liveQuery: {
@@ -702,11 +650,40 @@ describe('ParseLiveQuery', function () {
query.equalTo('objectId', object.id);
const subscription = await query.subscribe();
subscription.on('error', error => {
Parse.LiveQuery.removeAllListeners('error');
expect(error).toBe('You shall not subscribe!');
done();
});
});
it('can log on beforeSubscribe error', async () => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const logger = require('../lib/logger').logger;
spyOn(logger, 'error').and.callFake(() => {});
Parse.Cloud.beforeSubscribe(TestObject, () => {
/* eslint-disable no-undef */
foo.bar();
/* eslint-enable no-undef */
});
const query = new Parse.Query(TestObject);
const subscription = await query.subscribe();
await new Promise(resolve => subscription.on('error', resolve));
expect(logger.error).toHaveBeenCalledWith(
`Failed running beforeSubscribe on TestObject for session undefined with:\n Error: {"message":"foo is not defined","code":141}`
);
});
it('can handle mutate beforeSubscribe query', async done => {
await reconfigureServer({
liveQuery: {
@@ -796,6 +773,121 @@ describe('ParseLiveQuery', function () {
await object.save();
});
it('LiveQuery with ACL', async () => {
await reconfigureServer({
liveQuery: {
classNames: ['Chat'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const user = new Parse.User();
user.setUsername('username');
user.setPassword('password');
await user.signUp();
const calls = {
beforeConnect(req) {
expect(req.event).toBe('connect');
expect(req.clients).toBe(0);
expect(req.subscriptions).toBe(0);
expect(req.useMasterKey).toBe(false);
expect(req.installationId).toBeDefined();
expect(req.client).toBeDefined();
},
beforeSubscribe(req) {
expect(req.op).toBe('subscribe');
expect(req.requestId).toBe(1);
expect(req.query).toBeDefined();
expect(req.user).toBeDefined();
},
afterLiveQueryEvent(req) {
expect(req.user).toBeDefined();
expect(req.object.get('foo')).toBe('bar');
},
create(object) {
expect(object.get('foo')).toBe('bar');
},
delete(object) {
expect(object.get('foo')).toBe('bar');
},
};
for (const key in calls) {
spyOn(calls, key).and.callThrough();
}
Parse.Cloud.beforeConnect(calls.beforeConnect);
Parse.Cloud.beforeSubscribe('Chat', calls.beforeSubscribe);
Parse.Cloud.afterLiveQueryEvent('Chat', calls.afterLiveQueryEvent);
const chatQuery = new Parse.Query('Chat');
const subscription = await chatQuery.subscribe();
subscription.on('create', calls.create);
subscription.on('delete', calls.delete);
const object = new Parse.Object('Chat');
const acl = new Parse.ACL(user);
object.setACL(acl);
object.set({ foo: 'bar' });
await object.save();
await object.destroy();
await new Promise(resolve => setTimeout(resolve, 200));
for (const key in calls) {
expect(calls[key]).toHaveBeenCalled();
}
});
it('liveQuery on Session class', async done => {
await reconfigureServer({
liveQuery: { classNames: [Parse.Session] },
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const user = new Parse.User();
user.setUsername('username');
user.setPassword('password');
await user.signUp();
const query = new Parse.Query(Parse.Session);
const subscription = await query.subscribe();
subscription.on('create', async obj => {
await new Promise(resolve => setTimeout(resolve, 200));
expect(obj.get('user').id).toBe(user.id);
expect(obj.get('createdWith')).toEqual({ action: 'login', authProvider: 'password' });
expect(obj.get('expiresAt')).toBeInstanceOf(Date);
expect(obj.get('installationId')).toBeDefined();
expect(obj.get('createdAt')).toBeInstanceOf(Date);
expect(obj.get('updatedAt')).toBeInstanceOf(Date);
done();
});
await Parse.User.logIn('username', 'password');
});
it('prevent liveQuery on Session class when not logged in', async done => {
await reconfigureServer({
liveQuery: {
classNames: [Parse.Session],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
Parse.LiveQuery.on('error', error => {
expect(error).toBe('Invalid session token');
});
const query = new Parse.Query(Parse.Session);
const subscription = await query.subscribe();
subscription.on('error', error => {
Parse.LiveQuery.removeAllListeners('error');
expect(error).toBe('Invalid session token');
done();
});
});
it('handle invalid websocket payload length', async done => {
await reconfigureServer({
liveQuery: {
@@ -842,7 +934,7 @@ describe('ParseLiveQuery', function () {
await reconfigureServer({
liveQuery: {
classNames: ['_User'],
classNames: [Parse.User],
},
startLiveQueryServer: true,
verbose: false,
@@ -928,6 +1020,52 @@ describe('ParseLiveQuery', function () {
done();
});
it('should strip out session token in LiveQuery', async () => {
await reconfigureServer({
liveQuery: { classNames: ['_User'] },
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const user = new Parse.User();
user.setUsername('username');
user.setPassword('password');
user.set('foo', 'bar');
const query = new Parse.Query(Parse.User);
query.equalTo('foo', 'bar');
const subscription = await query.subscribe();
const events = ['create', 'update', 'enter', 'leave', 'delete'];
const response = (obj, prev) => {
expect(obj.get('sessionToken')).toBeUndefined();
expect(obj.sessionToken).toBeUndefined();
expect(prev && prev.sessionToken).toBeUndefined();
if (prev && prev.get) {
expect(prev.get('sessionToken')).toBeUndefined();
}
};
const calls = {};
for (const key of events) {
calls[key] = response;
spyOn(calls, key).and.callThrough();
subscription.on(key, calls[key]);
}
await user.signUp();
user.unset('foo');
await user.save();
user.set('foo', 'bar');
await user.save();
user.set('yolo', 'bar');
await user.save();
await user.destroy();
await new Promise(resolve => setTimeout(resolve, 10));
for (const key of events) {
expect(calls[key]).toHaveBeenCalled();
}
});
afterEach(async function (done) {
const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient();
client.close();
+141 -65
View File
@@ -9,6 +9,8 @@ const queryHashValue = 'hash';
const testUserId = 'userId';
const testClassName = 'TestObject';
const timeout = () => jasmine.timeout(100);
describe('ParseLiveQueryServer', function () {
beforeEach(function (done) {
// Mock ParseWebSocketServer
@@ -127,7 +129,10 @@ describe('ParseLiveQueryServer', function () {
serverStartComplete: () => {
expect(parseServer.liveQueryServer).not.toBeUndefined();
expect(parseServer.liveQueryServer.server).toBe(parseServer.server);
parseServer.server.close(done);
parseServer.server.close(async () => {
await reconfigureServer();
done();
});
},
});
});
@@ -149,7 +154,10 @@ describe('ParseLiveQueryServer', function () {
expect(parseServer.liveQueryServer).not.toBeUndefined();
expect(parseServer.liveQueryServer.server).not.toBe(parseServer.server);
parseServer.liveQueryServer.server.close(
parseServer.server.close.bind(parseServer.server, done)
parseServer.server.close.bind(parseServer.server, async () => {
await reconfigureServer();
done();
})
);
},
});
@@ -744,10 +752,10 @@ describe('ParseLiveQueryServer', function () {
// Make sure we send command to client, since _matchesACL is async, we have to
// wait and check
setTimeout(function () {
expect(client.pushDelete).toHaveBeenCalled();
done();
}, jasmine.ASYNC_TEST_WAIT_TIME);
await timeout();
expect(client.pushDelete).toHaveBeenCalled();
done();
});
it('has no subscription and can handle object save command', async () => {
@@ -779,14 +787,14 @@ describe('ParseLiveQueryServer', function () {
parseLiveQueryServer._onAfterSave(message);
// Make sure we do not send command to client
setTimeout(function () {
expect(client.pushCreate).not.toHaveBeenCalled();
expect(client.pushEnter).not.toHaveBeenCalled();
expect(client.pushUpdate).not.toHaveBeenCalled();
expect(client.pushDelete).not.toHaveBeenCalled();
expect(client.pushLeave).not.toHaveBeenCalled();
done();
}, jasmine.ASYNC_TEST_WAIT_TIME);
await timeout();
expect(client.pushCreate).not.toHaveBeenCalled();
expect(client.pushEnter).not.toHaveBeenCalled();
expect(client.pushUpdate).not.toHaveBeenCalled();
expect(client.pushDelete).not.toHaveBeenCalled();
expect(client.pushLeave).not.toHaveBeenCalled();
done();
});
it('can handle object enter command which matches some subscriptions', async done => {
@@ -816,14 +824,14 @@ describe('ParseLiveQueryServer', function () {
parseLiveQueryServer._onAfterSave(message);
// Make sure we send enter command to client
setTimeout(function () {
expect(client.pushCreate).not.toHaveBeenCalled();
expect(client.pushEnter).toHaveBeenCalled();
expect(client.pushUpdate).not.toHaveBeenCalled();
expect(client.pushDelete).not.toHaveBeenCalled();
expect(client.pushLeave).not.toHaveBeenCalled();
done();
}, jasmine.ASYNC_TEST_WAIT_TIME);
await timeout();
expect(client.pushCreate).not.toHaveBeenCalled();
expect(client.pushEnter).toHaveBeenCalled();
expect(client.pushUpdate).not.toHaveBeenCalled();
expect(client.pushDelete).not.toHaveBeenCalled();
expect(client.pushLeave).not.toHaveBeenCalled();
done();
});
it('can handle object update command which matches some subscriptions', async done => {
@@ -849,14 +857,14 @@ describe('ParseLiveQueryServer', function () {
parseLiveQueryServer._onAfterSave(message);
// Make sure we send update command to client
setTimeout(function () {
expect(client.pushCreate).not.toHaveBeenCalled();
expect(client.pushEnter).not.toHaveBeenCalled();
expect(client.pushUpdate).toHaveBeenCalled();
expect(client.pushDelete).not.toHaveBeenCalled();
expect(client.pushLeave).not.toHaveBeenCalled();
done();
}, jasmine.ASYNC_TEST_WAIT_TIME);
await timeout();
expect(client.pushCreate).not.toHaveBeenCalled();
expect(client.pushEnter).not.toHaveBeenCalled();
expect(client.pushUpdate).toHaveBeenCalled();
expect(client.pushDelete).not.toHaveBeenCalled();
expect(client.pushLeave).not.toHaveBeenCalled();
done();
});
it('can handle object leave command which matches some subscriptions', async done => {
@@ -886,14 +894,81 @@ describe('ParseLiveQueryServer', function () {
parseLiveQueryServer._onAfterSave(message);
// Make sure we send leave command to client
setTimeout(function () {
expect(client.pushCreate).not.toHaveBeenCalled();
expect(client.pushEnter).not.toHaveBeenCalled();
expect(client.pushUpdate).not.toHaveBeenCalled();
expect(client.pushDelete).not.toHaveBeenCalled();
expect(client.pushLeave).toHaveBeenCalled();
done();
}, jasmine.ASYNC_TEST_WAIT_TIME);
await timeout();
expect(client.pushCreate).not.toHaveBeenCalled();
expect(client.pushEnter).not.toHaveBeenCalled();
expect(client.pushUpdate).not.toHaveBeenCalled();
expect(client.pushDelete).not.toHaveBeenCalled();
expect(client.pushLeave).toHaveBeenCalled();
done();
});
it('sends correct events for object with multiple subscriptions', async done => {
const parseLiveQueryServer = new ParseLiveQueryServer({});
Parse.Cloud.afterLiveQueryEvent('TestObject', () => {
// Simulate delay due to trigger, auth, etc.
return jasmine.timeout(10);
});
// Make mock request message
const message = generateMockMessage(true);
// Add mock client
const clientId = 1;
const client = addMockClient(parseLiveQueryServer, clientId);
client.sessionToken = 'sessionToken';
// Mock queryHash for this special test
const mockQueryHash = jasmine.createSpy('matchesQuery').and.returnValue('hash1');
jasmine.mockLibrary('../lib/LiveQuery/QueryTools', 'queryHash', mockQueryHash);
// Add mock subscription 1
const requestId2 = 2;
await addMockSubscription(parseLiveQueryServer, clientId, requestId2, null, null, 'hash1');
// Mock queryHash for this special test
const mockQueryHash2 = jasmine.createSpy('matchesQuery').and.returnValue('hash2');
jasmine.mockLibrary('../lib/LiveQuery/QueryTools', 'queryHash', mockQueryHash2);
// Add mock subscription 2
const requestId3 = 3;
await addMockSubscription(parseLiveQueryServer, clientId, requestId3, null, null, 'hash2');
// Mock _matchesSubscription to return matching
// In order to mimic a leave, then enter, we need original match return true
// and the current match return false, then the other way around
let counter = 0;
parseLiveQueryServer._matchesSubscription = function (parseObject) {
if (!parseObject) {
return false;
}
counter += 1;
// true, false, false, true
return counter < 2 || counter > 3;
};
parseLiveQueryServer._matchesACL = function () {
// Simulate call
return jasmine.timeout(10).then(() => true);
};
parseLiveQueryServer._onAfterSave(message);
// Make sure we send leave and enter command to client
await timeout();
expect(client.pushCreate).not.toHaveBeenCalled();
expect(client.pushEnter).toHaveBeenCalledTimes(1);
expect(client.pushEnter).toHaveBeenCalledWith(
requestId3,
{ key: 'value', className: 'TestObject' },
{ key: 'originalValue', className: 'TestObject' }
);
expect(client.pushUpdate).not.toHaveBeenCalled();
expect(client.pushDelete).not.toHaveBeenCalled();
expect(client.pushLeave).toHaveBeenCalledTimes(1);
expect(client.pushLeave).toHaveBeenCalledWith(
requestId2,
{ key: 'value', className: 'TestObject' },
{ key: 'originalValue', className: 'TestObject' }
);
done();
});
it('can handle update command with original object', async done => {
@@ -930,15 +1005,15 @@ describe('ParseLiveQueryServer', function () {
parseLiveQueryServer._onAfterSave(message);
// Make sure we send update command to client
setTimeout(function () {
expect(client.pushUpdate).toHaveBeenCalled();
const args = parseWebSocket.send.calls.mostRecent().args;
const toSend = JSON.parse(args[0]);
await timeout();
expect(toSend.object).toBeDefined();
expect(toSend.original).toBeDefined();
done();
}, jasmine.ASYNC_TEST_WAIT_TIME);
expect(client.pushUpdate).toHaveBeenCalled();
const args = parseWebSocket.send.calls.mostRecent().args;
const toSend = JSON.parse(args[0]);
expect(toSend.object).toBeDefined();
expect(toSend.original).toBeDefined();
done();
});
it('can handle object create command which matches some subscriptions', async done => {
@@ -964,14 +1039,14 @@ describe('ParseLiveQueryServer', function () {
parseLiveQueryServer._onAfterSave(message);
// Make sure we send create command to client
setTimeout(function () {
expect(client.pushCreate).toHaveBeenCalled();
expect(client.pushEnter).not.toHaveBeenCalled();
expect(client.pushUpdate).not.toHaveBeenCalled();
expect(client.pushDelete).not.toHaveBeenCalled();
expect(client.pushLeave).not.toHaveBeenCalled();
done();
}, jasmine.ASYNC_TEST_WAIT_TIME);
await timeout();
expect(client.pushCreate).toHaveBeenCalled();
expect(client.pushEnter).not.toHaveBeenCalled();
expect(client.pushUpdate).not.toHaveBeenCalled();
expect(client.pushDelete).not.toHaveBeenCalled();
expect(client.pushLeave).not.toHaveBeenCalled();
done();
});
it('can handle create command with fields', async done => {
@@ -1014,14 +1089,14 @@ describe('ParseLiveQueryServer', function () {
parseLiveQueryServer._onAfterSave(message);
// Make sure we send create command to client
setTimeout(function () {
expect(client.pushCreate).toHaveBeenCalled();
const args = parseWebSocket.send.calls.mostRecent().args;
const toSend = JSON.parse(args[0]);
expect(toSend.object).toBeDefined();
expect(toSend.original).toBeUndefined();
done();
}, jasmine.ASYNC_TEST_WAIT_TIME);
await timeout();
expect(client.pushCreate).toHaveBeenCalled();
const args = parseWebSocket.send.calls.mostRecent().args;
const toSend = JSON.parse(args[0]);
expect(toSend.object).toBeDefined();
expect(toSend.original).toBeUndefined();
done();
});
it('can match subscription for null or undefined parse object', function () {
@@ -1731,7 +1806,8 @@ describe('ParseLiveQueryServer', function () {
clientId,
requestId,
parseWebSocket,
query
query,
customQueryHashValue
) {
// If parseWebSocket is null, we use the default one
if (!parseWebSocket) {
@@ -1759,12 +1835,12 @@ describe('ParseLiveQueryServer', function () {
// Make mock subscription
const subscription = parseLiveQueryServer.subscriptions
.get(query.className)
.get(queryHashValue);
.get(customQueryHashValue || queryHashValue);
subscription.hasSubscribingClient = function () {
return false;
};
subscription.className = query.className;
subscription.hash = queryHashValue;
subscription.hash = customQueryHashValue || queryHashValue;
if (subscription.clientRequestIds && subscription.clientRequestIds.has(clientId)) {
subscription.clientRequestIds.get(clientId).push(requestId);
} else {

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