Compare commits
251 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
591e1444f9 | ||
![]() |
5d5aebdb41 | ||
![]() |
83d16e72e1 | ||
![]() |
2a77763c51 | ||
![]() |
17614d6d47 | ||
![]() |
b4fcdbd2c4 | ||
![]() |
8e89a103db | ||
![]() |
978ceaadb6 | ||
![]() |
770b07179f | ||
![]() |
6d15167ad9 | ||
![]() |
39cba6bc74 | ||
![]() |
9558e66abf | ||
![]() |
ff7908955e | ||
![]() |
26b095b835 | ||
![]() |
feba2a32f9 | ||
![]() |
5090ece9b6 | ||
![]() |
221b19586e | ||
![]() |
3346c14255 | ||
![]() |
6e97e023c9 | ||
![]() |
b26e2ecf2e | ||
![]() |
d896238f23 | ||
![]() |
d2c8f5a75c | ||
![]() |
ce430d238c | ||
![]() |
ee397441ed | ||
![]() |
ba82d986c1 | ||
![]() |
2361cb521e | ||
![]() |
05f8d95281 | ||
![]() |
6c60b1c263 | ||
![]() |
0c32a0693c | ||
![]() |
807faa3c93 | ||
![]() |
fb53e37f7a | ||
![]() |
4ffdf98e16 | ||
![]() |
b8da721e39 | ||
![]() |
db8b98ca16 | ||
![]() |
01b8c600fe | ||
![]() |
69bd5549a2 | ||
![]() |
bc631e3931 | ||
![]() |
8ca4bc5a33 | ||
![]() |
58a569afb0 | ||
![]() |
db718d6fc3 | ||
![]() |
ca9cb8b07b | ||
![]() |
ef14586412 | ||
![]() |
09335fcd79 | ||
![]() |
15f1fca6fe | ||
![]() |
a570b8eb7a | ||
![]() |
02e2735b7a | ||
![]() |
54fa347142 | ||
![]() |
0c752beace | ||
![]() |
c14f808d29 | ||
![]() |
ad71173671 | ||
![]() |
204325ef44 | ||
![]() |
7ce6117659 | ||
![]() |
823a2c8b73 | ||
![]() |
741866e742 | ||
![]() |
41622678b0 | ||
![]() |
449b953401 | ||
![]() |
551548400f | ||
![]() |
6345ce5195 | ||
![]() |
95651f6163 | ||
![]() |
b02c1545b7 | ||
![]() |
2deaab9b24 | ||
![]() |
f0d4853533 | ||
![]() |
af81ae812f | ||
![]() |
bae76064e5 | ||
![]() |
07d9198cc8 | ||
![]() |
a2e07ea2f7 | ||
![]() |
864c762fe2 | ||
![]() |
167bb4e8a0 | ||
![]() |
4cf64ede74 | ||
![]() |
bb309fea6f | ||
![]() |
90a7b4c1c0 | ||
![]() |
1133362028 | ||
![]() |
eb9226bd4a | ||
![]() |
a9abdcc37e | ||
![]() |
6ace93bdbf | ||
![]() |
b89197939a | ||
![]() |
da788106af | ||
![]() |
49e92e6f1d | ||
![]() |
a6c3276104 | ||
![]() |
6388bfc714 | ||
![]() |
bebc3b181d | ||
![]() |
5a6d561c1a | ||
![]() |
5ba575fdfd | ||
![]() |
dcf8bbd804 | ||
![]() |
ff93ffd0b1 | ||
![]() |
395c09df92 | ||
![]() |
4c903cd08b | ||
![]() |
64cb98717c | ||
![]() |
b0e4ce54fb | ||
![]() |
d67a37002f | ||
![]() |
965ff8bc3f | ||
![]() |
400a495ad2 | ||
![]() |
09d0822a8d | ||
![]() |
7016c20ccc | ||
![]() |
df54895805 | ||
![]() |
62d5e6fe51 | ||
![]() |
4615a0b7ea | ||
![]() |
280d603b14 | ||
![]() |
36271f0749 | ||
![]() |
579638f932 | ||
![]() |
48871c82a6 | ||
![]() |
14056c42ef | ||
![]() |
90fe1576de | ||
![]() |
d61cf13985 | ||
![]() |
dfe6dfd0c6 | ||
![]() |
c138c7d0e9 | ||
![]() |
d542be947e | ||
![]() |
c76366e72e | ||
![]() |
75abfda783 | ||
![]() |
f3d8d7d4ad | ||
![]() |
7255eccb22 | ||
![]() |
a0decb70cc | ||
![]() |
532f562495 | ||
![]() |
27e58ae925 | ||
![]() |
abf30dfc1a | ||
![]() |
218b8ce86e | ||
![]() |
4867ffcb4b | ||
![]() |
e34c3b411d | ||
![]() |
c91b8be1a6 | ||
![]() |
9cb41644a1 | ||
![]() |
8c01cea147 | ||
![]() |
58eb55e90a | ||
![]() |
bb05e82e15 | ||
![]() |
5ab95ea175 | ||
![]() |
a25c4f1d1e | ||
![]() |
15287de8af | ||
![]() |
49b4d6b511 | ||
![]() |
d5b4a5d4ac | ||
![]() |
de480b491c | ||
![]() |
a949fda1fc | ||
![]() |
3e28af670c | ||
![]() |
b5310afb90 | ||
![]() |
da81ecf915 | ||
![]() |
f597066d16 | ||
![]() |
ec30606b24 | ||
![]() |
20dce14f17 | ||
![]() |
821742de85 | ||
![]() |
74dc108f62 | ||
![]() |
a05fe856bb | ||
![]() |
d13f51a32d | ||
![]() |
3dbe599cb3 | ||
![]() |
cf966dd83c | ||
![]() |
4e62f3654f | ||
![]() |
970d926563 | ||
![]() |
ff49c747ba | ||
![]() |
c46b8a5f4f | ||
![]() |
485324e204 | ||
![]() |
4696a03db1 | ||
![]() |
7885de36a9 | ||
![]() |
fac4339207 | ||
![]() |
9c70519021 | ||
![]() |
9ae77ecd5d | ||
![]() |
1c8e6f278d | ||
![]() |
c0a190a9f2 | ||
![]() |
e29e2a62f0 | ||
![]() |
1580640a35 | ||
![]() |
33c84b7fcc | ||
![]() |
9773ce75b0 | ||
![]() |
c310e8d152 | ||
![]() |
af251c7b81 | ||
![]() |
122483de0c | ||
![]() |
42c2131144 | ||
![]() |
71bc7a62c2 | ||
![]() |
87bfff07db | ||
![]() |
1cb5b780d2 | ||
![]() |
2f6acd4d6e | ||
![]() |
c2e2351505 | ||
![]() |
d847b5480b | ||
![]() |
32749ee58e | ||
![]() |
a531b8b5fe | ||
![]() |
148a0c5bb0 | ||
![]() |
39f9a58200 | ||
![]() |
edd113d344 | ||
![]() |
c641e8729b | ||
![]() |
2c4b13e4b5 | ||
![]() |
48fcf4dda7 | ||
![]() |
acfd980d4f | ||
![]() |
db9bfab812 | ||
![]() |
d32820ee09 | ||
![]() |
0f823fd19e | ||
![]() |
4308ed5850 | ||
![]() |
b9cd7c3983 | ||
![]() |
fa607aa961 | ||
![]() |
6900b71841 | ||
![]() |
bb230d67e8 | ||
![]() |
4f076ec3e3 | ||
![]() |
96a6cbfb95 | ||
![]() |
5bdc5aed72 | ||
![]() |
d38b0f088b | ||
![]() |
892710f705 | ||
![]() |
fbf898be64 | ||
![]() |
e3e2ecc1e1 | ||
![]() |
b59807d221 | ||
![]() |
163ad52285 | ||
![]() |
4023a6d1cc | ||
![]() |
ec827e5dc0 | ||
![]() |
a8f4fb7c22 | ||
![]() |
bc195ed452 | ||
![]() |
41568904ab | ||
![]() |
79050af391 | ||
![]() |
2e5b44c424 | ||
![]() |
7a437660d1 | ||
![]() |
47510e24d5 | ||
![]() |
91c9ef3068 | ||
![]() |
240854e4ac | ||
![]() |
0e4fc7efbc | ||
![]() |
b47e859225 | ||
![]() |
62a1072682 | ||
![]() |
c6f2a97591 | ||
![]() |
d66be231b3 | ||
![]() |
f73ffc8711 | ||
![]() |
e4c17c1bc7 | ||
![]() |
997e729535 | ||
![]() |
e0e313b8d1 | ||
![]() |
f0bd763e72 | ||
![]() |
6a7a90536b | ||
![]() |
ac8ddedfb5 | ||
![]() |
6fcd126ff8 | ||
![]() |
55d0966d48 | ||
![]() |
2583e08f7a | ||
![]() |
de72e62470 | ||
![]() |
91993dbb07 | ||
![]() |
d87ee4daa3 | ||
![]() |
6791e002ff | ||
![]() |
4ca84aa515 | ||
![]() |
8189cbc171 | ||
![]() |
73edb45ff7 | ||
![]() |
0bbe362660 | ||
![]() |
a76bee51fc | ||
![]() |
6e42b52414 | ||
![]() |
aed61209fa | ||
![]() |
f5d796ea77 | ||
![]() |
ecb04b4ba9 | ||
![]() |
dabb01e237 | ||
![]() |
c2d27d0fd4 | ||
![]() |
e62bd75fdf | ||
![]() |
2e917bd62b | ||
![]() |
e0492c4264 | ||
![]() |
7db68e2f96 | ||
![]() |
e9b05a37d1 | ||
![]() |
5613259536 | ||
![]() |
3209ff16ac | ||
![]() |
a49c8602d1 | ||
![]() |
7caa055e00 | ||
![]() |
0d62bc6c78 | ||
![]() |
bc0861fd9e | ||
![]() |
f280052d93 | ||
![]() |
21da49f79d | ||
![]() |
19a5ccf942 | ||
![]() |
2981fa5946 | ||
![]() |
05a3016557 |
@@ -5,8 +5,11 @@ BACKEND_PORT=3000
|
|||||||
WEB_PORT=3001
|
WEB_PORT=3001
|
||||||
|
|
||||||
echo "Configuring backend environment variables..."
|
echo "Configuring backend environment variables..."
|
||||||
|
|
||||||
cd packages/backend
|
cd packages/backend
|
||||||
|
|
||||||
rm -rf .env
|
rm -rf .env
|
||||||
|
|
||||||
echo "
|
echo "
|
||||||
PORT=$BACKEND_PORT
|
PORT=$BACKEND_PORT
|
||||||
WEB_APP_URL=http://localhost:$WEB_PORT
|
WEB_APP_URL=http://localhost:$WEB_PORT
|
||||||
@@ -21,24 +24,35 @@ WEBHOOK_SECRET_KEY=sample_webhook_secret_key
|
|||||||
APP_SECRET_KEY=sample_app_secret_key
|
APP_SECRET_KEY=sample_app_secret_key
|
||||||
REDIS_HOST=redis
|
REDIS_HOST=redis
|
||||||
SERVE_WEB_APP_SEPARATELY=true" >> .env
|
SERVE_WEB_APP_SEPARATELY=true" >> .env
|
||||||
|
|
||||||
|
echo "Installing backend dependencies..."
|
||||||
|
|
||||||
|
yarn
|
||||||
|
|
||||||
cd $CURRENT_DIR
|
cd $CURRENT_DIR
|
||||||
|
|
||||||
echo "Configuring web environment variables..."
|
echo "Configuring web environment variables..."
|
||||||
|
|
||||||
cd packages/web
|
cd packages/web
|
||||||
|
|
||||||
rm -rf .env
|
rm -rf .env
|
||||||
|
|
||||||
echo "
|
echo "
|
||||||
PORT=$WEB_PORT
|
PORT=$WEB_PORT
|
||||||
REACT_APP_BACKEND_URL=http://localhost:$BACKEND_PORT
|
REACT_APP_BACKEND_URL=http://localhost:$BACKEND_PORT
|
||||||
" >> .env
|
" >> .env
|
||||||
|
|
||||||
|
echo "Installing web dependencies..."
|
||||||
|
|
||||||
|
yarn
|
||||||
|
|
||||||
cd $CURRENT_DIR
|
cd $CURRENT_DIR
|
||||||
|
|
||||||
echo "Installing and linking dependencies..."
|
|
||||||
yarn
|
|
||||||
yarn lerna bootstrap
|
|
||||||
|
|
||||||
echo "Migrating database..."
|
echo "Migrating database..."
|
||||||
|
|
||||||
cd packages/backend
|
cd packages/backend
|
||||||
|
|
||||||
yarn db:migrate
|
yarn db:migrate
|
||||||
yarn db:seed:user
|
yarn db:seed:user
|
||||||
|
|
||||||
echo "Done!"
|
echo "Done!"
|
||||||
|
9
.github/workflows/backend.yml
vendored
9
.github/workflows/backend.yml
vendored
@@ -41,8 +41,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: cd packages/backend && yarn
|
run: yarn
|
||||||
|
working-directory: packages/backend
|
||||||
- name: Copy .env-example.test file to .env.test
|
- name: Copy .env-example.test file to .env.test
|
||||||
run: cd packages/backend && cp .env-example.test .env.test
|
run: cp .env-example.test .env.test
|
||||||
|
working-directory: packages/backend
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cd packages/backend && yarn test
|
run: yarn test:coverage
|
||||||
|
working-directory: packages/backend
|
||||||
|
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
@@ -18,11 +18,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: '18'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
cache-dependency-path: yarn.lock
|
cache-dependency-path: packages/backend/yarn.lock
|
||||||
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
|
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
|
||||||
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
||||||
- run: yarn --frozen-lockfile
|
- run: yarn --frozen-lockfile
|
||||||
- run: cd packages/backend && yarn lint
|
working-directory: packages/backend
|
||||||
|
- run: yarn lint
|
||||||
|
working-directory: packages/backend
|
||||||
- run: echo "🍏 This job's status is ${{ job.status }}."
|
- run: echo "🍏 This job's status is ${{ job.status }}."
|
||||||
start-backend-server:
|
start-backend-server:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -35,11 +37,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: '18'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
cache-dependency-path: yarn.lock
|
cache-dependency-path: packages/backend/yarn.lock
|
||||||
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
|
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
|
||||||
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
||||||
- run: yarn --frozen-lockfile && yarn lerna bootstrap
|
- run: yarn --frozen-lockfile
|
||||||
- run: cd packages/backend && yarn start
|
working-directory: packages/backend
|
||||||
|
- run: yarn start
|
||||||
|
working-directory: packages/backend
|
||||||
env:
|
env:
|
||||||
ENCRYPTION_KEY: sample_encryption_key
|
ENCRYPTION_KEY: sample_encryption_key
|
||||||
WEBHOOK_SECRET_KEY: sample_webhook_secret_key
|
WEBHOOK_SECRET_KEY: sample_webhook_secret_key
|
||||||
@@ -55,11 +59,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: '18'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
cache-dependency-path: yarn.lock
|
cache-dependency-path: packages/backend/yarn.lock
|
||||||
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
|
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
|
||||||
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
||||||
- run: yarn --frozen-lockfile && yarn lerna bootstrap
|
- run: yarn --frozen-lockfile
|
||||||
- run: cd packages/backend && yarn start:worker
|
working-directory: packages/backend
|
||||||
|
- run: yarn start:worker
|
||||||
|
working-directory: packages/backend
|
||||||
env:
|
env:
|
||||||
ENCRYPTION_KEY: sample_encryption_key
|
ENCRYPTION_KEY: sample_encryption_key
|
||||||
WEBHOOK_SECRET_KEY: sample_webhook_secret_key
|
WEBHOOK_SECRET_KEY: sample_webhook_secret_key
|
||||||
@@ -75,11 +81,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: '18'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
cache-dependency-path: yarn.lock
|
cache-dependency-path: packages/web/yarn.lock
|
||||||
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
|
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
|
||||||
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
||||||
- run: yarn --frozen-lockfile && yarn lerna bootstrap
|
- run: yarn --frozen-lockfile
|
||||||
- run: cd packages/web && yarn build
|
working-directory: packages/web
|
||||||
|
- run: yarn build
|
||||||
|
working-directory: packages/web
|
||||||
env:
|
env:
|
||||||
CI: false
|
CI: false
|
||||||
- run: echo "🍏 This job's status is ${{ job.status }}."
|
- run: echo "🍏 This job's status is ${{ job.status }}."
|
||||||
|
19
.github/workflows/playwright.yml
vendored
19
.github/workflows/playwright.yml
vendored
@@ -3,6 +3,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
# TODO: Add pull request after optimizing the total excecution time of the test suite.
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- 'packages/backend/**'
|
- 'packages/backend/**'
|
||||||
@@ -12,9 +13,6 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
BULLMQ_DASHBOARD_USERNAME: root
|
|
||||||
BULLMQ_DASHBOARD_PASSWORD: sample
|
|
||||||
ENABLE_BULLMQ_DASHBOARD: true
|
|
||||||
ENCRYPTION_KEY: sample_encryption_key
|
ENCRYPTION_KEY: sample_encryption_key
|
||||||
WEBHOOK_SECRET_KEY: sample_webhook_secret_key
|
WEBHOOK_SECRET_KEY: sample_webhook_secret_key
|
||||||
APP_SECRET_KEY: sample_app_secret_key
|
APP_SECRET_KEY: sample_app_secret_key
|
||||||
@@ -25,7 +23,6 @@ env:
|
|||||||
POSTGRES_PASSWORD: automatisch_password
|
POSTGRES_PASSWORD: automatisch_password
|
||||||
REDIS_HOST: localhost
|
REDIS_HOST: localhost
|
||||||
APP_ENV: production
|
APP_ENV: production
|
||||||
PORT: 3000
|
|
||||||
LICENSE_KEY: dummy_license_key
|
LICENSE_KEY: dummy_license_key
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -62,13 +59,21 @@ jobs:
|
|||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
- name: Install dependencies
|
- name: Install web dependencies
|
||||||
run: yarn && yarn lerna bootstrap
|
run: yarn
|
||||||
|
working-directory: ./packages/web
|
||||||
|
- name: Install backend dependencies
|
||||||
|
run: yarn
|
||||||
|
working-directory: ./packages/backend
|
||||||
|
- name: Install e2e-tests dependencies
|
||||||
|
run: yarn
|
||||||
|
working-directory: ./packages/e2e-tests
|
||||||
- name: Install Playwright Browsers
|
- name: Install Playwright Browsers
|
||||||
run: yarn playwright install --with-deps
|
run: yarn playwright install --with-deps
|
||||||
|
working-directory: ./packages/e2e-tests
|
||||||
- name: Build Automatisch web
|
- name: Build Automatisch web
|
||||||
working-directory: ./packages/web
|
|
||||||
run: yarn build
|
run: yarn build
|
||||||
|
working-directory: ./packages/web
|
||||||
env:
|
env:
|
||||||
# Keep this until we clean up warnings in build processes
|
# Keep this until we clean up warnings in build processes
|
||||||
CI: false
|
CI: false
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,7 +4,6 @@ logs
|
|||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
lerna-debug.log*
|
|
||||||
.pnpm-debug.log*
|
.pnpm-debug.log*
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
@@ -11,10 +11,12 @@ WORKDIR /automatisch
|
|||||||
# copy the app, note .dockerignore
|
# copy the app, note .dockerignore
|
||||||
COPY . /automatisch
|
COPY . /automatisch
|
||||||
|
|
||||||
RUN yarn
|
RUN cd packages/web && yarn
|
||||||
|
|
||||||
RUN cd packages/web && yarn build
|
RUN cd packages/web && yarn build
|
||||||
|
|
||||||
|
RUN cd packages/backend && yarn --production
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
rm -rf /usr/local/share/.cache/ && \
|
rm -rf /usr/local/share/.cache/ && \
|
||||||
apk del build-dependencies
|
apk del build-dependencies
|
||||||
|
13
lerna.json
13
lerna.json
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"packages": [
|
|
||||||
"packages/*"
|
|
||||||
],
|
|
||||||
"version": "0.10.0",
|
|
||||||
"npmClient": "yarn",
|
|
||||||
"useWorkspaces": true,
|
|
||||||
"command": {
|
|
||||||
"add": {
|
|
||||||
"exact": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
32
package.json
32
package.json
@@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@automatisch/root",
|
|
||||||
"license": "See LICENSE file",
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"start": "lerna run --stream --parallel --scope=@*/{web,backend} dev",
|
|
||||||
"start:web": "lerna run --stream --scope=@*/web dev",
|
|
||||||
"start:backend": "lerna run --stream --scope=@*/backend dev",
|
|
||||||
"build:docs": "cd ./packages/docs && yarn install && yarn build"
|
|
||||||
},
|
|
||||||
"workspaces": {
|
|
||||||
"packages": [
|
|
||||||
"packages/*"
|
|
||||||
],
|
|
||||||
"nohoist": [
|
|
||||||
"**/babel-loader",
|
|
||||||
"**/webpack",
|
|
||||||
"**/@automatisch/web",
|
|
||||||
"**/ajv"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"eslint": "^8.13.0",
|
|
||||||
"eslint-config-prettier": "^8.3.0",
|
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
|
||||||
"lerna": "^4.0.0",
|
|
||||||
"prettier": "^2.5.1"
|
|
||||||
},
|
|
||||||
"publishConfig": {
|
|
||||||
"access": "public"
|
|
||||||
}
|
|
||||||
}
|
|
@@ -12,6 +12,7 @@
|
|||||||
"pretest": "APP_ENV=test node ./test/setup/prepare-test-env.js",
|
"pretest": "APP_ENV=test node ./test/setup/prepare-test-env.js",
|
||||||
"test": "APP_ENV=test vitest run",
|
"test": "APP_ENV=test vitest run",
|
||||||
"test:watch": "APP_ENV=test vitest watch",
|
"test:watch": "APP_ENV=test vitest watch",
|
||||||
|
"test:coverage": "yarn test --coverage",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"db:create": "node ./bin/database/create.js",
|
"db:create": "node ./bin/database/create.js",
|
||||||
"db:seed:user": "node ./bin/database/seed-user.js",
|
"db:seed:user": "node ./bin/database/seed-user.js",
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bull-board/express": "^3.10.1",
|
"@bull-board/express": "^3.10.1",
|
||||||
"@casl/ability": "^6.5.0",
|
"@casl/ability": "^6.5.0",
|
||||||
|
"@faker-js/faker": "^9.2.0",
|
||||||
"@node-saml/passport-saml": "^4.0.4",
|
"@node-saml/passport-saml": "^4.0.4",
|
||||||
"@rudderstack/rudder-sdk-node": "^1.1.2",
|
"@rudderstack/rudder-sdk-node": "^1.1.2",
|
||||||
"@sentry/node": "^7.42.0",
|
"@sentry/node": "^7.42.0",
|
||||||
@@ -36,6 +38,9 @@
|
|||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
"debug": "~2.6.9",
|
"debug": "~2.6.9",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
|
"eslint": "^8.13.0",
|
||||||
|
"eslint-config-prettier": "^8.3.0",
|
||||||
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
"express": "~4.18.2",
|
"express": "~4.18.2",
|
||||||
"express-async-errors": "^3.1.1",
|
"express-async-errors": "^3.1.1",
|
||||||
"express-basic-auth": "^1.2.1",
|
"express-basic-auth": "^1.2.1",
|
||||||
@@ -61,6 +66,7 @@
|
|||||||
"pg": "^8.7.1",
|
"pg": "^8.7.1",
|
||||||
"php-serialize": "^4.0.2",
|
"php-serialize": "^4.0.2",
|
||||||
"pluralize": "^8.0.0",
|
"pluralize": "^8.0.0",
|
||||||
|
"prettier": "^2.5.1",
|
||||||
"raw-body": "^2.5.2",
|
"raw-body": "^2.5.2",
|
||||||
"showdown": "^2.1.0",
|
"showdown": "^2.1.0",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
@@ -92,10 +98,11 @@
|
|||||||
"url": "https://github.com/automatisch/automatisch/issues"
|
"url": "https://github.com/automatisch/automatisch/issues"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@vitest/coverage-v8": "^2.1.5",
|
||||||
"node-gyp": "^10.1.0",
|
"node-gyp": "^10.1.0",
|
||||||
"nodemon": "^2.0.13",
|
"nodemon": "^2.0.13",
|
||||||
"supertest": "^6.3.3",
|
"supertest": "^6.3.3",
|
||||||
"vitest": "^1.1.3"
|
"vitest": "^2.1.5"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
@@ -8,7 +8,7 @@ export default {
|
|||||||
key: 'instanceUrl',
|
key: 'instanceUrl',
|
||||||
label: 'WordPress instance URL',
|
label: 'WordPress instance URL',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
required: false,
|
required: true,
|
||||||
readOnly: false,
|
readOnly: false,
|
||||||
value: null,
|
value: null,
|
||||||
placeholder: null,
|
placeholder: null,
|
||||||
|
@@ -52,7 +52,7 @@ const appConfig = {
|
|||||||
isDev: appEnv === 'development',
|
isDev: appEnv === 'development',
|
||||||
isTest: appEnv === 'test',
|
isTest: appEnv === 'test',
|
||||||
isProd: appEnv === 'production',
|
isProd: appEnv === 'production',
|
||||||
version: '0.13.1',
|
version: '0.14.0',
|
||||||
postgresDatabase: process.env.POSTGRES_DATABASE || 'automatisch_development',
|
postgresDatabase: process.env.POSTGRES_DATABASE || 'automatisch_development',
|
||||||
postgresSchema: process.env.POSTGRES_SCHEMA || 'public',
|
postgresSchema: process.env.POSTGRES_SCHEMA || 'public',
|
||||||
postgresPort: parseInt(process.env.POSTGRES_PORT || '5432'),
|
postgresPort: parseInt(process.env.POSTGRES_PORT || '5432'),
|
||||||
|
@@ -32,7 +32,7 @@ describe('POST /api/v1/access-tokens', () => {
|
|||||||
})
|
})
|
||||||
.expect(422);
|
.expect(422);
|
||||||
|
|
||||||
expect(response.body.errors.general).toEqual([
|
expect(response.body.errors.general).toStrictEqual([
|
||||||
'Incorrect email or password.',
|
'Incorrect email or password.',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
@@ -83,7 +83,7 @@ describe('POST /api/v1/admin/apps/:appKey/auth-clients', () => {
|
|||||||
.send(appAuthClient)
|
.send(appAuthClient)
|
||||||
.expect(422);
|
.expect(422);
|
||||||
|
|
||||||
expect(response.body.meta.type).toEqual('ModelValidation');
|
expect(response.body.meta.type).toStrictEqual('ModelValidation');
|
||||||
expect(response.body.errors).toMatchObject({
|
expect(response.body.errors).toMatchObject({
|
||||||
name: ["must have required property 'name'"],
|
name: ["must have required property 'name'"],
|
||||||
formattedAuthDefaults: [
|
formattedAuthDefaults: [
|
||||||
|
@@ -10,12 +10,11 @@ export default async (request, response) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const appConfigParams = (request) => {
|
const appConfigParams = (request) => {
|
||||||
const { allowCustomConnection, shared, disabled } = request.body;
|
const { useOnlyPredefinedAuthClients, disabled } = request.body;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
key: request.params.appKey,
|
key: request.params.appKey,
|
||||||
allowCustomConnection,
|
useOnlyPredefinedAuthClients,
|
||||||
shared,
|
|
||||||
disabled,
|
disabled,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -23,8 +23,7 @@ describe('POST /api/v1/admin/apps/:appKey/config', () => {
|
|||||||
|
|
||||||
it('should return created app config', async () => {
|
it('should return created app config', async () => {
|
||||||
const appConfig = {
|
const appConfig = {
|
||||||
allowCustomConnection: true,
|
useOnlyPredefinedAuthClients: false,
|
||||||
shared: true,
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -38,14 +37,14 @@ describe('POST /api/v1/admin/apps/:appKey/config', () => {
|
|||||||
...appConfig,
|
...appConfig,
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(response.body).toMatchObject(expectedPayload);
|
expect(response.body).toMatchObject(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return HTTP 422 for already existing app config', async () => {
|
it('should return HTTP 422 for already existing app config', async () => {
|
||||||
const appConfig = {
|
const appConfig = {
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
allowCustomConnection: true,
|
useOnlyPredefinedAuthClients: false,
|
||||||
shared: true,
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -59,7 +58,7 @@ describe('POST /api/v1/admin/apps/:appKey/config', () => {
|
|||||||
})
|
})
|
||||||
.expect(422);
|
.expect(422);
|
||||||
|
|
||||||
expect(response.body.meta.type).toEqual('UniqueViolationError');
|
expect(response.body.meta.type).toStrictEqual('UniqueViolationError');
|
||||||
expect(response.body.errors).toMatchObject({
|
expect(response.body.errors).toMatchObject({
|
||||||
key: ["'key' must be unique."],
|
key: ["'key' must be unique."],
|
||||||
});
|
});
|
||||||
|
@@ -32,7 +32,7 @@ describe('GET /api/v1/admin/apps/:appKey/auth-clients/:appAuthClientId', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getAppAuthClientMock(currentAppAuthClient);
|
const expectedPayload = getAppAuthClientMock(currentAppAuthClient);
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for not existing app auth client ID', async () => {
|
it('should return not found response for not existing app auth client ID', async () => {
|
||||||
|
@@ -39,6 +39,6 @@ describe('GET /api/v1/admin/apps/:appKey/auth-clients', () => {
|
|||||||
appAuthClientOne,
|
appAuthClientOne,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -8,17 +8,19 @@ export default async (request, response) => {
|
|||||||
})
|
})
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
await appConfig.$query().patchAndFetch(appConfigParams(request));
|
await appConfig.$query().patchAndFetch({
|
||||||
|
...appConfigParams(request),
|
||||||
|
key: request.params.appKey,
|
||||||
|
});
|
||||||
|
|
||||||
renderObject(response, appConfig);
|
renderObject(response, appConfig);
|
||||||
};
|
};
|
||||||
|
|
||||||
const appConfigParams = (request) => {
|
const appConfigParams = (request) => {
|
||||||
const { allowCustomConnection, shared, disabled } = request.body;
|
const { useOnlyPredefinedAuthClients, disabled } = request.body;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
allowCustomConnection,
|
useOnlyPredefinedAuthClients,
|
||||||
shared,
|
|
||||||
disabled,
|
disabled,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -24,17 +24,15 @@ describe('PATCH /api/v1/admin/apps/:appKey/config', () => {
|
|||||||
it('should return updated app config', async () => {
|
it('should return updated app config', async () => {
|
||||||
const appConfig = {
|
const appConfig = {
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
allowCustomConnection: true,
|
useOnlyPredefinedAuthClients: true,
|
||||||
shared: true,
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
await createAppConfig(appConfig);
|
await createAppConfig(appConfig);
|
||||||
|
|
||||||
const newAppConfigValues = {
|
const newAppConfigValues = {
|
||||||
shared: false,
|
|
||||||
disabled: true,
|
disabled: true,
|
||||||
allowCustomConnection: false,
|
useOnlyPredefinedAuthClients: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
@@ -53,9 +51,8 @@ describe('PATCH /api/v1/admin/apps/:appKey/config', () => {
|
|||||||
|
|
||||||
it('should return not found response for unexisting app config', async () => {
|
it('should return not found response for unexisting app config', async () => {
|
||||||
const appConfig = {
|
const appConfig = {
|
||||||
shared: false,
|
|
||||||
disabled: true,
|
disabled: true,
|
||||||
allowCustomConnection: false,
|
useOnlyPredefinedAuthClients: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
await request(app)
|
await request(app)
|
||||||
@@ -68,8 +65,7 @@ describe('PATCH /api/v1/admin/apps/:appKey/config', () => {
|
|||||||
it('should return HTTP 422 for invalid app config data', async () => {
|
it('should return HTTP 422 for invalid app config data', async () => {
|
||||||
const appConfig = {
|
const appConfig = {
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
allowCustomConnection: true,
|
useOnlyPredefinedAuthClients: true,
|
||||||
shared: true,
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -83,7 +79,7 @@ describe('PATCH /api/v1/admin/apps/:appKey/config', () => {
|
|||||||
})
|
})
|
||||||
.expect(422);
|
.expect(422);
|
||||||
|
|
||||||
expect(response.body.meta.type).toEqual('ModelValidation');
|
expect(response.body.meta.type).toStrictEqual('ModelValidation');
|
||||||
expect(response.body.errors).toMatchObject({
|
expect(response.body.errors).toMatchObject({
|
||||||
disabled: ['must be boolean'],
|
disabled: ['must be boolean'],
|
||||||
});
|
});
|
||||||
|
@@ -50,8 +50,8 @@ describe('PATCH /api/v1/admin/config', () => {
|
|||||||
.send(newConfigValues)
|
.send(newConfigValues)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.data.title).toEqual(newTitle);
|
expect(response.body.data.title).toStrictEqual(newTitle);
|
||||||
expect(response.body.meta.type).toEqual('Config');
|
expect(response.body.meta.type).toStrictEqual('Config');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return created config for unexisting config', async () => {
|
it('should return created config for unexisting config', async () => {
|
||||||
@@ -67,8 +67,8 @@ describe('PATCH /api/v1/admin/config', () => {
|
|||||||
.send(newConfigValues)
|
.send(newConfigValues)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.data.title).toEqual(newTitle);
|
expect(response.body.data.title).toStrictEqual(newTitle);
|
||||||
expect(response.body.meta.type).toEqual('Config');
|
expect(response.body.meta.type).toStrictEqual('Config');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return null for deleted config entry', async () => {
|
it('should return null for deleted config entry', async () => {
|
||||||
@@ -83,6 +83,6 @@ describe('PATCH /api/v1/admin/config', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.data.title).toBeNull();
|
expect(response.body.data.title).toBeNull();
|
||||||
expect(response.body.meta.type).toEqual('Config');
|
expect(response.body.meta.type).toStrictEqual('Config');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -27,6 +27,6 @@ describe('GET /api/v1/admin/permissions/catalog', () => {
|
|||||||
|
|
||||||
const expectedPayload = await getPermissionsCatalogMock();
|
const expectedPayload = await getPermissionsCatalogMock();
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -58,7 +58,7 @@ describe('POST /api/v1/admin/roles', () => {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return unprocessable entity response for invalid role data', async () => {
|
it('should return unprocessable entity response for invalid role data', async () => {
|
||||||
|
@@ -92,21 +92,4 @@ describe('DELETE /api/v1/admin/roles/:roleId', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not delete role and permissions on unsuccessful response', async () => {
|
|
||||||
const role = await createRole();
|
|
||||||
const permission = await createPermission({ roleId: role.id });
|
|
||||||
await createUser({ roleId: role.id });
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.delete(`/api/v1/admin/roles/${role.id}`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(422);
|
|
||||||
|
|
||||||
const refetchedRole = await role.$query();
|
|
||||||
const refetchedPermission = await permission.$query();
|
|
||||||
|
|
||||||
expect(refetchedRole).toStrictEqual(role);
|
|
||||||
expect(refetchedPermission).toStrictEqual(permission);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
@@ -34,7 +34,7 @@ describe('GET /api/v1/admin/roles/:roleId', () => {
|
|||||||
permissionTwo,
|
permissionTwo,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for not existing role UUID', async () => {
|
it('should return not found response for not existing role UUID', async () => {
|
||||||
|
@@ -28,6 +28,6 @@ describe('GET /api/v1/admin/roles', () => {
|
|||||||
|
|
||||||
const expectedPayload = await getRolesMock([roleOne, roleTwo]);
|
const expectedPayload = await getRolesMock([roleOne, roleTwo]);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -7,7 +7,7 @@ export default async (request, response) => {
|
|||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
const roleMappings = await samlAuthProvider
|
const roleMappings = await samlAuthProvider
|
||||||
.$relatedQuery('samlAuthProvidersRoleMappings')
|
.$relatedQuery('roleMappings')
|
||||||
.orderBy('remote_role_name', 'asc');
|
.orderBy('remote_role_name', 'asc');
|
||||||
|
|
||||||
renderObject(response, roleMappings);
|
renderObject(response, roleMappings);
|
||||||
|
@@ -46,6 +46,6 @@ describe('GET /api/v1/admin/saml-auth-providers/:samlAuthProviderId/role-mapping
|
|||||||
roleMappingTwo,
|
roleMappingTwo,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -30,7 +30,7 @@ describe('GET /api/v1/admin/saml-auth-provider/:samlAuthProviderId', () => {
|
|||||||
|
|
||||||
const expectedPayload = await getSamlAuthProviderMock(samlAuthProvider);
|
const expectedPayload = await getSamlAuthProviderMock(samlAuthProvider);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for not existing saml auth provider UUID', async () => {
|
it('should return not found response for not existing saml auth provider UUID', async () => {
|
||||||
|
@@ -34,6 +34,6 @@ describe('GET /api/v1/admin/saml-auth-providers', () => {
|
|||||||
samlAuthProviderOne,
|
samlAuthProviderOne,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -8,15 +8,14 @@ export default async (request, response) => {
|
|||||||
.findById(samlAuthProviderId)
|
.findById(samlAuthProviderId)
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
const samlAuthProvidersRoleMappings =
|
const roleMappings = await samlAuthProvider.updateRoleMappings(
|
||||||
await samlAuthProvider.updateRoleMappings(
|
roleMappingsParams(request)
|
||||||
samlAuthProvidersRoleMappingsParams(request)
|
);
|
||||||
);
|
|
||||||
|
|
||||||
renderObject(response, samlAuthProvidersRoleMappings);
|
renderObject(response, roleMappings);
|
||||||
};
|
};
|
||||||
|
|
||||||
const samlAuthProvidersRoleMappingsParams = (request) => {
|
const roleMappingsParams = (request) => {
|
||||||
const roleMappings = request.body;
|
const roleMappings = request.body;
|
||||||
|
|
||||||
return roleMappings.map(({ roleId, remoteRoleName }) => ({
|
return roleMappings.map(({ roleId, remoteRoleName }) => ({
|
||||||
|
@@ -6,7 +6,7 @@ import createAuthTokenByUserId from '../../../../../helpers/create-auth-token-by
|
|||||||
import { createRole } from '../../../../../../test/factories/role.js';
|
import { createRole } from '../../../../../../test/factories/role.js';
|
||||||
import { createUser } from '../../../../../../test/factories/user.js';
|
import { createUser } from '../../../../../../test/factories/user.js';
|
||||||
import { createSamlAuthProvider } from '../../../../../../test/factories/saml-auth-provider.ee.js';
|
import { createSamlAuthProvider } from '../../../../../../test/factories/saml-auth-provider.ee.js';
|
||||||
import { createSamlAuthProvidersRoleMapping } from '../../../../../../test/factories/saml-auth-providers-role-mapping.js';
|
import { createRoleMapping } from '../../../../../../test/factories/role-mapping.js';
|
||||||
import createRoleMappingsMock from '../../../../../../test/mocks/rest/api/v1/admin/saml-auth-providers/update-role-mappings.ee.js';
|
import createRoleMappingsMock from '../../../../../../test/mocks/rest/api/v1/admin/saml-auth-providers/update-role-mappings.ee.js';
|
||||||
import * as license from '../../../../../helpers/license.ee.js';
|
import * as license from '../../../../../helpers/license.ee.js';
|
||||||
|
|
||||||
@@ -21,12 +21,12 @@ describe('PATCH /api/v1/admin/saml-auth-providers/:samlAuthProviderId/role-mappi
|
|||||||
|
|
||||||
samlAuthProvider = await createSamlAuthProvider();
|
samlAuthProvider = await createSamlAuthProvider();
|
||||||
|
|
||||||
await createSamlAuthProvidersRoleMapping({
|
await createRoleMapping({
|
||||||
samlAuthProviderId: samlAuthProvider.id,
|
samlAuthProviderId: samlAuthProvider.id,
|
||||||
remoteRoleName: 'Viewer',
|
remoteRoleName: 'Viewer',
|
||||||
});
|
});
|
||||||
|
|
||||||
await createSamlAuthProvidersRoleMapping({
|
await createRoleMapping({
|
||||||
samlAuthProviderId: samlAuthProvider.id,
|
samlAuthProviderId: samlAuthProvider.id,
|
||||||
remoteRoleName: 'Editor',
|
remoteRoleName: 'Editor',
|
||||||
});
|
});
|
||||||
@@ -64,7 +64,7 @@ describe('PATCH /api/v1/admin/saml-auth-providers/:samlAuthProviderId/role-mappi
|
|||||||
|
|
||||||
it('should delete role mappings when given empty role mappings', async () => {
|
it('should delete role mappings when given empty role mappings', async () => {
|
||||||
const existingRoleMappings = await samlAuthProvider.$relatedQuery(
|
const existingRoleMappings = await samlAuthProvider.$relatedQuery(
|
||||||
'samlAuthProvidersRoleMappings'
|
'roleMappings'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(existingRoleMappings.length).toBe(2);
|
expect(existingRoleMappings.length).toBe(2);
|
||||||
@@ -149,34 +149,4 @@ describe('PATCH /api/v1/admin/saml-auth-providers/:samlAuthProviderId/role-mappi
|
|||||||
.send(roleMappings)
|
.send(roleMappings)
|
||||||
.expect(404);
|
.expect(404);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not delete existing role mapping when error thrown', async () => {
|
|
||||||
const roleMappings = [
|
|
||||||
{
|
|
||||||
roleId: userRole.id,
|
|
||||||
remoteRoleName: {
|
|
||||||
invalid: 'data',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const roleMappingsBeforeRequest = await samlAuthProvider.$relatedQuery(
|
|
||||||
'samlAuthProvidersRoleMappings'
|
|
||||||
);
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.patch(
|
|
||||||
`/api/v1/admin/saml-auth-providers/${samlAuthProvider.id}/role-mappings`
|
|
||||||
)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.send(roleMappings)
|
|
||||||
.expect(422);
|
|
||||||
|
|
||||||
const roleMappingsAfterRequest = await samlAuthProvider.$relatedQuery(
|
|
||||||
'samlAuthProvidersRoleMappings'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(roleMappingsBeforeRequest).toStrictEqual(roleMappingsAfterRequest);
|
|
||||||
expect(roleMappingsAfterRequest.length).toBe(2);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
@@ -30,7 +30,7 @@ describe('GET /api/v1/admin/users/:userId', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getUserMock(anotherUser, anotherUserRole);
|
const expectedPayload = getUserMock(anotherUser, anotherUserRole);
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for not existing user UUID', async () => {
|
it('should return not found response for not existing user UUID', async () => {
|
||||||
|
@@ -40,6 +40,6 @@ describe('GET /api/v1/admin/users', () => {
|
|||||||
[anotherUserRole, currentUserRole]
|
[anotherUserRole, currentUserRole]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedResponsePayload);
|
expect(response.body).toStrictEqual(expectedResponsePayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -61,7 +61,8 @@ describe('PATCH /api/v1/admin/users/:userId', () => {
|
|||||||
.send(anotherUserUpdatedData)
|
.send(anotherUserUpdatedData)
|
||||||
.expect(422);
|
.expect(422);
|
||||||
|
|
||||||
expect(response.body.meta.type).toEqual('ModelValidation');
|
expect(response.body.meta.type).toStrictEqual('ModelValidation');
|
||||||
|
|
||||||
expect(response.body.errors).toMatchObject({
|
expect(response.body.errors).toMatchObject({
|
||||||
email: ['must be string'],
|
email: ['must be string'],
|
||||||
fullName: ['must be string'],
|
fullName: ['must be string'],
|
||||||
|
@@ -155,7 +155,7 @@ describe('POST /api/v1/apps/:appKey/connections', () => {
|
|||||||
await createAppConfig({
|
await createAppConfig({
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
allowCustomConnection: true,
|
useOnlyPredefinedAuthClients: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ describe('POST /api/v1/apps/:appKey/connections', () => {
|
|||||||
await createAppConfig({
|
await createAppConfig({
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
allowCustomConnection: false,
|
useOnlyPredefinedAuthClients: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -266,14 +266,14 @@ describe('POST /api/v1/apps/:appKey/connections', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('with auth clients enabled', async () => {
|
describe('with auth client enabled', async () => {
|
||||||
let appAuthClient;
|
let appAuthClient;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await createAppConfig({
|
await createAppConfig({
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
shared: true,
|
useOnlyPredefinedAuthClients: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
appAuthClient = await createAppAuthClient({
|
appAuthClient = await createAppAuthClient({
|
||||||
@@ -310,19 +310,6 @@ describe('POST /api/v1/apps/:appKey/connections', () => {
|
|||||||
expect(response.body).toStrictEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not authorized response for appAuthClientId and formattedData together', async () => {
|
|
||||||
const connectionData = {
|
|
||||||
appAuthClientId: appAuthClient.id,
|
|
||||||
formattedData: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.post('/api/v1/apps/gitlab/connections')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.send(connectionData)
|
|
||||||
.expect(403);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for invalid app key', async () => {
|
it('should return not found response for invalid app key', async () => {
|
||||||
await request(app)
|
await request(app)
|
||||||
.post('/api/v1/apps/invalid-app-key/connections')
|
.post('/api/v1/apps/invalid-app-key/connections')
|
||||||
@@ -349,18 +336,20 @@ describe('POST /api/v1/apps/:appKey/connections', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('with auth clients disabled', async () => {
|
|
||||||
|
describe('with auth client disabled', async () => {
|
||||||
let appAuthClient;
|
let appAuthClient;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await createAppConfig({
|
await createAppConfig({
|
||||||
key: 'gitlab',
|
key: 'gitlab',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
shared: false,
|
useOnlyPredefinedAuthClients: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
appAuthClient = await createAppAuthClient({
|
appAuthClient = await createAppAuthClient({
|
||||||
appKey: 'gitlab',
|
appKey: 'gitlab',
|
||||||
|
active: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -373,7 +362,7 @@ describe('POST /api/v1/apps/:appKey/connections', () => {
|
|||||||
.post('/api/v1/apps/gitlab/connections')
|
.post('/api/v1/apps/gitlab/connections')
|
||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.send(connectionData)
|
.send(connectionData)
|
||||||
.expect(403);
|
.expect(404);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for invalid app key', async () => {
|
it('should return not found response for invalid app key', async () => {
|
||||||
|
@@ -29,7 +29,7 @@ describe('GET /api/v1/apps/:appKey/actions/:actionKey/substeps', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getActionSubstepsMock(exampleAction.substeps);
|
const expectedPayload = getActionSubstepsMock(exampleAction.substeps);
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for invalid app key', async () => {
|
it('should return not found response for invalid app key', async () => {
|
||||||
@@ -47,6 +47,6 @@ describe('GET /api/v1/apps/:appKey/actions/:actionKey/substeps', () => {
|
|||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.data).toEqual([]);
|
expect(response.body.data).toStrictEqual([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -23,7 +23,7 @@ describe('GET /api/v1/apps/:appKey/actions', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getActionsMock(exampleApp.actions);
|
const expectedPayload = getActionsMock(exampleApp.actions);
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for invalid app key', async () => {
|
it('should return not found response for invalid app key', async () => {
|
||||||
|
@@ -23,7 +23,7 @@ describe('GET /api/v1/apps/:appKey', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getAppMock(exampleApp);
|
const expectedPayload = getAppMock(exampleApp);
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for invalid app key', async () => {
|
it('should return not found response for invalid app key', async () => {
|
||||||
|
@@ -22,7 +22,7 @@ describe('GET /api/v1/apps', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getAppsMock(apps);
|
const expectedPayload = getAppsMock(apps);
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return all apps filtered by name', async () => {
|
it('should return all apps filtered by name', async () => {
|
||||||
@@ -34,7 +34,7 @@ describe('GET /api/v1/apps', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getAppsMock(appsWithNameGit);
|
const expectedPayload = getAppsMock(appsWithNameGit);
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return only the apps with triggers', async () => {
|
it('should return only the apps with triggers', async () => {
|
||||||
@@ -46,7 +46,7 @@ describe('GET /api/v1/apps', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getAppsMock(appsWithTriggers);
|
const expectedPayload = getAppsMock(appsWithTriggers);
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return only the apps with actions', async () => {
|
it('should return only the apps with actions', async () => {
|
||||||
@@ -58,6 +58,6 @@ describe('GET /api/v1/apps', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getAppsMock(appsWithActions);
|
const expectedPayload = getAppsMock(appsWithActions);
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -29,7 +29,7 @@ describe('GET /api/v1/apps/:appKey/auth-clients/:appAuthClientId', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getAppAuthClientMock(currentAppAuthClient);
|
const expectedPayload = getAppAuthClientMock(currentAppAuthClient);
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for not existing app auth client ID', async () => {
|
it('should return not found response for not existing app auth client ID', async () => {
|
||||||
|
@@ -37,6 +37,6 @@ describe('GET /api/v1/apps/:appKey/auth-clients', () => {
|
|||||||
appAuthClientOne,
|
appAuthClientOne,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -23,7 +23,7 @@ describe('GET /api/v1/apps/:appKey/auth', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getAuthMock(exampleApp.auth);
|
const expectedPayload = getAuthMock(exampleApp.auth);
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for invalid app key', async () => {
|
it('should return not found response for invalid app key', async () => {
|
||||||
|
@@ -17,8 +17,7 @@ describe('GET /api/v1/apps/:appKey/config', () => {
|
|||||||
|
|
||||||
appConfig = await createAppConfig({
|
appConfig = await createAppConfig({
|
||||||
key: 'deepl',
|
key: 'deepl',
|
||||||
allowCustomConnection: true,
|
useOnlyPredefinedAuthClients: false,
|
||||||
shared: true,
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -32,7 +31,7 @@ describe('GET /api/v1/apps/:appKey/config', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getAppConfigMock(appConfig);
|
const expectedPayload = getAppConfigMock(appConfig);
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for not existing app key', async () => {
|
it('should return not found response for not existing app key', async () => {
|
||||||
|
@@ -47,7 +47,7 @@ describe('GET /api/v1/apps/:appKey/connections', () => {
|
|||||||
currentUserConnectionOne,
|
currentUserConnectionOne,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the connections data of specified app for another user', async () => {
|
it('should return the connections data of specified app for another user', async () => {
|
||||||
@@ -82,19 +82,19 @@ describe('GET /api/v1/apps/:appKey/connections', () => {
|
|||||||
anotherUserConnectionOne,
|
anotherUserConnectionOne,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for invalid connection UUID', async () => {
|
it('should return not found response for invalid connection UUID', async () => {
|
||||||
await createPermission({
|
await createPermission({
|
||||||
action: 'update',
|
action: 'read',
|
||||||
subject: 'Connection',
|
subject: 'Connection',
|
||||||
roleId: currentUserRole.id,
|
roleId: currentUserRole.id,
|
||||||
conditions: ['isCreator'],
|
conditions: ['isCreator'],
|
||||||
});
|
});
|
||||||
|
|
||||||
await request(app)
|
await request(app)
|
||||||
.get('/api/v1/connections/invalid-connection-id/connections')
|
.get('/api/v1/apps/invalid-connection-id/connections')
|
||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.expect(404);
|
.expect(404);
|
||||||
});
|
});
|
||||||
|
@@ -62,7 +62,7 @@ describe('GET /api/v1/apps/:appKey/flows', () => {
|
|||||||
[triggerStepFlowOne, actionStepFlowOne]
|
[triggerStepFlowOne, actionStepFlowOne]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the flows data of specified app for another user', async () => {
|
it('should return the flows data of specified app for another user', async () => {
|
||||||
@@ -110,7 +110,7 @@ describe('GET /api/v1/apps/:appKey/flows', () => {
|
|||||||
[triggerStepFlowOne, actionStepFlowOne]
|
[triggerStepFlowOne, actionStepFlowOne]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for invalid app key', async () => {
|
it('should return not found response for invalid app key', async () => {
|
||||||
|
@@ -29,7 +29,7 @@ describe('GET /api/v1/apps/:appKey/triggers/:triggerKey/substeps', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getTriggerSubstepsMock(exampleTrigger.substeps);
|
const expectedPayload = getTriggerSubstepsMock(exampleTrigger.substeps);
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for invalid app key', async () => {
|
it('should return not found response for invalid app key', async () => {
|
||||||
@@ -47,6 +47,6 @@ describe('GET /api/v1/apps/:appKey/triggers/:triggerKey/substeps', () => {
|
|||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.data).toEqual([]);
|
expect(response.body.data).toStrictEqual([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -23,7 +23,7 @@ describe('GET /api/v1/apps/:appKey/triggers', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getTriggersMock(exampleApp.triggers);
|
const expectedPayload = getTriggersMock(exampleApp.triggers);
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(expectedPayload).toMatchObject(response.body);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for invalid app key', async () => {
|
it('should return not found response for invalid app key', async () => {
|
||||||
|
@@ -20,6 +20,6 @@ describe('GET /api/v1/automatisch/info', () => {
|
|||||||
|
|
||||||
const expectedPayload = infoMock();
|
const expectedPayload = infoMock();
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -18,6 +18,6 @@ describe('GET /api/v1/automatisch/license', () => {
|
|||||||
|
|
||||||
const expectedPayload = licenseMock();
|
const expectedPayload = licenseMock();
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -10,7 +10,7 @@ describe('GET /api/v1/automatisch/version', () => {
|
|||||||
|
|
||||||
const expectedPayload = {
|
const expectedPayload = {
|
||||||
data: {
|
data: {
|
||||||
version: '0.13.1',
|
version: '0.14.0',
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
count: 1,
|
count: 1,
|
||||||
@@ -21,6 +21,6 @@ describe('GET /api/v1/automatisch/version', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -69,7 +69,7 @@ describe('GET /api/v1/connections/:connectionId/flows', () => {
|
|||||||
[triggerStepFlowOne, actionStepFlowOne]
|
[triggerStepFlowOne, actionStepFlowOne]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the flows data of specified connection for another user', async () => {
|
it('should return the flows data of specified connection for another user', async () => {
|
||||||
@@ -123,6 +123,6 @@ describe('GET /api/v1/connections/:connectionId/flows', () => {
|
|||||||
[triggerStepFlowOne, actionStepFlowOne]
|
[triggerStepFlowOne, actionStepFlowOne]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -47,7 +47,6 @@ describe('POST /api/v1/connections/:connectionId/reset', () => {
|
|||||||
|
|
||||||
const expectedPayload = resetConnectionMock({
|
const expectedPayload = resetConnectionMock({
|
||||||
...refetchedCurrentUserConnection,
|
...refetchedCurrentUserConnection,
|
||||||
reconnectable: refetchedCurrentUserConnection.reconnectable,
|
|
||||||
formattedData: {
|
formattedData: {
|
||||||
screenName: 'Connection name',
|
screenName: 'Connection name',
|
||||||
},
|
},
|
||||||
|
@@ -43,7 +43,7 @@ describe('POST /api/v1/connections/:connectionId/test', () => {
|
|||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.data.verified).toEqual(false);
|
expect(response.body.data.verified).toStrictEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update the connection as not verified for another user', async () => {
|
it('should update the connection as not verified for another user', async () => {
|
||||||
@@ -74,7 +74,7 @@ describe('POST /api/v1/connections/:connectionId/test', () => {
|
|||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.data.verified).toEqual(false);
|
expect(response.body.data.verified).toStrictEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for not existing connection UUID', async () => {
|
it('should return not found response for not existing connection UUID', async () => {
|
||||||
|
@@ -8,7 +8,7 @@ export default async (request, response) => {
|
|||||||
})
|
})
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
connection = await connection.update(connectionParams(request));
|
connection = await connection.updateFormattedData(connectionParams(request));
|
||||||
|
|
||||||
renderObject(response, connection);
|
renderObject(response, connection);
|
||||||
};
|
};
|
||||||
|
@@ -55,10 +55,9 @@ describe('PATCH /api/v1/connections/:connectionId', () => {
|
|||||||
|
|
||||||
const refetchedCurrentUserConnection = await currentUserConnection.$query();
|
const refetchedCurrentUserConnection = await currentUserConnection.$query();
|
||||||
|
|
||||||
const expectedPayload = updateConnectionMock({
|
const expectedPayload = updateConnectionMock(
|
||||||
...refetchedCurrentUserConnection,
|
refetchedCurrentUserConnection
|
||||||
reconnectable: refetchedCurrentUserConnection.reconnectable,
|
);
|
||||||
});
|
|
||||||
|
|
||||||
expect(response.body).toStrictEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
@@ -47,7 +47,7 @@ describe('POST /api/v1/connections/:connectionId/verify', () => {
|
|||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.data.verified).toEqual(true);
|
expect(response.body.data.verified).toStrictEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for not existing connection UUID', async () => {
|
it('should return not found response for not existing connection UUID', async () => {
|
||||||
|
@@ -69,7 +69,7 @@ describe('GET /api/v1/executions/:executionId/execution-steps', () => {
|
|||||||
[stepOne, stepTwo]
|
[stepOne, stepTwo]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the execution steps of another user execution', async () => {
|
it('should return the execution steps of another user execution', async () => {
|
||||||
@@ -118,7 +118,7 @@ describe('GET /api/v1/executions/:executionId/execution-steps', () => {
|
|||||||
[stepOne, stepTwo]
|
[stepOne, stepTwo]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for not existing execution step UUID', async () => {
|
it('should return not found response for not existing execution step UUID', async () => {
|
||||||
|
@@ -57,7 +57,7 @@ describe('GET /api/v1/executions/:executionId', () => {
|
|||||||
[stepOne, stepTwo]
|
[stepOne, stepTwo]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the execution data of another user', async () => {
|
it('should return the execution data of another user', async () => {
|
||||||
@@ -99,7 +99,7 @@ describe('GET /api/v1/executions/:executionId', () => {
|
|||||||
[stepOne, stepTwo]
|
[stepOne, stepTwo]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for not existing execution UUID', async () => {
|
it('should return not found response for not existing execution UUID', async () => {
|
||||||
|
@@ -66,7 +66,7 @@ describe('GET /api/v1/executions', () => {
|
|||||||
[stepOne, stepTwo]
|
[stepOne, stepTwo]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the executions of another user', async () => {
|
it('should return the executions of another user', async () => {
|
||||||
@@ -114,6 +114,6 @@ describe('GET /api/v1/executions', () => {
|
|||||||
[stepOne, stepTwo]
|
[stepOne, stepTwo]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
import { renderObject } from '../../../../helpers/renderer.js';
|
||||||
|
|
||||||
export default async (request, response) => {
|
export default async (request, response) => {
|
||||||
let flow = await request.currentUser.$relatedQuery('flows').insert({
|
const flow = await request.currentUser.$relatedQuery('flows').insertAndFetch({
|
||||||
name: 'Name your flow',
|
name: 'Name your flow',
|
||||||
});
|
});
|
||||||
|
|
||||||
flow = await flow.createInitialSteps();
|
await flow.createInitialSteps();
|
||||||
|
|
||||||
renderObject(response, flow, { status: 201 });
|
renderObject(response, flow, { status: 201 });
|
||||||
};
|
};
|
||||||
|
@@ -6,7 +6,7 @@ export default async (request, response) => {
|
|||||||
.findById(request.params.flowId)
|
.findById(request.params.flowId)
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
const createdActionStep = await flow.createActionStep(
|
const createdActionStep = await flow.createStepAfter(
|
||||||
request.body.previousStepId
|
request.body.previousStepId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -41,7 +41,7 @@ describe('GET /api/v1/flows/:flowId', () => {
|
|||||||
actionStep,
|
actionStep,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the flow data of another user', async () => {
|
it('should return the flow data of another user', async () => {
|
||||||
@@ -67,7 +67,7 @@ describe('GET /api/v1/flows/:flowId', () => {
|
|||||||
actionStep,
|
actionStep,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for not existing flow UUID', async () => {
|
it('should return not found response for not existing flow UUID', async () => {
|
||||||
|
@@ -63,7 +63,7 @@ describe('GET /api/v1/flows', () => {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the flows data of another user', async () => {
|
it('should return the flows data of another user', async () => {
|
||||||
@@ -113,6 +113,6 @@ describe('GET /api/v1/flows', () => {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -53,7 +53,7 @@ describe('POST /api/v1/installation/users', () => {
|
|||||||
|
|
||||||
const usersCountAfter = await User.query().resultSize();
|
const usersCountAfter = await User.query().resultSize();
|
||||||
|
|
||||||
expect(usersCountBefore).toEqual(usersCountAfter);
|
expect(usersCountBefore).toStrictEqual(usersCountAfter);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -28,6 +28,6 @@ describe('GET /api/v1/payment/paddle-info', () => {
|
|||||||
|
|
||||||
const expectedResponsePayload = await getPaddleInfoMock();
|
const expectedResponsePayload = await getPaddleInfoMock();
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedResponsePayload);
|
expect(response.body).toStrictEqual(expectedResponsePayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -24,6 +24,6 @@ describe('GET /api/v1/payment/plans', () => {
|
|||||||
|
|
||||||
const expectedResponsePayload = await getPaymentPlansMock();
|
const expectedResponsePayload = await getPaymentPlansMock();
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedResponsePayload);
|
expect(response.body).toStrictEqual(expectedResponsePayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -25,6 +25,6 @@ describe('GET /api/v1/saml-auth-providers', () => {
|
|||||||
samlAuthProviderOne,
|
samlAuthProviderOne,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -78,7 +78,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-data', () => {
|
|||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.data).toEqual(repositories);
|
expect(response.body.data).toStrictEqual(repositories);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('of the another users step', async () => {
|
it('of the another users step', async () => {
|
||||||
@@ -117,7 +117,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-data', () => {
|
|||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.data).toEqual(repositories);
|
expect(response.body.data).toStrictEqual(repositories);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-data', () => {
|
|||||||
})
|
})
|
||||||
.expect(422);
|
.expect(422);
|
||||||
|
|
||||||
expect(response.body.errors).toEqual(errors);
|
expect(response.body.errors).toStrictEqual(errors);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-data', () => {
|
|||||||
const notExistingStepUUID = Crypto.randomUUID();
|
const notExistingStepUUID = Crypto.randomUUID();
|
||||||
|
|
||||||
await request(app)
|
await request(app)
|
||||||
.get(`/api/v1/steps/${notExistingStepUUID}/dynamic-data`)
|
.post(`/api/v1/steps/${notExistingStepUUID}/dynamic-data`)
|
||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.expect(404);
|
.expect(404);
|
||||||
});
|
});
|
||||||
@@ -216,7 +216,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-data', () => {
|
|||||||
const step = await createStep({ appKey: null });
|
const step = await createStep({ appKey: null });
|
||||||
|
|
||||||
await request(app)
|
await request(app)
|
||||||
.get(`/api/v1/steps/${step.id}/dynamic-data`)
|
.post(`/api/v1/steps/${step.id}/dynamic-data`)
|
||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.expect(404);
|
.expect(404);
|
||||||
});
|
});
|
||||||
|
@@ -56,7 +56,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-fields', () => {
|
|||||||
|
|
||||||
const expectedPayload = await createDynamicFieldsMock();
|
const expectedPayload = await createDynamicFieldsMock();
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return dynamically created fields of the another users step', async () => {
|
it('should return dynamically created fields of the another users step', async () => {
|
||||||
@@ -97,7 +97,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-fields', () => {
|
|||||||
|
|
||||||
const expectedPayload = await createDynamicFieldsMock();
|
const expectedPayload = await createDynamicFieldsMock();
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for not existing step UUID', async () => {
|
it('should return not found response for not existing step UUID', async () => {
|
||||||
@@ -118,7 +118,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-fields', () => {
|
|||||||
const notExistingStepUUID = Crypto.randomUUID();
|
const notExistingStepUUID = Crypto.randomUUID();
|
||||||
|
|
||||||
await request(app)
|
await request(app)
|
||||||
.get(`/api/v1/steps/${notExistingStepUUID}/dynamic-fields`)
|
.post(`/api/v1/steps/${notExistingStepUUID}/dynamic-fields`)
|
||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.expect(404);
|
.expect(404);
|
||||||
});
|
});
|
||||||
@@ -138,10 +138,11 @@ describe('POST /api/v1/steps/:stepId/dynamic-fields', () => {
|
|||||||
conditions: [],
|
conditions: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const step = await createStep({ appKey: null });
|
const step = await createStep();
|
||||||
|
await step.$query().patch({ appKey: null });
|
||||||
|
|
||||||
await request(app)
|
await request(app)
|
||||||
.get(`/api/v1/steps/${step.id}/dynamic-fields`)
|
.post(`/api/v1/steps/${step.id}/dynamic-fields`)
|
||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.expect(404);
|
.expect(404);
|
||||||
});
|
});
|
||||||
|
@@ -43,7 +43,7 @@ describe('GET /api/v1/steps/:stepId/connection', () => {
|
|||||||
|
|
||||||
const expectedPayload = await getConnectionMock(currentUserConnection);
|
const expectedPayload = await getConnectionMock(currentUserConnection);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the current user connection data of specified step', async () => {
|
it('should return the current user connection data of specified step', async () => {
|
||||||
@@ -70,7 +70,7 @@ describe('GET /api/v1/steps/:stepId/connection', () => {
|
|||||||
|
|
||||||
const expectedPayload = await getConnectionMock(anotherUserConnection);
|
const expectedPayload = await getConnectionMock(anotherUserConnection);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for not existing step without connection', async () => {
|
it('should return not found response for not existing step without connection', async () => {
|
||||||
|
@@ -70,7 +70,7 @@ describe('GET /api/v1/steps/:stepId/previous-steps', () => {
|
|||||||
[executionStepOne, executionStepTwo]
|
[executionStepOne, executionStepTwo]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the previous steps of the specified step of another user', async () => {
|
it('should return the previous steps of the specified step of another user', async () => {
|
||||||
@@ -124,7 +124,7 @@ describe('GET /api/v1/steps/:stepId/previous-steps', () => {
|
|||||||
[executionStepOne, executionStepTwo]
|
[executionStepOne, executionStepTwo]
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response for not existing step UUID', async () => {
|
it('should return not found response for not existing step UUID', async () => {
|
||||||
|
@@ -79,7 +79,7 @@ describe('GET /api/v1/users/:userId/apps', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getAppsMock();
|
const expectedPayload = getAppsMock();
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return all apps of the another user', async () => {
|
it('should return all apps of the another user', async () => {
|
||||||
@@ -143,7 +143,7 @@ describe('GET /api/v1/users/:userId/apps', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getAppsMock();
|
const expectedPayload = getAppsMock();
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return specified app of the current user', async () => {
|
it('should return specified app of the current user', async () => {
|
||||||
@@ -204,7 +204,7 @@ describe('GET /api/v1/users/:userId/apps', () => {
|
|||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.data.length).toEqual(1);
|
expect(response.body.data.length).toStrictEqual(1);
|
||||||
expect(response.body.data[0].key).toEqual('deepl');
|
expect(response.body.data[0].key).toStrictEqual('deepl');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -39,6 +39,6 @@ describe('GET /api/v1/users/me', () => {
|
|||||||
permissionTwo,
|
permissionTwo,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -29,6 +29,6 @@ describe('GET /api/v1/user/invoices', () => {
|
|||||||
|
|
||||||
const expectedPayload = await getInvoicesMock(invoices);
|
const expectedPayload = await getInvoicesMock(invoices);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -36,7 +36,7 @@ describe('GET /api/v1/users/:userId/plan-and-usage', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(response.body.data).toEqual(expectedResponseData);
|
expect(response.body.data).toStrictEqual(expectedResponseData);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return current plan and usage data', async () => {
|
it('should return current plan and usage data', async () => {
|
||||||
@@ -63,6 +63,6 @@ describe('GET /api/v1/users/:userId/plan-and-usage', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(response.body.data).toEqual(expectedResponseData);
|
expect(response.body.data).toStrictEqual(expectedResponseData);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -33,7 +33,7 @@ describe('GET /api/v1/users/:userId/subscription', () => {
|
|||||||
|
|
||||||
const expectedPayload = getSubscriptionMock(subscription);
|
const expectedPayload = getSubscriptionMock(subscription);
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toStrictEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return not found response if there is no current subscription', async () => {
|
it('should return not found response if there is no current subscription', async () => {
|
||||||
|
@@ -32,7 +32,7 @@ describe('GET /api/v1/users/:userId/trial', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedResponsePayload = await getUserTrialMock(user);
|
const expectedResponsePayload = await getUserTrialMock(user);
|
||||||
expect(response.body).toEqual(expectedResponsePayload);
|
expect(response.body).toStrictEqual(expectedResponsePayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -43,7 +43,7 @@ describe('PATCH /api/v1/users/:userId/password', () => {
|
|||||||
.send(userData)
|
.send(userData)
|
||||||
.expect(422);
|
.expect(422);
|
||||||
|
|
||||||
expect(response.body.meta.type).toEqual('ValidationError');
|
expect(response.body.meta.type).toStrictEqual('ValidationError');
|
||||||
expect(response.body.errors).toMatchObject({
|
expect(response.body.errors).toMatchObject({
|
||||||
currentPassword: ['is incorrect.'],
|
currentPassword: ['is incorrect.'],
|
||||||
});
|
});
|
||||||
|
@@ -47,7 +47,8 @@ describe('PATCH /api/v1/users/:userId', () => {
|
|||||||
.send(userData)
|
.send(userData)
|
||||||
.expect(422);
|
.expect(422);
|
||||||
|
|
||||||
expect(response.body.meta.type).toEqual('ModelValidation');
|
expect(response.body.meta.type).toStrictEqual('ModelValidation');
|
||||||
|
|
||||||
expect(response.body.errors).toMatchObject({
|
expect(response.body.errors).toMatchObject({
|
||||||
email: ['must be string'],
|
email: ['must be string'],
|
||||||
fullName: ['must be string'],
|
fullName: ['must be string'],
|
||||||
|
@@ -0,0 +1,37 @@
|
|||||||
|
export async function up(knex) {
|
||||||
|
await knex.schema.alterTable('app_configs', (table) => {
|
||||||
|
table.boolean('connection_allowed').defaultTo(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
const appConfigs = await knex('app_configs').select('*');
|
||||||
|
|
||||||
|
for (const appConfig of appConfigs) {
|
||||||
|
const appAuthClients = await knex('app_auth_clients').where(
|
||||||
|
'app_key',
|
||||||
|
appConfig.key
|
||||||
|
);
|
||||||
|
|
||||||
|
const hasSomeActiveAppAuthClients = !!appAuthClients?.some(
|
||||||
|
(appAuthClient) => appAuthClient.active
|
||||||
|
);
|
||||||
|
const shared = appConfig.shared;
|
||||||
|
const active = appConfig.disabled === false;
|
||||||
|
|
||||||
|
const connectionAllowedConditions = [
|
||||||
|
hasSomeActiveAppAuthClients,
|
||||||
|
shared,
|
||||||
|
active,
|
||||||
|
];
|
||||||
|
const connectionAllowed = connectionAllowedConditions.every(Boolean);
|
||||||
|
|
||||||
|
await knex('app_configs')
|
||||||
|
.where('id', appConfig.id)
|
||||||
|
.update({ connection_allowed: connectionAllowed });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex) {
|
||||||
|
await knex.schema.alterTable('app_configs', (table) => {
|
||||||
|
table.dropColumn('connection_allowed');
|
||||||
|
});
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
export async function up(knex) {
|
||||||
|
return knex.schema.alterTable('app_configs', (table) => {
|
||||||
|
table.renameColumn('allow_custom_connection', 'custom_connection_allowed');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex) {
|
||||||
|
return knex.schema.alterTable('app_configs', (table) => {
|
||||||
|
table.renameColumn('custom_connection_allowed', 'allow_custom_connection');
|
||||||
|
});
|
||||||
|
}
|
@@ -0,0 +1,13 @@
|
|||||||
|
export async function up(knex) {
|
||||||
|
return knex.schema.alterTable('app_configs', function (table) {
|
||||||
|
table.dropPrimary();
|
||||||
|
table.primary('key');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex) {
|
||||||
|
return knex.schema.alterTable('app_configs', function (table) {
|
||||||
|
table.dropPrimary();
|
||||||
|
table.primary('id');
|
||||||
|
});
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
export async function up(knex) {
|
||||||
|
return knex.schema.alterTable('app_configs', function (table) {
|
||||||
|
table.dropColumn('id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex) {
|
||||||
|
return knex.schema.alterTable('app_configs', function (table) {
|
||||||
|
table.uuid('id').defaultTo(knex.raw('gen_random_uuid()'));
|
||||||
|
});
|
||||||
|
}
|
@@ -0,0 +1,52 @@
|
|||||||
|
export async function up(knex) {
|
||||||
|
await knex.schema.createTable('role_mappings', (table) => {
|
||||||
|
table.uuid('id').primary().defaultTo(knex.raw('gen_random_uuid()'));
|
||||||
|
table
|
||||||
|
.uuid('saml_auth_provider_id')
|
||||||
|
.references('id')
|
||||||
|
.inTable('saml_auth_providers');
|
||||||
|
table.uuid('role_id').references('id').inTable('roles');
|
||||||
|
table.string('remote_role_name').notNullable();
|
||||||
|
|
||||||
|
table.unique(['saml_auth_provider_id', 'remote_role_name']);
|
||||||
|
|
||||||
|
table.timestamps(true, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
const existingRoleMappings = await knex('saml_auth_providers_role_mappings');
|
||||||
|
|
||||||
|
if (existingRoleMappings.length) {
|
||||||
|
await knex('role_mappings').insert(existingRoleMappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await knex.schema.dropTable('saml_auth_providers_role_mappings');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex) {
|
||||||
|
await knex.schema.createTable(
|
||||||
|
'saml_auth_providers_role_mappings',
|
||||||
|
(table) => {
|
||||||
|
table.uuid('id').primary().defaultTo(knex.raw('gen_random_uuid()'));
|
||||||
|
table
|
||||||
|
.uuid('saml_auth_provider_id')
|
||||||
|
.references('id')
|
||||||
|
.inTable('saml_auth_providers');
|
||||||
|
table.uuid('role_id').references('id').inTable('roles');
|
||||||
|
table.string('remote_role_name').notNullable();
|
||||||
|
|
||||||
|
table.unique(['saml_auth_provider_id', 'remote_role_name']);
|
||||||
|
|
||||||
|
table.timestamps(true, true);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const existingRoleMappings = await knex('role_mappings');
|
||||||
|
|
||||||
|
if (existingRoleMappings.length) {
|
||||||
|
await knex('saml_auth_providers_role_mappings').insert(
|
||||||
|
existingRoleMappings
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await knex.schema.dropTable('role_mappings');
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
export async function up(knex) {
|
||||||
|
return await knex.schema.alterTable('app_configs', (table) => {
|
||||||
|
table.boolean('use_only_predefined_auth_clients').defaultTo(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex) {
|
||||||
|
return await knex.schema.alterTable('app_configs', (table) => {
|
||||||
|
table.dropColumn('use_only_predefined_auth_clients');
|
||||||
|
});
|
||||||
|
}
|
@@ -0,0 +1,15 @@
|
|||||||
|
export async function up(knex) {
|
||||||
|
return await knex.schema.alterTable('app_configs', (table) => {
|
||||||
|
table.dropColumn('shared');
|
||||||
|
table.dropColumn('connection_allowed');
|
||||||
|
table.dropColumn('custom_connection_allowed');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex) {
|
||||||
|
return await knex.schema.alterTable('app_configs', (table) => {
|
||||||
|
table.boolean('shared').defaultTo(false);
|
||||||
|
table.boolean('connection_allowed').defaultTo(false);
|
||||||
|
table.boolean('custom_connection_allowed').defaultTo(false);
|
||||||
|
});
|
||||||
|
}
|
@@ -30,7 +30,7 @@ const findOrCreateUserBySamlIdentity = async (
|
|||||||
: [mappedUser.role];
|
: [mappedUser.role];
|
||||||
|
|
||||||
const samlAuthProviderRoleMapping = await samlAuthProvider
|
const samlAuthProviderRoleMapping = await samlAuthProvider
|
||||||
.$relatedQuery('samlAuthProvidersRoleMappings')
|
.$relatedQuery('roleMappings')
|
||||||
.whereIn('remote_role_name', mappedRoles)
|
.whereIn('remote_role_name', mappedRoles)
|
||||||
.limit(1)
|
.limit(1)
|
||||||
.first();
|
.first();
|
||||||
|
46
packages/backend/src/helpers/user-ability.test.js
Normal file
46
packages/backend/src/helpers/user-ability.test.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import userAbility from './user-ability.js';
|
||||||
|
|
||||||
|
describe('userAbility', () => {
|
||||||
|
it('should return PureAbility instantiated with user permissions', () => {
|
||||||
|
const user = {
|
||||||
|
permissions: [
|
||||||
|
{
|
||||||
|
subject: 'Flow',
|
||||||
|
action: 'read',
|
||||||
|
conditions: ['isCreator'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
role: {
|
||||||
|
name: 'User',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const ability = userAbility(user);
|
||||||
|
|
||||||
|
expect(ability.rules).toStrictEqual(user.permissions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return permission-less PureAbility for user with no role', () => {
|
||||||
|
const user = {
|
||||||
|
permissions: [
|
||||||
|
{
|
||||||
|
subject: 'Flow',
|
||||||
|
action: 'read',
|
||||||
|
conditions: ['isCreator'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
role: null,
|
||||||
|
};
|
||||||
|
const ability = userAbility(user);
|
||||||
|
|
||||||
|
expect(ability.rules).toStrictEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return permission-less PureAbility for user with no permissions', () => {
|
||||||
|
const user = { permissions: null, role: { name: 'User' } };
|
||||||
|
const ability = userAbility(user);
|
||||||
|
|
||||||
|
expect(ability.rules).toStrictEqual([]);
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,33 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`AppConfig model > jsonSchema should have correct validations 1`] = `
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"useOnlyPredefinedAuthClients": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"key",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
}
|
||||||
|
`;
|
42
packages/backend/src/models/__snapshots__/flow.test.js.snap
Normal file
42
packages/backend/src/models/__snapshots__/flow.test.js.snap
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`Flow model > jsonSchema should have correct validations 1`] = `
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"active": {
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"deletedAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"publishedAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"remoteWebhookId": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"userId": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
}
|
||||||
|
`;
|
@@ -0,0 +1,42 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`Permission model > jsonSchema should have correct validations 1`] = `
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"action": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"conditions": {
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"roleId": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"roleId",
|
||||||
|
"action",
|
||||||
|
"subject",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
}
|
||||||
|
`;
|
@@ -0,0 +1,30 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`RoleMapping model > jsonSchema should have the correct schema 1`] = `
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"remoteRoleName": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"roleId": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"samlAuthProviderId": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"samlAuthProviderId",
|
||||||
|
"roleId",
|
||||||
|
"remoteRoleName",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
}
|
||||||
|
`;
|
33
packages/backend/src/models/__snapshots__/role.test.js.snap
Normal file
33
packages/backend/src/models/__snapshots__/role.test.js.snap
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`Role model > jsonSchema should have correct validations 1`] = `
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"maxLength": 255,
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
}
|
||||||
|
`;
|
@@ -0,0 +1,72 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`SamlAuthProvider model > jsonSchema should have the correct schema 1`] = `
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"active": {
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
|
"certificate": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"defaultRoleId": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"emailAttributeName": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"entryPoint": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"firstnameAttributeName": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"issuer": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"roleAttributeName": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"signatureAlgorithm": {
|
||||||
|
"enum": [
|
||||||
|
"sha1",
|
||||||
|
"sha256",
|
||||||
|
"sha512",
|
||||||
|
],
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"surnameAttributeName": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"certificate",
|
||||||
|
"signatureAlgorithm",
|
||||||
|
"entryPoint",
|
||||||
|
"issuer",
|
||||||
|
"firstnameAttributeName",
|
||||||
|
"surnameAttributeName",
|
||||||
|
"emailAttributeName",
|
||||||
|
"roleAttributeName",
|
||||||
|
"defaultRoleId",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
}
|
||||||
|
`;
|
@@ -1,6 +1,6 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`SamlAuthProvidersRoleMapping model > jsonSchema should have the correct schema 1`] = `
|
exports[`RoleMapping model > jsonSchema should have the correct schema 1`] = `
|
||||||
{
|
{
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
@@ -28,14 +28,3 @@ exports[`SamlAuthProvidersRoleMapping model > jsonSchema should have the correct
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SamlAuthProvidersRoleMapping model > relationMappings should have samlAuthProvider relation 1`] = `
|
|
||||||
{
|
|
||||||
"join": {
|
|
||||||
"from": "saml_auth_providers_role_mappings.saml_auth_provider_id",
|
|
||||||
"to": "saml_auth_providers.id",
|
|
||||||
},
|
|
||||||
"modelClass": [Function],
|
|
||||||
"relation": [Function],
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
77
packages/backend/src/models/__snapshots__/step.test.js.snap
Normal file
77
packages/backend/src/models/__snapshots__/step.test.js.snap
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`Step model > jsonSchema should have correct validations 1`] = `
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"appKey": {
|
||||||
|
"maxLength": 255,
|
||||||
|
"minLength": 1,
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"connectionId": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"deletedAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"flowId": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"type": "integer",
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"default": "incomplete",
|
||||||
|
"enum": [
|
||||||
|
"incomplete",
|
||||||
|
"completed",
|
||||||
|
],
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"enum": [
|
||||||
|
"action",
|
||||||
|
"trigger",
|
||||||
|
],
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"webhookPath": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
}
|
||||||
|
`;
|
81
packages/backend/src/models/__snapshots__/user.test.js.snap
Normal file
81
packages/backend/src/models/__snapshots__/user.test.js.snap
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`User model > jsonSchema should have correct validations 1`] = `
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"deletedAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"format": "email",
|
||||||
|
"maxLength": 255,
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"fullName": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"invitationToken": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"invitationTokenSentAt": {
|
||||||
|
"format": "date-time",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"minLength": 6,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"resetPasswordToken": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"resetPasswordTokenSentAt": {
|
||||||
|
"format": "date-time",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"roleId": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"default": "active",
|
||||||
|
"enum": [
|
||||||
|
"active",
|
||||||
|
"invited",
|
||||||
|
],
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"trialExpiryDate": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"fullName",
|
||||||
|
"email",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
}
|
||||||
|
`;
|
@@ -2,6 +2,7 @@ import AES from 'crypto-js/aes.js';
|
|||||||
import enc from 'crypto-js/enc-utf8.js';
|
import enc from 'crypto-js/enc-utf8.js';
|
||||||
import appConfig from '../config/app.js';
|
import appConfig from '../config/app.js';
|
||||||
import Base from './base.js';
|
import Base from './base.js';
|
||||||
|
import AppConfig from './app-config.js';
|
||||||
|
|
||||||
class AppAuthClient extends Base {
|
class AppAuthClient extends Base {
|
||||||
static tableName = 'app_auth_clients';
|
static tableName = 'app_auth_clients';
|
||||||
@@ -21,6 +22,17 @@ class AppAuthClient extends Base {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static relationMappings = () => ({
|
||||||
|
appConfig: {
|
||||||
|
relation: Base.BelongsToOneRelation,
|
||||||
|
modelClass: AppConfig,
|
||||||
|
join: {
|
||||||
|
from: 'app_auth_clients.app_key',
|
||||||
|
to: 'app_configs.key',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
encryptData() {
|
encryptData() {
|
||||||
if (!this.eligibleForEncryption()) return;
|
if (!this.eligibleForEncryption()) return;
|
||||||
|
|
||||||
@@ -52,14 +64,24 @@ class AppAuthClient extends Base {
|
|||||||
// beforeInsert and beforeUpdate separately for the same operation.
|
// beforeInsert and beforeUpdate separately for the same operation.
|
||||||
async $beforeInsert(queryContext) {
|
async $beforeInsert(queryContext) {
|
||||||
await super.$beforeInsert(queryContext);
|
await super.$beforeInsert(queryContext);
|
||||||
|
|
||||||
this.encryptData();
|
this.encryptData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async $afterInsert(queryContext) {
|
||||||
|
await super.$afterInsert(queryContext);
|
||||||
|
}
|
||||||
|
|
||||||
async $beforeUpdate(opt, queryContext) {
|
async $beforeUpdate(opt, queryContext) {
|
||||||
await super.$beforeUpdate(opt, queryContext);
|
await super.$beforeUpdate(opt, queryContext);
|
||||||
|
|
||||||
this.encryptData();
|
this.encryptData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async $afterUpdate(opt, queryContext) {
|
||||||
|
await super.$afterUpdate(opt, queryContext);
|
||||||
|
}
|
||||||
|
|
||||||
async $afterFind() {
|
async $afterFind() {
|
||||||
this.decryptData();
|
this.decryptData();
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,9 @@ import { describe, it, expect, vi } from 'vitest';
|
|||||||
import AES from 'crypto-js/aes.js';
|
import AES from 'crypto-js/aes.js';
|
||||||
import enc from 'crypto-js/enc-utf8.js';
|
import enc from 'crypto-js/enc-utf8.js';
|
||||||
|
|
||||||
|
import AppConfig from './app-config.js';
|
||||||
import AppAuthClient from './app-auth-client.js';
|
import AppAuthClient from './app-auth-client.js';
|
||||||
|
import Base from './base.js';
|
||||||
import appConfig from '../config/app.js';
|
import appConfig from '../config/app.js';
|
||||||
import { createAppAuthClient } from '../../test/factories/app-auth-client.js';
|
import { createAppAuthClient } from '../../test/factories/app-auth-client.js';
|
||||||
|
|
||||||
@@ -15,6 +17,23 @@ describe('AppAuthClient model', () => {
|
|||||||
expect(AppAuthClient.jsonSchema).toMatchSnapshot();
|
expect(AppAuthClient.jsonSchema).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('relationMappings should return correct associations', () => {
|
||||||
|
const relationMappings = AppAuthClient.relationMappings();
|
||||||
|
|
||||||
|
const expectedRelations = {
|
||||||
|
appConfig: {
|
||||||
|
relation: Base.BelongsToOneRelation,
|
||||||
|
modelClass: AppConfig,
|
||||||
|
join: {
|
||||||
|
from: 'app_auth_clients.app_key',
|
||||||
|
to: 'app_configs.key',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(relationMappings).toStrictEqual(expectedRelations);
|
||||||
|
});
|
||||||
|
|
||||||
describe('encryptData', () => {
|
describe('encryptData', () => {
|
||||||
it('should return undefined if eligibleForEncryption is not true', async () => {
|
it('should return undefined if eligibleForEncryption is not true', async () => {
|
||||||
vi.spyOn(
|
vi.spyOn(
|
||||||
@@ -49,7 +68,9 @@ describe('AppAuthClient model', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(formattedAuthDefaults).toStrictEqual(expectedDecryptedValue);
|
expect(formattedAuthDefaults).toStrictEqual(expectedDecryptedValue);
|
||||||
expect(appAuthClient.authDefaults).not.toEqual(formattedAuthDefaults);
|
expect(appAuthClient.authDefaults).not.toStrictEqual(
|
||||||
|
formattedAuthDefaults
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should encrypt formattedAuthDefaults and remove formattedAuthDefaults', async () => {
|
it('should encrypt formattedAuthDefaults and remove formattedAuthDefaults', async () => {
|
||||||
@@ -104,7 +125,9 @@ describe('AppAuthClient model', () => {
|
|||||||
expect(appAuthClient.formattedAuthDefaults).toStrictEqual(
|
expect(appAuthClient.formattedAuthDefaults).toStrictEqual(
|
||||||
formattedAuthDefaults
|
formattedAuthDefaults
|
||||||
);
|
);
|
||||||
expect(appAuthClient.authDefaults).not.toEqual(formattedAuthDefaults);
|
expect(appAuthClient.authDefaults).not.toStrictEqual(
|
||||||
|
formattedAuthDefaults
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -5,6 +5,10 @@ import Base from './base.js';
|
|||||||
class AppConfig extends Base {
|
class AppConfig extends Base {
|
||||||
static tableName = 'app_configs';
|
static tableName = 'app_configs';
|
||||||
|
|
||||||
|
static get idColumn() {
|
||||||
|
return 'key';
|
||||||
|
}
|
||||||
|
|
||||||
static jsonSchema = {
|
static jsonSchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
required: ['key'],
|
required: ['key'],
|
||||||
@@ -12,8 +16,7 @@ class AppConfig extends Base {
|
|||||||
properties: {
|
properties: {
|
||||||
id: { type: 'string', format: 'uuid' },
|
id: { type: 'string', format: 'uuid' },
|
||||||
key: { type: 'string' },
|
key: { type: 'string' },
|
||||||
allowCustomConnection: { type: 'boolean', default: false },
|
useOnlyPredefinedAuthClients: { type: 'boolean', default: false },
|
||||||
shared: { type: 'boolean', default: false },
|
|
||||||
disabled: { type: 'boolean', default: false },
|
disabled: { type: 'boolean', default: false },
|
||||||
createdAt: { type: 'string' },
|
createdAt: { type: 'string' },
|
||||||
updatedAt: { type: 'string' },
|
updatedAt: { type: 'string' },
|
||||||
@@ -31,26 +34,6 @@ class AppConfig extends Base {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
static get virtualAttributes() {
|
|
||||||
return ['canConnect', 'canCustomConnect'];
|
|
||||||
}
|
|
||||||
|
|
||||||
get canCustomConnect() {
|
|
||||||
return !this.disabled && this.allowCustomConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
get canConnect() {
|
|
||||||
const hasSomeActiveAppAuthClients = !!this.appAuthClients?.some(
|
|
||||||
(appAuthClient) => appAuthClient.active
|
|
||||||
);
|
|
||||||
const shared = this.shared;
|
|
||||||
const active = this.disabled === false;
|
|
||||||
|
|
||||||
const conditions = [hasSomeActiveAppAuthClients, shared, active];
|
|
||||||
|
|
||||||
return conditions.every(Boolean);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getApp() {
|
async getApp() {
|
||||||
if (!this.key) return null;
|
if (!this.key) return null;
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user