diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
deleted file mode 100644
index 8cf7f1968..000000000
--- a/.github/workflows/codeql-analysis.yml
+++ /dev/null
@@ -1,45 +0,0 @@
-# For most projects, this workflow file will not need changing; you simply need
-# to commit it to your repository.
-#
-# You may wish to alter this file to override the set of languages analyzed,
-# or to provide custom queries or build logic.
-name: "CodeQL"
-
-on:
- workflow_dispatch:
- schedule:
- - cron: "0 5 * * *"
-
-jobs:
- analyze:
- name: Analyze
- runs-on: ubuntu-latest
-
- strategy:
- fail-fast: false
- matrix:
- # Override automatic language detection by changing the below list
- # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
- language: ["javascript"]
- # Learn more...
- # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@v3
-
- # Initializes the CodeQL tools for scanning.
- - name: Initialize CodeQL
- uses: github/codeql-action/init@v2
- with:
- languages: ${{ matrix.language }}
- # If you wish to specify custom queries, you can do so here or in a config file.
- # By default, queries listed here will override any specified in a config file.
- # Prefix the list here with "+" to use these queries and those in the config file.
- # queries: ./path/to/local/query, your-org/your-repo/queries@main
-
- - name: Autobuild
- uses: github/codeql-action/autobuild@v2
-
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml
new file mode 100644
index 000000000..83aba6eb2
--- /dev/null
+++ b/.github/workflows/cypress.yml
@@ -0,0 +1,165 @@
+name: Cypress
+
+on:
+ push:
+ pull_request:
+ workflow_dispatch:
+
+# Cancel previous running jobs on the same branch in case of new pushs
+concurrency:
+ group: cypress-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+
+ strategy:
+ matrix:
+ stage: [lite, full, totp]
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: "3.11"
+ - name: Set up Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: "16.x"
+ - name: Install
+ env:
+ REF_BRANCH: ${{ github.ref }}
+ HEAD_REF_BRANCH: ${{ github.head_ref }}
+
+ run: |
+ python -m pip install --upgrade pip
+ # version is "x.y.0": convert in x.y
+ export CURRENT_VERSION=$(grep '"version"' src/package.json | awk {'print $2'} | tr -d '", ' | awk -F. {'print $1 "." $2'})
+ pip install --upgrade --no-cache-dir git+https://github.com/rapydo/do.git@${CURRENT_VERSION}
+ # auth_services=(postgres neo4j)
+ # AUTH=${auth_services[$(($RANDOM % ${#auth_services[@]}))]}
+ # echo "Selected random authentication service = ${AUTH}"
+ AUTH=neo4j
+ # Make the environment variable available to next steps
+ echo "AUTH=${AUTH}" >> $GITHUB_ENV
+ mkdir rapydo_tests
+ cd rapydo_tests
+ rapydo install compose
+ rapydo --testing create prj --auth ${AUTH} --frontend angular -e ENABLE_ANGULAR_MULTI_LANGUAGE=1 --origin-url https://your_remote_git/your_project.git
+
+ # REF contains the branch when commit, but contains refs/pull/XXX/merge on PRs
+ # with PRs use HEAD_REF
+ # Strip out refs/heads/ prefix
+ if [[ ! -z $HEAD_REF_BRANCH ]];
+ then
+ BRANCH=${HEAD_REF_BRANCH/refs\/heads\//}
+ else
+ BRANCH=${REF_BRANCH/refs\/heads\//}
+ fi
+ # Also strip out tags from the branch
+ BRANCH=${BRANCH/refs\/tags\/v/}
+ echo "Forcing rapydo-angular to branch ${BRANCH}"
+ echo " submodules:" >> projects/prj/project_configuration.yaml
+ echo " rapydo-angular:" >> projects/prj/project_configuration.yaml
+ echo " branch: \"${BRANCH}\"" >> projects/prj/project_configuration.yaml
+
+ # This is to create a commit in the history to fill the BUILD variable
+ git config --global user.email "tests@rapy.do"
+ git config --global user.name "RAPyDo"
+ git add -A && git commit -a -m "Initial commit"
+
+ - name: Setup Cypress
+ uses: rapydo/actions/setup-cypress@v2
+ if: ${{ github.event_name != 'pull_request'}}
+ with:
+ id: ${{ secrets.CYPRESS_PROJECT_ID }}
+ key: ${{ secrets.CYPRESS_RECORD_KEY }}
+
+ - name: Setup Project
+ run: |
+ cd rapydo_tests
+
+ rapydo --testing init
+ rapydo add --force component sink
+
+ rapydo pull --quiet
+
+ if [[ "${{ matrix.stage }}" == "full" ]]; then
+
+ rapydo \
+ -e API_AUTOSTART=1 \
+ -e PROJECT_TITLE="Your ${AUTH} ${{ matrix.stage }} Project" \
+ -e ALLOW_TERMS_OF_USE=1 \
+ -e AUTH_FORCE_FIRST_PASSWORD_CHANGE=1 \
+ -e AUTH_MIN_PASSWORD_LENGTH=10 \
+ -e AUTH_MAX_LOGIN_ATTEMPTS=10 \
+ -e AUTH_MAX_PASSWORD_VALIDITY=120 \
+ -e AUTH_DISABLE_UNUSED_CREDENTIALS_AFTER=60 \
+ start
+
+ elif [[ "${{ matrix.stage }}" == "totp" ]]; then
+
+ rapydo \
+ -e API_AUTOSTART=1 \
+ -e PROJECT_TITLE="Your ${AUTH} ${{ matrix.stage }} Project" \
+ -e ALLOW_TERMS_OF_USE=1 \
+ -e AUTH_FORCE_FIRST_PASSWORD_CHANGE=1 \
+ -e AUTH_MIN_PASSWORD_LENGTH=12 \
+ -e AUTH_MAX_LOGIN_ATTEMPTS=10 \
+ -e AUTH_MAX_PASSWORD_VALIDITY=120 \
+ -e AUTH_DISABLE_UNUSED_CREDENTIALS_AFTER=60 \
+ -e AUTH_SECOND_FACTOR_AUTHENTICATION=1 \
+ -e AUTH_TOTP_VALIDITY_WINDOW=10 \
+ start
+
+ else
+
+ rapydo \
+ -e API_AUTOSTART=1 \
+ -e PROJECT_TITLE="Your ${AUTH} ${{ matrix.stage }} Project" \
+ start
+
+ fi
+
+ sleep 30
+ rapydo logs
+ rapydo shell frontend "yarn install"
+ rapydo shell frontend "yarn workspaces focus --all"
+ rapydo shell frontend "reload-types"
+ rapydo shell frontend "yarn info --recursive --dependents"
+ rapydo logs
+
+ - name: Run Cypress
+ run: |
+ cd rapydo_tests
+
+ if [[ "${{github.actor}}" == "renovate[bot]" ]] || [[ "${{github.event_name}}" == "pull_request" ]]; then
+ rapydo shell frontend "yarn run cypress:start:norecord"
+ else
+ rapydo shell frontend "yarn run cypress:start:${{ matrix.stage }}"
+ fi
+
+ rapydo shell frontend "npx nyc --all report --reporter=lcov --report-dir /coverage"
+
+ - name: Coverage
+ uses: rapydo/actions/coverage@v2
+ with:
+ repository: rapydo_tests/submodules/rapydo-angular
+ cov_file: rapydo_tests/data/prj/karma/lcov.info
+
+ - name: Print backend logs on failure
+ if: ${{ failure() }}
+ run: cat rapydo_tests/data/logs/backend-server.log
+
+ - name: Print mocked email on failure
+ if: ${{ failure() }}
+ run: cat rapydo_tests/data/logs/mock.mail.*.body 2>/dev/null || true
+
+ - name: Docker logs on failure
+ if: failure()
+ run: |
+ cd rapydo_tests
+ rapydo logs
diff --git a/.github/workflows/karma.yml b/.github/workflows/karma.yml
new file mode 100644
index 000000000..4c3493171
--- /dev/null
+++ b/.github/workflows/karma.yml
@@ -0,0 +1,87 @@
+name: Karma
+
+on:
+ push:
+ pull_request:
+ workflow_dispatch:
+
+# Cancel previous running jobs on the same branch in case of new pushs
+concurrency:
+ group: karma-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: "3.11"
+ - name: Set up Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: "16.x"
+ - name: Install
+ env:
+ REF_BRANCH: ${{ github.ref }}
+ HEAD_REF_BRANCH: ${{ github.head_ref }}
+
+ run: |
+ python -m pip install --upgrade pip
+ # version is "x.y.0": convert in x.y
+ export CURRENT_VERSION=$(grep '"version"' src/package.json | awk {'print $2'} | tr -d '", ' | awk -F. {'print $1 "." $2'})
+ pip install --upgrade --no-cache-dir git+https://github.com/rapydo/do.git@${CURRENT_VERSION}
+ mkdir rapydo_tests
+ cd rapydo_tests
+ rapydo install compose
+ rapydo --testing create prj --auth neo4j --frontend angular --origin-url https://your_remote_git/your_project.git
+
+ # REF contains the branch when commit, but contains refs/pull/XXX/merge on PRs
+ # with PRs use HEAD_REF
+ # Strip out refs/heads/ prefix
+ if [[ ! -z $HEAD_REF_BRANCH ]];
+ then
+ BRANCH=${HEAD_REF_BRANCH/refs\/heads\//}
+ else
+ BRANCH=${REF_BRANCH/refs\/heads\//}
+ fi
+ # Also strip out tags from the branch
+ BRANCH=${BRANCH/refs\/tags\/v/}
+ echo "Forcing rapydo-angular to branch ${BRANCH}"
+ echo " submodules:" >> projects/prj/project_configuration.yaml
+ echo " rapydo-angular:" >> projects/prj/project_configuration.yaml
+ echo " branch: \"${BRANCH}\"" >> projects/prj/project_configuration.yaml
+
+ # This is to create a commit in the history to fill the BUILD variable
+ git config --global user.email "tests@rapy.do"
+ git config --global user.name "RAPyDo"
+ git add -A && git commit -a -m "Initial commit"
+
+ - name: Run Karma
+ run: |
+ cd rapydo_tests
+ rapydo --testing init
+ rapydo pull --quiet frontend
+ rapydo start frontend
+ sleep 5
+ rapydo shell frontend "yarn install"
+ rapydo shell frontend "yarn workspaces focus --all"
+ rapydo shell frontend "reload-types"
+ rapydo shell frontend "yarn info --recursive --dependents"
+ rapydo shell frontend "yarn run test:single"
+
+ - name: Coverage
+ uses: rapydo/actions/coverage@v2
+ with:
+ repository: rapydo_tests/submodules/rapydo-angular
+ cov_file: rapydo_tests/data/prj/karma/lcov.info
+
+ - name: Docker logs on failure
+ if: failure()
+ run: |
+ cd rapydo_tests
+ rapydo logs
diff --git a/.github/workflows/ossar-analysis.yml b/.github/workflows/ossar-analysis.yml
deleted file mode 100644
index 37701687b..000000000
--- a/.github/workflows/ossar-analysis.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-# This workflow integrates a collection of open source static analysis tools
-# with GitHub code scanning. For documentation, or to provide feedback, visit
-# https://github.com/github/ossar-action
-name: OSSAR
-
-on:
- workflow_dispatch:
- schedule:
- - cron: "0 5 * * *"
-
-jobs:
- OSSAR-Scan:
- # OSSAR runs on windows-latest.
- # ubuntu-latest and macos-latest support coming soon
- runs-on: windows-latest
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@v3
-
- # Ensure a compatible version of dotnet is installed.
- # The [Microsoft Security Code Analysis CLI](https://aka.ms/mscadocs) is built with dotnet v3.1.201.
- # A version greater than or equal to v3.1.201 of dotnet must be installed on the agent in order to run this action.
- # GitHub hosted runners already have a compatible version of dotnet installed and this step may be skipped.
- # For self-hosted runners, ensure dotnet version 3.1.201 or later is installed by including this action:
- # - name: Install .NET
- # uses: actions/setup-dotnet@v1
- # with:
- # dotnet-version: '3.1.x'
- # Run open source static analysis tools
- - name: Run OSSAR
- uses: github/ossar-action@v1
- id: ossar
-
- # Upload results to the Security tab
- - name: Upload OSSAR results
- uses: github/codeql-action/upload-sarif@v2
- with:
- sarif_file: ${{ steps.ossar.outputs.sarifFile }}
diff --git a/.github/workflows/tests.yml b/.github/workflows/prod.yml
similarity index 66%
rename from .github/workflows/tests.yml
rename to .github/workflows/prod.yml
index c34271672..71b20bf5f 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/prod.yml
@@ -1,4 +1,4 @@
-name: Test
+name: Prod
on:
push:
@@ -7,7 +7,7 @@ on:
# Cancel previous running jobs on the same branch in case of new pushs
concurrency:
- group: tests-${{ github.ref }}
+ group: prod-${{ github.ref }}
cancel-in-progress: true
jobs:
@@ -15,26 +15,14 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 60
- strategy:
- matrix:
- stage:
- [
- karma,
- cypress-lite,
- cypress-full,
- cypress-totp,
- cypress-hiddenlogin,
- prod,
- ]
-
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Set up Node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
node-version: "16.x"
- name: Install
@@ -47,15 +35,10 @@ jobs:
# version is "x.y.0": convert in x.y
export CURRENT_VERSION=$(grep '"version"' src/package.json | awk {'print $2'} | tr -d '", ' | awk -F. {'print $1 "." $2'})
pip install --upgrade --no-cache-dir git+https://github.com/rapydo/do.git@${CURRENT_VERSION}
- auth_services=(postgres neo4j)
- AUTH=${auth_services[$(($RANDOM % ${#auth_services[@]}))]}
- echo "Selected random authentication service = ${AUTH}"
- # Make the environment variable available to next steps
- echo "AUTH=${AUTH}" >> $GITHUB_ENV
mkdir rapydo_tests
cd rapydo_tests
rapydo install compose
- rapydo --testing create prj --auth ${AUTH} --frontend angular --origin-url https://your_remote_git/your_project.git
+ rapydo --testing create prj --auth no --frontend angular --origin-url https://your_remote_git/your_project.git
# REF contains the branch when commit, but contains refs/pull/XXX/merge on PRs
# with PRs use HEAD_REF
@@ -69,116 +52,16 @@ jobs:
# Also strip out tags from the branch
BRANCH=${BRANCH/refs\/tags\/v/}
echo "Forcing rapydo-angular to branch ${BRANCH}"
- sed -i "s|# branch: \"rapydo-angular-branch\"|branch: \"${BRANCH}\"|g" projects/prj/project_configuration.yaml
+ echo " submodules:" >> projects/prj/project_configuration.yaml
+ echo " rapydo-angular:" >> projects/prj/project_configuration.yaml
+ echo " branch: \"${BRANCH}\"" >> projects/prj/project_configuration.yaml
# This is to create a commit in the history to fill the BUILD variable
git config --global user.email "tests@rapy.do"
git config --global user.name "RAPyDo"
git add -A && git commit -a -m "Initial commit"
- - name: Setup Cypress
- uses: rapydo/actions/setup-cypress@v2
- if: ${{ matrix.stage != 'karma' && matrix.stage != 'prod' && github.event_name != 'pull_request'}}
- with:
- id: ${{ secrets.CYPRESS_PROJECT_ID }}
- key: ${{ secrets.CYPRESS_RECORD_KEY }}
-
- - name: Setup Project
- if: ${{ matrix.stage != 'karma' && matrix.stage != 'prod' }}
- run: |
- cd rapydo_tests
-
- rapydo --testing init
- rapydo add --force component sink
-
- rapydo pull --quiet
-
- STAGE="${{ matrix.stage }}"
- LABEL=${STAGE/cypress-/}
-
- if [[ "${LABEL}" == "full" ]]; then
-
- rapydo \
- -e API_AUTOSTART=1 \
- -e PROJECT_TITLE="Your ${AUTH} ${LABEL} Project" \
- -e ALLOW_TERMS_OF_USE=1 \
- -e AUTH_FORCE_FIRST_PASSWORD_CHANGE=1 \
- -e AUTH_MIN_PASSWORD_LENGTH=10 \
- -e AUTH_MAX_LOGIN_ATTEMPTS=10 \
- -e AUTH_MAX_PASSWORD_VALIDITY=120 \
- -e AUTH_DISABLE_UNUSED_CREDENTIALS_AFTER=60 \
- start
-
- elif [[ "${LABEL}" == "totp" ]]; then
-
- rapydo \
- -e API_AUTOSTART=1 \
- -e PROJECT_TITLE="Your ${AUTH} ${LABEL} Project" \
- -e ALLOW_TERMS_OF_USE=1 \
- -e AUTH_FORCE_FIRST_PASSWORD_CHANGE=1 \
- -e AUTH_MIN_PASSWORD_LENGTH=12 \
- -e AUTH_MAX_LOGIN_ATTEMPTS=10 \
- -e AUTH_MAX_PASSWORD_VALIDITY=120 \
- -e AUTH_DISABLE_UNUSED_CREDENTIALS_AFTER=60 \
- -e AUTH_SECOND_FACTOR_AUTHENTICATION=1 \
- -e AUTH_TOTP_VALIDITY_WINDOW=10 \
- start
-
- elif [[ "${LABEL}" == "hiddenlogin" ]]; then
-
- rapydo \
- -e API_AUTOSTART=1 \
- -e PROJECT_TITLE="Your ${AUTH} ${LABEL} Project" \
- -e SHOW_LOGIN=0 \
- start
-
- else
-
- rapydo \
- -e API_AUTOSTART=1 \
- -e PROJECT_TITLE="Your ${AUTH} ${LABEL} Project" \
- start
-
- fi
-
- sleep 30
- rapydo logs
- rapydo shell frontend "yarn install"
- rapydo shell frontend "yarn workspaces focus --all"
- rapydo shell frontend "reload-types"
- rapydo logs
-
- - name: Run Karma
- if: ${{ matrix.stage == 'karma' }}
- run: |
- cd rapydo_tests
- rapydo --testing init
- rapydo pull --quiet frontend
- rapydo start frontend
- sleep 5
- rapydo shell frontend "yarn install"
- rapydo shell frontend "yarn workspaces focus --all"
- rapydo shell frontend "reload-types"
- rapydo shell frontend "yarn run test:single"
-
- - name: Run Cypress
- if: ${{ matrix.stage != 'karma' && matrix.stage != 'prod' }}
- run: |
- cd rapydo_tests
-
- STAGE="${{ matrix.stage }}"
- LABEL=${STAGE/cypress-/}
-
- if [[ "${{github.actor}}" == "dependabot[bot]" ]] || [[ "${{github.event_name}}" == "pull_request" ]]; then
- rapydo shell frontend "yarn run cypress:start:norecord"
- else
- rapydo shell frontend "yarn run cypress:start:${LABEL}"
- fi
-
- rapydo shell frontend "npx nyc --all report --reporter=lcov --report-dir /coverage"
-
- name: Run Production Tests
- if: ${{ matrix.stage == 'prod' }}
run: |
cd rapydo_tests
rapydo --testing --prod init
@@ -308,21 +191,6 @@ jobs:
rapydo logs --tail 6 frontend 2>&1 | grep "files have been compressed."
curl --insecure -X GET https://localhost
- - name: Coverage
- uses: rapydo/actions/coverage@v2
- if: ${{ matrix.stage != 'prod' }}
- with:
- repository: rapydo_tests/submodules/rapydo-angular
- cov_file: rapydo_tests/data/prj/karma/lcov.info
-
- - name: Print backend logs on failure
- if: ${{ failure() && matrix.stage != 'karma' && matrix.stage != 'prod' }}
- run: cat rapydo_tests/data/logs/backend-server.log
-
- - name: Print mocked email on failure
- if: ${{ failure() && matrix.stage != 'karma' && matrix.stage != 'prod' }}
- run: cat rapydo_tests/data/logs/mock.mail.*.body 2>/dev/null || true
-
- name: Docker logs on failure
if: failure()
run: |
diff --git a/.github/workflows/semgrep-analysis.yml b/.github/workflows/semgrep-analysis.yml
deleted file mode 100644
index 63a086254..000000000
--- a/.github/workflows/semgrep-analysis.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-# This workflow file requires a free account on Semgrep.dev to
-# manage rules, file ignores, notifications, and more.
-#
-# See https://semgrep.dev/docs
-
-name: Semgrep
-
-on:
- workflow_dispatch:
- schedule:
- - cron: "0 5 * * *"
-
-jobs:
- semgrep:
- name: Scan
- runs-on: ubuntu-latest
- steps:
- # Checkout project source
- - uses: actions/checkout@v3
-
- # Scan code using project's configuration on https://semgrep.dev/manage
- - uses: returntocorp/semgrep-action@v1
- with:
- publishToken: ${{ secrets.SEMGREP_APP_TOKEN }}
- generateSarif: "1"
-
- # Upload SARIF file generated in previous step
- - name: Upload SARIF file
- uses: github/codeql-action/upload-sarif@v2
- with:
- sarif_file: semgrep.sarif
- if: always()
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
new file mode 100644
index 000000000..e1629823e
--- /dev/null
+++ b/.github/workflows/static-analysis.yml
@@ -0,0 +1,83 @@
+name: "Static Analysis"
+
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: "0 5 * * *"
+
+jobs:
+ codeql:
+ name: CodeQL
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v3
+ with:
+ languages: "javascript"
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v3
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v3
+
+ ossar:
+ name: OSSAR
+ # OSSAR runs on windows-latest.
+ # ubuntu-latest and macos-latest support coming soon
+ runs-on: windows-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ # Ensure a compatible version of dotnet is installed.
+ # The [Microsoft Security Code Analysis CLI](https://aka.ms/mscadocs) is built with dotnet v3.1.201.
+ # A version greater than or equal to v3.1.201 of dotnet must be installed on the agent in order to run this action.
+ # GitHub hosted runners already have a compatible version of dotnet installed and this step may be skipped.
+ # For self-hosted runners, ensure dotnet version 3.1.201 or later is installed by including this action:
+ # - name: Install .NET
+ # uses: actions/setup-dotnet@v1
+ # with:
+ # dotnet-version: '3.1.x'
+ # Run open source static analysis tools
+ - name: Run OSSAR
+ uses: github/ossar-action@v1
+ id: ossar
+
+ # Upload results to the Security tab
+ - name: Upload OSSAR results
+ uses: github/codeql-action/upload-sarif@v3
+ with:
+ sarif_file: ${{ steps.ossar.outputs.sarifFile }}
+
+ semgrep:
+ name: Semgrep
+ runs-on: ubuntu-latest
+ steps:
+ # Checkout project source
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
+ with:
+ python-version: "3.10"
+ - name: Install Semgrep
+ run: python3 -m pip install semgrep
+ - name: Run Semgrep
+ env:
+ SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
+ run: semgrep ci --sarif > semgrep.sarif
+
+ # Upload SARIF file generated in previous step
+ - name: Upload SARIF file
+ uses: github/codeql-action/upload-sarif@v3
+ with:
+ sarif_file: semgrep.sarif
+ if: always()
diff --git a/.gitignore b/.gitignore
index 445bbbc1e..a5108b13c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,6 @@ coverage.xml
# GitGuardian
.cache_ggshield
+
+# Ignore compiled i18n translations
+src/assets/i18n
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index e36d953d1..cd8ecd611 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,11 +1,5 @@
repos:
- repo: https://github.com/pre-commit/mirrors-prettier
- rev: v2.7.1
+ rev: v3.1.0
hooks:
- id: prettier
- - repo: https://github.com/gitguardian/gg-shield
- rev: v1.13.6
- hooks:
- - id: ggshield
- language_version: python3
- stages: [commit]
diff --git a/README.md b/README.md
index 1bb3176d3..3a3736878 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ Based on:
- ngx-uploadx
- file-saver(es)
- ngx-toastr
-- moment + ngx-moment
+- date-fns + ngx-date-fns
- font-awesome
- ngx-clipboard
- angular2-cookie-law
diff --git a/cypress.config.ts b/cypress.config.ts
index c43d24828..6ca1295b6 100644
--- a/cypress.config.ts
+++ b/cypress.config.ts
@@ -4,10 +4,12 @@ export default defineConfig({
e2e: {
baseUrl: "http://localhost:8080",
watchForFileChanges: false,
- specPattern: "/app/cypress/e2e/**/*.ts",
+ specPattern: "/e2e/**/*.ts",
screenshotsFolder: "/cypress",
+ video: true,
videosFolder: "/cypress",
downloadsFolder: "/cypress",
+ supportFile: "/e2e/support/e2e.js",
retries: {
openMode: 0,
runMode: 0,
diff --git a/cypress/e2e/404.spec.ts b/cypress/e2e/404.spec.ts
index fd00a8143..aef928214 100644
--- a/cypress/e2e/404.spec.ts
+++ b/cypress/e2e/404.spec.ts
@@ -13,10 +13,10 @@ describe("404", () => {
cy.get("div.card-header h1").contains("404 - Page not found");
cy.get("div.card-body h2").contains(
- "The page you requested could not be found!"
+ "The page you requested could not be found!",
);
cy.get("div.card-body h4").contains(
- "Please report the error if you reached this page by following a link"
+ "Please report the error if you reached this page by following a link",
);
cy.contains("GO HOME");
diff --git a/cypress/e2e/aaa_init_default_user.spec.ts b/cypress/e2e/aaa_init_default_user.spec.ts
index ad5480c8d..cf6deca3c 100644
--- a/cypress/e2e/aaa_init_default_user.spec.ts
+++ b/cypress/e2e/aaa_init_default_user.spec.ts
@@ -1,7 +1,7 @@
// This is to silence ESLint about undefined cy
/*global cy, Cypress*/
-import { getpassword, get_totp } from "../../fixtures/utilities";
+import { getpassword, get_totp } from "../fixtures/utilities";
describe("Init user", () => {
it("Login via form to change first password / setup TOTP if needed", () => {
@@ -34,7 +34,7 @@ describe("Init user", () => {
.clear()
.type(pwd, { parseSpecialCharSequences: false });
cy.get(
- 'input[placeholder="Type again the new password for confirmation"]'
+ 'input[placeholder="Type again the new password for confirmation"]',
)
.clear()
.type(pwd, { parseSpecialCharSequences: false });
@@ -46,6 +46,9 @@ describe("Init user", () => {
}
cy.get("button:contains('Submit')").click();
+ cy.location().should((location) => {
+ expect(location.pathname).to.not.eq("/app/profile/changepassword");
+ });
}
if (Cypress.env("AUTH_DISABLE_UNUSED_CREDENTIALS_AFTER")) {
diff --git a/cypress/e2e/admin_groups.spec.ts b/cypress/e2e/admin_groups.spec.ts
index b05ff8aaa..1ec52b71a 100644
--- a/cypress/e2e/admin_groups.spec.ts
+++ b/cypress/e2e/admin_groups.spec.ts
@@ -49,20 +49,20 @@ describe("AdminGroups", () => {
cy.get("datatable-body").contains(
"datatable-body-cell",
- "_TestGroup-" + randval
+ "_TestGroup-" + randval,
);
// Test duplications
cy.get('button:contains("new group")').click({ force: true });
cy.get('input[placeholder="Short name"]').type("_TestGroup-" + randval);
cy.get('input[placeholder="Full name"]').type(
- "Long name for test Group " + randval
+ "Long name for test Group " + randval,
);
cy.get("@submit").click({ force: true });
cy.checkalert(
- "A Group already exists with shortname: _TestGroup-" + randval
+ "A Group already exists with shortname: _TestGroup-" + randval,
);
cy.get('button:contains("Close")').click({ force: true });
diff --git a/cypress/e2e/admin_groups_staff.spec.ts b/cypress/e2e/admin_groups_staff.spec.ts
index 607da8ad9..54495781f 100644
--- a/cypress/e2e/admin_groups_staff.spec.ts
+++ b/cypress/e2e/admin_groups_staff.spec.ts
@@ -1,6 +1,6 @@
// This is to silence ESLint about undefined cy
/*global cy, Cypress*/
-import { getpassword, get_random_username } from "../../fixtures/utilities";
+import { getpassword, get_random_username } from "../fixtures/utilities";
/* mostly copied From AdminUsers */
@@ -64,20 +64,20 @@ if (Cypress.env("AUTH_ROLES").includes(",staff_user,")) {
cy.get("datatable-body").contains(
"datatable-body-cell",
- "_TestGroup-" + randval
+ "_TestGroup-" + randval,
);
// Test duplications
cy.get('button:contains("new group")').click({ force: true });
cy.get('input[placeholder="Short name"]').type("_TestGroup-" + randval);
cy.get('input[placeholder="Full name"]').type(
- "Long name for test Group " + randval
+ "Long name for test Group " + randval,
);
cy.get("@submit").click({ force: true });
cy.checkalert(
- "A Group already exists with shortname: _TestGroup-" + randval
+ "A Group already exists with shortname: _TestGroup-" + randval,
);
cy.get('button:contains("Close")').click({ force: true });
diff --git a/cypress/e2e/admin_logins.spec.ts b/cypress/e2e/admin_logins.spec.ts
index 7f1bf9e26..40422dd68 100644
--- a/cypress/e2e/admin_logins.spec.ts
+++ b/cypress/e2e/admin_logins.spec.ts
@@ -1,6 +1,6 @@
// This is to silence ESLint about undefined cy
/*global cy, Cypress*/
-import { getpassword, get_random_username } from "../../fixtures/utilities";
+import { getpassword, get_random_username } from "../fixtures/utilities";
describe("AdminLogins", () => {
const random_username = get_random_username("random");
diff --git a/cypress/e2e/admin_mail.spec.ts b/cypress/e2e/admin_mail.spec.ts
index e32293233..2dbb16a4f 100644
--- a/cypress/e2e/admin_mail.spec.ts
+++ b/cypress/e2e/admin_mail.spec.ts
@@ -26,8 +26,7 @@ describe("AdminMail", () => {
cy.get('input[placeholder="Subject of your email"]')
.clear()
.type("Your subject");
- // It should work because there is only 1 textarea
- cy.get("textarea").clear().type("Your body!");
+ cy.get("textarea").first().clear().type("Your body!");
cy.get('input[placeholder="Destination email address"]')
.clear()
.type("Your email");
@@ -45,7 +44,7 @@ describe("AdminMail", () => {
.click({ force: true });
cy.get("div.modal-header h1.modal-title").contains(
- "Do you want to send the following email?"
+ "Do you want to send the following email?",
);
cy.get("div.modal-body").contains("Subject: Your subject");
cy.get("div.modal-body").contains("To: sample@nomail.org");
@@ -72,7 +71,7 @@ describe("AdminMail", () => {
cy.checkalert("Mail successfully sent");
cy.get("div.card-body").contains(
- "Your email with subject: Your subject has been successfully sent!"
+ "Your email with subject: Your subject has been successfully sent!",
);
cy.get("div.card-body").contains("Destination address: sample@nomail.org");
@@ -84,16 +83,15 @@ describe("AdminMail", () => {
cy.get('input[placeholder="Subject of your email"]')
.clear()
.type("Your subject");
- // It should work because there is only 1 textarea
- cy.get("textarea").clear().type("Your body!");
+ cy.get("textarea").first().clear().type("Your body!");
cy.get('input[placeholder="Destination email address"]')
.clear()
.type("sample@nomail.org");
- cy.get('input[placeholder="CC email addresses (comma-delimited list)"]')
+ cy.get('textarea[placeholder="CC email addresses (comma-delimited list)"]')
.clear()
.type("Your email");
- cy.get('input[placeholder="BCC email addresses (comma-delimited list)"]')
+ cy.get('textarea[placeholder="BCC email addresses (comma-delimited list)"]')
.clear()
.type("Your email");
@@ -102,15 +100,11 @@ describe("AdminMail", () => {
.click({ force: true });
cy.checkalert("Not a valid email address.");
- // Without this wait the click will happen on the same popup...
- // let's wait the first to disappear before clicking on the ther
- cy.wait(300);
- cy.checkalert("Not a valid email address.");
- cy.get('input[placeholder="CC email addresses (comma-delimited list)"]')
+ cy.get('textarea[placeholder="CC email addresses (comma-delimited list)"]')
.clear()
.type("sample1@nomail.org,sample2");
- cy.get('input[placeholder="BCC email addresses (comma-delimited list)"]')
+ cy.get('textarea[placeholder="BCC email addresses (comma-delimited list)"]')
.clear()
.type("sample3@nomail.org,sample4");
@@ -119,15 +113,11 @@ describe("AdminMail", () => {
.click({ force: true });
cy.checkalert("Not a valid email address.");
- // Without this wait the click will happen on the same popup...
- // let's wait the first to disappear before clicking on the ther
- cy.wait(300);
- cy.checkalert("Not a valid email address.");
- cy.get('input[placeholder="CC email addresses (comma-delimited list)"]')
+ cy.get('textarea[placeholder="CC email addresses (comma-delimited list)"]')
.clear()
.type("sample1@nomail.org,sample2@nomail.org");
- cy.get('input[placeholder="BCC email addresses (comma-delimited list)"]')
+ cy.get('textarea[placeholder="BCC email addresses (comma-delimited list)"]')
.clear()
.type("sample3@nomail.org,sample4@nomail.org");
@@ -136,15 +126,15 @@ describe("AdminMail", () => {
.click({ force: true });
cy.get("div.modal-header h1.modal-title").contains(
- "Do you want to send the following email?"
+ "Do you want to send the following email?",
);
cy.get("div.modal-body").contains("Subject: Your subject");
cy.get("div.modal-body").contains("To: sample@nomail.org");
cy.get("div.modal-body").contains(
- "CC: sample1@nomail.org,sample2@nomail.org"
+ "CC: sample1@nomail.org,sample2@nomail.org",
);
cy.get("div.modal-body").contains(
- "BCC: sample3@nomail.org,sample4@nomail.org"
+ "BCC: sample3@nomail.org,sample4@nomail.org",
);
cy.get("ul.nav-tabs li.nav-item a").contains("Plain Body").click();
@@ -169,14 +159,14 @@ describe("AdminMail", () => {
cy.checkalert("Mail successfully sent");
cy.get("div.card-body").contains(
- "Your email with subject: Your subject has been successfully sent!"
+ "Your email with subject: Your subject has been successfully sent!",
);
cy.get("div.card-body").contains("Destination address: sample@nomail.org");
cy.get("div.card-body").contains(
- "CC: sample1@nomail.org,sample2@nomail.org"
+ "CC: sample1@nomail.org,sample2@nomail.org",
);
cy.get("div.card-body").contains(
- "BCC: sample3@nomail.org,sample4@nomail.org"
+ "BCC: sample3@nomail.org,sample4@nomail.org",
);
});
});
diff --git a/cypress/e2e/admin_sessions.spec.ts b/cypress/e2e/admin_sessions.spec.ts
index 9166a8f11..3dae716a8 100644
--- a/cypress/e2e/admin_sessions.spec.ts
+++ b/cypress/e2e/admin_sessions.spec.ts
@@ -83,7 +83,7 @@ describe("AdminSessions", () => {
// cy.checkalert("Token successfully copied");
// Clipboard verification requires an additional plugin...
- }
+ },
);
// This is the same as in profile.sessions.spec
@@ -107,7 +107,7 @@ describe("AdminSessions", () => {
cy.get("button").contains("Yes, delete").click();
cy.checkalert("Confirmation: token successfully deleted");
- }
+ },
);
it("Backend errors", () => {
diff --git a/cypress/e2e/admin_users.spec.ts b/cypress/e2e/admin_users.spec.ts
index 9e09e1712..3353af4b0 100644
--- a/cypress/e2e/admin_users.spec.ts
+++ b/cypress/e2e/admin_users.spec.ts
@@ -2,7 +2,7 @@
/*global cy, Cypress*/
/* mostly copied in StaffUsers */
-import { getpassword, get_random_username } from "../../fixtures/utilities";
+import { getpassword, get_random_username } from "../fixtures/utilities";
describe("AdminUsers", () => {
// do not directly create the random values here,
@@ -57,7 +57,7 @@ describe("AdminUsers", () => {
2,
"Should have at least " +
Cypress.env("AUTH_MIN_PASSWORD_LENGTH") +
- " characters"
+ " characters",
);
cy.contains("random").click({ force: true });
@@ -92,7 +92,7 @@ describe("AdminUsers", () => {
cy.checkalert(
"A User already exists with email: " +
- Cypress.env("AUTH_DEFAULT_USERNAME")
+ Cypress.env("AUTH_DEFAULT_USERNAME"),
);
cy.get("@email").clear().type(username);
@@ -231,6 +231,11 @@ describe("AdminUsers", () => {
cy.get("datatable-body-row").its("length").should("be.gte", 1);
});
+ it("Download users as excel", () => {
+ cy.get("div.card-header div i.fa-download").click();
+ // TODO: to be implemented. See profile.sessions.spec.ts
+ });
+
it("Backend errors", () => {
cy.intercept("DELETE", /\/api\/admin\/users\/*/, {
statusCode: 500,
diff --git a/cypress/e2e/admin_users_staff.spec.ts b/cypress/e2e/admin_users_staff.spec.ts
index 779191182..aeacaaa14 100644
--- a/cypress/e2e/admin_users_staff.spec.ts
+++ b/cypress/e2e/admin_users_staff.spec.ts
@@ -2,7 +2,7 @@
/*global cy, Cypress*/
/* mostly copied From AdminUsers */
-import { getpassword, get_random_username } from "../../fixtures/utilities";
+import { getpassword, get_random_username } from "../fixtures/utilities";
if (Cypress.env("AUTH_ROLES").includes(",staff_user,")) {
describe("StaffUsers", () => {
@@ -67,7 +67,7 @@ if (Cypress.env("AUTH_ROLES").includes(",staff_user,")) {
2,
"Should have at least " +
Cypress.env("AUTH_MIN_PASSWORD_LENGTH") +
- " characters"
+ " characters",
);
cy.get("@password")
diff --git a/cypress/e2e/authorizations.spec.ts b/cypress/e2e/authorizations.spec.ts
index 5439f64c6..d3ad7a536 100644
--- a/cypress/e2e/authorizations.spec.ts
+++ b/cypress/e2e/authorizations.spec.ts
@@ -1,6 +1,6 @@
// This is to silence ESLint about undefined cy
/*global cy, Cypress*/
-import { getpassword, get_random_username } from "../../fixtures/utilities";
+import { getpassword, get_random_username } from "../fixtures/utilities";
describe("Test Authorizations", () => {
it("Test Admin authorizations", () => {
@@ -65,13 +65,11 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/group/users");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
- // cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
// Delete temporary user
- // cy.logout();
cy.login();
cy.deleteuser(email);
});
@@ -120,7 +118,7 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/admin/sessions");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
@@ -129,7 +127,7 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/admin/stats");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
@@ -138,7 +136,7 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/admin/mail");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
@@ -147,13 +145,11 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/group/users");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
- // cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
// Delete temporary user
- // cy.logout();
cy.login();
cy.deleteuser(email);
});
@@ -190,7 +186,7 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/admin/users");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
@@ -199,7 +195,7 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/admin/groups");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
@@ -208,7 +204,7 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/admin/sessions");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
@@ -217,7 +213,7 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/admin/stats");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
@@ -226,7 +222,7 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/admin/mail");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
@@ -238,7 +234,6 @@ describe("Test Authorizations", () => {
////////////////////////////////////////////////////////////////////
// Delete temporary user
- cy.logout();
cy.login();
cy.deleteuser(email);
});
@@ -274,7 +269,7 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/admin/users");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
@@ -283,7 +278,7 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/admin/groups");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
@@ -292,7 +287,7 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/admin/sessions");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
@@ -301,7 +296,7 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/admin/stats");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
@@ -310,7 +305,7 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/admin/mail");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
@@ -319,13 +314,11 @@ describe("Test Authorizations", () => {
expect(location.pathname).to.not.eq("/app/group/users");
});
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
- // cy.login(email, pwd);
////////////////////////////////////////////////////////////////////
// Delete temporary user
- // cy.logout();
cy.login();
cy.deleteuser(email);
});
diff --git a/cypress/e2e/group_users.spec.ts b/cypress/e2e/group_users.spec.ts
index d3cebdace..49080d9c1 100644
--- a/cypress/e2e/group_users.spec.ts
+++ b/cypress/e2e/group_users.spec.ts
@@ -1,6 +1,6 @@
// This is to silence ESLint about undefined cy
/*global cy, Cypress*/
-import { getpassword, get_random_username } from "../../fixtures/utilities";
+import { getpassword, get_random_username } from "../fixtures/utilities";
describe("GroupUsers", () => {
it("Test Group Users", () => {
diff --git a/cypress/e2e/kitchen.sink.spec.ts b/cypress/e2e/kitchen.sink.spec.ts
index de6bc519b..56f5cfae6 100644
--- a/cypress/e2e/kitchen.sink.spec.ts
+++ b/cypress/e2e/kitchen.sink.spec.ts
@@ -49,7 +49,7 @@ describe("KitchenSink", () => {
cy.get("input[ngbdatepicker]").click();
cy.get(
- 'ngb-datepicker-navigation-select select[title="Select year"]'
+ 'ngb-datepicker-navigation-select select[title="Select year"]',
).as("year");
const current_year = new Date().getFullYear();
@@ -81,7 +81,7 @@ describe("KitchenSink", () => {
cy.get("@year").select((current_year + 1).toString());
cy.get(
- 'ngb-datepicker-navigation-select select[title="Select month"]'
+ 'ngb-datepicker-navigation-select select[title="Select month"]',
).select("5");
cy.get("div.ngb-dp-day div").contains("19").click({ force: true });
@@ -104,13 +104,13 @@ describe("KitchenSink", () => {
cy.get("@url").clear().type("www.google.co");
cy.get("formly-validation-message").should(
"not.contain",
- "Invalid web address"
+ "Invalid web address",
);
cy.get("@url").clear().type("wwwgoogle.com");
cy.get("formly-validation-message").should(
"not.contain",
- "Invalid web address"
+ "Invalid web address",
);
// Not allowed in cypress...
@@ -119,13 +119,13 @@ describe("KitchenSink", () => {
cy.get("@url").clear().type("http://www.google.com");
cy.get("formly-validation-message").should(
"not.contain",
- "Invalid web address"
+ "Invalid web address",
);
cy.get("@url").clear().type("https://www.google.com");
cy.get("formly-validation-message").should(
"not.contain",
- "Invalid web address"
+ "Invalid web address",
);
cy.get("@url").clear().type("httpx://www.google.com");
@@ -134,19 +134,19 @@ describe("KitchenSink", () => {
cy.get("@url").clear().type("ftp://www.google.com");
cy.get("formly-validation-message").should(
"not.contain",
- "Invalid web address"
+ "Invalid web address",
);
cy.get("@url").clear().type("user@sample.org");
cy.get("formly-validation-message").should(
"not.contain",
- "Invalid web address"
+ "Invalid web address",
);
cy.get("@url").clear().type("www.google.com");
cy.get("formly-validation-message").should(
"not.contain",
- "Invalid web address"
+ "Invalid web address",
);
cy.get("@text").clear().type("123");
@@ -154,7 +154,7 @@ describe("KitchenSink", () => {
cy.get("@text").clear().type("1234");
cy.get("formly-validation-message").should(
"not.contain",
- "Should have at least 4 characters"
+ "Should have at least 4 characters",
);
cy.get("@text").clear().type("12345678");
// due to max: 6 on field definition
@@ -163,7 +163,7 @@ describe("KitchenSink", () => {
// the input does not permit to include more than specified max
cy.get("formly-validation-message").should(
"not.contain",
- "Should have no more than 6 characters"
+ "Should have no more than 6 characters",
);
cy.get("@number").clear().type("0");
@@ -173,32 +173,32 @@ describe("KitchenSink", () => {
cy.get("@number").clear().type("5");
cy.get("formly-validation-message").should(
"not.contain",
- "Should be greater than 1"
+ "Should be greater than 1",
);
cy.get("formly-validation-message").should(
"not.contain",
- "Should be lower than 9"
+ "Should be lower than 9",
);
cy.get("@number").clear().type("2.5");
cy.get("formly-validation-message").should(
"not.contain",
- "Should be greater than 1"
+ "Should be greater than 1",
);
cy.get("formly-validation-message").should(
"not.contain",
- "Should be lower than 9"
+ "Should be lower than 9",
);
// 30e-1 == 3
cy.get("@number").clear().type("30e-1");
cy.get("formly-validation-message").should(
"not.contain",
- "Should be greater than 1"
+ "Should be greater than 1",
);
cy.get("formly-validation-message").should(
"not.contain",
- "Should be lower than 9"
+ "Should be lower than 9",
);
// Let's remove the validation error introduced to ease check of missing errors
@@ -335,7 +335,7 @@ describe("KitchenSink", () => {
cy.get("@date").click();
cy.get(
- 'ngb-datepicker-navigation-select select[title="Select year"]'
+ 'ngb-datepicker-navigation-select select[title="Select year"]',
).as("year");
const current_year = new Date().getFullYear();
@@ -345,7 +345,7 @@ describe("KitchenSink", () => {
cy.get("@year").select((current_year + 1).toString());
cy.get(
- 'ngb-datepicker-navigation-select select[title="Select month"]'
+ 'ngb-datepicker-navigation-select select[title="Select month"]',
).select("5");
cy.get("div.ngb-dp-day div").contains("19").click({ force: true });
diff --git a/cypress/e2e/login.ban.spec.ts b/cypress/e2e/login.ban.spec.ts
index 8703a8a37..7498d8e4f 100644
--- a/cypress/e2e/login.ban.spec.ts
+++ b/cypress/e2e/login.ban.spec.ts
@@ -5,7 +5,7 @@ import {
getpassword,
get_random_username,
get_totp,
-} from "../../fixtures/utilities";
+} from "../fixtures/utilities";
describe("Login Ban", () => {
if (Cypress.env("AUTH_MAX_LOGIN_ATTEMPTS") > 0) {
@@ -19,10 +19,10 @@ describe("Login Ban", () => {
cy.get("div.card-header h1").contains("Invalid unlock token");
cy.get("div.card-body p").contains(
- "The received token is not valid, if you copied the URL please verify that you copied all parts of it."
+ "The received token is not valid, if you copied the URL please verify that you copied all parts of it.",
);
cy.get("div.card-body p").contains(
- "If the URL is correct the token could be invalid because your credentials are already unlocked."
+ "If the URL is correct the token could be invalid because your credentials are already unlocked.",
);
cy.get("div.card-body p").contains("To verify that you can try to");
@@ -60,14 +60,14 @@ describe("Login Ban", () => {
.type(pwd, { parseSpecialCharSequences: false });
cy.get("button").contains("Login").click();
cy.checkalert(
- "Sorry, this account is temporarily blocked due to the number of failed login attempts."
+ "Sorry, this account is temporarily blocked due to the number of failed login attempts.",
);
cy.visit("/public/reset");
cy.get("input[id=formly_1_input_reset_email_0]").clear().type(email);
cy.get("button:contains('Submit request')").click();
cy.checkalert(
- "Sorry, this account is temporarily blocked due to the number of failed login attempts."
+ "Sorry, this account is temporarily blocked due to the number of failed login attempts.",
);
cy.getmail().then((body) => {
@@ -86,7 +86,6 @@ describe("Login Ban", () => {
cy.login(email, pwd);
cy.goto_profile();
- cy.logout();
});
cy.login();
@@ -102,7 +101,7 @@ describe("Login Ban", () => {
// 10 is the default used by backend (services/authentication) in testing mode
const max_failures = Math.max(
Cypress.env("AUTH_MAX_LOGIN_ATTEMPTS"),
- 10
+ 10,
);
cy.visit("/app/login");
@@ -131,14 +130,14 @@ describe("Login Ban", () => {
.type(get_totp());
cy.get("button").contains("Authorize").click();
cy.checkalert(
- "Sorry, this account is temporarily blocked due to the number of failed login attempts."
+ "Sorry, this account is temporarily blocked due to the number of failed login attempts.",
);
cy.visit("/public/reset");
cy.get("input[id=formly_1_input_reset_email_0]").clear().type(email);
cy.get("button:contains('Submit request')").click();
cy.checkalert(
- "Sorry, this account is temporarily blocked due to the number of failed login attempts."
+ "Sorry, this account is temporarily blocked due to the number of failed login attempts.",
);
cy.getmail().then((body) => {
@@ -157,7 +156,6 @@ describe("Login Ban", () => {
cy.login(email, pwd);
cy.goto_profile();
- cy.logout();
});
cy.login();
diff --git a/cypress/e2e/login.expired.spec.ts b/cypress/e2e/login.expired.spec.ts
index 2e490135a..4c5ad3c6c 100644
--- a/cypress/e2e/login.expired.spec.ts
+++ b/cypress/e2e/login.expired.spec.ts
@@ -1,7 +1,7 @@
// This is to silence ESLint about undefined cy
/*global cy, Cypress*/
-import { getpassword, get_random_username } from "../../fixtures/utilities";
+import { getpassword, get_random_username } from "../fixtures/utilities";
describe("AccountExpired", () => {
it("LOGIN EXPIRED", () => {
@@ -31,7 +31,7 @@ describe("AccountExpired", () => {
cy.intercept("POST", "/auth/reset").as("reset");
cy.get(
- 'input[placeholder="Type here your email address to receive the reset link"]'
+ 'input[placeholder="Type here your email address to receive the reset link"]',
)
.clear()
.type(email);
@@ -64,15 +64,15 @@ describe("AccountExpired", () => {
.click({ force: true });
// Open the datepicker
cy.get(
- 'input[placeholder="This user will be blocked after this date"]'
+ 'input[placeholder="This user will be blocked after this date"]',
).click();
// Select the 31 - 12 - 2050 (the max allowed)
cy.get(
- 'ngb-datepicker-navigation-select select[title="Select year"]'
+ 'ngb-datepicker-navigation-select select[title="Select year"]',
).select("2050");
cy.get(
- 'ngb-datepicker-navigation-select select[title="Select month"]'
+ 'ngb-datepicker-navigation-select select[title="Select month"]',
).select("12");
cy.get("div.ngb-dp-day div").contains("31").click({ force: true });
cy.get('button:contains("Submit")').click({ force: true });
diff --git a/cypress/e2e/login.failed.spec.ts b/cypress/e2e/login.failed.spec.ts
index dce45042e..7ed99015f 100644
--- a/cypress/e2e/login.failed.spec.ts
+++ b/cypress/e2e/login.failed.spec.ts
@@ -72,7 +72,7 @@ describe("FailedLogin", () => {
cy.wait("@login1");
cy.checkalert(
- "Unable to login due to a server error. If this error persists please contact system administrators"
+ "Unable to login due to a server error. If this error persists please contact system administrators",
);
cy.intercept("POST", "/auth/login", {
diff --git a/cypress/e2e/login.mocked.spec.ts b/cypress/e2e/login.mocked.spec.ts
index 29139ec3d..9a0f19def 100644
--- a/cypress/e2e/login.mocked.spec.ts
+++ b/cypress/e2e/login.mocked.spec.ts
@@ -1,7 +1,7 @@
// This is to silence ESLint about undefined cy
/*global cy, Cypress*/
-import { getpassword } from "../../fixtures/utilities";
+import { getpassword } from "../fixtures/utilities";
describe("Mocked login", () => {
beforeEach(() => {
@@ -9,10 +9,10 @@ describe("Mocked login", () => {
cy.closecookielaw();
cy.get("input[placeholder='Your username (email)']").type(
- Cypress.env("AUTH_DEFAULT_USERNAME")
+ Cypress.env("AUTH_DEFAULT_USERNAME"),
);
cy.get("input[placeholder='Your password']").type(
- Cypress.env("AUTH_DEFAULT_PASSWORD")
+ Cypress.env("AUTH_DEFAULT_PASSWORD"),
);
});
diff --git a/cypress/e2e/login.password.expired.spec.ts b/cypress/e2e/login.password.expired.spec.ts
index bb144bffa..ca711e8ae 100644
--- a/cypress/e2e/login.password.expired.spec.ts
+++ b/cypress/e2e/login.password.expired.spec.ts
@@ -5,7 +5,7 @@ import {
getpassword,
get_random_username,
get_totp,
-} from "../../fixtures/utilities";
+} from "../fixtures/utilities";
describe("Login", () => {
// do not directly create the random values here,
@@ -27,49 +27,35 @@ describe("Login", () => {
cy.get("input[placeholder='Your username (email)']").as("user");
cy.get("input[placeholder='Your password']").as("pwd");
- // Cypress is still not able to undo an intercept..
- // A single intercept is needed here,
- // then the test should continue with normal responses
- // TO BE REMOVED:
- cy.server();
- cy.route({
- method: "POST",
- url: "/auth/login",
- status: 403,
- response: {
- actions: ["PASSWORD EXPIRED"],
- errors: ["Your password is expired, please change it"],
+ cy.intercept(
+ // routeMatcher
+ {
+ path: "/auth/login",
+ method: "POST",
+ times: 1,
},
- });
-
- // TO BE REPLACED WITH:
- // cy.intercept("POST", "/auth/login", {
- // statusCode: 403,
- // body: {
- // actions: ["PASSWORD EXPIRED"],
- // errors: ["Your password is expired, please change it"],
- // },
- // }).as("login");
+ // staticResponse
+ {
+ statusCode: 403,
+ body: {
+ actions: ["PASSWORD EXPIRED"],
+ errors: ["Your password is expired, please change it"],
+ },
+ },
+ ).as("login");
cy.get("@user").type(email);
cy.get("@pwd").type(pwd, { parseSpecialCharSequences: false });
cy.get("button").contains("Login").click();
- // TO BE ADDED
- // cy.wait("@login");
+ cy.wait("@login");
cy.location().should((location) => {
expect(location.pathname).to.eq("/app/login");
});
- // TO BE REMOVED:
- cy.server({ enable: false });
-
- // TO BE REPLACED WITH SOMETHING TO UNDO THE PREVIOUS INTERCEPT
- // cy.intercept("POST", "/auth/login");
-
cy.checkalert("Your password is expired, please change it");
cy.get("div.card-header h1").contains(
- "Your password is expired, please change it"
+ "Your password is expired, please change it",
);
cy.get("button").contains("Change").click();
@@ -84,7 +70,7 @@ describe("Login", () => {
0,
"Should have at least " +
Cypress.env("AUTH_MIN_PASSWORD_LENGTH") +
- " characters"
+ " characters",
);
cy.get("button").contains("Change").click();
@@ -183,8 +169,6 @@ describe("Login", () => {
} else {
cy.get("button").contains("Change").click();
}
-
- cy.logout();
});
after(() => {
diff --git a/cypress/e2e/login.spec.ts b/cypress/e2e/login.spec.ts
index 8241fc3b4..e7556195f 100644
--- a/cypress/e2e/login.spec.ts
+++ b/cypress/e2e/login.spec.ts
@@ -4,7 +4,7 @@ import {
getpassword,
get_random_username,
get_totp,
-} from "../../fixtures/utilities";
+} from "../fixtures/utilities";
describe("SuccessfulLogin", () => {
// do not directly create the random values here,
@@ -84,7 +84,7 @@ describe("SuccessfulLogin", () => {
cy.get("a").find(".fa-user");
cy.get("table").find("td").contains(email);
- cy.logout();
+ cy.logout(false);
// After the logout you are automatically redirected to the default page...
// more in generale not on the profile page
diff --git a/cypress/e2e/login.totp.spec.ts b/cypress/e2e/login.totp.spec.ts
index 748bdc15f..dc9ef61ca 100644
--- a/cypress/e2e/login.totp.spec.ts
+++ b/cypress/e2e/login.totp.spec.ts
@@ -5,7 +5,7 @@ import {
getpassword,
get_random_username,
get_totp,
-} from "../../fixtures/utilities";
+} from "../fixtures/utilities";
if (Cypress.env("AUTH_SECOND_FACTOR_AUTHENTICATION")) {
describe("Login with TOTP", () => {
@@ -38,10 +38,10 @@ if (Cypress.env("AUTH_SECOND_FACTOR_AUTHENTICATION")) {
cy.checkalert("You do not provided a valid verification code");
cy.get("div.card-header h1").contains(
- "Configure Two-Factor with Google Authenticator"
+ "Configure Two-Factor with Google Authenticator",
);
cy.get("div.card-header.bg-warning h1").contains(
- "Please change your temporary password"
+ "Please change your temporary password",
);
cy.checkalert("Please change your temporary password");
@@ -98,7 +98,7 @@ if (Cypress.env("AUTH_SECOND_FACTOR_AUTHENTICATION")) {
if (Cypress.env("ALLOW_TERMS_OF_USE")) {
cy.get("div.modal-footer h1").contains(
- "Do you accept our Terms of Use?"
+ "Do you accept our Terms of Use?",
);
cy.get("div.modal-footer button").first().contains("YES").click();
}
@@ -107,8 +107,6 @@ if (Cypress.env("AUTH_SECOND_FACTOR_AUTHENTICATION")) {
cy.goto_profile();
cy.get("table").find("td").contains(email);
-
- cy.logout();
});
it("TOTP - login", () => {
@@ -127,7 +125,7 @@ if (Cypress.env("AUTH_SECOND_FACTOR_AUTHENTICATION")) {
cy.get("input[placeholder='Your password']").should("not.exist");
cy.get("div.card-header.bg-warning h1").contains(
- "Provide the verification code"
+ "Provide the verification code",
);
// Authorization code is missing
@@ -209,7 +207,7 @@ if (Cypress.env("AUTH_SECOND_FACTOR_AUTHENTICATION")) {
.clear()
.type(pwd + "!");
cy.get(
- 'input[placeholder="Type again the new password for confirmation"]'
+ 'input[placeholder="Type again the new password for confirmation"]',
)
.clear()
.type(pwd + "!");
@@ -274,7 +272,7 @@ if (Cypress.env("AUTH_SECOND_FACTOR_AUTHENTICATION")) {
cy.wait("@login");
cy.get("div.card-header.bg-warning h1").contains(
- "Provide the verification code"
+ "Provide the verification code",
);
cy.get("input[placeholder='TOTP verification code']")
.clear()
@@ -288,8 +286,6 @@ if (Cypress.env("AUTH_SECOND_FACTOR_AUTHENTICATION")) {
});
after(() => {
- cy.logout();
-
cy.login();
cy.deleteuser(email);
});
diff --git a/cypress/e2e/profile.change.password.spec.ts b/cypress/e2e/profile.change.password.spec.ts
index 0c08dbd93..4dc5cf939 100644
--- a/cypress/e2e/profile.change.password.spec.ts
+++ b/cypress/e2e/profile.change.password.spec.ts
@@ -5,7 +5,7 @@ import {
getpassword,
get_random_username,
get_totp,
-} from "../../fixtures/utilities";
+} from "../fixtures/utilities";
describe("ChangePassword", () => {
// do not directly create the random values here,
@@ -53,10 +53,10 @@ describe("ChangePassword", () => {
cy.checkvalidation(0, "This field is required");
cy.get('input[placeholder="Type the desidered new password"]').as(
- "new_password"
+ "new_password",
);
cy.get(
- 'input[placeholder="Type again the new password for confirmation"]'
+ 'input[placeholder="Type again the new password for confirmation"]',
).as("confirm_password");
cy.get("@new_password").clear().type("short");
@@ -77,7 +77,7 @@ describe("ChangePassword", () => {
0,
"Should have at least " +
Cypress.env("AUTH_MIN_PASSWORD_LENGTH") +
- " characters"
+ " characters",
);
let newPassword = getpassword(1);
@@ -190,8 +190,6 @@ describe("ChangePassword", () => {
});
after(() => {
- cy.logout();
-
cy.login();
cy.deleteuser(email);
});
diff --git a/cypress/e2e/profile.change.temporary.password.spec.ts b/cypress/e2e/profile.change.temporary.password.spec.ts
index 37109b327..4e9a6fbf6 100644
--- a/cypress/e2e/profile.change.temporary.password.spec.ts
+++ b/cypress/e2e/profile.change.temporary.password.spec.ts
@@ -5,7 +5,7 @@ import {
getpassword,
get_random_username,
get_totp,
-} from "../../fixtures/utilities";
+} from "../fixtures/utilities";
if (Cypress.env("AUTH_FORCE_FIRST_PASSWORD_CHANGE") === 1) {
describe("ChangeTemporaryPassword", () => {
@@ -36,17 +36,17 @@ if (Cypress.env("AUTH_FORCE_FIRST_PASSWORD_CHANGE") === 1) {
cy.get("button").contains("Authorize").as("submit");
cy.get("div.card-header h1").contains(
- "Configure Two-Factor with Google Authenticator"
+ "Configure Two-Factor with Google Authenticator",
);
cy.get("div.card-header.bg-warning h1").contains(
- "Please change your temporary password"
+ "Please change your temporary password",
);
cy.checkalert("You do not provided a valid verification code");
cy.get("input[placeholder='TOTP verification code']").type(get_totp());
} else {
cy.get("div.card-header.bg-warning h1").contains(
- "Please change your temporary password"
+ "Please change your temporary password",
);
cy.get('button:contains("Change")').as("submit");
@@ -65,7 +65,7 @@ if (Cypress.env("AUTH_FORCE_FIRST_PASSWORD_CHANGE") === 1) {
0,
"Should have at least " +
Cypress.env("AUTH_MIN_PASSWORD_LENGTH") +
- " characters"
+ " characters",
);
let newPassword = getpassword(1);
@@ -124,7 +124,7 @@ if (Cypress.env("AUTH_FORCE_FIRST_PASSWORD_CHANGE") === 1) {
if (Cypress.env("ALLOW_TERMS_OF_USE")) {
cy.get("div.modal-footer h1").contains(
- "Do you accept our Terms of Use?"
+ "Do you accept our Terms of Use?",
);
cy.get("div.modal-footer button").first().contains("YES").click();
}
@@ -132,8 +132,6 @@ if (Cypress.env("AUTH_FORCE_FIRST_PASSWORD_CHANGE") === 1) {
cy.goto_profile();
cy.get("table").find("td").contains(email);
- cy.logout();
-
cy.login(email, pwd + "!new!");
cy.goto_profile();
@@ -141,8 +139,6 @@ if (Cypress.env("AUTH_FORCE_FIRST_PASSWORD_CHANGE") === 1) {
});
after(() => {
- cy.logout();
-
cy.login();
cy.deleteuser(email);
});
diff --git a/cypress/e2e/registration.spec.ts b/cypress/e2e/registration.spec.ts
index cd8a117f6..df5102cc3 100644
--- a/cypress/e2e/registration.spec.ts
+++ b/cypress/e2e/registration.spec.ts
@@ -5,7 +5,7 @@ import {
getpassword,
get_random_username,
get_totp,
-} from "../../fixtures/utilities";
+} from "../fixtures/utilities";
describe("Registration", () => {
if (!Cypress.env("ALLOW_REGISTRATION")) {
@@ -79,10 +79,10 @@ describe("Registration", () => {
cy.get('input[placeholder="Type here your surname"]').as("surname");
cy.get('input[placeholder="Type here your email address"]').as("email");
cy.get('input[placeholder="Type here the desidered password"]').as(
- "password"
+ "password",
);
cy.get(
- 'input[placeholder="Type again the desidered password for confirmation"]'
+ 'input[placeholder="Type again the desidered password for confirmation"]',
).as("confirmation");
cy.get('button:contains("Register")').as("submit");
@@ -109,7 +109,7 @@ describe("Registration", () => {
1,
"Should have at least " +
Cypress.env("AUTH_MIN_PASSWORD_LENGTH") +
- " characters"
+ " characters",
);
cy.get("@password")
@@ -177,7 +177,7 @@ describe("Registration", () => {
cy.get("@submit").click({ force: true });
cy.checkalert(
- "This user already exists: " + Cypress.env("AUTH_DEFAULT_USERNAME")
+ "This user already exists: " + Cypress.env("AUTH_DEFAULT_USERNAME"),
);
// Failures on password validation: missing upper case letters
@@ -238,7 +238,7 @@ describe("Registration", () => {
cy.get("div.card-header h1").contains("Account registered");
cy.contains(
- "User successfully registered. You will receive an email to confirm your registraton and activate your account"
+ "User successfully registered. You will receive an email to confirm your registraton and activate your account",
);
});
@@ -259,14 +259,14 @@ describe("Registration", () => {
cy.wait("@login");
cy.get("div.card-header.bg-warning h1").contains(
- "This account is not active"
+ "This account is not active",
);
cy.get("div.card-body").contains("Didn't receive an activation link?");
cy.get("a").contains("Click here to send again").click({ force: true });
cy.checkalert(
- "We are sending an email to your email address where you will find the link to activate your account"
+ "We are sending an email to your email address where you will find the link to activate your account",
);
cy.location().should((location) => {
@@ -284,7 +284,7 @@ describe("Registration", () => {
cy.get("div.card-header h1").contains("Invalid activation token");
cy.get("div.card-body").contains(
- "This activation token is not valid and your request cannot be satisfied."
+ "This activation token is not valid and your request cannot be satisfied.",
);
cy.getmail().then((body) => {
@@ -303,7 +303,7 @@ describe("Registration", () => {
cy.get("div.card-header h1").contains("Invalid activation token");
cy.get("div.card-body").contains(
- "This activation token is not valid and your request cannot be satisfied."
+ "This activation token is not valid and your request cannot be satisfied.",
);
});
});
@@ -324,21 +324,21 @@ describe("Registration", () => {
if (Cypress.env("AUTH_SECOND_FACTOR_AUTHENTICATION")) {
cy.get("div.card-header h1").contains(
- "Configure Two-Factor with Google Authenticator"
+ "Configure Two-Factor with Google Authenticator",
);
cy.get("input[placeholder='Your new password']").type(
- newPassword + "!"
+ newPassword + "!",
);
cy.get("input[placeholder='Confirm your new password']").type(
- newPassword + "!"
+ newPassword + "!",
);
cy.get("input[placeholder='TOTP verification code']").type(get_totp());
cy.get("button").contains("Authorize").click();
} else if (Cypress.env("AUTH_FORCE_FIRST_PASSWORD_CHANGE") === 1) {
cy.get("div.card-header.bg-warning h1").contains(
- "Please change your temporary password"
+ "Please change your temporary password",
);
cy.checkalert("Please change your temporary password");
@@ -359,16 +359,14 @@ describe("Registration", () => {
cy.visit("/app/admin/users");
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
cy.visit("/app/admin/sessions");
cy.checkalert(
- "Permission denied: you are not authorized to access this page"
+ "Permission denied: you are not authorized to access this page",
);
-
- cy.logout();
});
after(() => {
diff --git a/cypress/e2e/reset.password.spec.ts b/cypress/e2e/reset.password.spec.ts
index ceee1dc5f..463074eaa 100644
--- a/cypress/e2e/reset.password.spec.ts
+++ b/cypress/e2e/reset.password.spec.ts
@@ -5,7 +5,7 @@ import {
getpassword,
get_random_username,
get_totp,
-} from "../../fixtures/utilities";
+} from "../fixtures/utilities";
if (Cypress.env("ALLOW_PASSWORD_RESET")) {
describe("ResetPassword", () => {
@@ -37,7 +37,7 @@ if (Cypress.env("ALLOW_PASSWORD_RESET")) {
cy.checkvalidation(0, "This field is required");
cy.get(
- 'input[placeholder="Type here your email address to receive the reset link"]'
+ 'input[placeholder="Type here your email address to receive the reset link"]',
).as("email");
cy.get("@email").clear().type("invalid");
@@ -48,7 +48,7 @@ if (Cypress.env("ALLOW_PASSWORD_RESET")) {
cy.get("button:contains('Submit request')").click();
cy.checkalert(
- "Sorry, invalid@sample.com is not recognized as a valid username"
+ "Sorry, invalid@sample.com is not recognized as a valid username",
);
cy.intercept("POST", "/auth/reset").as("reset");
@@ -60,11 +60,11 @@ if (Cypress.env("ALLOW_PASSWORD_RESET")) {
cy.get("div.card-header h1").contains("Reset your password");
cy.get("div.card-body").contains(
- "We'll send instructions to the email provided if it's associated with an account. Please check your spam/junk folder."
+ "We'll send instructions to the email provided if it's associated with an account. Please check your spam/junk folder.",
);
cy.intercept("PUT", "/auth/reset/token-received-by-email").as(
- "validate1"
+ "validate1",
);
cy.visit("/public/reset/token-received-by-email");
@@ -88,10 +88,10 @@ if (Cypress.env("ALLOW_PASSWORD_RESET")) {
cy.checkvalidation(1, "This field is required");
cy.get('input[placeholder="Type here your new password"]').as(
- "new_password"
+ "new_password",
);
cy.get(
- 'input[placeholder="Type again your new password for confirmation"]'
+ 'input[placeholder="Type again your new password for confirmation"]',
).as("confirm_password");
cy.get("@new_password").clear().type("short");
@@ -101,7 +101,7 @@ if (Cypress.env("ALLOW_PASSWORD_RESET")) {
0,
"Should have at least " +
Cypress.env("AUTH_MIN_PASSWORD_LENGTH") +
- " characters"
+ " characters",
);
cy.checkvalidation(1, "This field is required");
@@ -152,7 +152,7 @@ if (Cypress.env("ALLOW_PASSWORD_RESET")) {
cy.get("@confirm_password").clear().type(newPassword);
cy.get("button:contains('Submit')").click();
cy.checkalert(
- "Password successfully changed. Please login with your new password"
+ "Password successfully changed. Please login with your new password",
);
cy.location().should((location) => {
@@ -179,7 +179,7 @@ if (Cypress.env("ALLOW_PASSWORD_RESET")) {
if (Cypress.env("AUTH_SECOND_FACTOR_AUTHENTICATION")) {
cy.get("input[placeholder='Your password']").should("not.exist");
cy.get("div.card-header h1").contains(
- "Provide the verification code"
+ "Provide the verification code",
);
cy.get("input[placeholder='TOTP verification code']")
.clear()
@@ -193,8 +193,6 @@ if (Cypress.env("ALLOW_PASSWORD_RESET")) {
});
after(() => {
- cy.logout();
-
cy.login();
cy.deleteuser(email);
});
diff --git a/cypress/e2e/responsive.spec.ts b/cypress/e2e/responsive.spec.ts
index c738453c9..04ba582c5 100644
--- a/cypress/e2e/responsive.spec.ts
+++ b/cypress/e2e/responsive.spec.ts
@@ -1,7 +1,7 @@
// This is to silence ESLint about undefined cy
/*global cy, Cypress*/
-import { get_totp } from "../../fixtures/utilities";
+import { get_totp } from "../fixtures/utilities";
describe("Responsive tests", () => {
let expected_collapsed_navbar = false;
@@ -78,8 +78,5 @@ describe("Responsive tests", () => {
});
cy.get("div.card-header h1").contains("Your profile");
-
- // Logout Confirmation modal is not opened on Cypress when navbar is collapsed...
- // cy.logout(expected_collapsed_navbar);
});
});
diff --git a/cypress/e2e/terms.of.use.acceptance.spec.ts b/cypress/e2e/terms.of.use.acceptance.spec.ts
index 4d0c97f24..774f2557f 100644
--- a/cypress/e2e/terms.of.use.acceptance.spec.ts
+++ b/cypress/e2e/terms.of.use.acceptance.spec.ts
@@ -5,7 +5,7 @@ import {
getpassword,
get_random_username,
get_totp,
-} from "../../fixtures/utilities";
+} from "../fixtures/utilities";
if (Cypress.env("ALLOW_TERMS_OF_USE")) {
describe("Terms of use", () => {
@@ -37,7 +37,7 @@ if (Cypress.env("ALLOW_TERMS_OF_USE")) {
cy.checkalert("You do not provided a valid verification code");
cy.get("div.card-header h1").contains(
- "Configure Two-Factor with Google Authenticator"
+ "Configure Two-Factor with Google Authenticator",
);
pwd = pwd + "!";
@@ -59,7 +59,7 @@ if (Cypress.env("ALLOW_TERMS_OF_USE")) {
cy.wait("@login");
} else if (Cypress.env("AUTH_FORCE_FIRST_PASSWORD_CHANGE") === 1) {
cy.get("div.card-header.bg-warning h1").contains(
- "Please change your temporary password"
+ "Please change your temporary password",
);
cy.checkalert("Please change your temporary password");
@@ -83,7 +83,7 @@ if (Cypress.env("ALLOW_TERMS_OF_USE")) {
cy.get("div.modal-footer button").last().contains("NO").click();
cy.checkalert(
- "We apologize but you are not allowed to login, as you have not accepted our Terms of Use"
+ "We apologize but you are not allowed to login, as you have not accepted our Terms of Use",
);
});
@@ -154,8 +154,6 @@ if (Cypress.env("ALLOW_TERMS_OF_USE")) {
});
after(() => {
- cy.logout();
-
cy.login();
cy.visit("/app/admin/users");
diff --git a/cypress/e2e/zzz_inactivity_ban.spec.ts b/cypress/e2e/zzz_inactivity_ban.spec.ts
index c11c2e948..5a2382734 100644
--- a/cypress/e2e/zzz_inactivity_ban.spec.ts
+++ b/cypress/e2e/zzz_inactivity_ban.spec.ts
@@ -1,7 +1,7 @@
// This is to silence ESLint about undefined cy
/*global cy, Cypress*/
-import { getpassword, get_totp } from "../../fixtures/utilities";
+import { getpassword, get_totp } from "../fixtures/utilities";
if (Cypress.env("AUTH_DISABLE_UNUSED_CREDENTIALS_AFTER")) {
describe("Test inactivity ban", () => {
diff --git a/cypress/fixtures/utilities.ts b/cypress/fixtures/utilities.ts
index d61efc1b1..408473ae9 100644
--- a/cypress/fixtures/utilities.ts
+++ b/cypress/fixtures/utilities.ts
@@ -1,7 +1,53 @@
// This is to silence ESLint about undefined Cypress
/*global cy, Cypress*/
-import * as generator from "generate-password-browser";
+function generatePassword(
+ length: number,
+ useUppercase: boolean,
+ useNumbers: boolean,
+ useSymbols: boolean,
+): string {
+ const lowercase = "abcdefghijklmnopqrstuvwxyz";
+ const uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ const numbers = "0123456789";
+ const symbols = "!@#$%^&*()-_=+[]{}|;:',.<>/?";
+
+ let password = [];
+
+ let charset = lowercase;
+ password.push(lowercase.charAt(Math.floor(Math.random() * lowercase.length)));
+
+ if (useUppercase) {
+ charset += uppercase;
+ password.push(
+ uppercase.charAt(Math.floor(Math.random() * uppercase.length)),
+ );
+ }
+ if (useNumbers) {
+ charset += numbers;
+ password.push(numbers.charAt(Math.floor(Math.random() * numbers.length)));
+ }
+ if (useSymbols) {
+ charset += symbols;
+ password.push(symbols.charAt(Math.floor(Math.random() * symbols.length)));
+ }
+
+ if (charset === "") {
+ throw new Error("At least one character type should be selected");
+ }
+
+ for (let i = password.length, n = charset.length; i < length; ++i) {
+ password.push(charset.charAt(Math.floor(Math.random() * n)));
+ }
+
+ // Shuffle the password array
+ for (let i = password.length - 1; i > 0; i--) {
+ const j = Math.floor(Math.random() * (i + 1));
+ [password[i], password[j]] = [password[j], password[i]]; // Swap
+ }
+
+ return password.join("");
+}
// type can be:
// 1 = only lower case letters
@@ -13,30 +59,11 @@ export function getpassword(type, len = 0) {
len = Cypress.env("AUTH_MIN_PASSWORD_LENGTH");
}
- const password = generator.generate({
- length: len,
- lowercase: true,
- uppercase: type >= 2,
- numbers: type >= 3,
- symbols: type >= 4,
- excludeSimilarCharacters: false,
- strict: true,
- });
-
- return password;
+ return generatePassword(len, type >= 2, type >= 3, type >= 4);
}
export function get_random_username(prefix: string) {
- const randval = generator.generate({
- length: 16,
- lowercase: true,
- uppercase: false,
- numbers: false,
- symbols: false,
- excludeSimilarCharacters: false,
- strict: false,
- });
-
+ const randval = generatePassword(16, false, false, false);
return `${prefix}_${randval}@sample.org`;
}
diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js
index 36349e9c7..39c194363 100644
--- a/cypress/support/e2e.js
+++ b/cypress/support/e2e.js
@@ -91,7 +91,7 @@ Cypress.Commands.add("change_expired_password", (email, pwd, formtype) => {
cy.get("input[placeholder='Your password']").should("not.exist");
cy.get("div.card-header.bg-warning h1").contains(
- "Provide the verification code"
+ "Provide the verification code",
);
cy.get("input[placeholder='TOTP verification code']")
.clear()
@@ -193,7 +193,7 @@ Cypress.Commands.add("login_and_init_user", (email = null, pwd = null) => {
if (Cypress.env("AUTH_SECOND_FACTOR_AUTHENTICATION")) {
cy.get("div.card-header h1").contains(
- "Configure Two-Factor with Google Authenticator"
+ "Configure Two-Factor with Google Authenticator",
);
cy.checkalert("Please change your temporary password");
@@ -215,7 +215,7 @@ Cypress.Commands.add("login_and_init_user", (email = null, pwd = null) => {
cy.wait(200);
} else if (Cypress.env("AUTH_FORCE_FIRST_PASSWORD_CHANGE") === 1) {
cy.get("div.card-header.bg-warning h1").contains(
- "Please change your temporary password"
+ "Please change your temporary password",
);
cy.checkalert("Please change your temporary password");
@@ -239,32 +239,22 @@ Cypress.Commands.add("login_and_init_user", (email = null, pwd = null) => {
cy.wait(300);
});
-Cypress.Commands.add("logout", (collapsed = false) => {
- if (collapsed) {
- cy.get("button.navbar-toggler").click();
-
- // cy.get("a").find(".fa-right-from-bracket").parent().click({ force: true });
- // cy.get("div.modal-footer")
- // .find("button")
- // .contains("Confirm")
- // .click({ force: true });
-
- cy.get("i.fa-right-from-bracket").parent().click();
- cy.scrollTo("top");
+// With Angular 15 I'm experiencing issues with the logout modal
+// that often does not trigger the modal opening when clicked
+// Warning: at the moment all logouts have via_modal false !!
+Cypress.Commands.add("logout", (via_modal = true) => {
+ if (via_modal) {
+ cy.get("button[id=logout-icon]").click({ force: true });
cy.get("button").contains("Confirm").click();
} else {
- cy.get("i.fa-right-from-bracket").parent().click();
- cy.get("button").contains("Confirm").click();
+ // access to login page triggers tokens invalidation
+ cy.visit("/app/login");
}
});
// Replaces cy.visit("/app/profile") to introduces automatic waits on DOM elements
// instead of requiring waits on the http call
-Cypress.Commands.add("goto_profile", (collapsed = false) => {
- if (collapsed) {
- cy.get("button.navbar-toggler").click();
- }
-
+Cypress.Commands.add("goto_profile", () => {
// Why this wait?
// Cypress does not offer a way to automatically wait for all pending XHR requests and
// often some requests e.g. GET /auth/status, are still under the hook when this click
@@ -299,7 +289,9 @@ Cypress.Commands.add("closecookielaw", (quiet = false) => {
});
Cypress.Commands.add("checkalert", (msg) => {
- cy.get("div[role=alert]").contains(msg).click({ force: true });
+ cy.get("div[role=alert]")
+ .contains(msg)
+ .click({ force: true, multiple: true });
});
Cypress.Commands.add("checkvalidation", (index, msg) => {
@@ -374,14 +366,14 @@ Cypress.Commands.add(
if (expired) {
cy.get(
- 'input[placeholder="This user will be blocked after this date"]'
+ 'input[placeholder="This user will be blocked after this date"]',
).click();
cy.get(
- 'ngb-datepicker-navigation-select select[title="Select year"]'
+ 'ngb-datepicker-navigation-select select[title="Select year"]',
).select("2020");
cy.get(
- 'ngb-datepicker-navigation-select select[title="Select month"]'
+ 'ngb-datepicker-navigation-select select[title="Select month"]',
).select("12");
cy.get("div.ngb-dp-day div").contains("31").click({ force: true });
@@ -410,7 +402,7 @@ Cypress.Commands.add(
cy.checkalert("Confirmation: user successfully created");
- cy.logout();
+ cy.logout(false);
if (init_user) {
cy.visit("/app/login");
@@ -445,7 +437,7 @@ Cypress.Commands.add(
cy.get("input[placeholder='Your password']").should("not.exist");
cy.get("div.card-header h1").contains(
- "Configure Two-Factor with Google Authenticator"
+ "Configure Two-Factor with Google Authenticator",
);
cy.checkalert("Please change your temporary password");
@@ -467,7 +459,7 @@ Cypress.Commands.add(
} else if (Cypress.env("AUTH_FORCE_FIRST_PASSWORD_CHANGE") === 1) {
cy.get("input[placeholder='Your password']").should("not.exist");
cy.get("div.card-header.bg-warning h1").contains(
- "Please change your temporary password"
+ "Please change your temporary password",
);
cy.checkalert("Please change your temporary password");
@@ -486,15 +478,15 @@ Cypress.Commands.add(
if (Cypress.env("ALLOW_TERMS_OF_USE")) {
cy.get("div.modal-footer h1").contains(
- "Do you accept our Terms of Use?"
+ "Do you accept our Terms of Use?",
);
cy.get("div.modal-footer button").first().contains("YES").click();
cy.wait(300);
}
- cy.logout();
+ cy.logout(false);
}
- }
+ },
);
Cypress.Commands.add("deleteuser", (email) => {
diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json
index 7dae11ed4..c5cdd1e10 100644
--- a/cypress/tsconfig.json
+++ b/cypress/tsconfig.json
@@ -2,8 +2,8 @@
"compilerOptions": {
"strict": true,
"baseUrl": "/app/node_modules/",
- "target": "es5",
- "lib": ["es5", "dom"],
+ "target": "es6",
+ "lib": ["es6", "dom"],
"types": ["cypress"]
},
"include": ["**/*.ts"]
diff --git a/polyfills.ts b/polyfills.ts
index e04a31f80..1a81f733f 100644
--- a/polyfills.ts
+++ b/polyfills.ts
@@ -1,94 +1,13 @@
/**
- * This file includes polyfills needed by Angular and is loaded before the app.
- * You can add your own extra polyfills to this file.
- *
- * This file is divided into 2 sections:
- * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
- * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
- * file.
- *
- * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
- * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
- * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
- *
- * Learn more in https://angular.io/guide/browser-support
+ * Angular 9 introduced a global $localize() function that needs to be loaded.
+ * Please add import '@angular/localize'; to your polyfills.ts file.
*/
-/***************************************************************************************************
- * BROWSER POLYFILLS
- */
-
-// Old Safari and IE
-import "core-js/stable";
-
-/** Evergreen browsers require these. **/
-// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
-import "core-js/proposals/reflect-metadata";
-
-/** IE10 and IE11 requires the following for NgClass support on SVG elements */
-import "angular-polyfills/dist/classlist.js";
-
-/**
- * Web Animations `@angular/platform-browser/animations`
- * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
- * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
- **/
-// import 'web-animations-js';
+import "@angular/localize/init";
/**
- * By default, zone.js will patch all possible macroTask and DomEvents
- * user can disable parts of macroTask/DomEvents patch by setting following flags
- * because those flags need to be set before `zone.js` being loaded, and webpack
- * will put import in the top of bundle, so user need to create a separate file
- * in this directory (for example: zone-flags.ts), and put the following flags
- * into that file, and then add the following code before importing zone.js.
- * import './zone-flags.ts';
- *
- * The flags allowed in zone-flags.ts are listed here.
- *
- * The following flags will work for all browsers.
- *
- * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
- * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
- * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
- *
- * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
- * with the following flag, it will bypass `zone.js` patch for IE/Edge
- *
- * (window as any).__Zone_enable_cross_context_check = true;
- *
+ * To reference and create an instance of the Buffer.
+ * This requires to install the buffer package.
*/
-
-/***************************************************************************************************
-
-/** Zone JS is required by default for Angular itself. */
-import "zone.js/dist/zone";
-import "zone.js/dist/long-stack-trace-zone";
-
-/** APPLICATION IMPORTS */
-
-// import 'angular-polyfills/dist/all.js';
-import "angular-polyfills/dist/typedarray.js";
-import "angular-polyfills/dist/blob.js";
-import "angular-polyfills/dist/formdata.js";
-import "angular-polyfills/dist/intl.js";
-import "angular-polyfills/dist/shim.js";
-// This fails to import with error (on version 1.0.1):
-// TypeError: Cannot set property 'true' of undefined
-// import 'angular-polyfills/dist/webanimations.js';
-
-/* istanbul ignore next */
-// if (typeof (window as any).global === "undefined") {
-// (window as any).global = window;
-// }
-
-// Angular 9 introduced a global $localize() function that needs to be loaded.
-// Please add import '@angular/localize'; to your polyfills.ts file.
-import "@angular/localize/init";
-
-// required by exceljs (no longer used)
-// import "regenerator-runtime/runtime";
-
-/* To reference and create an instance of the Buffer. This requires to install the buffer package. */
(window as any).global = window;
declare var global: any;
declare var require: any;
diff --git a/renovate.json b/renovate.json
index f0fe12609..ca75084bd 100644
--- a/renovate.json
+++ b/renovate.json
@@ -4,6 +4,7 @@
"commitMessageAction": "Bump",
"commitMessageTopic": "{{depName}}",
"commitMessageExtra": "to {{newVersion}}",
+ "branchConcurrentLimit": 0,
"pre-commit": {
"enabled": true,
"groupName": "pre-commit"
diff --git a/src/angular.json b/src/angular.json
index 3537e51f4..2b222c4f5 100644
--- a/src/angular.json
+++ b/src/angular.json
@@ -17,7 +17,7 @@
"index": "app/rapydo/index.html",
"main": "app/rapydo/main.ts",
"deleteOutputPath": false,
- "polyfills": "polyfills.ts",
+ "polyfills": ["zone.js", "polyfills.ts"],
"tsConfig": "tsconfig.app.json",
"aot": true,
"sourceMap": true,
@@ -112,7 +112,7 @@
"browserTarget": "RAPyDo:build:production"
},
"cypress": {
- "extraWebpackConfig": "./cypress/coverage.webpack.js"
+ "extraWebpackConfig": "/app/cypress/coverage.webpack.js"
}
}
},
@@ -125,12 +125,11 @@
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
- "main": "app/rapydo/tests.ts",
- "polyfills": "polyfills.ts",
- "tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
- "assets": ["./app/rapydo/assets", "./app/custom/assets"],
+ "polyfills": ["zone.js", "zone.js/testing"],
+ "tsConfig": "tsconfig.spec.json",
"styles": ["./app/rapydo/styles/rapydo.scss"],
+ "assets": ["./app/rapydo/assets", "./app/custom/assets"],
"scripts": []
}
}
diff --git a/src/app/app.auth.guard.ts b/src/app/app.auth.guard.ts
index 98f4e8e59..71cef6f46 100644
--- a/src/app/app.auth.guard.ts
+++ b/src/app/app.auth.guard.ts
@@ -16,12 +16,12 @@ export class AuthGuard implements CanActivate {
constructor(
public auth: AuthService,
public api: ApiService,
- public router: Router
+ public router: Router,
) {}
canActivate(
route: ActivatedRouteSnapshot,
- state: RouterStateSnapshot
+ state: RouterStateSnapshot,
): Observable {
const expectedRoles = route.data.roles;
@@ -46,7 +46,7 @@ export class AuthGuard implements CanActivate {
}
return false;
- })
+ }),
);
}
}
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 1131e8bb9..cb88a922c 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,4 +1,4 @@
-
+