mirror of
https://github.com/parse-community/parse-server
synced 2026-08-09 13:03:18 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fc6e0a938 |
@@ -1,14 +1,9 @@
|
||||
{
|
||||
"plugins": [
|
||||
"@babel/plugin-transform-flow-strip-types",
|
||||
"@babel/plugin-proposal-object-rest-spread"
|
||||
"transform-flow-strip-types"
|
||||
],
|
||||
"presets": [
|
||||
["@babel/preset-env", {
|
||||
"targets": {
|
||||
"node": "12"
|
||||
}
|
||||
}]
|
||||
],
|
||||
"sourceMaps": "inline"
|
||||
"es2015",
|
||||
"stage-0"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@ lib/
|
||||
|
||||
# Tests
|
||||
spec/
|
||||
# Keep local dependencies used to CI tests
|
||||
!spec/dependencies/
|
||||
|
||||
# IDEs
|
||||
.idea/
|
||||
|
||||
+2
-3
@@ -1,3 +1,2 @@
|
||||
lib
|
||||
coverage
|
||||
out
|
||||
lib/*
|
||||
coverage/*
|
||||
|
||||
+2
-5
@@ -14,15 +14,12 @@
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"indent": ["error", 2, { "SwitchCase": 1 }],
|
||||
"indent": ["error", 2],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"no-trailing-spaces": 2,
|
||||
"eol-last": 2,
|
||||
"space-in-parens": ["error", "never"],
|
||||
"no-multiple-empty-lines": 1,
|
||||
"prefer-const": "error",
|
||||
"space-infix-ops": "error",
|
||||
"no-useless-escape": "off",
|
||||
"require-atomic-updates": "off"
|
||||
"prefer-const": "error"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,4 +7,3 @@
|
||||
[libs]
|
||||
|
||||
[options]
|
||||
suppress_comment= \\(.\\|\n\\)*\\@flow-disable-next
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
* text=auto eol=lf
|
||||
|
||||
*.js text
|
||||
*.html text
|
||||
*.less text
|
||||
*.json text
|
||||
*.css text
|
||||
*.xml text
|
||||
*.md text
|
||||
*.txt text
|
||||
*.yml text
|
||||
*.sql text
|
||||
*.sh text
|
||||
|
||||
*.png binary
|
||||
@@ -0,0 +1,67 @@
|
||||
Please read the following instructions carefully.
|
||||
|
||||
Check out https://github.com/ParsePlatform/parse-server/issues/1271 for an ideal bug report.
|
||||
The closer your issue report is to that one, the more likely we are to be able to help, and the more likely we will be to fix the issue quickly!
|
||||
|
||||
Many members of the community use Stack Overflow and Server Fault to ask questions.
|
||||
Read through the existing questions or ask your own!
|
||||
- Stack Overflow: http://stackoverflow.com/questions/tagged/parse.com
|
||||
- Server Fault: https://serverfault.com/tags/parse
|
||||
|
||||
For database migration help, please file a bug report at https://parse.com/help#report
|
||||
|
||||
Make sure these boxes are checked before submitting your issue -- thanks for reporting issues back to Parse Server!
|
||||
|
||||
- [ ] You've met the prerequisites: https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#prerequisites.
|
||||
|
||||
- [ ] You're running the latest version of Parse Server: https://github.com/ParsePlatform/parse-server/releases
|
||||
|
||||
- [ ] You've searched through existing issues: https://github.com/ParsePlatform/Parse-Server/issues?utf8=%E2%9C%93&q=is%3Aissue Chances are that your issue has been reported or resolved before.
|
||||
|
||||
- [ ] You have filled out every section below. Issues without sufficient information are more likely to be closed.
|
||||
|
||||
--
|
||||
|
||||
### Issue Description
|
||||
|
||||
[DELETE EVERYTHING ABOVE THIS LINE BEFORE SUBMITTING YOUR ISSUE]
|
||||
|
||||
Describe your issue in as much detail as possible.
|
||||
|
||||
[FILL THIS OUT]
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
Please include a detailed list of steps that reproduce the issue. Include curl commands when applicable.
|
||||
|
||||
1. [FILL THIS OUT]
|
||||
2. [FILL THIS OUT]
|
||||
3. [FILL THIS OUT]
|
||||
|
||||
#### Expected Results
|
||||
|
||||
[FILL THIS OUT]
|
||||
|
||||
#### Actual Outcome
|
||||
|
||||
[FILL THIS OUT]
|
||||
|
||||
### Environment Setup
|
||||
|
||||
- **Server**
|
||||
- parse-server version (Be specific! Don't say 'latest'.) : [FILL THIS OUT]
|
||||
- Operating System: [FILL THIS OUT]
|
||||
- Hardware: [FILL THIS OUT]
|
||||
- Localhost or remote server? (AWS, Heroku, Azure, Digital Ocean, etc): [FILL THIS OUT]
|
||||
|
||||
- **Database**
|
||||
- MongoDB version: [FILL THIS OUT]
|
||||
- Storage engine: [FILL THIS OUT]
|
||||
- Hardware: [FILL THIS OUT]
|
||||
- Localhost or remote server? (AWS, mLab, ObjectRocket, Digital Ocean, etc): [FILL THIS OUT]
|
||||
|
||||
### Logs/Trace
|
||||
|
||||
You can turn on additional logging by configuring VERBOSE=1 in your environment.
|
||||
|
||||
[FILL THIS OUT]
|
||||
@@ -1,51 +0,0 @@
|
||||
---
|
||||
name: "\U0001F41B Report an issue"
|
||||
about: A feature of Parse Server is not working as expected.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### New Issue Checklist
|
||||
<!--
|
||||
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).
|
||||
- [ ] I have searched through [existing issues](https://github.com/parse-community/parse-server/issues?q=is%3Aissue).
|
||||
- [ ] I can reproduce the issue with the [latest version of Parse Server](https://github.com/parse-community/parse-server/releases). <!-- We don't investigate issues for outdated releases. -->
|
||||
|
||||
### Issue Description
|
||||
<!-- What is the specific issue with Parse Server? -->
|
||||
|
||||
### Steps to reproduce
|
||||
<!-- How can someone else reproduce the issue? -->
|
||||
|
||||
### Actual Outcome
|
||||
<!-- What outcome, for example query result, did you get? -->
|
||||
|
||||
### Expected Outcome
|
||||
<!-- What outcome, for example query result, did you expect? -->
|
||||
### Environment
|
||||
<!-- Be specific with versions, don't use "latest" or semver ranges like "~x.y.z" or "^x.y.z". -->
|
||||
|
||||
Server
|
||||
- Parse Server version: `FILL_THIS_OUT`
|
||||
- Operating system: `FILL_THIS_OUT`
|
||||
- Local or remote host (AWS, Azure, Google Cloud, Heroku, Digital Ocean, etc): `FILL_THIS_OUT`
|
||||
|
||||
Database
|
||||
- System (MongoDB or Postgres): `FILL_THIS_OUT`
|
||||
- Database version: `FILL_THIS_OUT`
|
||||
- Local or remote host (MongoDB Atlas, mLab, AWS, Azure, Google Cloud, etc): `FILL_THIS_OUT`
|
||||
|
||||
Client
|
||||
- SDK (iOS, Android, JavaScript, PHP, Unity, etc): `FILL_THIS_OUT`
|
||||
- SDK version: `FILL_THIS_OUT`
|
||||
|
||||
### Logs
|
||||
<!-- Include relevant logs here. Turn on additional logging by configuring VERBOSE=1 in your environment. -->
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
name: "\U0001F4A1 Request a feature"
|
||||
about: Suggest new functionality or an enhancement of existing functionality.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### 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!
|
||||
-->
|
||||
|
||||
- [ ] 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).
|
||||
|
||||
### Current Limitation
|
||||
<!-- Which current limitation is the feature or enhancement addressing? -->
|
||||
|
||||
### 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? -->
|
||||
@@ -1,8 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: 🙋🏽♀️ Getting help with code
|
||||
url: https://stackoverflow.com/questions/tagged/parse-platform
|
||||
about: Get help with code-level questions on Stack Overflow.
|
||||
- name: 🙋 Getting general help
|
||||
url: https://community.parseplatform.org
|
||||
about: Get help with other questions on our Community Forum.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -1,29 +0,0 @@
|
||||
### 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)
|
||||
@@ -1,62 +0,0 @@
|
||||
# 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.*
|
||||
@@ -1,257 +0,0 @@
|
||||
name: ci
|
||||
on:
|
||||
push:
|
||||
branches: [ release, alpha, beta, next-major ]
|
||||
pull_request:
|
||||
branches:
|
||||
- '**'
|
||||
env:
|
||||
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: MongoDB 5.2, ReplicaSet, WiredTiger
|
||||
MONGODB_VERSION: 5.2.1
|
||||
MONGODB_TOPOLOGY: replicaset
|
||||
MONGODB_STORAGE_ENGINE: wiredTiger
|
||||
NODE_VERSION: 14.18.1
|
||||
- name: MongoDB 5.1, ReplicaSet, WiredTiger
|
||||
MONGODB_VERSION: 5.1.1
|
||||
MONGODB_TOPOLOGY: replicaset
|
||||
MONGODB_STORAGE_ENGINE: wiredTiger
|
||||
NODE_VERSION: 14.18.1
|
||||
- name: MongoDB 5.0, ReplicaSet, WiredTiger
|
||||
MONGODB_VERSION: 5.0.6
|
||||
MONGODB_TOPOLOGY: replicaset
|
||||
MONGODB_STORAGE_ENGINE: wiredTiger
|
||||
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
|
||||
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: 15
|
||||
runs-on: ubuntu-18.04
|
||||
services:
|
||||
redis:
|
||||
image: redis
|
||||
ports:
|
||||
- 6379:6379
|
||||
env:
|
||||
MONGODB_VERSION: ${{ matrix.MONGODB_VERSION }}
|
||||
MONGODB_TOPOLOGY: ${{ matrix.MONGODB_TOPOLOGY }}
|
||||
MONGODB_STORAGE_ENGINE: ${{ matrix.MONGODB_STORAGE_ENGINE }}
|
||||
PARSE_SERVER_TEST_CACHE: ${{ matrix.PARSE_SERVER_TEST_CACHE }}
|
||||
NODE_VERSION: ${{ matrix.NODE_VERSION }}
|
||||
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 pretest
|
||||
- run: npm run coverage
|
||||
env:
|
||||
CI: true
|
||||
- run: bash <(curl -s https://codecov.io/bash)
|
||||
check-postgres:
|
||||
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:
|
||||
image: redis
|
||||
ports:
|
||||
- 6379:6379
|
||||
postgres:
|
||||
image: ${{ matrix.POSTGRES_IMAGE }}
|
||||
env:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
env:
|
||||
PARSE_SERVER_TEST_DB: postgres
|
||||
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 ${{ 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: |
|
||||
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)
|
||||
@@ -1,74 +0,0 @@
|
||||
# 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"!*
|
||||
@@ -1,115 +0,0 @@
|
||||
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
|
||||
@@ -1,57 +0,0 @@
|
||||
# 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 }}
|
||||
@@ -13,11 +13,6 @@ lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
.nyc_output
|
||||
|
||||
# docs output
|
||||
out
|
||||
docs
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
@@ -56,6 +51,3 @@ lib/
|
||||
|
||||
# Folder created by FileSystemAdapter
|
||||
/files
|
||||
|
||||
# Redis Dump
|
||||
dump.rdb
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
instrumentation:
|
||||
excludes: ["**/spec/**"]
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"detectiveOptions": {
|
||||
"ts": {
|
||||
"skipTypeImports": true
|
||||
},
|
||||
"es6": {
|
||||
"skipTypeImports": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"reporter": [
|
||||
"lcov",
|
||||
"text-summary"
|
||||
],
|
||||
"exclude": [
|
||||
"**/spec/**"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
semi: true
|
||||
trailingComma: "es5"
|
||||
singleQuote: true
|
||||
arrowParens: "avoid"
|
||||
printWidth: 100
|
||||
@@ -1,61 +0,0 @@
|
||||
*{{#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}}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{{#if noteGroups}}
|
||||
{{#each noteGroups}}
|
||||
|
||||
### {{title}}
|
||||
|
||||
{{#each notes}}
|
||||
* {{#if commit.scope}}**{{commit.scope}}:** {{/if}}{{text}} ([{{commit.shortHash}}]({{commit.shortHash}}))
|
||||
{{/each}}
|
||||
{{/each}}
|
||||
|
||||
{{/if}}
|
||||
@@ -1,25 +0,0 @@
|
||||
{{#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}}
|
||||
@@ -1,14 +0,0 @@
|
||||
{{> header}}
|
||||
|
||||
{{#each commitGroups}}
|
||||
|
||||
{{#if title}}
|
||||
### {{title}}
|
||||
|
||||
{{/if}}
|
||||
{{#each commits}}
|
||||
{{> commit root=@root}}
|
||||
{{/each}}
|
||||
{{/each}}
|
||||
|
||||
{{> footer}}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
language: node_js
|
||||
dist: trusty
|
||||
node_js:
|
||||
- '4.5'
|
||||
- '6.1'
|
||||
services:
|
||||
- postgresql
|
||||
- redis-server
|
||||
- docker
|
||||
addons:
|
||||
postgresql: '9.5'
|
||||
apt_packages:
|
||||
- postgresql-9.5-postgis-2.3
|
||||
before_script:
|
||||
- ls -al "$HOME/.mongodb/versions"
|
||||
- psql -c 'create database parse_server_postgres_adapter_test_database;' -U postgres
|
||||
- psql -c 'CREATE EXTENSION postgis;' -U postgres -d parse_server_postgres_adapter_test_database
|
||||
- psql -c 'CREATE EXTENSION postgis_topology;' -U postgres -d parse_server_postgres_adapter_test_database
|
||||
env:
|
||||
global:
|
||||
- COVERAGE_OPTION='./node_modules/.bin/istanbul cover'
|
||||
matrix:
|
||||
- MONGODB_VERSION=3.0.8
|
||||
- MONGODB_VERSION=3.2.6
|
||||
- PARSE_SERVER_TEST_DB=postgres
|
||||
- PARSE_SERVER_TEST_CACHE=redis
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- env: PARSE_SERVER_TEST_DB=postgres
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /^[0-9]+.[0-9]+.[0-9]+(-.*)?$/
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
- "$HOME/.mongodb/versions"
|
||||
after_script:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
after_failure:
|
||||
- (cd resources; python travis_after_all.py)
|
||||
after_success:
|
||||
- (cd resources; python travis_after_all.py)
|
||||
- export $(cat resources/.to_export_back)
|
||||
|
||||
deploy:
|
||||
- provider: npm
|
||||
skip_cleanup: true
|
||||
email:
|
||||
secure: T3LwSJFcu632SDfCoavcKL39NktWLEOOFzonAjeHAglmMyDp9hvU8xHwQ4JJy2CRA03c+ezAe2gH3Va+jfxvh1JtFUan+p88vaCHHKuNwPSp4WZBPt1ZTDmG+ACG6j+ZWHK+eP7hLvtlCi/M9/v4/bVojpm7v01LLiM+MRhnE9E7eLemQC4zb6RVtf2oGQ3mX51kMeya218kEm5bsQPpRJElI9jwletFa8qYK5AFgaCHpll059RRHQTTE9MTNcN58P/Kf6Qb3KGpKNoaHTXoOD4U6LcXLWvdHONVB6AzGefxg2b/dvtaO4nd5lDooMBR3u9kWpopXkyAuf+fO/8je9JTxO6CDUtDjHRcR2mCEXWX6rculIAbNXOv1ccRYCTQ8aFtYnFlMSb1+QIAdyT6HHmeT5ktk3+XJRuEv0PJJvqHTo+j7tPngjiv5sPNutgGFlOFO90omTbzEkIT/D/LsgXbWm2QKYWejbLiuSINg+FiFiZN90doCf4aCpm2y1Q/9GzvK+eXcpqzPCGxOykE7EuPZK3+S/ZU2oaWL2uSpbKPtC0qxebrneR307aVEa7C85HCkTMMBzE4tjUr8h5HhLqtWvqmDcnBo3PfQhf9cEO6jQLd3qhEVJmcwKz/yOCfgPXlCbRqiKk7j94perpNCIalXtMI9ySYjJNjHsB4600=
|
||||
api_key:
|
||||
secure: WLjhHVAdUkDy6UdNWveTpZqphw9olN0alCpyPpU0cJjlN/hk7YxPP+YHOSVnMZaRZoHM0LL11jPKLf970nymBfvJHDWxKk71c/5xyTX8pBtSxmGmGy23a5g2VrHVMd2JxsI7NEAH500tlFz+01t4E3Steo0NpAkHR3Q51kj01gQy8IumsksfhRc9uvjZ7zjm99Yk4L+cxyei79v4esfpx7Bgm0HTfAAAG/19F+r0hvvFiV517SREDU/YtcX/rIjVepEy1uiLKEohnmYtVIRSA3Hjh6VlHVhdj2WDd/dYrxi/Ioysq2zOM9pZVLamO9asB1e6JrTEipWE9jSZXxsbnfFzuNLxcOjKv1wd3OzQKF/7pGKGiWRTv5Xm19D/FrXoE/ULs6bHcC/Ke8Gs2RxPlOCdvAFehCkyf5P4HOPCQdR7o8Yiuvt+5JWKBflElNbSd4nWgwUOo3Yv8vC4Vj53fwmM+Uqfu3IgYFWktYxCm4RWIKMfB/gtmjcF6QYFfjvEMwAvRfBV81kuynCsnubXWzQeBE/b3JOhBfpGciKCjKfy+tS6bZfFjCtQV98hMMiCPre8Y7PahHDYc65wU9Ake+ZE+dDaSbeV3DZ5JeifLJHzKW2J2dWeRANkOaiSwO9VBC9/rht5ulK5qQ1pB2+sKDToAaiKy6RMlB/HgIoYqsU=
|
||||
on:
|
||||
tags: true
|
||||
all_branches: true
|
||||
condition: "$BUILD_LEADER$BUILD_AGGREGATE_STATUS = YESothers_succeeded"
|
||||
repo: ParsePlatform/parse-server
|
||||
- provider: script
|
||||
skip_cleanup: true
|
||||
script: ./resources/npm-git.sh
|
||||
on:
|
||||
branch: master
|
||||
condition: "$BUILD_LEADER$BUILD_AGGREGATE_STATUS = YESothers_succeeded"
|
||||
- provider: script
|
||||
skip_cleanup: true
|
||||
script: ./resources/docker-hub.sh
|
||||
on:
|
||||
tags: true
|
||||
all_branches: true
|
||||
condition: "$BUILD_LEADER$BUILD_AGGREGATE_STATUS = YESothers_succeeded"
|
||||
@@ -1,226 +0,0 @@
|
||||
# Upgrading Parse Server to version 3.0.0
|
||||
|
||||
parse-server 3.0.0 comes also with the JS SDK version 2.0 which requires a migration. Follow the migration guide [here](https://github.com/parse-community/Parse-SDK-JS/blob/master/2.0.0.md).
|
||||
|
||||
With the 3.0.0, parse-server has completely revamped it's cloud code interface. Gone are the backbone style calls, welcome promises and async/await.
|
||||
|
||||
In order to leverage those new nodejs features, you'll need to run at least node 8.10. We've dropped the support of node 6 a few months ago, so if you haven't made the change yet, now would be a really good time to take the plunge.
|
||||
|
||||
## Migrating Cloud Code Hooks
|
||||
|
||||
### Synchronous validations:
|
||||
|
||||
```js
|
||||
// before
|
||||
Parse.Cloud.beforeSave('MyClassName', function(request, response) {
|
||||
if (!passesValidation(request.object)) {
|
||||
response.error('Ooops something went wrong');
|
||||
} else {
|
||||
response.success();
|
||||
}
|
||||
});
|
||||
|
||||
// after
|
||||
Parse.Cloud.beforeSave('MyClassName', (request) => {
|
||||
if (!passesValidation(request.object)) {
|
||||
throw 'Ooops something went wrong';
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
All methods are wrapped in promises, so you can freely `throw` `Error`, `Parse.Error` or `string` to mark an error.
|
||||
|
||||
### Asynchronous validations:
|
||||
|
||||
For asynchronous code, you can use promises or async / await.
|
||||
|
||||
Consider the following beforeSave call that would replace the contents of a fileURL with a proper copy of the image as a Parse.File.
|
||||
|
||||
```js
|
||||
// before
|
||||
Parse.Cloud.beforeSave('Post', function(request, response) {
|
||||
Parse.Cloud.httpRequest({
|
||||
url: request.object.get('fileURL'),
|
||||
success: function(contents) {
|
||||
const file = new Parse.File('image.png', { base64: contents.buffer.toString('base64') });
|
||||
file.save({
|
||||
success: function() {
|
||||
request.object.set('file', file);
|
||||
response.success();
|
||||
},
|
||||
error: response.error
|
||||
});
|
||||
},
|
||||
error: response.error
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
As we can see the current way, with backbone style callbacks is quite tough to read and maintain.
|
||||
It's also not really trivial to handle errors, as you need to pass the response.error to each error handlers.
|
||||
|
||||
Now it can be modernized with promises:
|
||||
|
||||
```js
|
||||
// after (with promises)
|
||||
Parse.Cloud.beforeSave('MyClassName', (request) => {
|
||||
return Parse.Cloud.httpRequest({
|
||||
url: request.object.get('fileURL')
|
||||
}).then((contents) => {
|
||||
const file = new Parse.File('image.png', { base64: contents.buffer.toString('base64') });
|
||||
request.object.set('file', file);
|
||||
return file.save();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
And you can even make it better with async/await.
|
||||
|
||||
```js
|
||||
// after with async/await
|
||||
Parse.Cloud.beforeSave('MyClassName', async (request) => {
|
||||
const contents = await Parse.Cloud.httpRequest({
|
||||
url: request.object.get('fileURL')
|
||||
});
|
||||
|
||||
const file = new Parse.File('image.png', { base64: contents.buffer.toString('base64') });
|
||||
request.object.set('file', file);
|
||||
await file.save();
|
||||
});
|
||||
```
|
||||
|
||||
## Aborting hooks and functions
|
||||
|
||||
In order to abort a `beforeSave` or any hook, you now need to throw an error:
|
||||
|
||||
```js
|
||||
// after with async/await
|
||||
Parse.Cloud.beforeSave('MyClassName', async (request) => {
|
||||
// valid, will result in a Parse.Error(SCRIPT_FAILED, 'Something went wrong')
|
||||
throw 'Something went wrong'
|
||||
// also valid, will fail with Parse.Error(SCRIPT_FAILED, 'Something else went wrong')
|
||||
throw new Error('Something else went wrong')
|
||||
// using a Parse.Error is also valid
|
||||
throw new Parse.Error(1001, 'My error')
|
||||
});
|
||||
```
|
||||
|
||||
## Migrating Functions
|
||||
|
||||
Cloud Functions can be migrated the same way as cloud code hooks.
|
||||
In functions, the response object is not passed anymore, as it is in cloud code hooks
|
||||
|
||||
Continuing with the image downloader example:
|
||||
|
||||
```js
|
||||
// before
|
||||
Parse.Cloud.define('downloadImage', function(request, response) {
|
||||
Parse.Cloud.httpRequest({
|
||||
url: request.params.url,
|
||||
success: function(contents) {
|
||||
const file = new Parse.File(request.params.name, { base64: contents.buffer.toString('base64') });
|
||||
file.save({
|
||||
success: function() {
|
||||
response.success(file);
|
||||
},
|
||||
error: response.error
|
||||
});
|
||||
},
|
||||
error: response.error
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
You would call this method with:
|
||||
|
||||
```js
|
||||
Parse.Cloud.run('downloadImage',{
|
||||
url: 'https://example.com/file',
|
||||
name: 'my-file'
|
||||
});
|
||||
```
|
||||
|
||||
To migrate this function you would follow the same practices as the ones before, and we'll jump right away to the async/await implementation:
|
||||
|
||||
```js
|
||||
// after with async/await
|
||||
Parse.Cloud.define('downloadImage', async (request) => {
|
||||
const {
|
||||
url, name
|
||||
} = request.params;
|
||||
const response = await Parse.Cloud.httpRequest({ url });
|
||||
|
||||
const file = new Parse.File(name, { base64: response.buffer.toString('base64') });
|
||||
await file.save();
|
||||
return file;
|
||||
});
|
||||
```
|
||||
|
||||
## Migrating jobs
|
||||
|
||||
As with hooks and functions, jobs don't have a status object anymore.
|
||||
The message method has been moved to the request object.
|
||||
|
||||
```js
|
||||
// before
|
||||
Parse.Cloud.job('downloadImageJob', function(request, status) {
|
||||
var query = new Parse.Query('ImagesToDownload');
|
||||
query.find({
|
||||
success: function(images) {
|
||||
var done = 0;
|
||||
for (var i = 0; i<images.length; i++) {
|
||||
var image = images[i];
|
||||
status.message('Doing '+image.get('url'));
|
||||
Parse.Cloud.httpRequest({
|
||||
url: image.get('url'),
|
||||
success: function(contents) {
|
||||
status.message('Got '+image.get('url'));
|
||||
const file = new Parse.File(image.get('name'), { base64: contents.buffer.toString('base64') });
|
||||
file.save({
|
||||
success: function() {
|
||||
status.message('Saved '+image.get('url'));
|
||||
done++;
|
||||
if (done == images.length) {
|
||||
status.success();
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
response.message('Error '+image.get('url'));
|
||||
done++;
|
||||
if (done == images.length) {
|
||||
status.error();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
error: status.error
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
Parse.Cloud.job('downloadImageJob', async function(request) {
|
||||
const query = new Parse.Query('ImagesToDownload');
|
||||
const images = await query.find();
|
||||
const promises = images.map(async (image) => {
|
||||
request.message('Doing ' + image.get('url'));
|
||||
const contents = await Parse.Cloud.httpRequest({
|
||||
url: image.get('url')
|
||||
});
|
||||
request.message('Got ' + image.get('url'));
|
||||
const file = new Parse.File(image.get('name'), { base64: contents.buffer.toString('base64') });
|
||||
await file.save();
|
||||
request.message('Saved ' + image.get('url'));
|
||||
});
|
||||
await Promise.all(promises);
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
As you can see the new implementation is more concise, easier to read and maintain.
|
||||
|
||||
If you encounter a problem or discover an issue with this guide, or with any Parse Community project, feel free to [reach out on github](https://github.com/parse-community/parse-server/issues/new/choose)
|
||||
|
||||
+555
-35
@@ -1,50 +1,570 @@
|
||||
# Changelog
|
||||
## Parse Server Changelog
|
||||
|
||||
Changelogs are separated by release type for better overview.
|
||||
### 2.3.0
|
||||
[Full Changelog](https://github.com/ParsePlatform/parse-server/compare/2.2.25...2.3.0)
|
||||
|
||||
## ✅ [Stable Releases][log_release]
|
||||
#### Breaking changes
|
||||
* Parse.Cloud.useMasterKey() is a no-op, please refer to (Cloud Code migration guide)[https://github.com/ParsePlatform/parse-server/wiki/Compatibility-with-Hosted-Parse#cloud-code]
|
||||
* Authentication helpers are now proper adapters, deprecates oauth option in favor of auth.
|
||||
* DEPRECATES: facebookAppIds, use `auth: { facebook: { appIds: ["AAAAAAAAA" ] } }`
|
||||
* `email` field is not returned anymore for `Parse.User` queries. (Provided only on the user itself if provided).
|
||||
|
||||
> ### “Stable for production!”
|
||||
#### New Features
|
||||
* Adds ability to restrict access through Class Level Permissions to only authenticated users [see docs](http://parseplatform.github.io/docs/ios/guide/#requires-authentication-permission-requires-parse-server---230)
|
||||
* Adds ability to strip sensitive data from _User responses, strips emails by default, thanks to [Arthur Cinader](https://github.com/acinader)
|
||||
* Adds password history support for password policies, thanks to [Bhaskar Reddy Yasa](https://github.com/bhaskaryasa)
|
||||
|
||||
These are the official, stable releases that you can use in your production environments.
|
||||
#### Improvements
|
||||
* Bump parse-server-s3-adapter to 1.0.6, thanks to [Arthur Cinader](https://github.com/acinader)
|
||||
* Using PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS let you create user sessions when passing {installationId: "xxx-xxx"} on signup in cloud code, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Add CLI option to pass `host` parameter when creating parse-server from CLI, thanks to [Kulshekhar Kabra](https://github.com/kulshekhar)
|
||||
|
||||
Details:
|
||||
- Stability: *stable*
|
||||
- NPM channel: `@latest`
|
||||
- Branch: [release][branch_release]
|
||||
- Purpose: official release
|
||||
- Suitable environment: production
|
||||
#### Bug fixes
|
||||
* Ensure batch routes are only using posix paths, thanks to [Steven Shipton](https://github.com/steven-supersolid)
|
||||
* Ensure falsy options from CLI are properly taken into account, thanks to [Steven Shipton](https://github.com/steven-supersolid)
|
||||
* Fixes issues affecting calls to `matchesKeyInQuery` with pointers.
|
||||
* Ensure that `select` keys can be changed in triggers (beforeFind...), thanks to [Arthur Cinader](https://github.com/acinader)
|
||||
|
||||
## ⚠️ [Beta Releases][log_beta]
|
||||
#### Housekeeping
|
||||
* Enables and enforces linting with eslint, thanks to [Arthur Cinader](https://github.com/acinader)
|
||||
|
||||
> ### “Please try out, we’d love your feedback!”
|
||||
### 2.2.25
|
||||
|
||||
These are releases that are pretty stable, but may have still some bugs to be fixed before official release.
|
||||
Postgres support requires v9.5
|
||||
|
||||
Details:
|
||||
- Stability: *pretty stable*
|
||||
- NPM channel: `@beta`
|
||||
- Branch: [beta][branch_beta]
|
||||
- Purpose: feature maturation
|
||||
- Suitable environment: development
|
||||
#### New Features
|
||||
* Dockerizing Parse Server, thanks to [Kirill Kravinsky](https://github.com/woyorus)
|
||||
* Login with qq, wechat, weibo, thanks to [haifeizhang]()
|
||||
* Password policy, validation and expiration, thanks to [Bhaskar Reddy Yasa](https://github.com/bhaskaryasa)
|
||||
* Health check on /health, thanks to [Kirill Kravinsky](https://github.com/woyorus)
|
||||
* Reuse SchemaCache across requests option, thanks to [Steven Shipton](https://github.com/steven-supersolid)
|
||||
|
||||
## 🔥 [Alpha Releases][log_alpha]
|
||||
#### Improvements
|
||||
* Better support for CLI options, thanks to [Steven Shipton](https://github.com/steven-supersolid)
|
||||
* Specity a database timeout with maxTimeMS, thanks to [Tyler Brock](https://github.com/TylerBrock)
|
||||
* Adds the username to reset password success pages, thanks to [Halim Qarroum](https://github.com/HQarroum)
|
||||
* Better support for Redis cache adapter, thanks to [Tyler Brock](https://github.com/TylerBrock)
|
||||
* Better coverage of Postgres, thanks to [Kulshekhar Kabra](https://github.com/kulshekhar)
|
||||
|
||||
> ### “If you are curious to see what's next!”
|
||||
#### Bug Fixes
|
||||
* Fixes issue when sending push to multiple installations, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fixes issues with twitter authentication, thanks to [jonas-db](https://github.com/jonas-db)
|
||||
* Ignore createdAt fields update, thanks to [Yuki Takeichi](https://github.com/yuki-takeichi)
|
||||
* Improve support for array equality with LiveQuery, thanks to [David Poetzsch-Heffter](https://github.com/dpoetzsch)
|
||||
* Improve support for batch endpoint when serverURL and publicServerURL have different paths, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Support saving relation objects, thanks to [Yuki Takeichi](https://github.com/yuki-takeichi)
|
||||
|
||||
These releases contain the latest development changes, but you should be prepared for anything, including sudden breaking changes or code refactoring. Use this branch to contribute to the project and open pull requests.
|
||||
### 2.2.24
|
||||
|
||||
Details:
|
||||
- Stability: *unstable*
|
||||
- NPM channel: `@alpha`
|
||||
- Branch: [alpha][branch_alpha]
|
||||
- Purpose: product development
|
||||
- Suitable environment: experimental
|
||||
#### New Features
|
||||
* LiveQuery: Bring your own adapter (#2902), thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* LiveQuery: Adds "update" operator to update a query subscription (#2935), thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
|
||||
#### Improvements
|
||||
* Better Postgres support, thanks to [Kulshekhar Kabra](https://github.com/kulshekhar)
|
||||
* Logs the function name when failing (#2963), thanks to [Michael Helvey](https://github.com/michaelhelvey)
|
||||
* CLI: forces closing the connections with SIGINT/SIGTERM (#2964), thanks to [Kulshekhar Kabra](https://github.com/kulshekhar)
|
||||
* Reduce the number of calls to the _SCHEMA table (#2912), thanks to [Steven Shipton](https://github.com/steven-supersolid)
|
||||
* LiveQuery: Support for Role ACL's, thanks to [Aaron Blondeau](https://github.com/aaron-blondeau-dose)
|
||||
|
||||
#### Bug Fixes
|
||||
* Better support for checking application and client keys, thanks to [Steven Shipton](https://github.com/steven-supersolid)
|
||||
* Google OAuth, better support for android and web logins, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
|
||||
### 2.2.23
|
||||
|
||||
* Run liveQuery server from CLI with a different port, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Support for Postgres databaseURI, thanks to [Kulshekhar Kabra](https://github.com/kulshekhar)
|
||||
* Support for Postgres options, thanks to [Kulshekhar Kabra](https://github.com/kulshekhar)
|
||||
* Improved support for google login (id_token and access_token), thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Improvements with VKontakte login, thanks to [Eugene Antropov](https://github.com/antigp)
|
||||
* Improved support for `select` and `include`, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
* Fix error when updating installation with useMasterKey (#2888), thanks to [Jeremy Louie](https://github.com/JeremyPlease)
|
||||
* Fix bug affecting usage of multiple `notEqualTo`, thanks to [Jeremy Louie](https://github.com/JeremyPlease)
|
||||
* Improved support for null values in arrays, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
|
||||
### 2.2.22
|
||||
|
||||
* Minimum nodejs engine is now 4.5
|
||||
|
||||
#### New Features
|
||||
* New: CLI for parse-live-query-server, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* New: Start parse-live-query-server for parse-server CLI, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
|
||||
#### Bug fixes
|
||||
* Fix: Include with pointers are not conflicting with get CLP anymore, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: Removes dependency on babel-polyfill, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: Support nested select calls, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: Use native column selection instead of runtime, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: installationId header is properly used when updating `_Installation` objects, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: don't crash parse-server on improperly formatted live-query messages, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: Passwords are properly stripped out of logs, thanks to [Arthur Cinader](https://github.com/acinader)
|
||||
* Fix: Lookup for email in username if email is not set, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
|
||||
### 2.2.21
|
||||
|
||||
* Fix: Reverts removal of babel-polyfill
|
||||
|
||||
### 2.2.20
|
||||
|
||||
* New: Adds CloudCode handler for `beforeFind`, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* New: RedisCacheAdapter for syncing schema, role and user caches across servers, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* New: Latest master build available at `ParsePlatform/parse-server#latest`, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: Better support for upgradeToRevocableSession with missing session token, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: Removes babel-polyfill runtime dependency, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: Cluster option now support a boolean value for automatically choosing the right number of processes, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: Filenames now appear correctly, thanks to [Lama Chandrasena](https://github.com/lama-buddy)
|
||||
* Fix: `_acl` is properly updated, thanks to [Steven Shipton](https://github.com/steven-supersolid)
|
||||
|
||||
Other fixes by [Mathias Rangel Wulff](https://github.com/mathiasrw)
|
||||
|
||||
### 2.2.19
|
||||
|
||||
* New: support for upgrading to revocable sessions, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* New: NullCacheAdapter for disabling caching, thanks to [Yuki Takeichi](https://github.com/yuki-takeichi)
|
||||
* New: Account lockout policy [#2601](https://github.com/ParsePlatform/parse-server/pull/2601), thanks to [Diwakar Cherukumilli](https://github.com/cherukumilli)
|
||||
* New: Jobs endpoint for defining and run jobs (no scheduling), thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* New: Add --cluster option to the CLI, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* New: Support for login with vk.com, thanks to [Nurdaulet Bolatov](https://github.com/nbolatov)
|
||||
* New: experimental support for postgres databases, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: parse-server doesn't call next() after successful responses, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: Nested objects are properly includeed with Pointer Permissions on, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: null values in include calls are properly handled, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: Schema validations now runs after beforeSave hooks, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: usersname and passwords are properly type checked, thanks to [Bam Wang](https://github.com/bamwang)
|
||||
* Fix: logging in info log would log also in error log, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: removes extaneous logging from ParseLiveQueryServer, thanks to [Flavio Torres](https://github.com/flavionegrao)
|
||||
* Fix: support for Range requests for files, thanks to [Brage G. Staven](https://github.com/Bragegs)
|
||||
|
||||
### 2.2.18
|
||||
|
||||
* Fix: Improve support for objects in push alert, thanks to [Antoine Lenoir](https://github.com/alenoir)
|
||||
* Fix; Prevent pointed from getting clobbered when they are changed in a beforeSave, thanks to [sud](https://github.com/sud80)
|
||||
* Fix: Improve support for "Bytes" type, thanks to [CongHoang](https://github.com/conghoang)
|
||||
* Fix: Better logging compatability with Parse.com, thanks to [Arthur Cinader](https://github.com/acinader)
|
||||
* New: Add Janrain Capture and Janrain Engage auth provider, thanks to [Andrew Lane](https://github.com/AndrewLane)
|
||||
* Improved: Include content length header in files response, thanks to [Steven Van Bael](https://github.com/vbsteven)
|
||||
* Improved: Support byte range header for files, thanks to [Brage G. Staven](https://github.com/Bragegs)
|
||||
* Improved: Validations for LinkedIn access_tokens, thanks to [Felix Dumit](https://github.com/felix-dumit)
|
||||
* Improved: Experimental postgres support, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Perf: Use native bcrypt implementation if available, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
|
||||
|
||||
[log_release]: https://github.com/parse-community/parse-server/blob/release/changelogs/CHANGELOG_release.md
|
||||
[log_beta]: https://github.com/parse-community/parse-server/blob/beta/changelogs/CHANGELOG_beta.md
|
||||
[log_alpha]: https://github.com/parse-community/parse-server/blob/alpha/changelogs/CHANGELOG_alpha.md
|
||||
[branch_release]: https://github.com/parse-community/parse-server/tree/release
|
||||
[branch_beta]: https://github.com/parse-community/parse-server/tree/beta
|
||||
[branch_alpha]: https://github.com/parse-community/parse-server/tree/alpha
|
||||
### [2.2.17](https://github.com/ParsePlatform/parse-server/tree/2.2.17) (07/23/2016)
|
||||
[Full Changelog](https://github.com/ParsePlatform/parse-server/compare/2.2.16...2.2.17)
|
||||
|
||||
* Cloud code logs [\#2370](https://github.com/ParsePlatform/parse-server/pull/2370) ([flovilmart](https://github.com/flovilmart))
|
||||
* Make sure \_PushStatus operations are run in order [\#2367](https://github.com/ParsePlatform/parse-server/pull/2367) ([flovilmart](https://github.com/flovilmart))
|
||||
* Typo fix for error message when can't ensure uniqueness of user email addresses [\#2360](https://github.com/ParsePlatform/parse-server/pull/2360) ([AndrewLane](https://github.com/AndrewLane))
|
||||
* LiveQuery constrains matching fix [\#2357](https://github.com/ParsePlatform/parse-server/pull/2357) ([simonas-notcat](https://github.com/simonas-notcat))
|
||||
* Fix typo in logging for commander parseConfigFile [\#2352](https://github.com/ParsePlatform/parse-server/pull/2352) ([AndrewLane](https://github.com/AndrewLane))
|
||||
* Fix minor typos in test names [\#2351](https://github.com/ParsePlatform/parse-server/pull/2351) ([acinader](https://github.com/acinader))
|
||||
* Makes sure we don't strip authData or session token from users using masterKey [\#2348](https://github.com/ParsePlatform/parse-server/pull/2348) ([flovilmart](https://github.com/flovilmart))
|
||||
* Run coverage with istanbul [\#2340](https://github.com/ParsePlatform/parse-server/pull/2340) ([flovilmart](https://github.com/flovilmart))
|
||||
* Run next\(\) after successfully sending data to the client [\#2338](https://github.com/ParsePlatform/parse-server/pull/2338) ([blacha](https://github.com/blacha))
|
||||
* Cache all the mongodb/version folder [\#2336](https://github.com/ParsePlatform/parse-server/pull/2336) ([flovilmart](https://github.com/flovilmart))
|
||||
* updates usage of setting: emailVerifyTokenValidityDuration [\#2331](https://github.com/ParsePlatform/parse-server/pull/2331) ([cherukumilli](https://github.com/cherukumilli))
|
||||
* Update Mongodb client to 2.2.4 [\#2329](https://github.com/ParsePlatform/parse-server/pull/2329) ([flovilmart](https://github.com/flovilmart))
|
||||
* Allow usage of analytics adapter [\#2327](https://github.com/ParsePlatform/parse-server/pull/2327) ([deashay](https://github.com/deashay))
|
||||
* Fix flaky tests [\#2324](https://github.com/ParsePlatform/parse-server/pull/2324) ([flovilmart](https://github.com/flovilmart))
|
||||
* don't serve null authData values [\#2320](https://github.com/ParsePlatform/parse-server/pull/2320) ([yuzeh](https://github.com/yuzeh))
|
||||
* Fix null relation problem [\#2319](https://github.com/ParsePlatform/parse-server/pull/2319) ([flovilmart](https://github.com/flovilmart))
|
||||
* Clear the connectionPromise upon close or error [\#2314](https://github.com/ParsePlatform/parse-server/pull/2314) ([flovilmart](https://github.com/flovilmart))
|
||||
* Report validation errors with correct error code [\#2299](https://github.com/ParsePlatform/parse-server/pull/2299) ([flovilmart](https://github.com/flovilmart))
|
||||
* Parses correctly Parse.Files and Dates when sent to Cloud Code Functions [\#2297](https://github.com/ParsePlatform/parse-server/pull/2297) ([flovilmart](https://github.com/flovilmart))
|
||||
* Adding proper generic Not Implemented. [\#2292](https://github.com/ParsePlatform/parse-server/pull/2292) ([vitaly-t](https://github.com/vitaly-t))
|
||||
* Adds schema caching capabilities \(5s by default\) [\#2286](https://github.com/ParsePlatform/parse-server/pull/2286) ([flovilmart](https://github.com/flovilmart))
|
||||
* add digits oauth provider [\#2284](https://github.com/ParsePlatform/parse-server/pull/2284) ([ranhsd](https://github.com/ranhsd))
|
||||
* Improve installations query [\#2281](https://github.com/ParsePlatform/parse-server/pull/2281) ([flovilmart](https://github.com/flovilmart))
|
||||
* Adding request headers to cloud functions fixes \#1461 [\#2274](https://github.com/ParsePlatform/parse-server/pull/2274) ([blacha](https://github.com/blacha))
|
||||
* Creates a new sessionToken when updating password [\#2266](https://github.com/ParsePlatform/parse-server/pull/2266) ([flovilmart](https://github.com/flovilmart))
|
||||
* Add Gitter chat link to the README. [\#2264](https://github.com/ParsePlatform/parse-server/pull/2264) ([nlutsenko](https://github.com/nlutsenko))
|
||||
* Restores ability to include non pointer keys [\#2263](https://github.com/ParsePlatform/parse-server/pull/2263) ([flovilmart](https://github.com/flovilmart))
|
||||
* Allow next middleware handle error in handleParseErrors [\#2260](https://github.com/ParsePlatform/parse-server/pull/2260) ([mejcz](https://github.com/mejcz))
|
||||
* Exposes the ClientSDK infos if available [\#2259](https://github.com/ParsePlatform/parse-server/pull/2259) ([flovilmart](https://github.com/flovilmart))
|
||||
* Adds support for multiple twitter auths options [\#2256](https://github.com/ParsePlatform/parse-server/pull/2256) ([flovilmart](https://github.com/flovilmart))
|
||||
* validate\_purchase fix for SANDBOX requests [\#2253](https://github.com/ParsePlatform/parse-server/pull/2253) ([valeryvaskabovich](https://github.com/valeryvaskabovich))
|
||||
|
||||
### 2.2.16 (7/10/2016)
|
||||
|
||||
* New: Expose InMemoryCacheAdapter publicly, thanks to [Steven Shipton](https://github.com/steven-supersolid)
|
||||
* New: Add ability to prevent login with unverified email, thanks to [Diwakar Cherukumilli](https://github.com/cherukumilli)
|
||||
* Improved: Better error message for incorrect type, thanks to [Andrew Lane](https://github.com/AndrewLane)
|
||||
* Improved: Better error message for permission denied, thanks to [Blayne Chard](https://github.com/blacha)
|
||||
* Improved: Update authData on login, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Improved: Ability to not check for old files on Parse.com, thanks to [OzgeAkin](https://github.com/OzgeAkin)
|
||||
* Fix: Issues with email adapter validation, thanks to [Tyler Brock](https://github.com/TylerBrock)
|
||||
* Fix: Issues with nested $or queries, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
|
||||
### 2.2.15 (6/30/2016)
|
||||
|
||||
* Fix: Type in description for Parse.Error.INVALID_QUERY, thanks to [Andrew Lane](https://github.com/AndrewLane)
|
||||
* Improvement: Stop requiring verifyUserEmails for password reset functionality, thanks to [Tyler Brock](https://github.com/TylerBrock)
|
||||
* Improvement: Kill without validation, thanks to [Drew Gross](https://github.com/drew-gross)
|
||||
* Fix: Deleting a file does not delete from fs.files, thanks to [David Keita](https://github.com/maninga)
|
||||
* Fix: Postgres stoage adapter fix, thanks to [Vitaly Tomilov](https://github.com/vitaly-t)
|
||||
* Fix: Results invalid session when providing an invalid session token, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: issue creating an anonymous user, thanks to [Hussam Moqhim](https://github.com/hmoqhim)
|
||||
* Fix: make http response serializable, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* New: Add postmark email adapter alternative [Glenn Reyes](https://github.com/glennreyes)
|
||||
|
||||
### 2.2.14 (6/25/2016)
|
||||
|
||||
* Hotfix: Fix Parse.Cloud.HTTPResponse serialization
|
||||
|
||||
### 2.2.13 (6/12/2016)
|
||||
|
||||
* Hotfix: Pin version of deepcopy
|
||||
|
||||
### 2.2.12 (6/9/2016)
|
||||
|
||||
* New: Custom error codes in cloud code response.error, thanks to [Jeremy Pease](https://github.com/JeremyPlease)
|
||||
* Fix: Crash in beforeSave when response is not an object, thanks to [Tyler Brock](https://github.com/TylerBrock)
|
||||
* Fix: Allow "get" on installations
|
||||
* Fix: Fix overly restrictive Class Level Permissions, thanks to [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: Fix nested date parsing in Cloud Code, thanks to [Marco Cheung](https://github.com/Marco129)
|
||||
* Fix: Support very old file formats from Parse.com
|
||||
|
||||
### 2.2.11 (5/31/2016)
|
||||
|
||||
* Security: Censor user password in logs, thanks to [Marco Cheung](https://github.com/Marco129)
|
||||
* New: Add PARSE_SERVER_LOGS_FOLDER env var for setting log folder, thanks to [KartikeyaRokde](https://github.com/KartikeyaRokde)
|
||||
* New: Webhook key support, thanks to [Tyler Brock](https://github.com/TylerBrock)
|
||||
* Perf: Add cache adapter and default caching of certain objects, thanks to [Blayne Chard](https://github.com/blacha)
|
||||
* Improvement: Better error messages for schema type mismatches, thanks to [Jeremy Pease](https://github.com/JeremyPlease)
|
||||
* Improvement: Better error messages for reset password emails
|
||||
* Improvement: Webhook key support in CLI, thanks to [Tyler Brock](https://github.com/TylerBrock)
|
||||
* Fix: Remove read only fields when using beforeSave, thanks to [Tyler Brock](https://github.com/TylerBrock)
|
||||
* Fix: Use content type provided by JS SDK, thanks to [Blayne Chard](https://github.com/blacha) and [Florent Vilmart](https://github.com/flovilmart)
|
||||
* Fix: Tell the dashboard the stored push data is available, thanks to [Jeremy Pease](https://github.com/JeremyPlease)
|
||||
* Fix: Add support for HTTP Basic Auth, thanks to [Hussam Moqhim](https://github.com/hmoqhim)
|
||||
* Fix: Support for MongoDB version 3.2.6, (note: do not use MongoDB 3.2 with migrated apps that still have traffic on Parse.com), thanks to [Tyler Brock](https://github.com/TylerBrock)
|
||||
* Fix: Prevent `pm2` from crashing when push notifications fail, thanks to [benishak](https://github.com/benishak)
|
||||
* Fix: Add full list of default _Installation fields, thanks to [Jeremy Pease](https://github.com/JeremyPlease)
|
||||
* Fix: Strip objectId out of hooks responses, thanks to [Tyler Brock](https://github.com/TylerBrock)
|
||||
* Fix: Fix external webhook response format, thanks to [Tyler Brock](https://github.com/TylerBrock)
|
||||
* Fix: Fix beforeSave when object is passed to `success`, thanks to [Madhav Bhagat](https://github.com/codebreach)
|
||||
* Fix: Remove use of deprecated APIs, thanks to [Emad Ehsan](https://github.com/emadehsan)
|
||||
* Fix: Crash when multiple Parse Servers on the same machine try to write to the same logs folder, thanks to [Steven Shipton](https://github.com/steven-supersolid)
|
||||
* Fix: Various issues with key names in `Parse.Object`s
|
||||
* Fix: Treat Bytes type properly
|
||||
* Fix: Caching bugs that caused writes by masterKey or other session token to not show up to users reading with a different session token
|
||||
* Fix: Pin mongo driver version, preventing a regression in version 2.1.19
|
||||
* Fix: Various issues with pointer fields not being treated properly
|
||||
* Fix: Issues with pointed getting un-fetched due to changes in beforeSave
|
||||
* Fix: Fixed crash when deleting classes that have CLPs
|
||||
|
||||
### 2.2.10 (5/15/2016)
|
||||
|
||||
* Fix: Write legacy ACLs to Mongo so that clients that still go through Parse.com can read them, thanks to [Tyler Brock](https://github.com/TylerBrock) and [carmenlau](https://github.com/carmenlau)
|
||||
* Fix: Querying installations with limit = 0 and count = 1 now works, thanks to [ssk7833](https://github.com/ssk7833)
|
||||
* Fix: Return correct error when violating unique index, thanks to [Marco Cheung](https://github.com/Marco129)
|
||||
* Fix: Allow unsetting user's email, thanks to [Marco Cheung](https://github.com/Marco129)
|
||||
* New: Support for Node 6.1
|
||||
|
||||
### 2.2.9 (5/9/2016)
|
||||
|
||||
* Fix: Fix a regression that caused Parse Server to crash when a null parameter is passed to a Cloud function
|
||||
|
||||
### 2.2.8 (5/8/2016)
|
||||
|
||||
* New: Support for Pointer Permissions
|
||||
* New: Expose logger in Cloud Code
|
||||
* New: Option to revoke sessions on password reset
|
||||
* New: Option to expire inactive sessions
|
||||
* Perf: Improvements in ACL checking query
|
||||
* Fix: Issues when sending pushes to list of devices that contains invalid values
|
||||
* Fix: Issues caused by using babel-polyfill outside of Parse Server, but in the same express app
|
||||
* Fix: Remove creation of extra session tokens
|
||||
* Fix: Return authData when querying with master key
|
||||
* Fix: Bugs when deleting webhooks
|
||||
* Fix: Ignore _RevocableSession header, which might be sent by the JS SDK
|
||||
* Fix: Issues with querying via URL params
|
||||
* Fix: Properly encode "Date" parameters to cloud code functions
|
||||
|
||||
|
||||
### 2.2.7 (4/15/2016)
|
||||
|
||||
* Adds support for --verbose and verbose option when running ParseServer [\#1414](https://github.com/ParsePlatform/parse-server/pull/1414) ([flovilmart](https://github.com/flovilmart))
|
||||
* Adds limit = 0 as a valid parameter for queries [\#1493](https://github.com/ParsePlatform/parse-server/pull/1493) ([seijiakiyama](https://github.com/seijiakiyama))
|
||||
* Makes sure we preserve Installations when updating a token \(\#1475\) [\#1486](https://github.com/ParsePlatform/parse-server/pull/1486) ([flovilmart](https://github.com/flovilmart))
|
||||
* Hotfix for tests [\#1503](https://github.com/ParsePlatform/parse-server/pull/1503) ([flovilmart](https://github.com/flovilmart))
|
||||
* Enable logs [\#1502](https://github.com/ParsePlatform/parse-server/pull/1502) ([drew-gross](https://github.com/drew-gross))
|
||||
* Do some triple equals for great justice [\#1499](https://github.com/ParsePlatform/parse-server/pull/1499) ([TylerBrock](https://github.com/TylerBrock))
|
||||
* Apply credential stripping to all untransforms for \_User [\#1498](https://github.com/ParsePlatform/parse-server/pull/1498) ([TylerBrock](https://github.com/TylerBrock))
|
||||
* Checking if object has defined key for Pointer constraints in liveQuery [\#1487](https://github.com/ParsePlatform/parse-server/pull/1487) ([simonas-notcat](https://github.com/simonas-notcat))
|
||||
* Remove collection prefix and default mongo URI [\#1479](https://github.com/ParsePlatform/parse-server/pull/1479) ([drew-gross](https://github.com/drew-gross))
|
||||
* Store collection prefix in mongo adapter, and clean up adapter interface [\#1472](https://github.com/ParsePlatform/parse-server/pull/1472) ([drew-gross](https://github.com/drew-gross))
|
||||
* Move field deletion logic into mongo adapter [\#1471](https://github.com/ParsePlatform/parse-server/pull/1471) ([drew-gross](https://github.com/drew-gross))
|
||||
* Adds support for Long and Double mongodb types \(fixes \#1316\) [\#1470](https://github.com/ParsePlatform/parse-server/pull/1470) ([flovilmart](https://github.com/flovilmart))
|
||||
* Schema.js database agnostic [\#1468](https://github.com/ParsePlatform/parse-server/pull/1468) ([flovilmart](https://github.com/flovilmart))
|
||||
* Remove console.log [\#1465](https://github.com/ParsePlatform/parse-server/pull/1465) ([drew-gross](https://github.com/drew-gross))
|
||||
* Push status nits [\#1462](https://github.com/ParsePlatform/parse-server/pull/1462) ([flovilmart](https://github.com/flovilmart))
|
||||
* Fixes \#1444 [\#1451](https://github.com/ParsePlatform/parse-server/pull/1451) ([flovilmart](https://github.com/flovilmart))
|
||||
* Removing sessionToken and authData from \_User objects included in a query [\#1450](https://github.com/ParsePlatform/parse-server/pull/1450) ([simonas-notcat](https://github.com/simonas-notcat))
|
||||
* Move mongo field type logic into mongoadapter [\#1432](https://github.com/ParsePlatform/parse-server/pull/1432) ([drew-gross](https://github.com/drew-gross))
|
||||
* Prevents \_User lock out when setting ACL on signup or afterwards [\#1429](https://github.com/ParsePlatform/parse-server/pull/1429) ([flovilmart](https://github.com/flovilmart))
|
||||
* Update .travis.yml [\#1428](https://github.com/ParsePlatform/parse-server/pull/1428) ([flovilmart](https://github.com/flovilmart))
|
||||
* Adds relation fields to objects [\#1424](https://github.com/ParsePlatform/parse-server/pull/1424) ([flovilmart](https://github.com/flovilmart))
|
||||
* Update .travis.yml [\#1423](https://github.com/ParsePlatform/parse-server/pull/1423) ([flovilmart](https://github.com/flovilmart))
|
||||
* Sets the defaultSchemas keys in the SchemaCollection [\#1421](https://github.com/ParsePlatform/parse-server/pull/1421) ([flovilmart](https://github.com/flovilmart))
|
||||
* Fixes \#1417 [\#1420](https://github.com/ParsePlatform/parse-server/pull/1420) ([drew-gross](https://github.com/drew-gross))
|
||||
* Untransform should treat Array's as nested objects [\#1416](https://github.com/ParsePlatform/parse-server/pull/1416) ([blacha](https://github.com/blacha))
|
||||
* Adds X-Parse-Push-Status-Id header [\#1412](https://github.com/ParsePlatform/parse-server/pull/1412) ([flovilmart](https://github.com/flovilmart))
|
||||
* Schema format cleanup [\#1407](https://github.com/ParsePlatform/parse-server/pull/1407) ([drew-gross](https://github.com/drew-gross))
|
||||
* Updates the publicServerURL option [\#1397](https://github.com/ParsePlatform/parse-server/pull/1397) ([flovilmart](https://github.com/flovilmart))
|
||||
* Fix exception with non-expiring session tokens. [\#1386](https://github.com/ParsePlatform/parse-server/pull/1386) ([0x18B2EE](https://github.com/0x18B2EE))
|
||||
* Move mongo schema format related logic into mongo adapter [\#1385](https://github.com/ParsePlatform/parse-server/pull/1385) ([drew-gross](https://github.com/drew-gross))
|
||||
* WIP: Huge performance improvement on roles queries [\#1383](https://github.com/ParsePlatform/parse-server/pull/1383) ([flovilmart](https://github.com/flovilmart))
|
||||
* Removes GCS Adapter from provided adapters [\#1339](https://github.com/ParsePlatform/parse-server/pull/1339) ([flovilmart](https://github.com/flovilmart))
|
||||
* DBController refactoring [\#1228](https://github.com/ParsePlatform/parse-server/pull/1228) ([flovilmart](https://github.com/flovilmart))
|
||||
* Spotify authentication [\#1226](https://github.com/ParsePlatform/parse-server/pull/1226) ([1nput0utput](https://github.com/1nput0utput))
|
||||
* Expose DatabaseAdapter to simplify application tests [\#1121](https://github.com/ParsePlatform/parse-server/pull/1121) ([steven-supersolid](https://github.com/steven-supersolid))
|
||||
|
||||
### 2.2.6 (4/5/2016)
|
||||
|
||||
* Important Fix: Disables find on installation from clients [\#1374](https://github.com/ParsePlatform/parse-server/pull/1374) ([flovilmart](https://github.com/flovilmart))
|
||||
* Adds missing options to the CLI [\#1368](https://github.com/ParsePlatform/parse-server/pull/1368) ([flovilmart](https://github.com/flovilmart))
|
||||
* Removes only master on travis [\#1367](https://github.com/ParsePlatform/parse-server/pull/1367) ([flovilmart](https://github.com/flovilmart))
|
||||
* Auth.\_loadRoles should not query the same role twice. [\#1366](https://github.com/ParsePlatform/parse-server/pull/1366) ([blacha](https://github.com/blacha))
|
||||
|
||||
### 2.2.5 (4/4/2016)
|
||||
|
||||
* Improves config loading and tests [\#1363](https://github.com/ParsePlatform/parse-server/pull/1363) ([flovilmart](https://github.com/flovilmart))
|
||||
* Adds travis configuration to deploy NPM on new version tags [\#1361](https://github.com/ParsePlatform/parse-server/pull/1361) ([gfosco](https://github.com/gfosco))
|
||||
* Inject the default schemas properties when loading it [\#1357](https://github.com/ParsePlatform/parse-server/pull/1357) ([flovilmart](https://github.com/flovilmart))
|
||||
* Adds console transport when testing with VERBOSE=1 [\#1351](https://github.com/ParsePlatform/parse-server/pull/1351) ([flovilmart](https://github.com/flovilmart))
|
||||
* Make notEqual work on relations [\#1350](https://github.com/ParsePlatform/parse-server/pull/1350) ([flovilmart](https://github.com/flovilmart))
|
||||
* Accept only bool for $exists in LiveQuery [\#1315](https://github.com/ParsePlatform/parse-server/pull/1315) ([drew-gross](https://github.com/drew-gross))
|
||||
* Adds more options when using CLI/config [\#1305](https://github.com/ParsePlatform/parse-server/pull/1305) ([flovilmart](https://github.com/flovilmart))
|
||||
* Update error message [\#1297](https://github.com/ParsePlatform/parse-server/pull/1297) ([drew-gross](https://github.com/drew-gross))
|
||||
* Properly let masterKey add fields [\#1291](https://github.com/ParsePlatform/parse-server/pull/1291) ([flovilmart](https://github.com/flovilmart))
|
||||
* Point to \#1271 as how to write a good issue report [\#1290](https://github.com/ParsePlatform/parse-server/pull/1290) ([drew-gross](https://github.com/drew-gross))
|
||||
* Adds ability to override mount with publicServerURL for production uses [\#1287](https://github.com/ParsePlatform/parse-server/pull/1287) ([flovilmart](https://github.com/flovilmart))
|
||||
* Single object queries to use include and keys [\#1280](https://github.com/ParsePlatform/parse-server/pull/1280) ([jeremyjackson89](https://github.com/jeremyjackson89))
|
||||
* Improves report for Push error in logs and \_PushStatus [\#1269](https://github.com/ParsePlatform/parse-server/pull/1269) ([flovilmart](https://github.com/flovilmart))
|
||||
* Removes all stdout/err logs while testing [\#1268](https://github.com/ParsePlatform/parse-server/pull/1268) ([flovilmart](https://github.com/flovilmart))
|
||||
* Matching queries with doesNotExist constraint [\#1250](https://github.com/ParsePlatform/parse-server/pull/1250) ([andrecardoso](https://github.com/andrecardoso))
|
||||
* Added session length option for session tokens to server configuration [\#997](https://github.com/ParsePlatform/parse-server/pull/997) ([Kenishi](https://github.com/Kenishi))
|
||||
* Regression test for \#1259 [\#1286](https://github.com/ParsePlatform/parse-server/pull/1286) ([drew-gross](https://github.com/drew-gross))
|
||||
* Regression test for \#871 [\#1283](https://github.com/ParsePlatform/parse-server/pull/1283) ([drew-gross](https://github.com/drew-gross))
|
||||
* Add a test to repro \#701 [\#1281](https://github.com/ParsePlatform/parse-server/pull/1281) ([drew-gross](https://github.com/drew-gross))
|
||||
* Fix for \#1334: using relative cloud code files broken [\#1353](https://github.com/ParsePlatform/parse-server/pull/1353) ([airdrummingfool](https://github.com/airdrummingfool))
|
||||
* Fix Issue/1288 [\#1346](https://github.com/ParsePlatform/parse-server/pull/1346) ([flovilmart](https://github.com/flovilmart))
|
||||
* Fixes \#1271 [\#1295](https://github.com/ParsePlatform/parse-server/pull/1295) ([drew-gross](https://github.com/drew-gross))
|
||||
* Fixes issue \#1302 [\#1314](https://github.com/ParsePlatform/parse-server/pull/1314) ([flovilmart](https://github.com/flovilmart))
|
||||
* Fixes bug related to include in queries [\#1312](https://github.com/ParsePlatform/parse-server/pull/1312) ([flovilmart](https://github.com/flovilmart))
|
||||
|
||||
|
||||
### 2.2.4 (3/29/2016)
|
||||
|
||||
* Hotfix: fixed imports issue for S3Adapter, GCSAdapter, FileSystemAdapter [\#1263](https://github.com/ParsePlatform/parse-server/pull/1263) ([drew-gross](https://github.com/drew-gross)
|
||||
* Fix: Clean null authData values on _User update [\#1199](https://github.com/ParsePlatform/parse-server/pull/1199) ([yuzeh](https://github.com/yuzeh))
|
||||
|
||||
### 2.2.3 (3/29/2016)
|
||||
|
||||
* Fixed bug with invalid email verification link on email update. [\#1253](https://github.com/ParsePlatform/parse-server/pull/1253) ([kzielonka](https://github.com/kzielonka))
|
||||
* Badge update supports increment as well as Increment [\#1248](https://github.com/ParsePlatform/parse-server/pull/1248) ([flovilmart](https://github.com/flovilmart))
|
||||
* Config/Push Tested with the dashboard. [\#1235](https://github.com/ParsePlatform/parse-server/pull/1235) ([drew-gross](https://github.com/drew-gross))
|
||||
* Better logging with winston [\#1234](https://github.com/ParsePlatform/parse-server/pull/1234) ([flovilmart](https://github.com/flovilmart))
|
||||
* Make GlobalConfig work like parse.com [\#1210](https://github.com/ParsePlatform/parse-server/pull/1210) ([framp](https://github.com/framp))
|
||||
* Improve flattening of results from pushAdapter [\#1204](https://github.com/ParsePlatform/parse-server/pull/1204) ([flovilmart](https://github.com/flovilmart))
|
||||
* Push adapters are provided by external packages [\#1195](https://github.com/ParsePlatform/parse-server/pull/1195) ([flovilmart](https://github.com/flovilmart))
|
||||
* Fix flaky test [\#1188](https://github.com/ParsePlatform/parse-server/pull/1188) ([drew-gross](https://github.com/drew-gross))
|
||||
* Fixes problem affecting finding array pointers [\#1185](https://github.com/ParsePlatform/parse-server/pull/1185) ([flovilmart](https://github.com/flovilmart))
|
||||
* Moves Files adapters to external packages [\#1172](https://github.com/ParsePlatform/parse-server/pull/1172) ([flovilmart](https://github.com/flovilmart))
|
||||
* Mark push as enabled in serverInfo endpoint [\#1164](https://github.com/ParsePlatform/parse-server/pull/1164) ([drew-gross](https://github.com/drew-gross))
|
||||
* Document email adapter [\#1144](https://github.com/ParsePlatform/parse-server/pull/1144) ([drew-gross](https://github.com/drew-gross))
|
||||
* Reset password fix [\#1133](https://github.com/ParsePlatform/parse-server/pull/1133) ([carmenlau](https://github.com/carmenlau))
|
||||
|
||||
### 2.2.2 (3/23/2016)
|
||||
|
||||
* Important Fix: Mounts createLiveQueryServer, fix babel induced problem [\#1153](https://github.com/ParsePlatform/parse-server/pull/1153) (flovilmart)
|
||||
* Move ParseServer to it's own file [\#1166](https://github.com/ParsePlatform/parse-server/pull/1166) (flovilmart)
|
||||
* Update README.md * remove deploy buttons * replace with community links [\#1139](https://github.com/ParsePlatform/parse-server/pull/1139) (drew-gross)
|
||||
* Adds bootstrap.sh [\#1138](https://github.com/ParsePlatform/parse-server/pull/1138) (flovilmart)
|
||||
* Fix: Do not override username [\#1142](https://github.com/ParsePlatform/parse-server/pull/1142) (flovilmart)
|
||||
* Fix: Add pushId back to GCM payload [\#1168](https://github.com/ParsePlatform/parse-server/pull/1168) (wangmengyan95)
|
||||
|
||||
### 2.2.1 (3/22/2016)
|
||||
|
||||
* New: Add FileSystemAdapter file adapter [\#1098](https://github.com/ParsePlatform/parse-server/pull/1098) (dtsolis)
|
||||
* New: Enabled CLP editing [\#1128](https://github.com/ParsePlatform/parse-server/pull/1128) (drew-gross)
|
||||
* Improvement: Reduces the number of connections to mongo created [\#1111](https://github.com/ParsePlatform/parse-server/pull/1111) (flovilmart)
|
||||
* Improvement: Make ParseServer a class [\#980](https://github.com/ParsePlatform/parse-server/pull/980) (flovilmart)
|
||||
* Fix: Adds support for plain object in $add, $addUnique, $remove [\#1114](https://github.com/ParsePlatform/parse-server/pull/1114) (flovilmart)
|
||||
* Fix: Generates default CLP, freezes objects [\#1132](https://github.com/ParsePlatform/parse-server/pull/1132) (flovilmart)
|
||||
* Fix: Properly sets installationId on creating session with 3rd party auth [\#1110](https://github.com/ParsePlatform/parse-server/pull/1110) (flovilmart)
|
||||
|
||||
### 2.2.0 (3/18/2016)
|
||||
|
||||
* New Feature: Real-time functionality with Live Queries! [\#1092](https://github.com/ParsePlatform/parse-server/pull/1092) (wangmengyan95)
|
||||
* Improvement: Push Status API [\#1004](https://github.com/ParsePlatform/parse-server/pull/1004) (flovilmart)
|
||||
* Improvement: Allow client operations on Roles [\#1068](https://github.com/ParsePlatform/parse-server/pull/1068) (flovilmart)
|
||||
* Improvement: Add URI encoding to mongo auth parameters [\#986](https://github.com/ParsePlatform/parse-server/pull/986) (bgw)
|
||||
* Improvement: Adds support for apps key in config file, but only support single app for now [\#979](https://github.com/ParsePlatform/parse-server/pull/979) (flovilmart)
|
||||
* Documentation: Getting Started and Configuring Parse Server [\#988](https://github.com/ParsePlatform/parse-server/pull/988) (hramos)
|
||||
* Fix: Various edge cases with REST API [\#1066](https://github.com/ParsePlatform/parse-server/pull/1066) (flovilmart)
|
||||
* Fix: Makes sure the location in results has the proper objectId [\#1065](https://github.com/ParsePlatform/parse-server/pull/1065) (flovilmart)
|
||||
* Fix: Third-party auth is properly removed when unlinked [\#1081](https://github.com/ParsePlatform/parse-server/pull/1081) (flovilmart)
|
||||
* Fix: Clear the session-user cache when changing \_User objects [\#1072](https://github.com/ParsePlatform/parse-server/pull/1072) (gfosco)
|
||||
* Fix: Bug related to subqueries on unfetched objects [\#1046](https://github.com/ParsePlatform/parse-server/pull/1046) (flovilmart)
|
||||
* Fix: Properly urlencode parameters for email validation and password reset [\#1001](https://github.com/ParsePlatform/parse-server/pull/1001) (flovilmart)
|
||||
* Fix: Better sanitization/decoding of object data for afterSave triggers [\#992](https://github.com/ParsePlatform/parse-server/pull/992) (flovilmart)
|
||||
* Fix: Changes default encoding for httpRequest [\#892](https://github.com/ParsePlatform/parse-server/pull/892) (flovilmart)
|
||||
|
||||
### 2.1.6 (3/11/2016)
|
||||
|
||||
* Improvement: Full query support for badge Increment \(\#931\) [\#983](https://github.com/ParsePlatform/parse-server/pull/983) (flovilmart)
|
||||
* Improvement: Shutdown standalone parse server gracefully [\#958](https://github.com/ParsePlatform/parse-server/pull/958) (raulr)
|
||||
* Improvement: Add database options to ParseServer constructor and pass to MongoStorageAdapter [\#956](https://github.com/ParsePlatform/parse-server/pull/956) (steven-supersolid)
|
||||
* Improvement: AuthData logic refactor [\#952](https://github.com/ParsePlatform/parse-server/pull/952) (flovilmart)
|
||||
* Improvement: Changed FileLoggerAdapterSpec to fail gracefully on Windows [\#946](https://github.com/ParsePlatform/parse-server/pull/946) (aneeshd16)
|
||||
* Improvement: Add new schema collection type and replace all usages of direct mongo collection for schema operations. [\#943](https://github.com/ParsePlatform/parse-server/pull/943) (nlutsenko)
|
||||
* Improvement: Adds CLP API to Schema router [\#898](https://github.com/ParsePlatform/parse-server/pull/898) (flovilmart)
|
||||
* Fix: Cleans up authData null keys on login for android crash [\#978](https://github.com/ParsePlatform/parse-server/pull/978) (flovilmart)
|
||||
* Fix: Do master query for before/afterSaveHook [\#959](https://github.com/ParsePlatform/parse-server/pull/959) (wangmengyan95)
|
||||
* Fix: re-add shebang [\#944](https://github.com/ParsePlatform/parse-server/pull/944) (flovilmart)
|
||||
* Fix: Added test command for Windows support [\#886](https://github.com/ParsePlatform/parse-server/pull/886) (aneeshd16)
|
||||
|
||||
### 2.1.5 (3/9/2016)
|
||||
|
||||
* New: FileAdapter for Google Cloud Storage [\#708](https://github.com/ParsePlatform/parse-server/pull/708) (mcdonamp)
|
||||
* Improvement: Minimize extra schema queries in some scenarios. [\#919](https://github.com/ParsePlatform/parse-server/pull/919) (Marco129)
|
||||
* Improvement: Move DatabaseController and Schema fully to adaptive mongo collection. [\#909](https://github.com/ParsePlatform/parse-server/pull/909) (nlutsenko)
|
||||
* Improvement: Cleanup PushController/PushRouter, remove raw mongo collection access. [\#903](https://github.com/ParsePlatform/parse-server/pull/903) (nlutsenko)
|
||||
* Improvement: Increment badge the right way [\#902](https://github.com/ParsePlatform/parse-server/pull/902) (flovilmart)
|
||||
* Improvement: Migrate ParseGlobalConfig to new database storage API. [\#901](https://github.com/ParsePlatform/parse-server/pull/901) (nlutsenko)
|
||||
* Improvement: Improve delete flow for non-existent \_Join collection [\#881](https://github.com/ParsePlatform/parse-server/pull/881) (Marco129)
|
||||
* Improvement: Adding a role scenario test for issue 827 [\#878](https://github.com/ParsePlatform/parse-server/pull/878) (gfosco)
|
||||
* Improvement: Test empty authData block on login for \#413 [\#863](https://github.com/ParsePlatform/parse-server/pull/863) (gfosco)
|
||||
* Improvement: Modified the npm dev script to support Windows [\#846](https://github.com/ParsePlatform/parse-server/pull/846) (aneeshd16)
|
||||
* Improvement: Move HooksController to use MongoCollection instead of direct Mongo access. [\#844](https://github.com/ParsePlatform/parse-server/pull/844) (nlutsenko)
|
||||
* Improvement: Adds public\_html and views for packaging [\#839](https://github.com/ParsePlatform/parse-server/pull/839) (flovilmart)
|
||||
* Improvement: Better support for windows builds [\#831](https://github.com/ParsePlatform/parse-server/pull/831) (flovilmart)
|
||||
* Improvement: Convert Schema.js to ES6 class. [\#826](https://github.com/ParsePlatform/parse-server/pull/826) (nlutsenko)
|
||||
* Improvement: Remove duplicated instructions [\#816](https://github.com/ParsePlatform/parse-server/pull/816) (hramos)
|
||||
* Improvement: Completely migrate SchemasRouter to new MongoCollection API. [\#794](https://github.com/ParsePlatform/parse-server/pull/794) (nlutsenko)
|
||||
* Fix: Do not require where clause in $dontSelect condition on queries. [\#925](https://github.com/ParsePlatform/parse-server/pull/925) (nlutsenko)
|
||||
* Fix: Make sure that ACLs propagate to before/after save hooks. [\#924](https://github.com/ParsePlatform/parse-server/pull/924) (nlutsenko)
|
||||
* Fix: Support params option in Parse.Cloud.httpRequest. [\#912](https://github.com/ParsePlatform/parse-server/pull/912) (carmenlau)
|
||||
* Fix: Fix flaky Parse.GeoPoint test. [\#908](https://github.com/ParsePlatform/parse-server/pull/908) (nlutsenko)
|
||||
* Fix: Handle legacy \_client\_permissions key in \_SCHEMA. [\#900](https://github.com/ParsePlatform/parse-server/pull/900) (drew-gross)
|
||||
* Fix: Fixes bug when querying equalTo on objectId and relation [\#887](https://github.com/ParsePlatform/parse-server/pull/887) (flovilmart)
|
||||
* Fix: Allow crossdomain on filesRouter [\#876](https://github.com/ParsePlatform/parse-server/pull/876) (flovilmart)
|
||||
* Fix: Remove limit when counting results. [\#867](https://github.com/ParsePlatform/parse-server/pull/867) (gfosco)
|
||||
* Fix: beforeSave changes should propagate to the response [\#865](https://github.com/ParsePlatform/parse-server/pull/865) (gfosco)
|
||||
* Fix: Delete relation field when \_Join collection not exist [\#864](https://github.com/ParsePlatform/parse-server/pull/864) (Marco129)
|
||||
* Fix: Related query on non-existing column [\#861](https://github.com/ParsePlatform/parse-server/pull/861) (gfosco)
|
||||
* Fix: Update markdown in .github/ISSUE\_TEMPLATE.md [\#859](https://github.com/ParsePlatform/parse-server/pull/859) (igorshubovych)
|
||||
* Fix: Issue with creating wrong \_Session for Facebook login [\#857](https://github.com/ParsePlatform/parse-server/pull/857) (tobernguyen)
|
||||
* Fix: Leak warnings in tests, use mongodb-runner from node\_modules [\#843](https://github.com/ParsePlatform/parse-server/pull/843) (drew-gross)
|
||||
* Fix: Reversed roles lookup [\#841](https://github.com/ParsePlatform/parse-server/pull/841) (flovilmart)
|
||||
* Fix: Improves loading of Push Adapter, fix loading of S3Adapter [\#833](https://github.com/ParsePlatform/parse-server/pull/833) (flovilmart)
|
||||
* Fix: Add field to system schema [\#828](https://github.com/ParsePlatform/parse-server/pull/828) (Marco129)
|
||||
|
||||
### 2.1.4 (3/3/2016)
|
||||
|
||||
* New: serverInfo endpoint that returns server version and info about the server's features
|
||||
* Improvement: Add support for badges on iOS
|
||||
* Improvement: Improve failure handling in cloud code http requests
|
||||
* Improvement: Add support for queries on pointers and relations
|
||||
* Improvement: Add support for multiple $in clauses in a query
|
||||
* Improvement: Add allowClientClassCreation config option
|
||||
* Improvement: Allow atomically setting subdocument keys
|
||||
* Improvement: Allow arbitrarily deeply nested roles
|
||||
* Improvement: Set proper content-type in S3 File Adapter
|
||||
* Improvement: S3 adapter auto-creates buckets
|
||||
* Improvement: Better error messages for many errors
|
||||
* Performance: Improved algorithm for validating client keys
|
||||
* Experimental: Parse Hooks and Hooks API
|
||||
* Experimental: Email verification and password reset emails
|
||||
* Experimental: Improve compatability of logs feature with Parse.com
|
||||
* Fix: Fix for attempting to delete missing classes via schemas API
|
||||
* Fix: Allow creation of system classes via schemas API
|
||||
* Fix: Allow missing where cause in $select
|
||||
* Fix: Improve handling of invalid object ids
|
||||
* Fix: Replace query overwriting existing query
|
||||
* Fix: Propagate installationId in cloud code triggers
|
||||
* Fix: Session expiresAt is now a Date instead of a string
|
||||
* Fix: Fix count queries
|
||||
* Fix: Disallow _Role objects without names or without ACL
|
||||
* Fix: Better handling of invalid types submitted
|
||||
* Fix: beforeSave will not be triggered for attempts to save with invalid authData
|
||||
* Fix: Fix duplicate device token issues on Android
|
||||
* Fix: Allow empty authData on signup
|
||||
* Fix: Allow Master Key Headers (CORS)
|
||||
* Fix: Fix bugs if JavaScript key was not provided in server configuration
|
||||
* Fix: Parse Files on objects can now be stored without URLs
|
||||
* Fix: allow both objectId or installationId when modifying installation
|
||||
* Fix: Command line works better when not given options
|
||||
|
||||
### 2.1.3 (2/24/2016)
|
||||
|
||||
* Feature: Add initial support for in-app purchases
|
||||
* Feature: Better error messages when attempting to run the server on a port that is already in use or without a server URL
|
||||
* Feature: Allow customization of max file size
|
||||
* Performance: Faster saves if not using beforeSave triggers
|
||||
* Fix: Send session token in response to current user endpoint
|
||||
* Fix: Remove triggers for _Session collection
|
||||
* Fix: Improve compatability of cloud code beforeSave hook for newly created object
|
||||
* Fix: ACL creation for master key only objects
|
||||
* Fix: Allow uploading files without Content-Type
|
||||
* Fix: Add features to http requrest to match Parse.com
|
||||
* Fix: Bugs in development script when running from locations other than project root
|
||||
* Fix: Can pass query constraints in URL
|
||||
* Fix: Objects with legacy "_tombstone" key now don't cause issues.
|
||||
* Fix: Allow nested keys in objects to begin with underscores
|
||||
* Fix: Allow correct headers for CORS
|
||||
|
||||
### 2.1.2 (2/19/2016)
|
||||
|
||||
* Change: The S3 file adapter constructor requires a bucket name
|
||||
* Fix: Parse Query should throw if improperly encoded
|
||||
* Fix: Issue where roles were not used in some requests
|
||||
* Fix: serverURL will no longer default to api.parse.com/1
|
||||
|
||||
### 2.1.1 (2/18/2016)
|
||||
|
||||
* Experimental: Schemas API support for DELETE operations
|
||||
* Fix: Session token issue fetching Users
|
||||
* Fix: Facebook auth validation
|
||||
* Fix: Invalid error when deleting missing session
|
||||
|
||||
### 2.1.0 (2/17/2016)
|
||||
|
||||
* Feature: Support for additional OAuth providers
|
||||
* Feature: Ability to implement custom OAuth providers
|
||||
* Feature: Support for deleting Parse Files
|
||||
* Feature: Allow querying roles
|
||||
* Feature: Support for logs, extensible via Log Adapter
|
||||
* Feature: New Push Adapter for sending push notifications through OneSignal
|
||||
* Feature: Tighter default security for Users
|
||||
* Feature: Pass parameters to cloud code in query string
|
||||
* Feature: Disable anonymous users via configuration.
|
||||
* Experimental: Schemas API support for PUT operations
|
||||
* Fix: Prevent installation ID from being added to User
|
||||
* Fix: Becoming a user works properly with sessions
|
||||
* Fix: Including multiple object when some object are unavailable will get all the objects that are available
|
||||
* Fix: Invalid URL for Parse Files
|
||||
* Fix: Making a query without a limit now returns 100 results
|
||||
* Fix: Expose installation id in cloud code
|
||||
* Fix: Correct username for Anonymous users
|
||||
* Fix: Session token issue after fetching user
|
||||
* Fix: Issues during install process
|
||||
* Fix: Issue with Unity SDK sending _noBody
|
||||
|
||||
### 2.0.8 (2/11/2016)
|
||||
|
||||
* Add: support for Android and iOS push notifications
|
||||
* Experimental: cloud code validation hooks (can mark as non-experimental after we have docs)
|
||||
* Experimental: support for schemas API (GET and POST only)
|
||||
* Experimental: support for Parse Config (GET and POST only)
|
||||
* Fix: Querying objects with equality constraint on array column
|
||||
* Fix: User logout will remove session token
|
||||
* Fix: Various files related bugs
|
||||
* Fix: Force minimum node version 4.3 due to security issues in earlier version
|
||||
* Performance Improvement: Improved caching
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at codeofconduct@parseplatform.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
+10
-429
@@ -1,435 +1,16 @@
|
||||
# Contributing to Parse Server <!-- omit in toc -->
|
||||
### Contributing to Parse Server
|
||||
|
||||
## 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)
|
||||
#### Pull Requests Welcome!
|
||||
|
||||
## Contributing
|
||||
We really want Parse to be yours, to see it grow and thrive in the open source community.
|
||||
|
||||
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).
|
||||
##### Please Do's
|
||||
|
||||
> ⚠️ 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).
|
||||
* Take testing seriously! Aim to increase the test coverage with every pull request.
|
||||
* Run the tests for the file you are working on with `npm test spec/MyFile.spec.js`
|
||||
* Run the tests for the whole project and look at the coverage report to make sure your tests are exhaustive by running `npm test` and looking at (project-root)/lcov-report/parse-server/FileUnderTest.js.html
|
||||
* Lint your code by running `npm run lint` to make sure all your code is not gonna be rejected by the CI.
|
||||
|
||||
Please completely fill out any templates to provide essential information about your new feature or the bug you discovered.
|
||||
##### Code of Conduct
|
||||
|
||||
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 your local machine
|
||||
|
||||
* [Fork](https://github.com/parse-community/parse-server) this project and clone the fork on your local machine:
|
||||
|
||||
```sh
|
||||
$ git clone https://github.com/parse-community/parse-server
|
||||
$ cd parse-server # go into the clone directory
|
||||
$ npm install # install all the node dependencies
|
||||
$ code . # launch vscode
|
||||
$ npm run watch # run babel watching for local file changes
|
||||
```
|
||||
|
||||
> To launch VS Code from the terminal with the `code` command you first need to follow the [launching from the command line section](https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line) in the VS Code setup documentation.
|
||||
|
||||
Once you have babel running in watch mode, you can start making changes to parse-server.
|
||||
|
||||
### Good to Know
|
||||
|
||||
* 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
|
||||
|
||||
*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
|
||||
|
||||
*Question*: How do I use breakpoints and debug step by step?<br/>
|
||||
*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/[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
|
||||
|
||||
* Begin by reading the [Development Guide](http://docs.parseplatform.org/parse-server/guide/#development-guide) to learn how to get started running the parse-server.
|
||||
* Take testing seriously! Aim to increase the test coverage with every pull request. To obtain the test coverage of the project, run: `npm run coverage`
|
||||
* Run the tests for the file you are working on with the following command: `npm test spec/MyFile.spec.js`
|
||||
* 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.
|
||||
|
||||
### 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/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:
|
||||
|
||||
- `describe_only_db('mongo')` // will create a `describe` that runs only on mongoDB
|
||||
- `it_only_db('mongo')` // will make a test that only runs on mongo
|
||||
- `it_exclude_dbs(['postgres'])` // will make a test that runs against all DB's but postgres
|
||||
* Similarly, if your feature is intended to only work with PostgreSQL, you should disable MongoDB-specific tests with:
|
||||
|
||||
- `describe_only_db('postgres')` // will create a `describe` that runs only on postgres
|
||||
- `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
|
||||
|
||||
* 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: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:
|
||||
|
||||
```
|
||||
docker stop parse-postgres
|
||||
```
|
||||
|
||||
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
|
||||
COPY ./scripts/setup-dbs.sh /docker-entrypoint-initdb.d/setup-dbs.sh
|
||||
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.
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
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).
|
||||
|
||||
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
|
||||
|
||||
### 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.
|
||||
|
||||
[config]: http://parseplatform.org/parse-server/api/master/ParseServerOptions.html
|
||||
[config-def]: https://github.com/parse-community/parse-server/blob/master/src/Options/Definitions.js
|
||||
[config-docs]: https://github.com/parse-community/parse-server/blob/master/src/Options/docs.js
|
||||
[config-index]: https://github.com/parse-community/parse-server/blob/master/src/Options/index.js
|
||||
This project adheres to the [Open Code of Conduct](http://todogroup.org/opencodeofconduct/#Parse Server/fjm@fb.com). By participating, you are expected to honor this code.
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
# 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."
|
||||
+11
-43
@@ -1,53 +1,21 @@
|
||||
############################################################
|
||||
# Build stage
|
||||
############################################################
|
||||
FROM node:lts-alpine as build
|
||||
FROM node:boron
|
||||
|
||||
RUN apk update; \
|
||||
apk add git;
|
||||
WORKDIR /tmp
|
||||
RUN mkdir -p /parse-server
|
||||
COPY ./ /parse-server/
|
||||
|
||||
# Copy package.json first to benefit from layer caching
|
||||
COPY package*.json ./
|
||||
RUN mkdir -p /parse-server/config
|
||||
VOLUME /parse-server/config
|
||||
|
||||
# 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; \
|
||||
apk add git;
|
||||
|
||||
VOLUME /parse-server/cloud /parse-server/config
|
||||
RUN mkdir -p /parse-server/cloud
|
||||
VOLUME /parse-server/cloud
|
||||
|
||||
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
|
||||
COPY public_html public_html
|
||||
COPY views views
|
||||
COPY --from=build /tmp/lib lib
|
||||
RUN mkdir -p logs && chown -R node: logs
|
||||
RUN npm install && \
|
||||
npm run build
|
||||
|
||||
ENV PORT=1337
|
||||
USER node
|
||||
|
||||
EXPOSE $PORT
|
||||
|
||||
ENTRYPOINT ["node", "./bin/parse-server"]
|
||||
ENTRYPOINT ["npm", "start", "--"]
|
||||
|
||||
@@ -28,7 +28,3 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
-----
|
||||
|
||||
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.
|
||||
|
||||
@@ -31,7 +31,3 @@ necessarily infringed by the Software standing alone.
|
||||
A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
|
||||
or contributory infringement or inducement to infringe any patent, including a
|
||||
cross-claim or counterclaim.
|
||||
|
||||
-----
|
||||
|
||||
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.
|
||||
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
# Parse Community Vulnerability Disclosure Program
|
||||
If you believe you have found a security vulnerability on one of parse-community maintained packages,
|
||||
we encourage you to let us know right away.
|
||||
We will investigate all legitimate reports and do our best to quickly fix the problem.
|
||||
Before making a report, please review this page to understand our disclosure policy and how to communicate with us.
|
||||
|
||||
# Responsible Disclosure Policy
|
||||
If you comply with the policies below when reporting a security issue to parse community,
|
||||
we will not initiate a lawsuit or law enforcement investigation against you in response to your report.
|
||||
We ask that:
|
||||
|
||||
- You give us reasonable time to investigate and mitigate an issue you report before making public any information about the report or sharing such information with others. This means we request _at least_ **7 days** to get back to you with an initial response and _at least_ **30 days** from initial contact (made by you) to apply a patch.
|
||||
- You do not interact with an individual account (which includes modifying or accessing data from the account) if the account owner has not consented to such actions.
|
||||
- You make a good faith effort to avoid privacy violations and disruptions to others, including (but not limited to) destruction of data and interruption or degradation of our services.
|
||||
- You do not exploit a security issue you discover for any reason. (This includes demonstrating additional risk, such as attempted compromise of sensitive company data or probing for additional issues). You do not violate any other applicable laws or regulations.
|
||||
|
||||
# Communicating with us
|
||||
|
||||
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@parseplatform.org](mailto:security@parseplatform.org).
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var nodemon = require('nodemon');
|
||||
var babel = require("babel-core");
|
||||
var gaze = require('gaze');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
// Watch the src and transpile when changed
|
||||
gaze('src/**/*', function(err, watcher) {
|
||||
if (err) throw err;
|
||||
watcher.on('changed', function(sourceFile) {
|
||||
console.log(sourceFile + " has changed");
|
||||
try {
|
||||
targetFile = path.relative(__dirname, sourceFile).replace(/\/src\//, '/lib/');
|
||||
targetFile = path.resolve(__dirname, targetFile);
|
||||
fs.writeFile(targetFile, babel.transformFileSync(sourceFile).code);
|
||||
} catch (e) {
|
||||
console.error(e.message, e.stack);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
// Run and watch dist
|
||||
nodemon({
|
||||
script: 'bin/parse-server',
|
||||
ext: 'js json',
|
||||
watch: 'lib'
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e.message, e.stack);
|
||||
}
|
||||
|
||||
process.once('SIGINT', function() {
|
||||
process.exit(0);
|
||||
});
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
NC='\033[0m'
|
||||
@@ -95,10 +95,10 @@ confirm 'Y' 'Do you want to continue? (Y/n): '
|
||||
check_node
|
||||
check_npm
|
||||
|
||||
printf "Setting up parse-server in %s\n" "${INSTALL_DIR}"
|
||||
printf "Setting up parse-server in %s" "${INSTALL_DIR}\n"
|
||||
|
||||
if [ -d "${INSTALL_DIR}" ]; then
|
||||
echo "${CHECK} ${INSTALL_DIR} exists"
|
||||
echo "{CHECK} ${INSTALL_DIR} exists"
|
||||
else
|
||||
mkdir -p "${INSTALL_DIR}"
|
||||
echo "${CHECK} Created ${INSTALL_DIR}"
|
||||
@@ -163,7 +163,7 @@ cat > ./package.json << EOF
|
||||
"start": "parse-server config.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"parse-server": "^3.9.0"
|
||||
"parse-server": "^2.0.0"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
@@ -1,339 +0,0 @@
|
||||
# [5.3.0-alpha.3](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.2...5.3.0-alpha.3) (2022-03-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add MongoDB 5.2 support ([#7894](https://github.com/parse-community/parse-server/issues/7894)) ([6b4b358](https://github.com/parse-community/parse-server/commit/6b4b358f0842ae920e45652f5e8b2afebc6caf3a))
|
||||
|
||||
# [5.3.0-alpha.2](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.1...5.3.0-alpha.2) (2022-03-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* security upgrade parse push adapter from 4.1.0 to 4.1.2 ([#7893](https://github.com/parse-community/parse-server/issues/7893)) ([ef56e98](https://github.com/parse-community/parse-server/commit/ef56e98ef65041b4d3b7b82cce3473269c27f6fd))
|
||||
|
||||
# [5.3.0-alpha.1](https://github.com/parse-community/parse-server/compare/5.2.1-alpha.2...5.3.0-alpha.1) (2022-03-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add MongoDB 5.1 compatibility ([#7682](https://github.com/parse-community/parse-server/issues/7682)) ([90155cf](https://github.com/parse-community/parse-server/commit/90155cf1680e5e0499b0000e071c6cb0ce3aef96))
|
||||
|
||||
## [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)
|
||||
@@ -1,191 +0,0 @@
|
||||
# [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
@@ -1,290 +0,0 @@
|
||||
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;
|
||||
@@ -1,69 +0,0 @@
|
||||
'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();
|
||||
@@ -1,194 +0,0 @@
|
||||
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();
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"plugins": ["node_modules/jsdoc-babel", "plugins/markdown"],
|
||||
"babel": {
|
||||
"plugins": ["@babel/plugin-transform-flow-strip-types"]
|
||||
},
|
||||
"source": {
|
||||
"include": ["./README.md", "./src/cloud-code", "./src/Options/docs.js", "./src/ParseServer.js", "./src/Adapters"],
|
||||
"excludePattern": "(^|\\/|\\\\)_"
|
||||
},
|
||||
"templates": {
|
||||
"default": {
|
||||
"outputSourceFiles": false,
|
||||
"showInheritedInNav": false,
|
||||
"useLongnameInNav": true
|
||||
},
|
||||
"cleverLinks": true,
|
||||
"monospaceLinks": false
|
||||
},
|
||||
"opts": {
|
||||
"template": "node_modules/@parse/minami",
|
||||
"recurse": true
|
||||
}
|
||||
}
|
||||
Generated
-17165
File diff suppressed because it is too large
Load Diff
+56
-134
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "parse-server",
|
||||
"version": "5.3.0-alpha.3",
|
||||
"version": "2.3.0",
|
||||
"description": "An express module providing a Parse-compatible API server",
|
||||
"main": "lib/index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/parse-community/parse-server"
|
||||
"url": "https://github.com/ParsePlatform/parse-server"
|
||||
},
|
||||
"files": [
|
||||
"bin/",
|
||||
@@ -14,154 +14,76 @@
|
||||
"views/",
|
||||
"LICENSE",
|
||||
"PATENTS",
|
||||
"postinstall.js",
|
||||
"README.md"
|
||||
],
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@apollo/client": "3.5.8",
|
||||
"@apollographql/graphql-playground-html": "1.6.29",
|
||||
"@graphql-tools/links": "8.2.2",
|
||||
"@graphql-tools/stitch": "6.2.4",
|
||||
"@graphql-tools/utils": "6.2.4",
|
||||
"@parse/fs-files-adapter": "1.2.1",
|
||||
"@parse/push-adapter": "4.1.2",
|
||||
"apollo-server-express": "2.25.2",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.19.1",
|
||||
"commander": "5.1.0",
|
||||
"cors": "2.8.5",
|
||||
"deepcopy": "2.1.0",
|
||||
"express": "4.17.2",
|
||||
"follow-redirects": "1.14.8",
|
||||
"graphql": "15.7.1",
|
||||
"graphql-list-fields": "2.0.2",
|
||||
"graphql-relay": "0.7.0",
|
||||
"graphql-tag": "2.12.6",
|
||||
"graphql-upload": "11.0.0",
|
||||
"bcryptjs": "2.3.0",
|
||||
"body-parser": "1.15.2",
|
||||
"commander": "2.9.0",
|
||||
"deepcopy": "0.6.3",
|
||||
"express": "4.14.0",
|
||||
"intersect": "1.0.1",
|
||||
"jsonwebtoken": "8.5.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.1.2",
|
||||
"semver": "7.3.5",
|
||||
"subscriptions-transport-ws": "0.11.0",
|
||||
"tv4": "1.3.0",
|
||||
"uuid": "8.3.2",
|
||||
"winston": "3.5.1",
|
||||
"winston-daily-rotate-file": "4.6.0",
|
||||
"ws": "8.2.3"
|
||||
"lodash": "4.17.2",
|
||||
"lru-cache": "4.0.2",
|
||||
"mime": "1.3.4",
|
||||
"mongodb": "2.2.10",
|
||||
"multer": "1.2.0",
|
||||
"parse": "1.9.2",
|
||||
"parse-server-fs-adapter": "1.0.1",
|
||||
"parse-server-push-adapter": "1.1.0",
|
||||
"parse-server-s3-adapter": "1.0.6",
|
||||
"parse-server-simple-mailgun-adapter": "1.0.0",
|
||||
"pg-promise": "5.4.5",
|
||||
"redis": "2.6.3",
|
||||
"request": "2.79.0",
|
||||
"semver": "5.2.0",
|
||||
"tv4": "1.2.7",
|
||||
"winston": "2.3.0",
|
||||
"winston-daily-rotate-file": "1.4.0",
|
||||
"ws": "1.1.1"
|
||||
},
|
||||
"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",
|
||||
"@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",
|
||||
"babel-cli": "6.18.0",
|
||||
"babel-core": "6.18.2",
|
||||
"babel-eslint": "^7.1.1",
|
||||
"babel-plugin-syntax-flow": "6.13.0",
|
||||
"babel-plugin-transform-flow-strip-types": "6.18.0",
|
||||
"babel-preset-es2015": "6.14.0",
|
||||
"babel-preset-stage-0": "6.5.0",
|
||||
"babel-register": "6.18.0",
|
||||
"bcrypt-nodejs": "0.0.3",
|
||||
"cross-env": "7.0.2",
|
||||
"deep-diff": "1.0.2",
|
||||
"eslint": "6.8.0",
|
||||
"eslint-plugin-flowtype": "5.1.3",
|
||||
"flow-bin": "0.119.1",
|
||||
"form-data": "3.0.0",
|
||||
"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",
|
||||
"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",
|
||||
"semantic-release": "17.4.6",
|
||||
"yaml": "1.10.0"
|
||||
"cross-env": "3.1.3",
|
||||
"deep-diff": "0.3.4",
|
||||
"eslint": "^3.10.2",
|
||||
"eslint-plugin-flowtype": "^2.25.0",
|
||||
"gaze": "1.1.1",
|
||||
"istanbul": "1.0.0-alpha.1",
|
||||
"jasmine": "2.5.2",
|
||||
"jasmine-spec-reporter": "^2.7.0",
|
||||
"mongodb-runner": "3.4.0",
|
||||
"nodemon": "1.11.0",
|
||||
"request-promise": "4.1.1"
|
||||
},
|
||||
"scripts": {
|
||||
"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",
|
||||
"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.6": "npm run test:mongodb --dbversion=5.0.6",
|
||||
"test:mongodb:5.1.1": "npm run test:mongodb --dbversion=5.1.1",
|
||||
"test:mongodb:5.2.1": "npm run test:mongodb --dbversion=5.2.1",
|
||||
"posttest:mongodb": "mongodb-runner stop",
|
||||
"pretest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.2.1} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} mongodb-runner start",
|
||||
"testonly": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.2.1} 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:=5.2.1} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} mongodb-runner stop",
|
||||
"coverage": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.2.1} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} TESTING=1 nyc jasmine",
|
||||
"dev": "npm run build && node bin/dev",
|
||||
"lint": "eslint --cache ./",
|
||||
"build": "babel src/ -d lib/",
|
||||
"pretest": "npm run lint",
|
||||
"test": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=3.2.6} MONGODB_STORAGE_ENGINE=mmapv1 NODE_ENV=test TESTING=1 $COVERAGE_OPTION jasmine",
|
||||
"test:win": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=3.2.6} MONGODB_STORAGE_ENGINE=mmapv1 NODE_ENV=test TESTING=1 jasmine",
|
||||
"coverage": "cross-env COVERAGE_OPTION='./node_modules/.bin/istanbul cover' npm test",
|
||||
"coverage:win": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=3.2.6} MONGODB_STORAGE_ENGINE=mmapv1 NODE_ENV=test TESTING=1 node ./node_modules/istanbul/lib/cli.js cover ./node_modules/jasmine/bin/jasmine.js",
|
||||
"start": "node ./bin/parse-server",
|
||||
"prettier": "prettier --write {src,spec}/{**/*,*}.js",
|
||||
"prepare": "npm run build",
|
||||
"postinstall": "node -p 'require(\"./postinstall.js\")()'",
|
||||
"madge:circular": "node_modules/.bin/madge ./src --circular"
|
||||
"prepublish": "npm run build"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.22.10 <17"
|
||||
"node": ">=4.5"
|
||||
},
|
||||
"bin": {
|
||||
"parse-server": "bin/parse-server"
|
||||
"parse-server": "./bin/parse-server"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@node-rs/bcrypt": "1.1.0"
|
||||
},
|
||||
"collective": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parse-server",
|
||||
"logo": "https://opencollective.com/parse-server/logo.txt?reverse=true&variant=binary"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parse-server"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"{src,spec}/{**/*,*}.js": [
|
||||
"prettier --write",
|
||||
"eslint --fix --cache",
|
||||
"git add"
|
||||
]
|
||||
"bcrypt": "1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
const pkg = require('./package.json');
|
||||
|
||||
const version = parseFloat(process.version.substr(1));
|
||||
const minimum = parseFloat(pkg.engines.node.match(/\d+/g).join('.'));
|
||||
|
||||
module.exports = function () {
|
||||
const openCollective = `
|
||||
1111111111
|
||||
1111111111111111
|
||||
1111111111111111111111
|
||||
11111111111111111111111111
|
||||
111111111111111 11111111
|
||||
1111111111111 111111
|
||||
1111111111111 111111111 111111
|
||||
111111111111 11111111111 111111
|
||||
1111111111111 11111111111 111111
|
||||
1111111111111 1111111111 111111
|
||||
1111111111111111111111111 1111111
|
||||
11111111 11111111
|
||||
111111 1111111111111111111
|
||||
11111 11111 111111111111111111
|
||||
11111 11111111111111111
|
||||
111111 111111111111111111
|
||||
11111111111111111111111111
|
||||
1111111111111111111111
|
||||
111111111111111111
|
||||
11111111111
|
||||
|
||||
|
||||
Thanks for installing parse 🙏
|
||||
Please consider donating to our open collective
|
||||
to help us maintain this package.
|
||||
|
||||
👉 https://opencollective.com/parse-server
|
||||
|
||||
`;
|
||||
process.stdout.write(openCollective);
|
||||
if (version >= minimum) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const errorMessage = `
|
||||
⚠️ parse-server requires at least node@${minimum}!
|
||||
You have node@${version}
|
||||
|
||||
`;
|
||||
|
||||
process.stdout.write(errorMessage);
|
||||
process.exit(1);
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"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."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,24 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,21 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,21 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,19 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,18 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,65 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,19 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,18 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,24 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,21 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,21 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,19 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,18 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,65 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,19 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,18 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,24 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,21 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,21 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,19 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,18 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,65 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,19 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,18 +0,0 @@
|
||||
<!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>
|
||||
@@ -35,8 +35,6 @@
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Invalid Link</h1>
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- This page is displayed when someone navigates to a verify email or reset password link
|
||||
but their security token is wrong. This can either mean the user has clicked on a
|
||||
stale link (i.e. re-click on a password reset link after resetting their password) or
|
||||
(rarely) this could be a sign of a malicious user trying to tamper with your app.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Invalid Link</title>
|
||||
<style type='text/css'>
|
||||
.container {
|
||||
border-width: 0px;
|
||||
display: block;
|
||||
font: inherit;
|
||||
font-family: 'Helvetica Neue', Helvetica;
|
||||
font-size: 16px;
|
||||
height: 30px;
|
||||
line-height: 16px;
|
||||
margin: 45px 0px 0px 45px;
|
||||
padding: 0px 8px 0px 8px;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
color: #0067AB;
|
||||
display: block;
|
||||
font: inherit;
|
||||
font-family: 'Open Sans', 'Helvetica Neue', Helvetica;
|
||||
font-size: 30px;
|
||||
font-weight: 600;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
margin: 0 0 15px 0;
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<script type="text/javascript">
|
||||
function getUrlParameter(name) {
|
||||
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
|
||||
var results = regex.exec(location.search);
|
||||
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
|
||||
};
|
||||
|
||||
window.onload = addDataToForm;
|
||||
|
||||
function addDataToForm() {
|
||||
var username = getUrlParameter("username");
|
||||
document.getElementById("usernameField").value = username;
|
||||
|
||||
var appId = getUrlParameter("appId");
|
||||
document.getElementById("resendForm").action = '/apps/' + appId + '/resend_verification_email'
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Invalid Verification Link</h1>
|
||||
<form id="resendForm" method="POST" action="/resend_verification_email">
|
||||
<input id="usernameField" class="form-control" name="username" type="hidden" value="">
|
||||
<button type="submit" class="btn btn-default">Resend Link</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,45 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- This page is displayed when someone navigates to a verify email link with an invalid
|
||||
security token and requests a link resend. This page is displayed when the username from
|
||||
the original link is invalid or if the email of that user has already been verfieid when
|
||||
the resend request is made
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Invalid Link</title>
|
||||
<style type='text/css'>
|
||||
.container {
|
||||
border-width: 0px;
|
||||
display: block;
|
||||
font: inherit;
|
||||
font-family: 'Helvetica Neue', Helvetica;
|
||||
font-size: 16px;
|
||||
height: 30px;
|
||||
line-height: 16px;
|
||||
margin: 45px 0px 0px 45px;
|
||||
padding: 0px 8px 0px 8px;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
color: #0067AB;
|
||||
display: block;
|
||||
font: inherit;
|
||||
font-family: 'Open Sans', 'Helvetica Neue', Helvetica;
|
||||
font-size: 30px;
|
||||
font-weight: 600;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
margin: 0 0 15px 0;
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>No link sent. User not found or email already verified</h1>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,45 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- This page is displayed when someone navigates to a verify email link with an invalid
|
||||
security token and requests a link resend. This page is displayed when the username
|
||||
from the original verification link has been found and a new verification link has
|
||||
been successfully sent to the corresponding stored email
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Invalid Link</title>
|
||||
<style type='text/css'>
|
||||
.container {
|
||||
border-width: 0px;
|
||||
display: block;
|
||||
font: inherit;
|
||||
font-family: 'Helvetica Neue', Helvetica;
|
||||
font-size: 16px;
|
||||
height: 30px;
|
||||
line-height: 16px;
|
||||
margin: 45px 0px 0px 45px;
|
||||
padding: 0px 8px 0px 8px;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
color: #0067AB;
|
||||
display: block;
|
||||
font: inherit;
|
||||
font-family: 'Open Sans', 'Helvetica Neue', Helvetica;
|
||||
font-size: 30px;
|
||||
font-weight: 600;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
margin: 0 0 15px 0;
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Link Sent! Check your email.</h1>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,124 +0,0 @@
|
||||
/**
|
||||
* 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();
|
||||
@@ -1,29 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
set -x
|
||||
if [ "${GITHUB_ACTIONS}" = "" ];
|
||||
then
|
||||
echo "Cannot release docs without GITHUB_ACTIONS set"
|
||||
exit 0;
|
||||
fi
|
||||
REPO="https://github.com/parse-community/parse-server"
|
||||
|
||||
rm -rf docs
|
||||
git clone -b gh-pages --single-branch $REPO ./docs
|
||||
cd docs
|
||||
git pull origin gh-pages
|
||||
cd ..
|
||||
|
||||
DEST="master"
|
||||
|
||||
if [ "${SOURCE_TAG}" != "" ];
|
||||
then
|
||||
DEST="${SOURCE_TAG}"
|
||||
# change the default page to the latest
|
||||
echo "<meta http-equiv='refresh' content='0; url=/parse-server/api/${DEST}'>" > "docs/api/index.html"
|
||||
fi
|
||||
|
||||
npm run definitions
|
||||
npm run docs
|
||||
|
||||
mkdir -p "docs/api/${DEST}"
|
||||
cp -R out/* "docs/api/${DEST}"
|
||||
@@ -1,318 +0,0 @@
|
||||
/**
|
||||
* Parse Server Configuration Builder
|
||||
*
|
||||
* This module builds the definitions file (src/Options/Definitions.js)
|
||||
* from the src/Options/index.js options interfaces.
|
||||
* The Definitions.js module is responsible for the default values as well
|
||||
* as the mappings for the CLI.
|
||||
*
|
||||
* To rebuild the definitions file, run
|
||||
* `$ node resources/buildConfigDefinitions.js`
|
||||
*/
|
||||
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];
|
||||
}
|
||||
|
||||
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
function toENV(key) {
|
||||
let str = '';
|
||||
let previousIsUpper = false;
|
||||
for(let i = 0; i < key.length; i++) {
|
||||
const char = key[i];
|
||||
if (letters.indexOf(char) >= 0) {
|
||||
if (!previousIsUpper) {
|
||||
str += '_';
|
||||
previousIsUpper = true;
|
||||
}
|
||||
} else {
|
||||
previousIsUpper = false;
|
||||
}
|
||||
str += char;
|
||||
}
|
||||
return str.toUpperCase();
|
||||
}
|
||||
|
||||
function getCommentValue(comment) {
|
||||
if (!comment) { return }
|
||||
return comment.value.trim();
|
||||
}
|
||||
|
||||
function getENVPrefix(iface) {
|
||||
if (nestedOptionEnvPrefix[iface.id.name]) {
|
||||
return nestedOptionEnvPrefix[iface.id.name]
|
||||
}
|
||||
}
|
||||
|
||||
function processProperty(property, iface) {
|
||||
const firstComment = getCommentValue(last(property.leadingComments || []));
|
||||
const name = property.key.name;
|
||||
const prefix = getENVPrefix(iface);
|
||||
|
||||
if (!firstComment) {
|
||||
return;
|
||||
}
|
||||
const lines = firstComment.split('\n').map((line) => line.trim());
|
||||
let help = '';
|
||||
let envLine;
|
||||
let defaultLine;
|
||||
lines.forEach((line) => {
|
||||
if (line.indexOf(':ENV:') === 0) {
|
||||
envLine = line;
|
||||
} else if (line.indexOf(':DEFAULT:') === 0) {
|
||||
defaultLine = line;
|
||||
} else {
|
||||
help += line;
|
||||
}
|
||||
});
|
||||
let env;
|
||||
if (envLine) {
|
||||
env = envLine.split(' ')[1];
|
||||
} else {
|
||||
env = (prefix + toENV(name));
|
||||
}
|
||||
let defaultValue;
|
||||
if (defaultLine) {
|
||||
defaultValue = defaultLine.split(' ')[1];
|
||||
}
|
||||
let type = property.value.type;
|
||||
let isRequired = true;
|
||||
if (type == 'NullableTypeAnnotation') {
|
||||
isRequired = false;
|
||||
type = property.value.typeAnnotation.type;
|
||||
}
|
||||
return {
|
||||
name,
|
||||
env,
|
||||
help,
|
||||
type,
|
||||
defaultValue,
|
||||
types: property.value.types,
|
||||
typeAnnotation: property.value.typeAnnotation,
|
||||
required: isRequired
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function doInterface(iface) {
|
||||
return iface.body.properties
|
||||
.sort((a, b) => a.key.name.localeCompare(b.key.name))
|
||||
.map((prop) => processProperty(prop, iface))
|
||||
.filter((e) => e !== undefined);
|
||||
}
|
||||
|
||||
function mapperFor(elt, t) {
|
||||
const p = t.identifier('parsers');
|
||||
const wrap = (identifier) => t.memberExpression(p, identifier);
|
||||
|
||||
if (t.isNumberTypeAnnotation(elt)) {
|
||||
return t.callExpression(wrap(t.identifier('numberParser')), [t.stringLiteral(elt.name)]);
|
||||
} else if (t.isArrayTypeAnnotation(elt)) {
|
||||
return wrap(t.identifier('arrayParser'));
|
||||
} else if (t.isAnyTypeAnnotation(elt)) {
|
||||
return wrap(t.identifier('objectParser'));
|
||||
} else if (t.isBooleanTypeAnnotation(elt)) {
|
||||
return wrap(t.identifier('booleanParser'));
|
||||
} else if (t.isGenericTypeAnnotation(elt)) {
|
||||
const type = elt.typeAnnotation.id.name;
|
||||
if (type == 'Adapter') {
|
||||
return wrap(t.identifier('moduleOrObjectParser'));
|
||||
}
|
||||
if (type == 'NumberOrBoolean') {
|
||||
return wrap(t.identifier('numberOrBooleanParser'));
|
||||
}
|
||||
return wrap(t.identifier('objectParser'));
|
||||
}
|
||||
}
|
||||
|
||||
function parseDefaultValue(elt, value, t) {
|
||||
let literalValue;
|
||||
if (t.isStringTypeAnnotation(elt)) {
|
||||
if (value == '""' || value == "''") {
|
||||
literalValue = t.stringLiteral('');
|
||||
} else {
|
||||
literalValue = t.stringLiteral(value);
|
||||
}
|
||||
} else if (t.isNumberTypeAnnotation(elt)) {
|
||||
literalValue = t.numericLiteral(parsers.numberOrBoolParser('')(value));
|
||||
} else if (t.isArrayTypeAnnotation(elt)) {
|
||||
const array = parsers.objectParser(value);
|
||||
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');
|
||||
}
|
||||
}));
|
||||
} else if (t.isAnyTypeAnnotation(elt)) {
|
||||
literalValue = t.arrayExpression([]);
|
||||
} else if (t.isBooleanTypeAnnotation(elt)) {
|
||||
literalValue = t.booleanLiteral(parsers.booleanParser(value));
|
||||
} else if (t.isGenericTypeAnnotation(elt)) {
|
||||
const type = elt.typeAnnotation.id.name;
|
||||
if (type == 'NumberOrBoolean') {
|
||||
literalValue = t.numericLiteral(parsers.numberOrBoolParser('')(value));
|
||||
}
|
||||
|
||||
if (nestedOptionTypes.includes(type)) {
|
||||
const object = parsers.objectParser(value);
|
||||
const props = Object.keys(object).map((key) => {
|
||||
return t.objectProperty(key, object[value]);
|
||||
});
|
||||
literalValue = t.objectExpression(props);
|
||||
}
|
||||
if (type == 'ProtectedFields') {
|
||||
const prop = t.objectProperty(
|
||||
t.stringLiteral('_User'), t.objectPattern([
|
||||
t.objectProperty(t.stringLiteral('*'), t.arrayExpression([t.stringLiteral('email')]))
|
||||
])
|
||||
);
|
||||
literalValue = t.objectExpression([prop]);
|
||||
}
|
||||
}
|
||||
return literalValue;
|
||||
}
|
||||
|
||||
function inject(t, list) {
|
||||
let comments = '';
|
||||
const results = list.map((elt) => {
|
||||
if (!elt.name) {
|
||||
return;
|
||||
}
|
||||
const props = ['env', 'help'].map((key) => {
|
||||
if (elt[key]) {
|
||||
return t.objectProperty(t.stringLiteral(key), t.stringLiteral(elt[key]));
|
||||
}
|
||||
}).filter((e) => e !== undefined);
|
||||
if (elt.required) {
|
||||
props.push(t.objectProperty(t.stringLiteral('required'), t.booleanLiteral(true)))
|
||||
}
|
||||
const action = mapperFor(elt, t);
|
||||
if (action) {
|
||||
props.push(t.objectProperty(t.stringLiteral('action'), action))
|
||||
}
|
||||
if (elt.defaultValue) {
|
||||
const parsedValue = parseDefaultValue(elt, elt.defaultValue, t);
|
||||
if (parsedValue) {
|
||||
props.push(t.objectProperty(t.stringLiteral('default'), parsedValue));
|
||||
} else {
|
||||
throw new Error(`Unable to parse value for ${elt.name} `);
|
||||
}
|
||||
}
|
||||
let type = elt.type.replace('TypeAnnotation', '');
|
||||
if (type === 'Generic') {
|
||||
type = elt.typeAnnotation.id.name;
|
||||
}
|
||||
if (type === 'Array') {
|
||||
type = elt.typeAnnotation.elementType.id
|
||||
? `${elt.typeAnnotation.elementType.id.name}[]`
|
||||
: `${elt.typeAnnotation.elementType.type.replace('TypeAnnotation', '')}[]`;
|
||||
}
|
||||
if (type === 'NumberOrBoolean') {
|
||||
type = 'Number|Boolean';
|
||||
}
|
||||
if (type === 'NumberOrString') {
|
||||
type = 'Number|String';
|
||||
}
|
||||
if (type === 'Adapter') {
|
||||
const adapterType = elt.typeAnnotation.typeParameters.params[0].id.name;
|
||||
type = `Adapter<${adapterType}>`;
|
||||
}
|
||||
comments += ` * @property {${type}} ${elt.name} ${elt.help}\n`;
|
||||
const obj = t.objectExpression(props);
|
||||
return t.objectProperty(t.stringLiteral(elt.name), obj);
|
||||
}).filter((elt) => {
|
||||
return elt != undefined;
|
||||
});
|
||||
return { results, comments };
|
||||
}
|
||||
|
||||
const makeRequire = function(variableName, module, t) {
|
||||
const decl = t.variableDeclarator(t.identifier(variableName), t.callExpression(t.identifier('require'), [t.stringLiteral(module)]));
|
||||
return t.variableDeclaration('var', [decl])
|
||||
}
|
||||
let docs = ``;
|
||||
const plugin = function (babel) {
|
||||
const t = babel.types;
|
||||
const moduleExports = t.memberExpression(t.identifier('module'), t.identifier('exports'));
|
||||
return {
|
||||
visitor: {
|
||||
ImportDeclaration: function(path) {
|
||||
path.remove();
|
||||
},
|
||||
Program: function(path) {
|
||||
// Inject the parser's loader
|
||||
path.unshiftContainer('body', makeRequire('parsers', './parsers', t));
|
||||
},
|
||||
ExportDeclaration: function(path) {
|
||||
// Export declaration on an interface
|
||||
if (path.node && path.node.declaration && path.node.declaration.type == 'InterfaceDeclaration') {
|
||||
const { results, comments } = inject(t, doInterface(path.node.declaration));
|
||||
const id = path.node.declaration.id.name;
|
||||
const exports = t.memberExpression(moduleExports, t.identifier(id));
|
||||
docs += `/**\n * @interface ${id}\n${comments} */\n\n`;
|
||||
path.replaceWith(
|
||||
t.assignmentExpression('=', exports, t.objectExpression(results))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const auxiliaryCommentBefore = `
|
||||
**** GENERATED CODE ****
|
||||
This code has been generated by resources/buildConfigDefinitions.js
|
||||
Do not edit manually, but update Options/index.js
|
||||
`
|
||||
|
||||
const babel = require("@babel/core");
|
||||
const res = babel.transformFileSync('./src/Options/index.js', { plugins: [ plugin, '@babel/transform-flow-strip-types' ], babelrc: false, auxiliaryCommentBefore, sourceMaps: false });
|
||||
require('fs').writeFileSync('./src/Options/Definitions.js', res.code + '\n');
|
||||
require('fs').writeFileSync('./src/Options/docs.js', docs);
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
docker login -e="$DOCKER_EMAIL" -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"
|
||||
docker build -t parseplatform/parse-server:$TRAVIS_TAG .
|
||||
docker push parseplatform/parse-server:$TRAVIS_TAG
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
# This script maintains a git branch which mirrors master but in a form that
|
||||
# what will eventually be deployed to npm, allowing npm dependencies to use:
|
||||
#
|
||||
# "parse-server": "parseplatform/parse-server#latest"
|
||||
#
|
||||
|
||||
# From: https://github.com/graphql/graphql-js/blob/master/resources/npm-git.sh
|
||||
|
||||
BUILD_DIR=latest
|
||||
|
||||
npm run build
|
||||
|
||||
mkdir -p $BUILD_DIR
|
||||
|
||||
cp package.json $BUILD_DIR/
|
||||
cp README.md $BUILD_DIR/
|
||||
cp LICENSE $BUILD_DIR/
|
||||
cp PATENTS $BUILD_DIR/
|
||||
cp CHANGELOG.md $BUILD_DIR/
|
||||
cp -R lib $BUILD_DIR
|
||||
cp -R bin $BUILD_DIR
|
||||
cp -R public_html $BUILD_DIR
|
||||
cp -R views $BUILD_DIR
|
||||
|
||||
cd $BUILD_DIR
|
||||
git init
|
||||
git config user.name "Travis CI"
|
||||
git config user.email "github@fb.com"
|
||||
git add .
|
||||
git commit -m "Deploy master to LATEST branch"
|
||||
git push --force --quiet "https://${GH_TOKEN}@github.com/parseplatform/parse-server.git" master:latest
|
||||
@@ -0,0 +1,102 @@
|
||||
"""
|
||||
https://github.com/dmakhno/travis_after_all/blob/master/travis_after_all.py
|
||||
https://github.com/graphql/graphql-js/blob/master/resources/travis_after_all.py
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import logging
|
||||
|
||||
try:
|
||||
import urllib.request as urllib2
|
||||
except ImportError:
|
||||
import urllib2
|
||||
|
||||
log = logging.getLogger("travis.leader")
|
||||
log.addHandler(logging.StreamHandler())
|
||||
log.setLevel(logging.INFO)
|
||||
|
||||
TRAVIS_JOB_NUMBER = 'TRAVIS_JOB_NUMBER'
|
||||
TRAVIS_BUILD_ID = 'TRAVIS_BUILD_ID'
|
||||
POLLING_INTERVAL = 'LEADER_POLLING_INTERVAL'
|
||||
|
||||
build_id = os.getenv(TRAVIS_BUILD_ID)
|
||||
polling_interval = int(os.getenv(POLLING_INTERVAL, '5'))
|
||||
|
||||
#assume, first job is the leader
|
||||
is_leader = lambda job_number: job_number.endswith('.1')
|
||||
|
||||
if not os.getenv(TRAVIS_JOB_NUMBER):
|
||||
# seems even for builds with only one job, this won't get here
|
||||
log.fatal("Don't use defining leader for build without matrix")
|
||||
exit(1)
|
||||
elif is_leader(os.getenv(TRAVIS_JOB_NUMBER)):
|
||||
log.info("This is a leader")
|
||||
else:
|
||||
#since python is subprocess, env variables are exported back via file
|
||||
with open(".to_export_back", "w") as export_var:
|
||||
export_var.write("BUILD_MINION=YES")
|
||||
log.info("This is a minion")
|
||||
exit(0)
|
||||
|
||||
|
||||
class MatrixElement(object):
|
||||
def __init__(self, json_raw):
|
||||
self.is_finished = json_raw['finished_at'] is not None
|
||||
self.is_succeeded = json_raw['result'] == 0
|
||||
self.number = json_raw['number']
|
||||
self.is_leader = is_leader(self.number)
|
||||
|
||||
|
||||
def matrix_snapshot():
|
||||
"""
|
||||
:return: Matrix List
|
||||
"""
|
||||
response = urllib2.build_opener().open("https://api.travis-ci.org/builds/{0}".format(build_id)).read()
|
||||
raw_json = json.loads(response)
|
||||
matrix_without_leader = [MatrixElement(element) for element in raw_json["matrix"]]
|
||||
return matrix_without_leader
|
||||
|
||||
|
||||
def wait_others_to_finish():
|
||||
def others_finished():
|
||||
"""
|
||||
Dumps others to finish
|
||||
Leader cannot finish, it is working now
|
||||
:return: tuple(True or False, List of not finished jobs)
|
||||
"""
|
||||
snapshot = matrix_snapshot()
|
||||
finished = [el.is_finished for el in snapshot if not el.is_leader]
|
||||
return reduce(lambda a, b: a and b, finished), [el.number for el in snapshot if
|
||||
not el.is_leader and not el.is_finished]
|
||||
|
||||
while True:
|
||||
finished, waiting_list = others_finished()
|
||||
if finished: break
|
||||
log.info("Leader waits for minions {0}...".format(waiting_list)) # just in case do not get "silence timeout"
|
||||
time.sleep(polling_interval)
|
||||
|
||||
|
||||
try:
|
||||
wait_others_to_finish()
|
||||
|
||||
final_snapshot = matrix_snapshot()
|
||||
log.info("Final Results: {0}".format([(e.number, e.is_succeeded) for e in final_snapshot]))
|
||||
|
||||
BUILD_AGGREGATE_STATUS = 'BUILD_AGGREGATE_STATUS'
|
||||
others_snapshot = [el for el in final_snapshot if not el.is_leader]
|
||||
if reduce(lambda a, b: a and b, [e.is_succeeded for e in others_snapshot]):
|
||||
os.environ[BUILD_AGGREGATE_STATUS] = "others_succeeded"
|
||||
elif reduce(lambda a, b: a and b, [not e.is_succeeded for e in others_snapshot]):
|
||||
log.error("Others Failed")
|
||||
os.environ[BUILD_AGGREGATE_STATUS] = "others_failed"
|
||||
else:
|
||||
log.warn("Others Unknown")
|
||||
os.environ[BUILD_AGGREGATE_STATUS] = "unknown"
|
||||
#since python is subprocess, env variables are exported back via file
|
||||
with open(".to_export_back", "w") as export_var:
|
||||
export_var.write("BUILD_LEADER=YES {0}={1}".format(BUILD_AGGREGATE_STATUS, os.environ[BUILD_AGGREGATE_STATUS]))
|
||||
|
||||
except Exception as e:
|
||||
log.fatal(e)
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
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
|
||||
@@ -1,30 +0,0 @@
|
||||
#!/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 "$@"
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"plugins": [
|
||||
"transform-object-rest-spread"
|
||||
],
|
||||
"presets": [
|
||||
["env", {
|
||||
"targets": {
|
||||
"node": "8"
|
||||
}
|
||||
}]
|
||||
],
|
||||
"sourceMaps": "inline",
|
||||
"retainLines": true
|
||||
}
|
||||
+4
-14
@@ -13,29 +13,19 @@
|
||||
"Item": true,
|
||||
"Container": true,
|
||||
"equal": true,
|
||||
"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,
|
||||
"on_db": true,
|
||||
"defaultConfiguration": true,
|
||||
"expectSuccess": true,
|
||||
"range": true,
|
||||
"expectError": true,
|
||||
"jequal": true,
|
||||
"create": true,
|
||||
"arrayContains": true,
|
||||
"expectAsync": true,
|
||||
"databaseAdapter": true
|
||||
"arrayContains": true
|
||||
},
|
||||
"rules": {
|
||||
"no-console": [0],
|
||||
"no-var": "error"
|
||||
"no-console": [0]
|
||||
}
|
||||
}
|
||||
|
||||
+207
-355
@@ -1,70 +1,64 @@
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
const Config = require('../lib/Config');
|
||||
const Definitions = require('../lib/Options/Definitions');
|
||||
const request = require('../lib/request');
|
||||
const Config = require("../src/Config");
|
||||
|
||||
const loginWithWrongCredentialsShouldFail = function (username, password) {
|
||||
var loginWithWrongCredentialsShouldFail = function(username, password) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Parse.User.logIn(username, password)
|
||||
.then(() => reject('login should have failed'))
|
||||
.catch(err => {
|
||||
if (err.message === 'Invalid username/password.') {
|
||||
resolve();
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var isAccountLockoutError = function(username, password, duration, waitTime) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
Parse.User.logIn(username, password)
|
||||
.then(() => reject('login should have failed'))
|
||||
.catch(err => {
|
||||
if (err.message === 'Invalid username/password.') {
|
||||
if (err.message === 'Your account is locked due to multiple failed login attempts. Please try again after ' + duration + ' minute(s)') {
|
||||
resolve();
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const isAccountLockoutError = function (username, password, duration, waitTime) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
Parse.User.logIn(username, password)
|
||||
.then(() => reject('login should have failed'))
|
||||
.catch(err => {
|
||||
if (
|
||||
err.message ===
|
||||
'Your account is locked due to multiple failed login attempts. Please try again after ' +
|
||||
duration +
|
||||
' minute(s)'
|
||||
) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}, waitTime);
|
||||
});
|
||||
};
|
||||
|
||||
describe('Account Lockout Policy: ', () => {
|
||||
describe("Account Lockout Policy: ", () => {
|
||||
|
||||
it('account should not be locked even after failed login attempts if account lockout policy is not set', done => {
|
||||
reconfigureServer({
|
||||
appName: 'unlimited',
|
||||
publicServerURL: 'http://localhost:1337/1',
|
||||
})
|
||||
.then(() => {
|
||||
const user = new Parse.User();
|
||||
user.setUsername('username1');
|
||||
user.setPassword('password');
|
||||
return user.signUp(null);
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username1', 'incorrect password 1');
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username1', 'incorrect password 2');
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username1', 'incorrect password 3');
|
||||
})
|
||||
.then(() => done())
|
||||
.catch(err => {
|
||||
fail('allow unlimited failed login attempts failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
});
|
||||
.then(() => {
|
||||
var user = new Parse.User();
|
||||
user.setUsername('username1');
|
||||
user.setPassword('password');
|
||||
return user.signUp(null);
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username1', 'incorrect password 1');
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username1', 'incorrect password 2');
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username1', 'incorrect password 3');
|
||||
})
|
||||
.then(() => done())
|
||||
.catch(err => {
|
||||
fail('allow unlimited failed login attempts failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('throw error if duration is set to an invalid number', done => {
|
||||
@@ -72,26 +66,23 @@ describe('Account Lockout Policy: ', () => {
|
||||
appName: 'duration',
|
||||
accountLockout: {
|
||||
duration: 'invalid value',
|
||||
threshold: 5,
|
||||
threshold: 5
|
||||
},
|
||||
publicServerURL: 'https://my.public.server.com/1',
|
||||
publicServerURL: "https://my.public.server.com/1"
|
||||
})
|
||||
.then(() => {
|
||||
Config.get('test');
|
||||
fail('set duration to an invalid number test failed');
|
||||
.then(() => {
|
||||
new Config('test');
|
||||
fail('set duration to an invalid number test failed');
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
if (err && err === 'Account lockout duration should be greater than 0 and less than 100000') {
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
if (
|
||||
err &&
|
||||
err === 'Account lockout duration should be greater than 0 and less than 100000'
|
||||
) {
|
||||
done();
|
||||
} else {
|
||||
fail('set duration to an invalid number test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fail('set duration to an invalid number test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('throw error if threshold is set to an invalid number', done => {
|
||||
@@ -99,26 +90,23 @@ describe('Account Lockout Policy: ', () => {
|
||||
appName: 'threshold',
|
||||
accountLockout: {
|
||||
duration: 5,
|
||||
threshold: 'invalid number',
|
||||
threshold: 'invalid number'
|
||||
},
|
||||
publicServerURL: 'https://my.public.server.com/1',
|
||||
publicServerURL: "https://my.public.server.com/1"
|
||||
})
|
||||
.then(() => {
|
||||
Config.get('test');
|
||||
fail('set threshold to an invalid number test failed');
|
||||
.then(() => {
|
||||
new Config('test');
|
||||
fail('set threshold to an invalid number test failed');
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
if (err && err === 'Account lockout threshold should be an integer greater than 0 and less than 1000') {
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
if (
|
||||
err &&
|
||||
err === 'Account lockout threshold should be an integer greater than 0 and less than 1000'
|
||||
) {
|
||||
done();
|
||||
} else {
|
||||
fail('set threshold to an invalid number test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fail('set threshold to an invalid number test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('throw error if threshold is < 1', done => {
|
||||
@@ -126,26 +114,23 @@ describe('Account Lockout Policy: ', () => {
|
||||
appName: 'threshold',
|
||||
accountLockout: {
|
||||
duration: 5,
|
||||
threshold: 0,
|
||||
threshold: 0
|
||||
},
|
||||
publicServerURL: 'https://my.public.server.com/1',
|
||||
publicServerURL: "https://my.public.server.com/1"
|
||||
})
|
||||
.then(() => {
|
||||
Config.get('test');
|
||||
fail('threshold value < 1 is invalid test failed');
|
||||
.then(() => {
|
||||
new Config('test');
|
||||
fail('threshold value < 1 is invalid test failed');
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
if (err && err === 'Account lockout threshold should be an integer greater than 0 and less than 1000') {
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
if (
|
||||
err &&
|
||||
err === 'Account lockout threshold should be an integer greater than 0 and less than 1000'
|
||||
) {
|
||||
done();
|
||||
} else {
|
||||
fail('threshold value < 1 is invalid test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fail('threshold value < 1 is invalid test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('throw error if threshold is > 999', done => {
|
||||
@@ -153,26 +138,23 @@ describe('Account Lockout Policy: ', () => {
|
||||
appName: 'threshold',
|
||||
accountLockout: {
|
||||
duration: 5,
|
||||
threshold: 1000,
|
||||
threshold: 1000
|
||||
},
|
||||
publicServerURL: 'https://my.public.server.com/1',
|
||||
publicServerURL: "https://my.public.server.com/1"
|
||||
})
|
||||
.then(() => {
|
||||
Config.get('test');
|
||||
fail('threshold value > 999 is invalid test failed');
|
||||
.then(() => {
|
||||
new Config('test');
|
||||
fail('threshold value > 999 is invalid test failed');
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
if (err && err === 'Account lockout threshold should be an integer greater than 0 and less than 1000') {
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
if (
|
||||
err &&
|
||||
err === 'Account lockout threshold should be an integer greater than 0 and less than 1000'
|
||||
) {
|
||||
done();
|
||||
} else {
|
||||
fail('threshold value > 999 is invalid test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fail('threshold value > 999 is invalid test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('throw error if duration is <= 0', done => {
|
||||
@@ -180,26 +162,23 @@ describe('Account Lockout Policy: ', () => {
|
||||
appName: 'duration',
|
||||
accountLockout: {
|
||||
duration: 0,
|
||||
threshold: 5,
|
||||
threshold: 5
|
||||
},
|
||||
publicServerURL: 'https://my.public.server.com/1',
|
||||
publicServerURL: "https://my.public.server.com/1"
|
||||
})
|
||||
.then(() => {
|
||||
Config.get('test');
|
||||
fail('duration value < 1 is invalid test failed');
|
||||
.then(() => {
|
||||
new Config('test');
|
||||
fail('duration value < 1 is invalid test failed');
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
if (err && err === 'Account lockout duration should be greater than 0 and less than 100000') {
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
if (
|
||||
err &&
|
||||
err === 'Account lockout duration should be greater than 0 and less than 100000'
|
||||
) {
|
||||
done();
|
||||
} else {
|
||||
fail('duration value < 1 is invalid test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fail('duration value < 1 is invalid test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('throw error if duration is > 99999', done => {
|
||||
@@ -207,26 +186,23 @@ describe('Account Lockout Policy: ', () => {
|
||||
appName: 'duration',
|
||||
accountLockout: {
|
||||
duration: 100000,
|
||||
threshold: 5,
|
||||
threshold: 5
|
||||
},
|
||||
publicServerURL: 'https://my.public.server.com/1',
|
||||
publicServerURL: "https://my.public.server.com/1"
|
||||
})
|
||||
.then(() => {
|
||||
Config.get('test');
|
||||
fail('duration value > 99999 is invalid test failed');
|
||||
.then(() => {
|
||||
new Config('test');
|
||||
fail('duration value > 99999 is invalid test failed');
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
if (err && err === 'Account lockout duration should be greater than 0 and less than 100000') {
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
if (
|
||||
err &&
|
||||
err === 'Account lockout duration should be greater than 0 and less than 100000'
|
||||
) {
|
||||
done();
|
||||
} else {
|
||||
fail('duration value > 99999 is invalid test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fail('duration value > 99999 is invalid test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('lock account if failed login attempts are above threshold', done => {
|
||||
@@ -234,32 +210,32 @@ describe('Account Lockout Policy: ', () => {
|
||||
appName: 'lockout threshold',
|
||||
accountLockout: {
|
||||
duration: 1,
|
||||
threshold: 2,
|
||||
threshold: 2
|
||||
},
|
||||
publicServerURL: 'http://localhost:8378/1',
|
||||
publicServerURL: "http://localhost:8378/1"
|
||||
})
|
||||
.then(() => {
|
||||
const user = new Parse.User();
|
||||
user.setUsername('username2');
|
||||
user.setPassword('failedLoginAttemptsThreshold');
|
||||
return user.signUp();
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username2', 'wrong password');
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username2', 'wrong password');
|
||||
})
|
||||
.then(() => {
|
||||
return isAccountLockoutError('username2', 'wrong password', 1, 1);
|
||||
})
|
||||
.then(() => {
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
fail('lock account after failed login attempts test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
});
|
||||
.then(() => {
|
||||
var user = new Parse.User();
|
||||
user.setUsername("username2");
|
||||
user.setPassword("failedLoginAttemptsThreshold");
|
||||
return user.signUp();
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username2', 'wrong password');
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username2', 'wrong password');
|
||||
})
|
||||
.then(() => {
|
||||
return isAccountLockoutError('username2', 'wrong password', 1, 1);
|
||||
})
|
||||
.then(() => {
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
fail('lock account after failed login attempts test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('lock account for accountPolicy.duration minutes if failed login attempts are above threshold', done => {
|
||||
@@ -267,36 +243,36 @@ describe('Account Lockout Policy: ', () => {
|
||||
appName: 'lockout threshold',
|
||||
accountLockout: {
|
||||
duration: 0.05, // 0.05*60 = 3 secs
|
||||
threshold: 2,
|
||||
threshold: 2
|
||||
},
|
||||
publicServerURL: 'http://localhost:8378/1',
|
||||
publicServerURL: "http://localhost:8378/1"
|
||||
})
|
||||
.then(() => {
|
||||
const user = new Parse.User();
|
||||
user.setUsername('username3');
|
||||
user.setPassword('failedLoginAttemptsThreshold');
|
||||
return user.signUp();
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username3', 'wrong password');
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username3', 'wrong password');
|
||||
})
|
||||
.then(() => {
|
||||
return isAccountLockoutError('username3', 'wrong password', 0.05, 1);
|
||||
})
|
||||
.then(() => {
|
||||
// account should still be locked even after 2 seconds.
|
||||
return isAccountLockoutError('username3', 'wrong password', 0.05, 2000);
|
||||
})
|
||||
.then(() => {
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
fail('account should be locked for duration mins test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
});
|
||||
.then(() => {
|
||||
var user = new Parse.User();
|
||||
user.setUsername("username3");
|
||||
user.setPassword("failedLoginAttemptsThreshold");
|
||||
return user.signUp();
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username3', 'wrong password');
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username3', 'wrong password');
|
||||
})
|
||||
.then(() => {
|
||||
return isAccountLockoutError('username3', 'wrong password', 0.05, 1);
|
||||
})
|
||||
.then(() => {
|
||||
// account should still be locked even after 2 seconds.
|
||||
return isAccountLockoutError('username3', 'wrong password', 0.05, 2000);
|
||||
})
|
||||
.then(() => {
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
fail('account should be locked for duration mins test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('allow login for locked account after accountPolicy.duration minutes', done => {
|
||||
@@ -304,163 +280,39 @@ describe('Account Lockout Policy: ', () => {
|
||||
appName: 'lockout threshold',
|
||||
accountLockout: {
|
||||
duration: 0.05, // 0.05*60 = 3 secs
|
||||
threshold: 2,
|
||||
threshold: 2
|
||||
},
|
||||
publicServerURL: 'http://localhost:8378/1',
|
||||
publicServerURL: "http://localhost:8378/1"
|
||||
})
|
||||
.then(() => {
|
||||
const user = new Parse.User();
|
||||
user.setUsername('username4');
|
||||
user.setPassword('correct password');
|
||||
return user.signUp();
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username4', 'wrong password');
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username4', 'wrong password');
|
||||
})
|
||||
.then(() => {
|
||||
// allow locked user to login after 3 seconds with a valid userid and password
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
Parse.User.logIn('username4', 'correct password')
|
||||
.then(() => resolve())
|
||||
.catch(err => reject(err));
|
||||
}, 3001);
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
fail(
|
||||
'allow login for locked account after accountPolicy.duration minutes test failed: ' +
|
||||
JSON.stringify(err)
|
||||
);
|
||||
done();
|
||||
.then(() => {
|
||||
var user = new Parse.User();
|
||||
user.setUsername("username4");
|
||||
user.setPassword("correct password");
|
||||
return user.signUp();
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username4', 'wrong password');
|
||||
})
|
||||
.then(() => {
|
||||
return loginWithWrongCredentialsShouldFail('username4', 'wrong password');
|
||||
})
|
||||
.then(() => {
|
||||
// allow locked user to login after 3 seconds with a valid userid and password
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
Parse.User.logIn('username4', 'correct password')
|
||||
.then(() => resolve())
|
||||
.catch(err => reject(err));
|
||||
}, 3001);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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,
|
||||
})
|
||||
.then(() => {
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
fail('allow login for locked account after accountPolicy.duration minutes test failed: ' + JSON.stringify(err));
|
||||
done();
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,84 +1,83 @@
|
||||
const AdaptableController = require('../lib/Controllers/AdaptableController').AdaptableController;
|
||||
const FilesAdapter = require('../lib/Adapters/Files/FilesAdapter').default;
|
||||
const FilesController = require('../lib/Controllers/FilesController').FilesController;
|
||||
|
||||
const MockController = function (options) {
|
||||
var AdaptableController = require("../src/Controllers/AdaptableController").AdaptableController;
|
||||
var FilesAdapter = require("../src/Adapters/Files/FilesAdapter").default;
|
||||
var FilesController = require("../src/Controllers/FilesController").FilesController;
|
||||
|
||||
var MockController = function(options) {
|
||||
AdaptableController.call(this, options);
|
||||
};
|
||||
}
|
||||
MockController.prototype = Object.create(AdaptableController.prototype);
|
||||
MockController.prototype.constructor = AdaptableController;
|
||||
|
||||
describe('AdaptableController', () => {
|
||||
it('should use the provided adapter', done => {
|
||||
const adapter = new FilesAdapter();
|
||||
const controller = new FilesController(adapter);
|
||||
describe("AdaptableController", ()=>{
|
||||
it("should use the provided adapter", (done) => {
|
||||
var adapter = new FilesAdapter();
|
||||
var controller = new FilesController(adapter);
|
||||
expect(controller.adapter).toBe(adapter);
|
||||
// make sure _adapter is private
|
||||
expect(controller._adapter).toBe(undefined);
|
||||
// Override _adapter is not doing anything
|
||||
controller._adapter = 'Hello';
|
||||
controller._adapter = "Hello";
|
||||
expect(controller.adapter).toBe(adapter);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should throw when creating a new mock controller', done => {
|
||||
const adapter = new FilesAdapter();
|
||||
it("should throw when creating a new mock controller", (done) => {
|
||||
var adapter = new FilesAdapter();
|
||||
expect(() => {
|
||||
new MockController(adapter);
|
||||
}).toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should fail setting the wrong adapter to the controller', done => {
|
||||
it("should fail setting the wrong adapter to the controller", (done) => {
|
||||
function WrongAdapter() {}
|
||||
const adapter = new FilesAdapter();
|
||||
const controller = new FilesController(adapter);
|
||||
const otherAdapter = new WrongAdapter();
|
||||
var adapter = new FilesAdapter();
|
||||
var controller = new FilesController(adapter);
|
||||
var otherAdapter = new WrongAdapter();
|
||||
expect(() => {
|
||||
controller.adapter = otherAdapter;
|
||||
}).toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should fail to instantiate a controller with wrong adapter', done => {
|
||||
it("should fail to instantiate a controller with wrong adapter", (done) => {
|
||||
function WrongAdapter() {}
|
||||
const adapter = new WrongAdapter();
|
||||
var adapter = new WrongAdapter();
|
||||
expect(() => {
|
||||
new FilesController(adapter);
|
||||
}).toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should fail to instantiate a controller without an adapter', done => {
|
||||
it("should fail to instantiate a controller without an adapter", (done) => {
|
||||
expect(() => {
|
||||
new FilesController();
|
||||
}).toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should accept an object adapter', done => {
|
||||
const adapter = {
|
||||
createFile: function () {},
|
||||
deleteFile: function () {},
|
||||
getFileData: function () {},
|
||||
getFileLocation: function () {},
|
||||
validateFilename: function () {},
|
||||
};
|
||||
it("should accept an object adapter", (done) => {
|
||||
var adapter = {
|
||||
createFile: function() { },
|
||||
deleteFile: function() { },
|
||||
getFileData: function() { },
|
||||
getFileLocation: function() { },
|
||||
}
|
||||
expect(() => {
|
||||
new FilesController(adapter);
|
||||
}).not.toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should accept an prototype based object adapter', done => {
|
||||
it("should accept an object adapter", (done) => {
|
||||
function AGoodAdapter() {}
|
||||
AGoodAdapter.prototype.createFile = function () {};
|
||||
AGoodAdapter.prototype.deleteFile = function () {};
|
||||
AGoodAdapter.prototype.getFileData = function () {};
|
||||
AGoodAdapter.prototype.getFileLocation = function () {};
|
||||
AGoodAdapter.prototype.validateFilename = function () {};
|
||||
AGoodAdapter.prototype.createFile = function() { };
|
||||
AGoodAdapter.prototype.deleteFile = function() { };
|
||||
AGoodAdapter.prototype.getFileData = function() { };
|
||||
AGoodAdapter.prototype.getFileLocation = function() { };
|
||||
|
||||
const adapter = new AGoodAdapter();
|
||||
var adapter = new AGoodAdapter();
|
||||
expect(() => {
|
||||
new FilesController(adapter);
|
||||
}).not.toThrow();
|
||||
|
||||
+57
-82
@@ -1,39 +1,40 @@
|
||||
const loadAdapter = require('../lib/Adapters/AdapterLoader').loadAdapter;
|
||||
const FilesAdapter = require('@parse/fs-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/support/MockAdapter');
|
||||
var loadAdapter = require("../src/Adapters/AdapterLoader").loadAdapter;
|
||||
var FilesAdapter = require("parse-server-fs-adapter").default;
|
||||
var S3Adapter = require("parse-server-s3-adapter").default;
|
||||
var ParsePushAdapter = require("parse-server-push-adapter").default;
|
||||
|
||||
const adapter = loadAdapter({
|
||||
describe("AdapterLoader", ()=>{
|
||||
|
||||
it("should instantiate an adapter from string in object", (done) => {
|
||||
var adapterPath = require('path').resolve("./spec/MockAdapter");
|
||||
|
||||
var adapter = loadAdapter({
|
||||
adapter: adapterPath,
|
||||
options: {
|
||||
key: 'value',
|
||||
foo: 'bar',
|
||||
},
|
||||
key: "value",
|
||||
foo: "bar"
|
||||
}
|
||||
});
|
||||
|
||||
expect(adapter instanceof Object).toBe(true);
|
||||
expect(adapter.options.key).toBe('value');
|
||||
expect(adapter.options.foo).toBe('bar');
|
||||
expect(adapter.options.key).toBe("value");
|
||||
expect(adapter.options.foo).toBe("bar");
|
||||
done();
|
||||
});
|
||||
|
||||
it('should instantiate an adapter from string', done => {
|
||||
const adapterPath = require('path').resolve('./spec/support/MockAdapter');
|
||||
const adapter = loadAdapter(adapterPath);
|
||||
it("should instantiate an adapter from string", (done) => {
|
||||
var adapterPath = require('path').resolve("./spec/MockAdapter");
|
||||
var adapter = loadAdapter(adapterPath);
|
||||
|
||||
expect(adapter instanceof Object).toBe(true);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should instantiate an adapter from string that is module', done => {
|
||||
const adapterPath = require('path').resolve('./lib/Adapters/Files/FilesAdapter');
|
||||
const adapter = loadAdapter({
|
||||
adapter: adapterPath,
|
||||
it("should instantiate an adapter from string that is module", (done) => {
|
||||
var adapterPath = require('path').resolve("./src/Adapters/Files/FilesAdapter");
|
||||
var adapter = loadAdapter({
|
||||
adapter: adapterPath
|
||||
});
|
||||
|
||||
expect(typeof adapter).toBe('object');
|
||||
@@ -44,9 +45,9 @@ describe('AdapterLoader', () => {
|
||||
done();
|
||||
});
|
||||
|
||||
it('should instantiate an adapter from npm module', done => {
|
||||
const adapter = loadAdapter({
|
||||
module: '@parse/fs-files-adapter',
|
||||
it("should instantiate an adapter from npm module", (done) => {
|
||||
var adapter = loadAdapter({
|
||||
module: 'parse-server-fs-adapter'
|
||||
});
|
||||
|
||||
expect(typeof adapter).toBe('object');
|
||||
@@ -57,98 +58,72 @@ describe('AdapterLoader', () => {
|
||||
done();
|
||||
});
|
||||
|
||||
it('should instantiate an adapter from function/Class', done => {
|
||||
const adapter = loadAdapter({
|
||||
adapter: FilesAdapter,
|
||||
it("should instantiate an adapter from function/Class", (done) => {
|
||||
var adapter = loadAdapter({
|
||||
adapter: FilesAdapter
|
||||
});
|
||||
expect(adapter instanceof FilesAdapter).toBe(true);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should instantiate the default adapter from Class', done => {
|
||||
const adapter = loadAdapter(null, FilesAdapter);
|
||||
it("should instantiate the default adapter from Class", (done) => {
|
||||
var adapter = loadAdapter(null, FilesAdapter);
|
||||
expect(adapter instanceof FilesAdapter).toBe(true);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should use the default adapter', done => {
|
||||
const defaultAdapter = new FilesAdapter();
|
||||
const adapter = loadAdapter(null, defaultAdapter);
|
||||
it("should use the default adapter", (done) => {
|
||||
var defaultAdapter = new FilesAdapter();
|
||||
var adapter = loadAdapter(null, defaultAdapter);
|
||||
expect(adapter instanceof FilesAdapter).toBe(true);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should use the provided adapter', done => {
|
||||
const originalAdapter = new FilesAdapter();
|
||||
const adapter = loadAdapter(originalAdapter);
|
||||
it("should use the provided adapter", (done) => {
|
||||
var originalAdapter = new FilesAdapter();
|
||||
var adapter = loadAdapter(originalAdapter);
|
||||
expect(adapter).toBe(originalAdapter);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should fail loading an improperly configured adapter', done => {
|
||||
const Adapter = function (options) {
|
||||
it("should fail loading an improperly configured adapter", (done) => {
|
||||
var Adapter = function(options) {
|
||||
if (!options.foo) {
|
||||
throw 'foo is required for that adapter';
|
||||
throw "foo is required for that adapter";
|
||||
}
|
||||
};
|
||||
const adapterOptions = {
|
||||
param: 'key',
|
||||
doSomething: function () {},
|
||||
}
|
||||
var adapterOptions = {
|
||||
param: "key",
|
||||
doSomething: function() {}
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
const adapter = loadAdapter(adapterOptions, Adapter);
|
||||
var adapter = loadAdapter(adapterOptions, Adapter);
|
||||
expect(adapter).toEqual(adapterOptions);
|
||||
}).not.toThrow('foo is required for that adapter');
|
||||
}).not.toThrow("foo is required for that adapter");
|
||||
done();
|
||||
});
|
||||
|
||||
it('should load push adapter from options', done => {
|
||||
const options = {
|
||||
android: {
|
||||
senderId: 'yolo',
|
||||
apiKey: 'yolo',
|
||||
},
|
||||
};
|
||||
it("should load push adapter from options", (done) => {
|
||||
var options = {
|
||||
ios: {
|
||||
bundleId: 'bundle.id'
|
||||
}
|
||||
}
|
||||
expect(() => {
|
||||
const adapter = loadAdapter(undefined, ParsePushAdapter, options);
|
||||
var adapter = loadAdapter(undefined, ParsePushAdapter, options);
|
||||
expect(adapter.constructor).toBe(ParsePushAdapter);
|
||||
expect(adapter).not.toBe(undefined);
|
||||
}).not.toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should load custom push adapter from string (#3544)', done => {
|
||||
const adapterPath = require('path').resolve('./spec/support/MockPushAdapter');
|
||||
const options = {
|
||||
ios: {
|
||||
bundleId: 'bundle.id',
|
||||
},
|
||||
};
|
||||
const pushAdapterOptions = {
|
||||
adapter: adapterPath,
|
||||
options,
|
||||
};
|
||||
it("should load S3Adapter from direct passing", (done) => {
|
||||
var s3Adapter = new S3Adapter("key", "secret", "bucket")
|
||||
expect(() => {
|
||||
reconfigureServer({
|
||||
push: pushAdapterOptions,
|
||||
}).then(() => {
|
||||
const config = Config.get(Parse.applicationId);
|
||||
const pushAdapter = config.pushWorker.adapter;
|
||||
expect(pushAdapter.getValidPushTypes()).toEqual(['ios']);
|
||||
expect(pushAdapter.options).toEqual(pushAdapterOptions);
|
||||
done();
|
||||
});
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('should load file adapter from direct passing', done => {
|
||||
spyOn(console, 'warn').and.callFake(() => {});
|
||||
const mockFilesAdapter = new MockFilesAdapter('key', 'secret', 'bucket');
|
||||
expect(() => {
|
||||
const adapter = loadAdapter(mockFilesAdapter, FilesAdapter);
|
||||
expect(adapter).toBe(mockFilesAdapter);
|
||||
var adapter = loadAdapter(s3Adapter, FilesAdapter);
|
||||
expect(adapter).toBe(s3Adapter);
|
||||
}).not.toThrow();
|
||||
done();
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
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 = [
|
||||
{
|
||||
group: { objectId: {} },
|
||||
},
|
||||
];
|
||||
const expected = [{ $group: { _id: {} } }];
|
||||
const result = AggregateRouter.getPipeline(body);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
|
||||
it('get pipeline from Object', () => {
|
||||
const body = {
|
||||
group: { objectId: {} },
|
||||
};
|
||||
const expected = [{ $group: { _id: {} } }];
|
||||
const result = AggregateRouter.getPipeline(body);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
|
||||
it('get pipeline from Pipeline Operator (Array)', () => {
|
||||
const body = {
|
||||
pipeline: [
|
||||
{
|
||||
group: { objectId: {} },
|
||||
},
|
||||
],
|
||||
};
|
||||
const expected = [{ $group: { _id: {} } }];
|
||||
const result = AggregateRouter.getPipeline(body);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
|
||||
it('get pipeline from Pipeline Operator (Object)', () => {
|
||||
const body = {
|
||||
pipeline: {
|
||||
group: { objectId: {} },
|
||||
},
|
||||
};
|
||||
const expected = [{ $group: { _id: {} } }];
|
||||
const result = AggregateRouter.getPipeline(body);
|
||||
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 = [
|
||||
{
|
||||
group: { objectId: {} },
|
||||
match: { name: 'Test' },
|
||||
},
|
||||
];
|
||||
try {
|
||||
AggregateRouter.getPipeline(body);
|
||||
} catch (e) {
|
||||
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 pipeline fails multiple keys in Pipeline Operator Array stage ', () => {
|
||||
const body = {
|
||||
pipeline: [
|
||||
{
|
||||
group: { objectId: {} },
|
||||
match: { name: 'Test' },
|
||||
},
|
||||
],
|
||||
};
|
||||
try {
|
||||
AggregateRouter.getPipeline(body);
|
||||
} catch (e) {
|
||||
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);
|
||||
});
|
||||
});
|
||||
+48
-56
@@ -1,69 +1,61 @@
|
||||
const analyticsAdapter = {
|
||||
appOpened: function () {},
|
||||
trackEvent: function () {},
|
||||
};
|
||||
appOpened: function() {},
|
||||
trackEvent: function() {}
|
||||
}
|
||||
|
||||
describe('AnalyticsController', () => {
|
||||
it('should track a simple event', done => {
|
||||
it('should track a simple event', (done) => {
|
||||
|
||||
spyOn(analyticsAdapter, 'trackEvent').and.callThrough();
|
||||
reconfigureServer({
|
||||
analyticsAdapter,
|
||||
})
|
||||
.then(() => {
|
||||
return Parse.Analytics.track('MyEvent', {
|
||||
key: 'value',
|
||||
count: '0',
|
||||
});
|
||||
analyticsAdapter
|
||||
}).then(() => {
|
||||
return Parse.Analytics.track('MyEvent', {
|
||||
key: 'value',
|
||||
count: '0'
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
expect(analyticsAdapter.trackEvent).toHaveBeenCalled();
|
||||
const lastCall = analyticsAdapter.trackEvent.calls.first();
|
||||
const args = lastCall.args;
|
||||
expect(args[0]).toEqual('MyEvent');
|
||||
expect(args[1]).toEqual({
|
||||
dimensions: {
|
||||
key: 'value',
|
||||
count: '0',
|
||||
},
|
||||
});
|
||||
done();
|
||||
},
|
||||
err => {
|
||||
fail(JSON.stringify(err));
|
||||
done();
|
||||
}).then(() => {
|
||||
expect(analyticsAdapter.trackEvent).toHaveBeenCalled();
|
||||
var lastCall = analyticsAdapter.trackEvent.calls.first();
|
||||
const args = lastCall.args;
|
||||
expect(args[0]).toEqual('MyEvent');
|
||||
expect(args[1]).toEqual({
|
||||
dimensions: {
|
||||
key: 'value',
|
||||
count: '0'
|
||||
}
|
||||
);
|
||||
});
|
||||
done();
|
||||
}, (err) => {
|
||||
fail(JSON.stringify(err));
|
||||
done();
|
||||
})
|
||||
});
|
||||
|
||||
it('should track a app opened event', done => {
|
||||
it('should track a app opened event', (done) => {
|
||||
|
||||
spyOn(analyticsAdapter, 'appOpened').and.callThrough();
|
||||
reconfigureServer({
|
||||
analyticsAdapter,
|
||||
})
|
||||
.then(() => {
|
||||
return Parse.Analytics.track('AppOpened', {
|
||||
key: 'value',
|
||||
count: '0',
|
||||
});
|
||||
analyticsAdapter
|
||||
}).then(() => {
|
||||
return Parse.Analytics.track('AppOpened', {
|
||||
key: 'value',
|
||||
count: '0'
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
expect(analyticsAdapter.appOpened).toHaveBeenCalled();
|
||||
const lastCall = analyticsAdapter.appOpened.calls.first();
|
||||
const args = lastCall.args;
|
||||
expect(args[0]).toEqual({
|
||||
dimensions: {
|
||||
key: 'value',
|
||||
count: '0',
|
||||
},
|
||||
});
|
||||
done();
|
||||
},
|
||||
err => {
|
||||
fail(JSON.stringify(err));
|
||||
done();
|
||||
}).then(() => {
|
||||
expect(analyticsAdapter.appOpened).toHaveBeenCalled();
|
||||
var lastCall = analyticsAdapter.appOpened.calls.first();
|
||||
const args = lastCall.args;
|
||||
expect(args[0]).toEqual({
|
||||
dimensions: {
|
||||
key: 'value',
|
||||
count: '0'
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
done();
|
||||
}, (err) => {
|
||||
fail(JSON.stringify(err));
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,422 +0,0 @@
|
||||
const auth = require('../lib/Auth');
|
||||
const Config = require('../lib/Config');
|
||||
const rest = require('../lib/rest');
|
||||
const request = require('../lib/request');
|
||||
const AudiencesRouter = require('../lib/Routers/AudiencesRouter').AudiencesRouter;
|
||||
|
||||
describe('AudiencesRouter', () => {
|
||||
it('uses find condition from request.body', done => {
|
||||
const config = Config.get('test');
|
||||
const androidAudienceRequest = {
|
||||
name: 'Android Users',
|
||||
query: '{ "test": "android" }',
|
||||
};
|
||||
const iosAudienceRequest = {
|
||||
name: 'Iphone Users',
|
||||
query: '{ "test": "ios" }',
|
||||
};
|
||||
const request = {
|
||||
config: config,
|
||||
auth: auth.master(config),
|
||||
body: {
|
||||
where: {
|
||||
query: '{ "test": "android" }',
|
||||
},
|
||||
},
|
||||
query: {},
|
||||
info: {},
|
||||
};
|
||||
|
||||
const router = new AudiencesRouter();
|
||||
rest
|
||||
.create(config, auth.nobody(config), '_Audience', androidAudienceRequest)
|
||||
.then(() => {
|
||||
return rest.create(config, auth.nobody(config), '_Audience', iosAudienceRequest);
|
||||
})
|
||||
.then(() => {
|
||||
return router.handleFind(request);
|
||||
})
|
||||
.then(res => {
|
||||
const results = res.response.results;
|
||||
expect(results.length).toEqual(1);
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
fail(JSON.stringify(err));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('uses find condition from request.query', done => {
|
||||
const config = Config.get('test');
|
||||
const androidAudienceRequest = {
|
||||
name: 'Android Users',
|
||||
query: '{ "test": "android" }',
|
||||
};
|
||||
const iosAudienceRequest = {
|
||||
name: 'Iphone Users',
|
||||
query: '{ "test": "ios" }',
|
||||
};
|
||||
const request = {
|
||||
config: config,
|
||||
auth: auth.master(config),
|
||||
body: {},
|
||||
query: {
|
||||
where: {
|
||||
query: '{ "test": "android" }',
|
||||
},
|
||||
},
|
||||
info: {},
|
||||
};
|
||||
|
||||
const router = new AudiencesRouter();
|
||||
rest
|
||||
.create(config, auth.nobody(config), '_Audience', androidAudienceRequest)
|
||||
.then(() => {
|
||||
return rest.create(config, auth.nobody(config), '_Audience', iosAudienceRequest);
|
||||
})
|
||||
.then(() => {
|
||||
return router.handleFind(request);
|
||||
})
|
||||
.then(res => {
|
||||
const results = res.response.results;
|
||||
expect(results.length).toEqual(1);
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
fail(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('query installations with limit = 0', done => {
|
||||
const config = Config.get('test');
|
||||
const androidAudienceRequest = {
|
||||
name: 'Android Users',
|
||||
query: '{ "test": "android" }',
|
||||
};
|
||||
const iosAudienceRequest = {
|
||||
name: 'Iphone Users',
|
||||
query: '{ "test": "ios" }',
|
||||
};
|
||||
const request = {
|
||||
config: config,
|
||||
auth: auth.master(config),
|
||||
body: {},
|
||||
query: {
|
||||
limit: 0,
|
||||
},
|
||||
info: {},
|
||||
};
|
||||
|
||||
Config.get('test');
|
||||
const router = new AudiencesRouter();
|
||||
rest
|
||||
.create(config, auth.nobody(config), '_Audience', androidAudienceRequest)
|
||||
.then(() => {
|
||||
return rest.create(config, auth.nobody(config), '_Audience', iosAudienceRequest);
|
||||
})
|
||||
.then(() => {
|
||||
return router.handleFind(request);
|
||||
})
|
||||
.then(res => {
|
||||
const response = res.response;
|
||||
expect(response.results.length).toEqual(0);
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
fail(JSON.stringify(err));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it_exclude_dbs(['postgres'])('query installations with count = 1', done => {
|
||||
const config = Config.get('test');
|
||||
const androidAudienceRequest = {
|
||||
name: 'Android Users',
|
||||
query: '{ "test": "android" }',
|
||||
};
|
||||
const iosAudienceRequest = {
|
||||
name: 'Iphone Users',
|
||||
query: '{ "test": "ios" }',
|
||||
};
|
||||
const request = {
|
||||
config: config,
|
||||
auth: auth.master(config),
|
||||
body: {},
|
||||
query: {
|
||||
count: 1,
|
||||
},
|
||||
info: {},
|
||||
};
|
||||
|
||||
const router = new AudiencesRouter();
|
||||
rest
|
||||
.create(config, auth.nobody(config), '_Audience', androidAudienceRequest)
|
||||
.then(() => rest.create(config, auth.nobody(config), '_Audience', iosAudienceRequest))
|
||||
.then(() => router.handleFind(request))
|
||||
.then(res => {
|
||||
const response = res.response;
|
||||
expect(response.results.length).toEqual(2);
|
||||
expect(response.count).toEqual(2);
|
||||
done();
|
||||
})
|
||||
.catch(error => {
|
||||
fail(JSON.stringify(error));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it_exclude_dbs(['postgres'])('query installations with limit = 0 and count = 1', done => {
|
||||
const config = Config.get('test');
|
||||
const androidAudienceRequest = {
|
||||
name: 'Android Users',
|
||||
query: '{ "test": "android" }',
|
||||
};
|
||||
const iosAudienceRequest = {
|
||||
name: 'Iphone Users',
|
||||
query: '{ "test": "ios" }',
|
||||
};
|
||||
const request = {
|
||||
config: config,
|
||||
auth: auth.master(config),
|
||||
body: {},
|
||||
query: {
|
||||
limit: 0,
|
||||
count: 1,
|
||||
},
|
||||
info: {},
|
||||
};
|
||||
|
||||
const router = new AudiencesRouter();
|
||||
rest
|
||||
.create(config, auth.nobody(config), '_Audience', androidAudienceRequest)
|
||||
.then(() => {
|
||||
return rest.create(config, auth.nobody(config), '_Audience', iosAudienceRequest);
|
||||
})
|
||||
.then(() => {
|
||||
return router.handleFind(request);
|
||||
})
|
||||
.then(res => {
|
||||
const response = res.response;
|
||||
expect(response.results.length).toEqual(0);
|
||||
expect(response.count).toEqual(2);
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
fail(JSON.stringify(err));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should create, read, update and delete audiences throw api', done => {
|
||||
Parse._request(
|
||||
'POST',
|
||||
'push_audiences',
|
||||
{ name: 'My Audience', query: JSON.stringify({ deviceType: 'ios' }) },
|
||||
{ useMasterKey: true }
|
||||
).then(() => {
|
||||
Parse._request('GET', 'push_audiences', {}, { useMasterKey: true }).then(results => {
|
||||
expect(results.results.length).toEqual(1);
|
||||
expect(results.results[0].name).toEqual('My Audience');
|
||||
expect(results.results[0].query.deviceType).toEqual('ios');
|
||||
Parse._request(
|
||||
'GET',
|
||||
`push_audiences/${results.results[0].objectId}`,
|
||||
{},
|
||||
{ useMasterKey: true }
|
||||
).then(results => {
|
||||
expect(results.name).toEqual('My Audience');
|
||||
expect(results.query.deviceType).toEqual('ios');
|
||||
Parse._request(
|
||||
'PUT',
|
||||
`push_audiences/${results.objectId}`,
|
||||
{ name: 'My Audience 2' },
|
||||
{ useMasterKey: true }
|
||||
).then(() => {
|
||||
Parse._request(
|
||||
'GET',
|
||||
`push_audiences/${results.objectId}`,
|
||||
{},
|
||||
{ useMasterKey: true }
|
||||
).then(results => {
|
||||
expect(results.name).toEqual('My Audience 2');
|
||||
expect(results.query.deviceType).toEqual('ios');
|
||||
Parse._request(
|
||||
'DELETE',
|
||||
`push_audiences/${results.objectId}`,
|
||||
{},
|
||||
{ useMasterKey: true }
|
||||
).then(() => {
|
||||
Parse._request('GET', 'push_audiences', {}, { useMasterKey: true }).then(
|
||||
results => {
|
||||
expect(results.results.length).toEqual(0);
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should only create with master key', done => {
|
||||
Parse._request('POST', 'push_audiences', {
|
||||
name: 'My Audience',
|
||||
query: JSON.stringify({ deviceType: 'ios' }),
|
||||
}).then(
|
||||
() => {},
|
||||
error => {
|
||||
expect(error.message).toEqual('unauthorized: master key is required');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should only find with master key', done => {
|
||||
Parse._request('GET', 'push_audiences', {}).then(
|
||||
() => {},
|
||||
error => {
|
||||
expect(error.message).toEqual('unauthorized: master key is required');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should only get with master key', done => {
|
||||
Parse._request('GET', `push_audiences/someId`, {}).then(
|
||||
() => {},
|
||||
error => {
|
||||
expect(error.message).toEqual('unauthorized: master key is required');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should only update with master key', done => {
|
||||
Parse._request('PUT', `push_audiences/someId`, {
|
||||
name: 'My Audience 2',
|
||||
}).then(
|
||||
() => {},
|
||||
error => {
|
||||
expect(error.message).toEqual('unauthorized: master key is required');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should only delete with master key', done => {
|
||||
Parse._request('DELETE', `push_audiences/someId`, {}).then(
|
||||
() => {},
|
||||
error => {
|
||||
expect(error.message).toEqual('unauthorized: master key is required');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it_exclude_dbs(['postgres'])('should support legacy parse.com audience fields', done => {
|
||||
const database = Config.get(Parse.applicationId).database.adapter.database;
|
||||
const now = new Date();
|
||||
Parse._request(
|
||||
'POST',
|
||||
'push_audiences',
|
||||
{ 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,
|
||||
},
|
||||
}
|
||||
)
|
||||
.then(result => {
|
||||
expect(result).toBeTruthy();
|
||||
database
|
||||
.collection('test__Audience')
|
||||
.find({ _id: audience.objectId })
|
||||
.toArray((error, rows) => {
|
||||
expect(error).toEqual(undefined);
|
||||
expect(rows[0]['times_used']).toEqual(1);
|
||||
expect(rows[0]['_last_used']).toEqual(now);
|
||||
Parse._request(
|
||||
'GET',
|
||||
'push_audiences/' + audience.objectId,
|
||||
{},
|
||||
{ useMasterKey: true }
|
||||
)
|
||||
.then(audience => {
|
||||
expect(audience.name).toEqual('My Audience');
|
||||
expect(audience.query.deviceType).toEqual('ios');
|
||||
expect(audience.timesUsed).toEqual(1);
|
||||
expect(audience.lastUsed).toEqual(now.toISOString());
|
||||
done();
|
||||
})
|
||||
.catch(error => {
|
||||
done.fail(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to search on audiences', done => {
|
||||
Parse._request(
|
||||
'POST',
|
||||
'push_audiences',
|
||||
{ name: 'neverUsed', query: JSON.stringify({ deviceType: 'ios' }) },
|
||||
{ useMasterKey: true }
|
||||
).then(() => {
|
||||
const query = {
|
||||
timesUsed: { $exists: false },
|
||||
lastUsed: { $exists: false },
|
||||
};
|
||||
Parse._request(
|
||||
'GET',
|
||||
'push_audiences?order=-createdAt&limit=1',
|
||||
{ where: query },
|
||||
{ useMasterKey: true }
|
||||
)
|
||||
.then(results => {
|
||||
expect(results.results.length).toEqual(1);
|
||||
const audience = results.results[0];
|
||||
expect(audience.name).toEqual('neverUsed');
|
||||
done();
|
||||
})
|
||||
.catch(error => {
|
||||
done.fail(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle _Audience invalid fields via rest', async () => {
|
||||
await reconfigureServer({
|
||||
appId: 'test',
|
||||
restAPIKey: 'test',
|
||||
publicServerURL: 'http://localhost:8378/1',
|
||||
});
|
||||
try {
|
||||
await request({
|
||||
method: 'POST',
|
||||
url: 'http://localhost:8378/1/classes/_Audience',
|
||||
body: { lorem: 'ipsum', _method: 'POST' },
|
||||
headers: {
|
||||
'X-Parse-Application-Id': 'test',
|
||||
'X-Parse-REST-API-Key': 'test',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
expect(true).toBeFalsy();
|
||||
} catch (e) {
|
||||
expect(e.data.code).toBe(107);
|
||||
expect(e.data.error).toBe('Could not add field lorem');
|
||||
}
|
||||
});
|
||||
});
|
||||
+56
-207
@@ -1,13 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
describe('Auth', () => {
|
||||
const { Auth, getAuthForSessionToken } = require('../lib/Auth.js');
|
||||
const Config = require('../lib/Config');
|
||||
var Auth = require('../src/Auth.js').Auth;
|
||||
|
||||
describe('getUserRoles', () => {
|
||||
let auth;
|
||||
let config;
|
||||
let currentRoles = null;
|
||||
const currentUserId = 'userId';
|
||||
var auth;
|
||||
var config;
|
||||
var currentRoles = null;
|
||||
var currentUserId = 'userId';
|
||||
|
||||
beforeEach(() => {
|
||||
currentRoles = ['role:userId'];
|
||||
@@ -16,229 +14,80 @@ describe('Auth', () => {
|
||||
cacheController: {
|
||||
role: {
|
||||
get: () => Promise.resolve(currentRoles),
|
||||
set: jasmine.createSpy('set'),
|
||||
},
|
||||
},
|
||||
};
|
||||
set: jasmine.createSpy('set')
|
||||
}
|
||||
}
|
||||
}
|
||||
spyOn(config.cacheController.role, 'get').and.callThrough();
|
||||
|
||||
auth = new Auth({
|
||||
config: config,
|
||||
isMaster: false,
|
||||
user: {
|
||||
id: currentUserId,
|
||||
id: currentUserId
|
||||
},
|
||||
installationId: 'installationId',
|
||||
installationId: 'installationId'
|
||||
});
|
||||
});
|
||||
|
||||
it('should get user roles from the cache', done => {
|
||||
auth.getUserRoles().then(roles => {
|
||||
const firstSet = config.cacheController.role.set.calls.first();
|
||||
expect(firstSet).toEqual(undefined);
|
||||
it('should get user roles from the cache', (done) => {
|
||||
auth.getUserRoles()
|
||||
.then((roles) => {
|
||||
var firstSet = config.cacheController.role.set.calls.first();
|
||||
expect(firstSet).toEqual(undefined);
|
||||
|
||||
const firstGet = config.cacheController.role.get.calls.first();
|
||||
expect(firstGet.args[0]).toEqual(currentUserId);
|
||||
expect(roles).toEqual(currentRoles);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should only query the roles once', done => {
|
||||
const loadRolesSpy = spyOn(auth, '_loadRoles').and.callThrough();
|
||||
auth
|
||||
.getUserRoles()
|
||||
.then(roles => {
|
||||
expect(roles).toEqual(currentRoles);
|
||||
return auth.getUserRoles();
|
||||
})
|
||||
.then(() => auth.getUserRoles())
|
||||
.then(() => auth.getUserRoles())
|
||||
.then(roles => {
|
||||
// Should only call the cache adapter once.
|
||||
expect(config.cacheController.role.get.calls.count()).toEqual(1);
|
||||
expect(loadRolesSpy.calls.count()).toEqual(1);
|
||||
|
||||
const firstGet = config.cacheController.role.get.calls.first();
|
||||
var firstGet = config.cacheController.role.get.calls.first();
|
||||
expect(firstGet.args[0]).toEqual(currentUserId);
|
||||
expect(roles).toEqual(currentRoles);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have any roles with no user', done => {
|
||||
auth.user = null;
|
||||
auth
|
||||
.getUserRoles()
|
||||
.then(roles => expect(roles).toEqual([]))
|
||||
.then(() => done());
|
||||
});
|
||||
it('should only query the roles once', (done) => {
|
||||
var loadRolesSpy = spyOn(auth, '_loadRoles').and.callThrough();
|
||||
auth.getUserRoles()
|
||||
.then((roles) => {
|
||||
expect(roles).toEqual(currentRoles);
|
||||
return auth.getUserRoles()
|
||||
})
|
||||
.then(() => auth.getUserRoles())
|
||||
.then(() => auth.getUserRoles())
|
||||
.then((roles) => {
|
||||
// Should only call the cache adapter once.
|
||||
expect(config.cacheController.role.get.calls.count()).toEqual(1);
|
||||
expect(loadRolesSpy.calls.count()).toEqual(1);
|
||||
|
||||
it('should not have any user roles with master', done => {
|
||||
auth.isMaster = true;
|
||||
auth
|
||||
.getUserRoles()
|
||||
.then(roles => expect(roles).toEqual([]))
|
||||
.then(() => done());
|
||||
});
|
||||
|
||||
it('should properly handle bcrypt upgrade', done => {
|
||||
const bcryptOriginal = require('bcrypt-nodejs');
|
||||
const bcryptNew = require('bcryptjs');
|
||||
bcryptOriginal.hash('my1Long:password', null, null, function (err, res) {
|
||||
bcryptNew.compare('my1Long:password', res, function (err, res) {
|
||||
expect(res).toBeTruthy();
|
||||
var firstGet = config.cacheController.role.get.calls.first();
|
||||
expect(firstGet.args[0]).toEqual(currentUserId);
|
||||
expect(roles).toEqual(currentRoles);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should load auth without a config', async () => {
|
||||
const user = new Parse.User();
|
||||
await user.signUp({
|
||||
username: 'hello',
|
||||
password: 'password',
|
||||
});
|
||||
expect(user.getSessionToken()).not.toBeUndefined();
|
||||
const userAuth = await getAuthForSessionToken({
|
||||
sessionToken: user.getSessionToken(),
|
||||
});
|
||||
expect(userAuth.user instanceof Parse.User).toBe(true);
|
||||
expect(userAuth.user.id).toBe(user.id);
|
||||
});
|
||||
|
||||
it('should load auth with a config', async () => {
|
||||
const user = new Parse.User();
|
||||
await user.signUp({
|
||||
username: 'hello',
|
||||
password: 'password',
|
||||
});
|
||||
expect(user.getSessionToken()).not.toBeUndefined();
|
||||
const userAuth = await getAuthForSessionToken({
|
||||
sessionToken: user.getSessionToken(),
|
||||
config: Config.get('test'),
|
||||
});
|
||||
expect(userAuth.user instanceof Parse.User).toBe(true);
|
||||
expect(userAuth.user.id).toBe(user.id);
|
||||
});
|
||||
|
||||
it('should load auth without a config', async () => {
|
||||
const user = new Parse.User();
|
||||
await user.signUp({
|
||||
username: 'hello',
|
||||
password: 'password',
|
||||
});
|
||||
expect(user.getSessionToken()).not.toBeUndefined();
|
||||
const userAuth = await getAuthForSessionToken({
|
||||
sessionToken: user.getSessionToken(),
|
||||
});
|
||||
expect(userAuth.user instanceof Parse.User).toBe(true);
|
||||
expect(userAuth.user.id).toBe(user.id);
|
||||
});
|
||||
|
||||
it('should load auth with a config', async () => {
|
||||
const user = new Parse.User();
|
||||
await user.signUp({
|
||||
username: 'hello',
|
||||
password: 'password',
|
||||
});
|
||||
expect(user.getSessionToken()).not.toBeUndefined();
|
||||
const userAuth = await getAuthForSessionToken({
|
||||
sessionToken: user.getSessionToken(),
|
||||
config: Config.get('test'),
|
||||
});
|
||||
expect(userAuth.user instanceof Parse.User).toBe(true);
|
||||
expect(userAuth.user.id).toBe(user.id);
|
||||
});
|
||||
|
||||
describe('getRolesForUser', () => {
|
||||
const rolesNumber = 100;
|
||||
|
||||
it('should load all roles without config', async () => {
|
||||
const user = new Parse.User();
|
||||
await user.signUp({
|
||||
username: 'hello',
|
||||
password: 'password',
|
||||
});
|
||||
expect(user.getSessionToken()).not.toBeUndefined();
|
||||
const userAuth = await getAuthForSessionToken({
|
||||
sessionToken: user.getSessionToken(),
|
||||
});
|
||||
const roles = [];
|
||||
for (let i = 0; i < rolesNumber; i++) {
|
||||
const acl = new Parse.ACL();
|
||||
const role = new Parse.Role('roleloadtest' + i, acl);
|
||||
role.getUsers().add([user]);
|
||||
roles.push(role);
|
||||
}
|
||||
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 with config', async () => {
|
||||
const user = new Parse.User();
|
||||
await user.signUp({
|
||||
username: 'hello',
|
||||
password: 'password',
|
||||
});
|
||||
expect(user.getSessionToken()).not.toBeUndefined();
|
||||
const userAuth = await getAuthForSessionToken({
|
||||
sessionToken: user.getSessionToken(),
|
||||
config: Config.get('test'),
|
||||
});
|
||||
const roles = [];
|
||||
for (let i = 0; i < rolesNumber; i++) {
|
||||
const acl = new Parse.ACL();
|
||||
const role = new Parse.Role('roleloadtest' + i, acl);
|
||||
role.getUsers().add([user]);
|
||||
roles.push(role);
|
||||
}
|
||||
const savedRoles = await Parse.Object.saveAll(roles);
|
||||
expect(savedRoles.length).toBe(rolesNumber);
|
||||
const cloudRoles = await userAuth.getRolesForUser();
|
||||
expect(cloudRoles.length).toBe(rolesNumber);
|
||||
it('should not have any roles with no user', (done) => {
|
||||
auth.user = null
|
||||
auth.getUserRoles()
|
||||
.then((roles) => expect(roles).toEqual([]))
|
||||
.then(() => done());
|
||||
});
|
||||
|
||||
it('should load all roles for different users with config', async () => {
|
||||
const user = new Parse.User();
|
||||
await user.signUp({
|
||||
username: 'hello',
|
||||
password: 'password',
|
||||
});
|
||||
const user2 = new Parse.User();
|
||||
await user2.signUp({
|
||||
username: 'world',
|
||||
password: '1234',
|
||||
});
|
||||
expect(user.getSessionToken()).not.toBeUndefined();
|
||||
const userAuth = await getAuthForSessionToken({
|
||||
sessionToken: user.getSessionToken(),
|
||||
config: Config.get('test'),
|
||||
});
|
||||
const user2Auth = await getAuthForSessionToken({
|
||||
sessionToken: user2.getSessionToken(),
|
||||
config: Config.get('test'),
|
||||
});
|
||||
const roles = [];
|
||||
for (let i = 0; i < rolesNumber; i += 1) {
|
||||
const acl = new Parse.ACL();
|
||||
const acl2 = new Parse.ACL();
|
||||
const role = new Parse.Role('roleloadtest' + i, acl);
|
||||
const role2 = new Parse.Role('role2loadtest' + i, acl2);
|
||||
role.getUsers().add([user]);
|
||||
role2.getUsers().add([user2]);
|
||||
roles.push(role);
|
||||
roles.push(role2);
|
||||
}
|
||||
const savedRoles = await Parse.Object.saveAll(roles);
|
||||
expect(savedRoles.length).toBe(rolesNumber * 2);
|
||||
const cloudRoles = await userAuth.getRolesForUser();
|
||||
const cloudRoles2 = await user2Auth.getRolesForUser();
|
||||
expect(cloudRoles.length).toBe(rolesNumber);
|
||||
expect(cloudRoles2.length).toBe(rolesNumber);
|
||||
it('should not have any user roles with master', (done) => {
|
||||
auth.isMaster = true
|
||||
auth.getUserRoles()
|
||||
.then((roles) => expect(roles).toEqual([]))
|
||||
.then(() => done());
|
||||
});
|
||||
|
||||
it('should properly handle bcrypt upgrade', (done) => {
|
||||
var bcryptOriginal = require('bcrypt-nodejs');
|
||||
var bcryptNew = require('bcryptjs');
|
||||
bcryptOriginal.hash('my1Long:password', null, null, function(err, res) {
|
||||
bcryptNew.compare('my1Long:password', res, function(err, res) {
|
||||
expect(res).toBeTruthy();
|
||||
done();
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
+168
-2048
File diff suppressed because it is too large
Load Diff
+49
-167
@@ -1,34 +1,32 @@
|
||||
'use strict';
|
||||
const commander = require('../lib/cli/utils/commander').default;
|
||||
const definitions = require('../lib/cli/definitions/parse-server').default;
|
||||
const liveQueryDefinitions = require('../lib/cli/definitions/parse-live-query-server').default;
|
||||
const path = require('path');
|
||||
const { spawn } = require('child_process');
|
||||
import commander from '../src/cli/utils/commander';
|
||||
import definitions from '../src/cli/definitions/parse-server';
|
||||
import liveQueryDefinitions from '../src/cli/definitions/parse-live-query-server';
|
||||
|
||||
const testDefinitions = {
|
||||
arg0: 'PROGRAM_ARG_0',
|
||||
arg1: {
|
||||
var testDefinitions = {
|
||||
'arg0': 'PROGRAM_ARG_0',
|
||||
'arg1': {
|
||||
env: 'PROGRAM_ARG_1',
|
||||
required: true,
|
||||
required: true
|
||||
},
|
||||
arg2: {
|
||||
'arg2': {
|
||||
env: 'PROGRAM_ARG_2',
|
||||
action: function (value) {
|
||||
const intValue = parseInt(value);
|
||||
action: function(value) {
|
||||
var intValue = parseInt(value);
|
||||
if (!Number.isInteger(intValue)) {
|
||||
throw 'arg2 is invalid';
|
||||
}
|
||||
return intValue;
|
||||
},
|
||||
},
|
||||
arg3: {},
|
||||
arg4: {
|
||||
default: 'arg4Value',
|
||||
}
|
||||
},
|
||||
'arg3': {},
|
||||
'arg4': {
|
||||
default: 'arg4Value'
|
||||
}
|
||||
};
|
||||
|
||||
describe('commander additions', () => {
|
||||
afterEach(done => {
|
||||
afterEach((done) => {
|
||||
commander.options = [];
|
||||
delete commander.arg0;
|
||||
delete commander.arg1;
|
||||
@@ -38,20 +36,9 @@ describe('commander additions', () => {
|
||||
done();
|
||||
});
|
||||
|
||||
it('should load properly definitions from args', done => {
|
||||
it('should load properly definitions from args', (done) => {
|
||||
commander.loadDefinitions(testDefinitions);
|
||||
commander.parse([
|
||||
'node',
|
||||
'./CLI.spec.js',
|
||||
'--arg0',
|
||||
'arg0Value',
|
||||
'--arg1',
|
||||
'arg1Value',
|
||||
'--arg2',
|
||||
'2',
|
||||
'--arg3',
|
||||
'some',
|
||||
]);
|
||||
commander.parse(['node','./CLI.spec.js','--arg0', 'arg0Value', '--arg1', 'arg1Value', '--arg2', '2', '--arg3', 'some']);
|
||||
expect(commander.arg0).toEqual('arg0Value');
|
||||
expect(commander.arg1).toEqual('arg1Value');
|
||||
expect(commander.arg2).toEqual(2);
|
||||
@@ -60,12 +47,12 @@ describe('commander additions', () => {
|
||||
done();
|
||||
});
|
||||
|
||||
it('should load properly definitions from env', done => {
|
||||
it('should load properly definitions from env', (done) => {
|
||||
commander.loadDefinitions(testDefinitions);
|
||||
commander.parse([], {
|
||||
PROGRAM_ARG_0: 'arg0ENVValue',
|
||||
PROGRAM_ARG_1: 'arg1ENVValue',
|
||||
PROGRAM_ARG_2: '3',
|
||||
'PROGRAM_ARG_0': 'arg0ENVValue',
|
||||
'PROGRAM_ARG_1': 'arg1ENVValue',
|
||||
'PROGRAM_ARG_2': '3',
|
||||
});
|
||||
expect(commander.arg0).toEqual('arg0ENVValue');
|
||||
expect(commander.arg1).toEqual('arg1ENVValue');
|
||||
@@ -74,13 +61,13 @@ describe('commander additions', () => {
|
||||
done();
|
||||
});
|
||||
|
||||
it('should load properly use args over env', done => {
|
||||
it('should load properly use args over env', (done) => {
|
||||
commander.loadDefinitions(testDefinitions);
|
||||
commander.parse(['node', './CLI.spec.js', '--arg0', 'arg0Value', '--arg4', ''], {
|
||||
PROGRAM_ARG_0: 'arg0ENVValue',
|
||||
PROGRAM_ARG_1: 'arg1ENVValue',
|
||||
PROGRAM_ARG_2: '4',
|
||||
PROGRAM_ARG_4: 'arg4ENVValue',
|
||||
commander.parse(['node','./CLI.spec.js','--arg0', 'arg0Value', '--arg4', ''], {
|
||||
'PROGRAM_ARG_0': 'arg0ENVValue',
|
||||
'PROGRAM_ARG_1': 'arg1ENVValue',
|
||||
'PROGRAM_ARG_2': '4',
|
||||
'PROGRAM_ARG_4': 'arg4ENVValue'
|
||||
});
|
||||
expect(commander.arg0).toEqual('arg0Value');
|
||||
expect(commander.arg1).toEqual('arg1ENVValue');
|
||||
@@ -89,28 +76,24 @@ describe('commander additions', () => {
|
||||
done();
|
||||
});
|
||||
|
||||
it('should fail in action as port is invalid', done => {
|
||||
it('should fail in action as port is invalid', (done) => {
|
||||
commander.loadDefinitions(testDefinitions);
|
||||
expect(() => {
|
||||
commander.parse(['node', './CLI.spec.js', '--arg0', 'arg0Value'], {
|
||||
PROGRAM_ARG_0: 'arg0ENVValue',
|
||||
PROGRAM_ARG_1: 'arg1ENVValue',
|
||||
PROGRAM_ARG_2: 'hello',
|
||||
expect(()=> {
|
||||
commander.parse(['node','./CLI.spec.js','--arg0', 'arg0Value'], {
|
||||
'PROGRAM_ARG_0': 'arg0ENVValue',
|
||||
'PROGRAM_ARG_1': 'arg1ENVValue',
|
||||
'PROGRAM_ARG_2': 'hello',
|
||||
});
|
||||
}).toThrow('arg2 is invalid');
|
||||
done();
|
||||
});
|
||||
|
||||
it('should not override config.json', done => {
|
||||
spyOn(console, 'log').and.callFake(() => {});
|
||||
it('should not override config.json', (done) => {
|
||||
commander.loadDefinitions(testDefinitions);
|
||||
commander.parse(
|
||||
['node', './CLI.spec.js', '--arg0', 'arg0Value', './spec/configs/CLIConfig.json'],
|
||||
{
|
||||
PROGRAM_ARG_0: 'arg0ENVValue',
|
||||
PROGRAM_ARG_1: 'arg1ENVValue',
|
||||
}
|
||||
);
|
||||
commander.parse(['node','./CLI.spec.js','--arg0', 'arg0Value', './spec/configs/CLIConfig.json'], {
|
||||
'PROGRAM_ARG_0': 'arg0ENVValue',
|
||||
'PROGRAM_ARG_1': 'arg1ENVValue',
|
||||
});
|
||||
const options = commander.getOptions();
|
||||
expect(options.arg2).toBe(8888);
|
||||
expect(options.arg3).toBe('hello'); //config value
|
||||
@@ -118,30 +101,26 @@ describe('commander additions', () => {
|
||||
done();
|
||||
});
|
||||
|
||||
it('should fail with invalid values in JSON', done => {
|
||||
it('should fail with invalid values in JSON', (done) => {
|
||||
commander.loadDefinitions(testDefinitions);
|
||||
expect(() => {
|
||||
commander.parse(
|
||||
['node', './CLI.spec.js', '--arg0', 'arg0Value', './spec/configs/CLIConfigFail.json'],
|
||||
{
|
||||
PROGRAM_ARG_0: 'arg0ENVValue',
|
||||
PROGRAM_ARG_1: 'arg1ENVValue',
|
||||
}
|
||||
);
|
||||
commander.parse(['node','./CLI.spec.js','--arg0', 'arg0Value', './spec/configs/CLIConfigFail.json'], {
|
||||
'PROGRAM_ARG_0': 'arg0ENVValue',
|
||||
'PROGRAM_ARG_1': 'arg1ENVValue',
|
||||
});
|
||||
}).toThrow('arg2 is invalid');
|
||||
done();
|
||||
});
|
||||
|
||||
it('should fail when too many apps are set', done => {
|
||||
it('should fail when too many apps are set', (done) => {
|
||||
commander.loadDefinitions(testDefinitions);
|
||||
expect(() => {
|
||||
commander.parse(['node', './CLI.spec.js', './spec/configs/CLIConfigFailTooManyApps.json']);
|
||||
commander.parse(['node','./CLI.spec.js','./spec/configs/CLIConfigFailTooManyApps.json']);
|
||||
}).toThrow('Multiple apps are not supported');
|
||||
done();
|
||||
});
|
||||
|
||||
it('should load config from apps', done => {
|
||||
spyOn(console, 'log').and.callFake(() => {});
|
||||
it('should load config from apps', (done) => {
|
||||
commander.loadDefinitions(testDefinitions);
|
||||
commander.parse(['node', './CLI.spec.js', './spec/configs/CLIConfigApps.json']);
|
||||
const options = commander.getOptions();
|
||||
@@ -152,7 +131,7 @@ describe('commander additions', () => {
|
||||
done();
|
||||
});
|
||||
|
||||
it('should fail when passing an invalid arguement', done => {
|
||||
it('should fail when passing an invalid arguement', (done) => {
|
||||
commander.loadDefinitions(testDefinitions);
|
||||
expect(() => {
|
||||
commander.parse(['node', './CLI.spec.js', './spec/configs/CLIConfigUnknownArg.json']);
|
||||
@@ -178,12 +157,6 @@ describe('definitions', () => {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw when using deprecated facebookAppIds', () => {
|
||||
expect(() => {
|
||||
definitions.facebookAppIds.action();
|
||||
}).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('LiveQuery definitions', () => {
|
||||
@@ -194,7 +167,7 @@ describe('LiveQuery definitions', () => {
|
||||
if (typeof definition.env !== 'undefined') {
|
||||
expect(typeof definition.env).toBe('string');
|
||||
}
|
||||
expect(typeof definition.help).toBe('string', `help for ${key} should be a string`);
|
||||
expect(typeof definition.help).toBe('string');
|
||||
if (typeof definition.required !== 'undefined') {
|
||||
expect(typeof definition.required).toBe('boolean');
|
||||
}
|
||||
@@ -204,94 +177,3 @@ describe('LiveQuery definitions', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('execution', () => {
|
||||
const binPath = path.resolve(__dirname, '../bin/parse-server');
|
||||
let childProcess;
|
||||
|
||||
afterEach(done => {
|
||||
if (childProcess) {
|
||||
childProcess.on('close', () => {
|
||||
childProcess = undefined;
|
||||
done();
|
||||
});
|
||||
childProcess.kill();
|
||||
}
|
||||
});
|
||||
|
||||
it('shoud start Parse Server', done => {
|
||||
childProcess = spawn(binPath, [
|
||||
'--appId',
|
||||
'test',
|
||||
'--masterKey',
|
||||
'test',
|
||||
'--databaseURI',
|
||||
'mongodb://localhost/test',
|
||||
'--port',
|
||||
'1339',
|
||||
]);
|
||||
childProcess.stdout.on('data', data => {
|
||||
data = data.toString();
|
||||
if (data.includes('parse-server running on')) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
childProcess.stderr.on('data', data => {
|
||||
done.fail(data.toString());
|
||||
});
|
||||
});
|
||||
|
||||
it('shoud start Parse Server with GraphQL', done => {
|
||||
childProcess = spawn(binPath, [
|
||||
'--appId',
|
||||
'test',
|
||||
'--masterKey',
|
||||
'test',
|
||||
'--databaseURI',
|
||||
'mongodb://localhost/test',
|
||||
'--port',
|
||||
'1340',
|
||||
'--mountGraphQL',
|
||||
]);
|
||||
let output = '';
|
||||
childProcess.stdout.on('data', data => {
|
||||
data = data.toString();
|
||||
output += data;
|
||||
if (data.includes('GraphQL running on')) {
|
||||
expect(output).toMatch('parse-server running on');
|
||||
done();
|
||||
}
|
||||
});
|
||||
childProcess.stderr.on('data', data => {
|
||||
done.fail(data.toString());
|
||||
});
|
||||
});
|
||||
|
||||
it('shoud start Parse Server with GraphQL and Playground', done => {
|
||||
childProcess = spawn(binPath, [
|
||||
'--appId',
|
||||
'test',
|
||||
'--masterKey',
|
||||
'test',
|
||||
'--databaseURI',
|
||||
'mongodb://localhost/test',
|
||||
'--port',
|
||||
'1341',
|
||||
'--mountGraphQL',
|
||||
'--mountPlayground',
|
||||
]);
|
||||
let output = '';
|
||||
childProcess.stdout.on('data', data => {
|
||||
data = data.toString();
|
||||
output += data;
|
||||
if (data.includes('Playground running on')) {
|
||||
expect(output).toMatch('GraphQL running on');
|
||||
expect(output).toMatch('parse-server running on');
|
||||
done();
|
||||
}
|
||||
});
|
||||
childProcess.stderr.on('data', data => {
|
||||
done.fail(data.toString());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user