diff --git a/.github/workflows/backend-integration-test.yaml b/.github/workflows/backend-integration-test.yaml index f88dcf7..ee26f5e 100644 --- a/.github/workflows/backend-integration-test.yaml +++ b/.github/workflows/backend-integration-test.yaml @@ -1,595 +1,595 @@ name: Backend Integration Tests on: - push: - paths: - - 'backend/src/**' - - 'backend/package.json' - - 'backend/package-lock.json' - - 'backend/tests/**' - pull_request: - paths: - - 'backend/src/**' - workflow_dispatch: - inputs: - use-aws: - description: 'Run recording tests in AWS EC2 runner' - default: 'true' - aws-instance-type: - description: 'AWS EC2 instance type' - default: 'c5.2xlarge' + push: + paths: + - 'backend/src/**' + - 'backend/package.json' + - 'backend/package-lock.json' + - 'backend/tests/**' + pull_request: + paths: + - 'backend/src/**' + workflow_dispatch: + inputs: + use-aws: + description: 'Run recording tests in AWS EC2 runner' + default: 'true' + aws-instance-type: + description: 'AWS EC2 instance type' + default: 'c5.2xlarge' jobs: - start-aws-runner: - name: Prepare AWS runner - runs-on: ov-actions-runner - if: ${{ inputs.use-aws != 'false' }} - outputs: - label: ${{ steps.start-ec2-runner.outputs.label }} - ec2-instance-id: ${{ steps.start-ec2-runner.outputs.ec2-instance-id }} - steps: - - name: Start AWS EC2 Runner - id: start-ec2-runner - uses: OpenVidu/actions/start-aws-runner@main - with: - aws-instance-type: ${{ inputs.aws-instance-type || 'c5.2xlarge' }} - aws-access-key-id: ${{ vars.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: ${{ vars.AWS_REGION }} - github-token: ${{ secrets.OPENVIDU_GITHUB_TOKEN }} - ec2-image-id: ${{ vars.AWS_GITHUB_ACTIONS_AMI }} - subnet-id: ${{ vars.AWS_SUBNET_ID }} - security-group-id: ${{ vars.AWS_SECURITY_GROUP_ID }} - workflow-name: ${{ github.workflow }} - repository-name: ${{ github.repository }} - test-rooms: - name: Rooms API Tests - runs-on: ov-actions-runner - strategy: - fail-fast: false - matrix: - storage-provider: [s3, abs] - steps: - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22.13' - - name: Install LK CLI - run: curl -sSL https://get.livekit.io/cli | bash - - name: Setup OpenVidu Local Deployment - uses: OpenVidu/actions/start-openvidu-local-deployment@main - with: - ref-openvidu-local-deployment: development - pre_startup_commands: | - cat <<'BASH' > pre_startup_commands.sh - #!/bin/bash - if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then - echo "Using Azure storage provider" - yq e -i ' - del(.storage.s3) | - .storage.azure = { - "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", - "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", - "container_name": "openvidu-appdata-rooms" - } - ' egress.yaml - fi + start-aws-runner: + name: Prepare AWS runner + runs-on: ov-actions-runner + if: ${{ inputs.use-aws != 'false' }} + outputs: + label: ${{ steps.start-ec2-runner.outputs.label }} + ec2-instance-id: ${{ steps.start-ec2-runner.outputs.ec2-instance-id }} + steps: + - name: Start AWS EC2 Runner + id: start-ec2-runner + uses: OpenVidu/actions/start-aws-runner@main + with: + aws-instance-type: ${{ inputs.aws-instance-type || 'c5.2xlarge' }} + aws-access-key-id: ${{ vars.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ vars.AWS_REGION }} + github-token: ${{ secrets.OPENVIDU_GITHUB_TOKEN }} + ec2-image-id: ${{ vars.AWS_GITHUB_ACTIONS_AMI }} + subnet-id: ${{ vars.AWS_SUBNET_ID }} + security-group-id: ${{ vars.AWS_SECURITY_GROUP_ID }} + workflow-name: ${{ github.workflow }} + repository-name: ${{ github.repository }} + test-rooms: + name: Rooms API Tests + runs-on: ov-actions-runner + strategy: + fail-fast: false + matrix: + storage-provider: [s3, abs] + steps: + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.13' + - name: Install LK CLI + run: curl -sSL https://get.livekit.io/cli | bash + - name: Setup OpenVidu Local Deployment + uses: OpenVidu/actions/start-openvidu-local-deployment@main + with: + ref-openvidu-local-deployment: development + pre_startup_commands: | + cat <<'BASH' > pre_startup_commands.sh + #!/bin/bash + if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then + echo "Using Azure storage provider" + yq e -i ' + del(.storage.s3) | + .storage.azure = { + "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", + "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", + "container_name": "openvidu-appdata-rooms" + } + ' egress.yaml + fi - echo "Commenting out openvidu-meet container in docker-compose.yaml" - if [ -f docker-compose.yaml ]; then - yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml - fi + echo "Commenting out openvidu-meet container in docker-compose.yaml" + if [ -f docker-compose.yaml ]; then + yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml + fi - BASH - chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh - - name: Setup OpenVidu Meet - uses: OpenVidu/actions/start-openvidu-meet@main - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-rooms' - - name: Run tests - run: | - cd backend - npm run test:integration-rooms - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-rooms' - JEST_JUNIT_OUTPUT_DIR: './reports/' - - name: Publish Test Report - uses: mikepenz/action-junit-report@v4 - if: always() - with: - report_paths: '**/reports/junit.xml' - fail_on_failure: true - require_tests: true - - name: Clean up - if: always() - uses: OpenVidu/actions/cleanup@main + BASH + chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh + - name: Setup OpenVidu Meet + uses: OpenVidu/actions/start-openvidu-meet@main + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-rooms' + - name: Run tests + run: | + cd backend + npm run test:integration-rooms + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-rooms' + JEST_JUNIT_OUTPUT_DIR: './reports/' + - name: Publish Test Report + uses: mikepenz/action-junit-report@v4 + if: always() + with: + report_paths: '**/reports/junit.xml' + fail_on_failure: true + require_tests: true + - name: Clean up + if: always() + uses: OpenVidu/actions/cleanup@main - test-recordings: - name: Recordings API Tests - needs: start-aws-runner - if: ${{ always() && (needs.start-aws-runner.result == 'success' || needs.start-aws-runner.result == 'skipped') }} - runs-on: ${{ needs.start-aws-runner.outputs.label || 'ov-actions-runner' }} - strategy: - fail-fast: false - matrix: - storage-provider: [s3, abs] - timeout-minutes: 30 - steps: - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22.13' - - name: Install LK CLI - run: curl -sSL https://get.livekit.io/cli | bash - - name: Setup OpenVidu Local Deployment - uses: OpenVidu/actions/start-openvidu-local-deployment@main - with: - ref-openvidu-local-deployment: development - pre_startup_commands: | - cat <<'BASH' > pre_startup_commands.sh - #!/bin/bash - if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then - echo "Using Azure storage provider" - yq e -i ' - del(.storage.s3) | - .storage.azure = { - "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", - "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", - "container_name": "openvidu-appdata-recordings" - } - ' egress.yaml + test-recordings: + name: Recordings API Tests + needs: start-aws-runner + if: ${{ always() && (needs.start-aws-runner.result == 'success' || needs.start-aws-runner.result == 'skipped') }} + runs-on: ${{ needs.start-aws-runner.outputs.label || 'ov-actions-runner' }} + strategy: + fail-fast: false + matrix: + storage-provider: [s3, abs] + timeout-minutes: 30 + steps: + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.13' + - name: Install LK CLI + run: curl -sSL https://get.livekit.io/cli | bash + - name: Setup OpenVidu Local Deployment + uses: OpenVidu/actions/start-openvidu-local-deployment@main + with: + ref-openvidu-local-deployment: development + pre_startup_commands: | + cat <<'BASH' > pre_startup_commands.sh + #!/bin/bash + if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then + echo "Using Azure storage provider" + yq e -i ' + del(.storage.s3) | + .storage.azure = { + "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", + "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", + "container_name": "openvidu-appdata-recordings" + } + ' egress.yaml - echo "Commenting out openvidu-meet container in docker-compose.yaml" - if [ -f docker-compose.yaml ]; then - yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml - fi - fi - BASH - chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh - - name: Setup OpenVidu Meet - uses: OpenVidu/actions/start-openvidu-meet@main - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-recordings' - - name: Run tests - run: | - cd backend - npm run test:integration-recordings - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-recordings' - JEST_JUNIT_OUTPUT_DIR: './reports/' - - name: Publish Test Report - uses: mikepenz/action-junit-report@v4 - if: always() - with: - report_paths: '**/reports/junit.xml' - fail_on_failure: true - require_tests: true - - name: Clean up - if: always() - uses: OpenVidu/actions/cleanup@main + echo "Commenting out openvidu-meet container in docker-compose.yaml" + if [ -f docker-compose.yaml ]; then + yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml + fi + fi + BASH + chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh + - name: Setup OpenVidu Meet + uses: OpenVidu/actions/start-openvidu-meet@main + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-recordings' + - name: Run tests + run: | + cd backend + npm run test:integration-recordings + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-recordings' + JEST_JUNIT_OUTPUT_DIR: './reports/' + - name: Publish Test Report + uses: mikepenz/action-junit-report@v4 + if: always() + with: + report_paths: '**/reports/junit.xml' + fail_on_failure: true + require_tests: true + - name: Clean up + if: always() + uses: OpenVidu/actions/cleanup@main - test-webhooks: - name: Webhook Tests - runs-on: ov-actions-runner - strategy: - fail-fast: false - matrix: - storage-provider: [s3, abs] - steps: - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22.13' - - name: Install LK CLI - run: curl -sSL https://get.livekit.io/cli | bash - - name: Setup OpenVidu Local Deployment - uses: OpenVidu/actions/start-openvidu-local-deployment@main - with: - ref-openvidu-local-deployment: development - pre_startup_commands: | - cat <<'BASH' > pre_startup_commands.sh - #!/bin/bash - if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then - echo "Using Azure storage provider" - yq e -i ' - del(.storage.s3) | - .storage.azure = { - "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", - "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", - "container_name": "openvidu-appdata-webhooks" - } - ' egress.yaml - fi - echo "Commenting out openvidu-meet container in docker-compose.yaml" - if [ -f docker-compose.yaml ]; then - yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml - fi - BASH - chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh - - name: Setup OpenVidu Meet - uses: OpenVidu/actions/start-openvidu-meet@main - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-webhooks' - - name: Run tests - run: | - cd backend - npm run test:integration-webhooks - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-webhooks' - JEST_JUNIT_OUTPUT_DIR: './reports/' - - name: Publish Test Report - uses: mikepenz/action-junit-report@v4 - if: always() - with: - report_paths: '**/reports/junit.xml' - fail_on_failure: true - require_tests: true - - name: Clean up - if: always() - uses: OpenVidu/actions/cleanup@main + test-webhooks: + name: Webhook Tests + runs-on: ov-actions-runner + strategy: + fail-fast: false + matrix: + storage-provider: [s3, abs] + steps: + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.13' + - name: Install LK CLI + run: curl -sSL https://get.livekit.io/cli | bash + - name: Setup OpenVidu Local Deployment + uses: OpenVidu/actions/start-openvidu-local-deployment@main + with: + ref-openvidu-local-deployment: development + pre_startup_commands: | + cat <<'BASH' > pre_startup_commands.sh + #!/bin/bash + if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then + echo "Using Azure storage provider" + yq e -i ' + del(.storage.s3) | + .storage.azure = { + "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", + "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", + "container_name": "openvidu-appdata-webhooks" + } + ' egress.yaml + fi + echo "Commenting out openvidu-meet container in docker-compose.yaml" + if [ -f docker-compose.yaml ]; then + yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml + fi + BASH + chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh + - name: Setup OpenVidu Meet + uses: OpenVidu/actions/start-openvidu-meet@main + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-webhooks' + - name: Run tests + run: | + cd backend + npm run test:integration-webhooks + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-webhooks' + JEST_JUNIT_OUTPUT_DIR: './reports/' + - name: Publish Test Report + uses: mikepenz/action-junit-report@v4 + if: always() + with: + report_paths: '**/reports/junit.xml' + fail_on_failure: true + require_tests: true + - name: Clean up + if: always() + uses: OpenVidu/actions/cleanup@main - test-security: - name: Security API Tests - runs-on: ov-actions-runner - strategy: - fail-fast: false - matrix: - storage-provider: [s3, abs] - steps: - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22.13' - - name: Install LK CLI - run: curl -sSL https://get.livekit.io/cli | bash - - name: Setup OpenVidu Local Deployment - uses: OpenVidu/actions/start-openvidu-local-deployment@main - with: - ref-openvidu-local-deployment: development - pre_startup_commands: | - cat <<'BASH' > pre_startup_commands.sh - #!/bin/bash - if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then - echo "Using Azure storage provider" - yq e -i ' - del(.storage.s3) | - .storage.azure = { - "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", - "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", - "container_name": "openvidu-appdata-security" - } - ' egress.yaml - fi - echo "Commenting out openvidu-meet container in docker-compose.yaml" - if [ -f docker-compose.yaml ]; then - yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml - fi - BASH - chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh - - name: Setup OpenVidu Meet - uses: OpenVidu/actions/start-openvidu-meet@main - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-security' - - name: Run tests - run: | - cd backend - npm run test:integration-security - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-security' - JEST_JUNIT_OUTPUT_DIR: './reports/' - - name: Publish Test Report - uses: mikepenz/action-junit-report@v4 - if: always() - with: - report_paths: '**/reports/junit.xml' - fail_on_failure: true - require_tests: true - - name: Clean up - if: always() - uses: OpenVidu/actions/cleanup@main + test-security: + name: Security API Tests + runs-on: ov-actions-runner + strategy: + fail-fast: false + matrix: + storage-provider: [s3, abs] + steps: + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.13' + - name: Install LK CLI + run: curl -sSL https://get.livekit.io/cli | bash + - name: Setup OpenVidu Local Deployment + uses: OpenVidu/actions/start-openvidu-local-deployment@main + with: + ref-openvidu-local-deployment: development + pre_startup_commands: | + cat <<'BASH' > pre_startup_commands.sh + #!/bin/bash + if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then + echo "Using Azure storage provider" + yq e -i ' + del(.storage.s3) | + .storage.azure = { + "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", + "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", + "container_name": "openvidu-appdata-security" + } + ' egress.yaml + fi + echo "Commenting out openvidu-meet container in docker-compose.yaml" + if [ -f docker-compose.yaml ]; then + yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml + fi + BASH + chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh + - name: Setup OpenVidu Meet + uses: OpenVidu/actions/start-openvidu-meet@main + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-security' + - name: Run tests + run: | + cd backend + npm run test:integration-security + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-security' + JEST_JUNIT_OUTPUT_DIR: './reports/' + - name: Publish Test Report + uses: mikepenz/action-junit-report@v4 + if: always() + with: + report_paths: '**/reports/junit.xml' + fail_on_failure: true + require_tests: true + - name: Clean up + if: always() + uses: OpenVidu/actions/cleanup@main - test-global-preferences: - name: Global Preferences API Tests - runs-on: ov-actions-runner - strategy: - fail-fast: false - matrix: - storage-provider: [s3, abs] - steps: - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22.13' - - name: Install LK CLI - run: curl -sSL https://get.livekit.io/cli | bash - - name: Setup OpenVidu Local Deployment - uses: OpenVidu/actions/start-openvidu-local-deployment@main - with: - ref-openvidu-local-deployment: development - pre_startup_commands: | - cat <<'BASH' > pre_startup_commands.sh - #!/bin/bash - if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then - echo "Using Azure storage provider" - yq e -i ' - del(.storage.s3) | - .storage.azure = { - "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", - "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", - "container_name": "openvidu-appdata-global-preferences" - } - ' egress.yaml - fi - echo "Commenting out openvidu-meet container in docker-compose.yaml" - if [ -f docker-compose.yaml ]; then - yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml - fi - BASH - chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh - - name: Setup OpenVidu Meet - uses: OpenVidu/actions/start-openvidu-meet@main - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-global-preferences' - - name: Run tests - run: | - cd backend - npm run test:integration-global-preferences - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-global-preferences' - JEST_JUNIT_OUTPUT_DIR: './reports/' - - name: Publish Test Report - uses: mikepenz/action-junit-report@v4 - if: always() - with: - report_paths: '**/reports/junit.xml' - fail_on_failure: true - require_tests: true - - name: Clean up - if: always() - uses: OpenVidu/actions/cleanup@main + test-global-config: + name: Global Config API Tests + runs-on: ov-actions-runner + strategy: + fail-fast: false + matrix: + storage-provider: [s3, abs] + steps: + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.13' + - name: Install LK CLI + run: curl -sSL https://get.livekit.io/cli | bash + - name: Setup OpenVidu Local Deployment + uses: OpenVidu/actions/start-openvidu-local-deployment@main + with: + ref-openvidu-local-deployment: development + pre_startup_commands: | + cat <<'BASH' > pre_startup_commands.sh + #!/bin/bash + if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then + echo "Using Azure storage provider" + yq e -i ' + del(.storage.s3) | + .storage.azure = { + "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", + "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", + "container_name": "openvidu-appdata-global-preferences" + } + ' egress.yaml + fi + echo "Commenting out openvidu-meet container in docker-compose.yaml" + if [ -f docker-compose.yaml ]; then + yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml + fi + BASH + chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh + - name: Setup OpenVidu Meet + uses: OpenVidu/actions/start-openvidu-meet@main + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-global-preferences' + - name: Run tests + run: | + cd backend + npm run test:integration-global-config + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-global-preferences' + JEST_JUNIT_OUTPUT_DIR: './reports/' + - name: Publish Test Report + uses: mikepenz/action-junit-report@v4 + if: always() + with: + report_paths: '**/reports/junit.xml' + fail_on_failure: true + require_tests: true + - name: Clean up + if: always() + uses: OpenVidu/actions/cleanup@main - test-participants: - name: Participants API Tests - runs-on: ov-actions-runner - strategy: - fail-fast: false - matrix: - storage-provider: [s3, abs] - steps: - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22.13' - - name: Install LK CLI - run: curl -sSL https://get.livekit.io/cli | bash - - name: Setup OpenVidu Local Deployment - uses: OpenVidu/actions/start-openvidu-local-deployment@main - with: - ref-openvidu-local-deployment: development - pre_startup_commands: | - cat <<'BASH' > pre_startup_commands.sh - #!/bin/bash - if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then - echo "Using Azure storage provider" - yq e -i ' - del(.storage.s3) | - .storage.azure = { - "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", - "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", - "container_name": "openvidu-appdata-participants" - } - ' egress.yaml - fi - echo "Commenting out openvidu-meet container in docker-compose.yaml" - if [ -f docker-compose.yaml ]; then - yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml - fi - BASH - chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh - - name: Setup OpenVidu Meet - uses: OpenVidu/actions/start-openvidu-meet@main - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-participants' - - name: Run tests - run: | - cd backend - npm run test:integration-participants - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-participants' - JEST_JUNIT_OUTPUT_DIR: './reports/' - - name: Publish Test Report - uses: mikepenz/action-junit-report@v4 - if: always() - with: - report_paths: '**/reports/junit.xml' - fail_on_failure: true - require_tests: true - - name: Clean up - if: always() - uses: OpenVidu/actions/cleanup@main + test-participants: + name: Participants API Tests + runs-on: ov-actions-runner + strategy: + fail-fast: false + matrix: + storage-provider: [s3, abs] + steps: + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.13' + - name: Install LK CLI + run: curl -sSL https://get.livekit.io/cli | bash + - name: Setup OpenVidu Local Deployment + uses: OpenVidu/actions/start-openvidu-local-deployment@main + with: + ref-openvidu-local-deployment: development + pre_startup_commands: | + cat <<'BASH' > pre_startup_commands.sh + #!/bin/bash + if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then + echo "Using Azure storage provider" + yq e -i ' + del(.storage.s3) | + .storage.azure = { + "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", + "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", + "container_name": "openvidu-appdata-participants" + } + ' egress.yaml + fi + echo "Commenting out openvidu-meet container in docker-compose.yaml" + if [ -f docker-compose.yaml ]; then + yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml + fi + BASH + chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh + - name: Setup OpenVidu Meet + uses: OpenVidu/actions/start-openvidu-meet@main + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-participants' + - name: Run tests + run: | + cd backend + npm run test:integration-participants + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-participants' + JEST_JUNIT_OUTPUT_DIR: './reports/' + - name: Publish Test Report + uses: mikepenz/action-junit-report@v4 + if: always() + with: + report_paths: '**/reports/junit.xml' + fail_on_failure: true + require_tests: true + - name: Clean up + if: always() + uses: OpenVidu/actions/cleanup@main - test-meetings: - name: Meetings API Tests - runs-on: ov-actions-runner - strategy: - fail-fast: false - matrix: - storage-provider: [s3, abs] - steps: - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22.13' - - name: Install LK CLI - run: curl -sSL https://get.livekit.io/cli | bash - - name: Setup OpenVidu Local Deployment - uses: OpenVidu/actions/start-openvidu-local-deployment@main - with: - ref-openvidu-local-deployment: development - pre_startup_commands: | - cat <<'BASH' > pre_startup_commands.sh - #!/bin/bash - if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then - echo "Using Azure storage provider" - yq e -i ' - del(.storage.s3) | - .storage.azure = { - "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", - "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", - "container_name": "openvidu-appdata-meetings" - } - ' egress.yaml - fi - echo "Commenting out openvidu-meet container in docker-compose.yaml" - if [ -f docker-compose.yaml ]; then - yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml - fi - BASH - chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh - - name: Setup OpenVidu Meet - uses: OpenVidu/actions/start-openvidu-meet@main - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-meetings' - - name: Run tests - run: | - cd backend - npm run test:integration-meetings - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-meetings' - JEST_JUNIT_OUTPUT_DIR: './reports/' - - name: Publish Test Report - uses: mikepenz/action-junit-report@v4 - if: always() - with: - report_paths: '**/reports/junit.xml' - fail_on_failure: true - require_tests: true - - name: Clean up - if: always() - uses: OpenVidu/actions/cleanup@main + test-meetings: + name: Meetings API Tests + runs-on: ov-actions-runner + strategy: + fail-fast: false + matrix: + storage-provider: [s3, abs] + steps: + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.13' + - name: Install LK CLI + run: curl -sSL https://get.livekit.io/cli | bash + - name: Setup OpenVidu Local Deployment + uses: OpenVidu/actions/start-openvidu-local-deployment@main + with: + ref-openvidu-local-deployment: development + pre_startup_commands: | + cat <<'BASH' > pre_startup_commands.sh + #!/bin/bash + if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then + echo "Using Azure storage provider" + yq e -i ' + del(.storage.s3) | + .storage.azure = { + "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", + "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", + "container_name": "openvidu-appdata-meetings" + } + ' egress.yaml + fi + echo "Commenting out openvidu-meet container in docker-compose.yaml" + if [ -f docker-compose.yaml ]; then + yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml + fi + BASH + chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh + - name: Setup OpenVidu Meet + uses: OpenVidu/actions/start-openvidu-meet@main + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-meetings' + - name: Run tests + run: | + cd backend + npm run test:integration-meetings + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-meetings' + JEST_JUNIT_OUTPUT_DIR: './reports/' + - name: Publish Test Report + uses: mikepenz/action-junit-report@v4 + if: always() + with: + report_paths: '**/reports/junit.xml' + fail_on_failure: true + require_tests: true + - name: Clean up + if: always() + uses: OpenVidu/actions/cleanup@main - test-users: - name: Users API Tests - runs-on: ov-actions-runner - strategy: - fail-fast: false - matrix: - storage-provider: [s3, abs] - steps: - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22.13' - - name: Install LK CLI - run: curl -sSL https://get.livekit.io/cli | bash - - name: Setup OpenVidu Local Deployment - uses: OpenVidu/actions/start-openvidu-local-deployment@main - with: - ref-openvidu-local-deployment: development - pre_startup_commands: | - cat <<'BASH' > pre_startup_commands.sh - #!/bin/bash - if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then - echo "Using Azure storage provider" - yq e -i ' - del(.storage.s3) | - .storage.azure = { - "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", - "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", - "container_name": "openvidu-appdata-users" - } - ' egress.yaml - fi - echo "Commenting out openvidu-meet container in docker-compose.yaml" - if [ -f docker-compose.yaml ]; then - yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml - fi - BASH - chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh - - name: Setup OpenVidu Meet - uses: OpenVidu/actions/start-openvidu-meet@main - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-users' - - name: Run tests - run: | - cd backend - npm run test:integration-users - env: - MEET_PREFERENCES_STORAGE_MODE: ${{ matrix.storage-provider }} - MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} - MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} - MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-users' - JEST_JUNIT_OUTPUT_DIR: './reports/' - - name: Publish Test Report - uses: mikepenz/action-junit-report@v4 - if: always() - with: - report_paths: '**/reports/junit.xml' - fail_on_failure: true - require_tests: true - - name: Clean up - if: always() - uses: OpenVidu/actions/cleanup@main + test-users: + name: Users API Tests + runs-on: ov-actions-runner + strategy: + fail-fast: false + matrix: + storage-provider: [s3, abs] + steps: + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.13' + - name: Install LK CLI + run: curl -sSL https://get.livekit.io/cli | bash + - name: Setup OpenVidu Local Deployment + uses: OpenVidu/actions/start-openvidu-local-deployment@main + with: + ref-openvidu-local-deployment: development + pre_startup_commands: | + cat <<'BASH' > pre_startup_commands.sh + #!/bin/bash + if [[ "${{ matrix['storage-provider'] }}" == "abs" ]]; then + echo "Using Azure storage provider" + yq e -i ' + del(.storage.s3) | + .storage.azure = { + "account_name": "${{ vars.MEET_AZURE_ACCOUNT_NAME }}", + "account_key": "${{ secrets.MEET_AZURE_ACCOUNT_KEY }}", + "container_name": "openvidu-appdata-users" + } + ' egress.yaml + fi + echo "Commenting out openvidu-meet container in docker-compose.yaml" + if [ -f docker-compose.yaml ]; then + yq e 'del(.services.openvidu-meet)' -i docker-compose.yaml + fi + BASH + chmod +x pre_startup_commands.sh && ./pre_startup_commands.sh + - name: Setup OpenVidu Meet + uses: OpenVidu/actions/start-openvidu-meet@main + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-users' + - name: Run tests + run: | + cd backend + npm run test:integration-users + env: + MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }} + MEET_AZURE_ACCOUNT_NAME: ${{ vars.MEET_AZURE_ACCOUNT_NAME }} + MEET_AZURE_ACCOUNT_KEY: ${{ secrets.MEET_AZURE_ACCOUNT_KEY }} + MEET_AZURE_CONTAINER_NAME: 'openvidu-appdata-users' + JEST_JUNIT_OUTPUT_DIR: './reports/' + - name: Publish Test Report + uses: mikepenz/action-junit-report@v4 + if: always() + with: + report_paths: '**/reports/junit.xml' + fail_on_failure: true + require_tests: true + - name: Clean up + if: always() + uses: OpenVidu/actions/cleanup@main - stop-runner: - name: Stop EC2 runner - needs: - - start-aws-runner - - test-recordings - runs-on: ov-actions-runner - if: ${{ always() && needs.start-aws-runner.outputs.label != '' }} - steps: - - name: Stop AWS EC2 Runner - id: stop-ec2-runner - uses: OpenVidu/actions/stop-aws-runner@main - with: - aws-access-key-id: ${{ vars.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: ${{ vars.AWS_REGION }} - github-token: ${{ secrets.OPENVIDU_GITHUB_TOKEN }} - label: ${{ needs.start-aws-runner.outputs.label }} - ec2-instance-id: ${{ needs.start-aws-runner.outputs.ec2-instance-id }} + stop-runner: + name: Stop EC2 runner + needs: + - start-aws-runner + - test-recordings + runs-on: ov-actions-runner + if: ${{ always() && needs.start-aws-runner.outputs.label != '' }} + steps: + - name: Stop AWS EC2 Runner + id: stop-ec2-runner + uses: OpenVidu/actions/stop-aws-runner@main + with: + aws-access-key-id: ${{ vars.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ vars.AWS_REGION }} + github-token: ${{ secrets.OPENVIDU_GITHUB_TOKEN }} + label: ${{ needs.start-aws-runner.outputs.label }} + ec2-instance-id: ${{ needs.start-aws-runner.outputs.ec2-instance-id }} diff --git a/backend/README.md b/backend/README.md index 2582d93..dcd19ab 100644 --- a/backend/README.md +++ b/backend/README.md @@ -25,14 +25,15 @@ npm run build:prod ## Storage Structure -The OpenVidu Meet backend uses an S3 bucket to store all application data, including rooms, recordings, user information, and system preferences. The bucket follows a hierarchical structure organized as follows: +The OpenVidu Meet backend uses an S3 bucket to store all application data, including rooms, recordings, user information, and system config. The bucket follows a hierarchical structure organized as follows: ### Bucket Structure ```plaintext openvidu-appdata/ ├── openvidu-meet/ -│ ├── global-preferences.json +│ ├── api-keys.json +│ ├── global-config.json │ ├── users/ │ │ └── admin.json │ ├── rooms/ @@ -56,13 +57,17 @@ openvidu-appdata/ ### Directory Descriptions -#### **Global Preferences** (`global-preferences.json`) +#### **API Keys** (`api-keys.json`) -Contains system-wide settings and configurations for the OpenVidu Meet application, such as default recording settings, UI preferences, and feature toggles. +Stores API keys used for authenticating requests to the OpenVidu Meet API. This file contains a list of valid API keys along with their creation dates. + +#### **Global Config** (`global-config.json`) + +Contains system-wide settings and configurations for the OpenVidu Meet application, such as security config, webhook config and global rooms appearance. #### **Users** (`users/`) -Stores user account information in individual JSON files. Each file is named using the username (e.g., `admin.json`) and contains user-specific data including authentication details, permissions, and preferences. +Stores user account information in individual JSON files. Each file is named using the username (e.g., `admin.json`) and contains user-specific data including authentication details and roles. #### **Rooms** (`rooms/`) diff --git a/backend/openapi/components/requestBodies/internal/update-security-config.yaml b/backend/openapi/components/requestBodies/internal/update-security-config.yaml new file mode 100644 index 0000000..6632214 --- /dev/null +++ b/backend/openapi/components/requestBodies/internal/update-security-config.yaml @@ -0,0 +1,6 @@ +description: New security config +required: true +content: + application/json: + schema: + $ref: '../../schemas/internal/global-security-config.yaml' diff --git a/backend/openapi/components/requestBodies/internal/update-security-preferences.yaml b/backend/openapi/components/requestBodies/internal/update-security-preferences.yaml deleted file mode 100644 index 572b973..0000000 --- a/backend/openapi/components/requestBodies/internal/update-security-preferences.yaml +++ /dev/null @@ -1,6 +0,0 @@ -description: New security preferences -required: true -content: - application/json: - schema: - $ref: '../../schemas/internal/security-preferences.yaml' diff --git a/backend/openapi/components/requestBodies/internal/update-webhooks-config.yaml b/backend/openapi/components/requestBodies/internal/update-webhooks-config.yaml new file mode 100644 index 0000000..de746d2 --- /dev/null +++ b/backend/openapi/components/requestBodies/internal/update-webhooks-config.yaml @@ -0,0 +1,6 @@ +description: New webhooks config +required: true +content: + application/json: + schema: + $ref: '../../schemas/internal/webhooks-config.yaml' diff --git a/backend/openapi/components/requestBodies/internal/update-webhooks-preferences.yaml b/backend/openapi/components/requestBodies/internal/update-webhooks-preferences.yaml deleted file mode 100644 index a656cc9..0000000 --- a/backend/openapi/components/requestBodies/internal/update-webhooks-preferences.yaml +++ /dev/null @@ -1,6 +0,0 @@ -description: New webhooks preferences -required: true -content: - application/json: - schema: - $ref: '../../schemas/internal/webhooks-preferences.yaml' diff --git a/backend/openapi/components/responses/internal/success-get-security-config.yaml b/backend/openapi/components/responses/internal/success-get-security-config.yaml new file mode 100644 index 0000000..eab7189 --- /dev/null +++ b/backend/openapi/components/responses/internal/success-get-security-config.yaml @@ -0,0 +1,5 @@ +description: Successfully retrieved security config +content: + application/json: + schema: + $ref: '../../schemas/internal/global-security-config.yaml' diff --git a/backend/openapi/components/responses/internal/success-get-security-preferences.yaml b/backend/openapi/components/responses/internal/success-get-security-preferences.yaml deleted file mode 100644 index 6bc017b..0000000 --- a/backend/openapi/components/responses/internal/success-get-security-preferences.yaml +++ /dev/null @@ -1,5 +0,0 @@ -description: Successfully retrieved security preferences -content: - application/json: - schema: - $ref: '../../schemas/internal/security-preferences.yaml' diff --git a/backend/openapi/components/responses/internal/success-get-webhooks-config.yaml b/backend/openapi/components/responses/internal/success-get-webhooks-config.yaml new file mode 100644 index 0000000..687da96 --- /dev/null +++ b/backend/openapi/components/responses/internal/success-get-webhooks-config.yaml @@ -0,0 +1,5 @@ +description: Successfully retrieved webhooks config +content: + application/json: + schema: + $ref: '../../schemas/internal/webhooks-config.yaml' diff --git a/backend/openapi/components/responses/internal/success-get-webhooks-preferences.yaml b/backend/openapi/components/responses/internal/success-get-webhooks-preferences.yaml deleted file mode 100644 index a1e2f47..0000000 --- a/backend/openapi/components/responses/internal/success-get-webhooks-preferences.yaml +++ /dev/null @@ -1,5 +0,0 @@ -description: Successfully retrieved webhooks preferences -content: - application/json: - schema: - $ref: '../../schemas/internal/webhooks-preferences.yaml' diff --git a/backend/openapi/components/responses/internal/success-update-security-preferences.yaml b/backend/openapi/components/responses/internal/success-update-security-config.yaml similarity index 54% rename from backend/openapi/components/responses/internal/success-update-security-preferences.yaml rename to backend/openapi/components/responses/internal/success-update-security-config.yaml index da5939a..d82a5c9 100644 --- a/backend/openapi/components/responses/internal/success-update-security-preferences.yaml +++ b/backend/openapi/components/responses/internal/success-update-security-config.yaml @@ -1,4 +1,4 @@ -description: Successfully updated security preferences +description: Successfully updated security config content: application/json: schema: @@ -6,4 +6,4 @@ content: properties: message: type: string - example: 'Security preferences updated successfully' + example: 'Security config updated successfully' diff --git a/backend/openapi/components/responses/internal/success-update-webhooks-preferences.yaml b/backend/openapi/components/responses/internal/success-update-webhooks-config.yaml similarity index 54% rename from backend/openapi/components/responses/internal/success-update-webhooks-preferences.yaml rename to backend/openapi/components/responses/internal/success-update-webhooks-config.yaml index f6b86dc..2b447f8 100644 --- a/backend/openapi/components/responses/internal/success-update-webhooks-preferences.yaml +++ b/backend/openapi/components/responses/internal/success-update-webhooks-config.yaml @@ -1,4 +1,4 @@ -description: Successfully updated webhooks preferences +description: Successfully updated webhooks config content: application/json: schema: @@ -6,4 +6,4 @@ content: properties: message: type: string - example: 'Webhooks preferences updated successfully' + example: 'Webhooks config updated successfully' diff --git a/backend/openapi/components/schemas/internal/security-preferences.yaml b/backend/openapi/components/schemas/internal/global-security-config.yaml similarity index 90% rename from backend/openapi/components/schemas/internal/security-preferences.yaml rename to backend/openapi/components/schemas/internal/global-security-config.yaml index 3a2adbc..871b9e0 100644 --- a/backend/openapi/components/schemas/internal/security-preferences.yaml +++ b/backend/openapi/components/schemas/internal/global-security-config.yaml @@ -1,10 +1,10 @@ type: object properties: authentication: - $ref: '#/AuthenticationPreferences' - description: Preferences for authentication. + $ref: '#/AuthenticationConfig' + description: Config for authentication. -AuthenticationPreferences: +AuthenticationConfig: type: object properties: authMethod: diff --git a/backend/openapi/components/schemas/internal/webhooks-preferences.yaml b/backend/openapi/components/schemas/internal/webhooks-config.yaml similarity index 100% rename from backend/openapi/components/schemas/internal/webhooks-preferences.yaml rename to backend/openapi/components/schemas/internal/webhooks-config.yaml diff --git a/backend/openapi/openvidu-meet-internal-api.yaml b/backend/openapi/openvidu-meet-internal-api.yaml index bbf6e90..aec9330 100644 --- a/backend/openapi/openvidu-meet-internal-api.yaml +++ b/backend/openapi/openvidu-meet-internal-api.yaml @@ -20,14 +20,14 @@ paths: $ref: './paths/internal/users.yaml#/~1users~1profile' /users/change-password: $ref: './paths/internal/users.yaml#/~1users~1change-password' - /preferences/webhooks: - $ref: './paths/internal/global-preferences.yaml#/~1preferences~1webhooks' - /preferences/webhooks/test: - $ref: './paths/internal/global-preferences.yaml#/~1preferences~1webhooks~1test' - /preferences/security: - $ref: './paths/internal/global-preferences.yaml#/~1preferences~1security' - /preferences/appearance: - $ref: './paths/internal/global-preferences.yaml#/~1preferences~1appearance' + /config/webhooks: + $ref: './paths/internal/meet-global-config.yaml#/~1config~1webhooks' + /config/webhooks/test: + $ref: './paths/internal/meet-global-config.yaml#/~1config~1webhooks~1test' + /config/security: + $ref: './paths/internal/meet-global-config.yaml#/~1config~1security' + /config/appearance: + $ref: './paths/internal/meet-global-config.yaml#/~1config~1appearance' /rooms/{roomId}/recording-token: $ref: './paths/internal/rooms.yaml#/~1rooms~1{roomId}~1recording-token' /rooms/{roomId}/roles: @@ -55,10 +55,10 @@ components: schemas: User: $ref: components/schemas/internal/user.yaml - WebhooksPreferences: - $ref: components/schemas/internal/webhooks-preferences.yaml - SecurityPreferences: - $ref: components/schemas/internal/security-preferences.yaml + WebhooksConfig: + $ref: components/schemas/internal/webhooks-config.yaml + SecurityConfig: + $ref: components/schemas/internal/global-security-config.yaml MeetRoom: $ref: components/schemas/meet-room.yaml MeetRoomOptions: diff --git a/backend/openapi/paths/internal/global-preferences.yaml b/backend/openapi/paths/internal/meet-global-config.yaml similarity index 65% rename from backend/openapi/paths/internal/global-preferences.yaml rename to backend/openapi/paths/internal/meet-global-config.yaml index add6233..7e7e5ac 100644 --- a/backend/openapi/paths/internal/global-preferences.yaml +++ b/backend/openapi/paths/internal/meet-global-config.yaml @@ -1,16 +1,16 @@ -/preferences/webhooks: +/config/webhooks: get: - operationId: getWebhooksPreferences - summary: Get webhooks preferences + operationId: getWebhooksConfig + summary: Get webhooks config description: > - Retrieves the webhooks preferences for the OpenVidu Meet application. + Retrieves the webhooks config for the OpenVidu Meet application. tags: - - Internal API - Global Preferences + - Internal API - Global Config security: - accessTokenCookie: [] responses: '200': - $ref: '../../components/responses/internal/success-get-webhooks-preferences.yaml' + $ref: '../../components/responses/internal/success-get-webhooks-config.yaml' '401': $ref: '../../components/responses/unauthorized-error.yaml' '403': @@ -18,19 +18,19 @@ '500': $ref: '../../components/responses/internal-server-error.yaml' put: - operationId: updateWebhooksPreferences - summary: Update webhooks preferences + operationId: updateWebhooksConfig + summary: Update webhooks config description: > - Updates the webhooks preferences for the OpenVidu Meet application. + Updates the webhooks config for the OpenVidu Meet application. tags: - - Internal API - Global Preferences + - Internal API - Global Config security: - accessTokenCookie: [] requestBody: - $ref: '../../components/requestBodies/internal/update-webhooks-preferences.yaml' + $ref: '../../components/requestBodies/internal/update-webhooks-config.yaml' responses: '200': - $ref: '../../components/responses/internal/success-update-webhooks-preferences.yaml' + $ref: '../../components/responses/internal/success-update-webhooks-config.yaml' '401': $ref: '../../components/responses/unauthorized-error.yaml' '403': @@ -40,14 +40,14 @@ '500': $ref: '../../components/responses/internal-server-error.yaml' -/preferences/webhooks/test: +/config/webhooks/test: post: operationId: testWebhookUrl summary: Test webhook URL description: > Tests the provided webhook URL to ensure it is valid and reachable. tags: - - Internal API - Global Preferences + - Internal API - Global Config requestBody: $ref: '../../components/requestBodies/internal/test-webhook-url-request.yaml' responses: @@ -60,33 +60,33 @@ '500': $ref: '../../components/responses/internal-server-error.yaml' -/preferences/security: +/config/security: get: - operationId: getSecurityPreferences - summary: Get security preferences + operationId: getSecurityConfig + summary: Get security config description: > - Retrieves the security preferences for the OpenVidu Meet application. + Retrieves the security config for the OpenVidu Meet application. tags: - - Internal API - Global Preferences + - Internal API - Global Config responses: '200': - $ref: '../../components/responses/internal/success-get-security-preferences.yaml' + $ref: '../../components/responses/internal/success-get-security-config.yaml' '500': $ref: '../../components/responses/internal-server-error.yaml' put: - operationId: updateSecurityPreferences - summary: Update security preferences + operationId: updateSecurityConfig + summary: Update security config description: > - Updates the security preferences for the OpenVidu Meet application. + Updates the security config for the OpenVidu Meet application. tags: - - Internal API - Global Preferences + - Internal API - Global Config security: - accessTokenCookie: [] requestBody: - $ref: '../../components/requestBodies/internal/update-security-preferences.yaml' + $ref: '../../components/requestBodies/internal/update-security-config.yaml' responses: '200': - $ref: '../../components/responses/internal/success-update-security-preferences.yaml' + $ref: '../../components/responses/internal/success-update-security-config.yaml' '401': $ref: '../../components/responses/unauthorized-error.yaml' '403': @@ -96,26 +96,26 @@ '500': $ref: '../../components/responses/internal-server-error.yaml' -/preferences/appearance: +/config/appearance: get: - operationId: getAppearancePreferences - summary: Get appearance preferences + operationId: getAppearanceConfig + summary: Get appearance config description: > - Retrieves the appearance preferences for the OpenVidu Meet application. + Retrieves the appearance config for the OpenVidu Meet application. tags: - - Internal API - Global Preferences + - Internal API - Global Config security: - accessTokenCookie: [] responses: '202': $ref: '../../components/responses/pro-feature-error.yaml' put: - operationId: updateAppearancePreferences - summary: Update appearance preferences + operationId: updateAppearanceConfig + summary: Update appearance config description: > - Updates the appearance preferences for the OpenVidu Meet application. + Updates the appearance config for the OpenVidu Meet application. tags: - - Internal API - Global Preferences + - Internal API - Global Config security: - accessTokenCookie: [] responses: diff --git a/backend/openapi/tags/tags.yaml b/backend/openapi/tags/tags.yaml index 0c942b0..d27abbf 100644 --- a/backend/openapi/tags/tags.yaml +++ b/backend/openapi/tags/tags.yaml @@ -6,8 +6,8 @@ description: Authentication operations - name: Internal API - Users description: Operations related to managing users in OpenVidu Meet -- name: Internal API - Global Preferences - description: Operations related to managing global preferences in OpenVidu Meet +- name: Internal API - Global Config + description: Operations related to managing global config in OpenVidu Meet - name: Internal API - Rooms description: Operations related to managing OpenVidu Meet rooms - name: Internal API - Participant diff --git a/backend/package.json b/backend/package.json index 4a66ffd..702c927 100644 --- a/backend/package.json +++ b/backend/package.json @@ -42,7 +42,7 @@ "test:integration-recordings": "node --experimental-vm-modules node_modules/.bin/jest --maxWorkers=1 --maxConcurrency=1 --forceExit --testPathPattern \"tests/integration/api/recordings\" --ci --reporters=default --reporters=jest-junit", "test:integration-webhooks": "node --experimental-vm-modules node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/webhooks\" --ci --reporters=default --reporters=jest-junit", "test:integration-security": "node --experimental-vm-modules node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/security\" --ci --reporters=default --reporters=jest-junit", - "test:integration-global-preferences": "node --experimental-vm-modules node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/global-preferences\" --ci --reporters=default --reporters=jest-junit", + "test:integration-global-config": "node --experimental-vm-modules node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/global-config\" --ci --reporters=default --reporters=jest-junit", "test:integration-participants": "node --experimental-vm-modules node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/participants\" --ci --reporters=default --reporters=jest-junit", "test:integration-meetings": "node --experimental-vm-modules node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/meetings\" --ci --reporters=default --reporters=jest-junit", "test:integration-users": "node --experimental-vm-modules node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/users\" --ci --reporters=default --reporters=jest-junit", diff --git a/backend/src/config/dependency-injector.config.ts b/backend/src/config/dependency-injector.config.ts index 6aef985..27ff6ea 100644 --- a/backend/src/config/dependency-injector.config.ts +++ b/backend/src/config/dependency-injector.config.ts @@ -1,15 +1,18 @@ import { Container } from 'inversify'; -import { MEET_PREFERENCES_STORAGE_MODE } from '../environment.js'; +import { MEET_BLOB_STORAGE_MODE } from '../environment.js'; import { ABSService, ABSStorageProvider, AuthService, + DistributedEventService, + FrontendEventService, LiveKitService, LivekitWebhookService, LoggerService, MeetStorageService, MutexService, OpenViduWebhookService, + ParticipantNameService, ParticipantService, RecordingService, RedisService, @@ -20,12 +23,9 @@ import { StorageFactory, StorageKeyBuilder, StorageProvider, - DistributedEventService, TaskSchedulerService, TokenService, - UserService, - FrontendEventService, - ParticipantNameService + UserService } from '../services/index.js'; export const container: Container = new Container(); @@ -51,7 +51,7 @@ export const registerDependencies = () => { container.bind(MutexService).toSelf().inSingletonScope(); container.bind(TaskSchedulerService).toSelf().inSingletonScope(); - configureStorage(MEET_PREFERENCES_STORAGE_MODE); + configureStorage(MEET_BLOB_STORAGE_MODE); container.bind(StorageFactory).toSelf().inSingletonScope(); container.bind(MeetStorageService).toSelf().inSingletonScope(); diff --git a/backend/src/controllers/global-config/appearance-config.controller.ts b/backend/src/controllers/global-config/appearance-config.controller.ts new file mode 100644 index 0000000..1993d2e --- /dev/null +++ b/backend/src/controllers/global-config/appearance-config.controller.ts @@ -0,0 +1,12 @@ +import { Request, Response } from 'express'; +import { errorProFeature, rejectRequestFromMeetError } from '../../models/error.model.js'; + +export const updateAppearanceConfig = async (_req: Request, res: Response) => { + const error = errorProFeature('update appearance config'); + rejectRequestFromMeetError(res, error); +}; + +export const getAppearanceConfig = async (_req: Request, res: Response) => { + const error = errorProFeature('get appearance config'); + rejectRequestFromMeetError(res, error); +}; diff --git a/backend/src/controllers/global-config/security-config.controller.ts b/backend/src/controllers/global-config/security-config.controller.ts new file mode 100644 index 0000000..7f24d0b --- /dev/null +++ b/backend/src/controllers/global-config/security-config.controller.ts @@ -0,0 +1,42 @@ +import { SecurityConfig } from '@typings-ce'; +import { Request, Response } from 'express'; +import { container } from '../../config/index.js'; +import { handleError } from '../../models/error.model.js'; +import { LoggerService, MeetStorageService } from '../../services/index.js'; + +export const updateSecurityConfig = async (req: Request, res: Response) => { + const logger = container.get(LoggerService); + const storageService = container.get(MeetStorageService); + + logger.verbose(`Updating security config: ${JSON.stringify(req.body)}`); + const securityConfig = req.body as SecurityConfig; + + try { + const globalConfig = await storageService.getGlobalConfig(); + const currentAuth = globalConfig.securityConfig.authentication; + const newAuth = securityConfig.authentication; + + currentAuth.authMethod = newAuth.authMethod; + currentAuth.authModeToAccessRoom = newAuth.authModeToAccessRoom; + await storageService.saveGlobalConfig(globalConfig); + + return res.status(200).json({ message: 'Security config updated successfully' }); + } catch (error) { + handleError(res, error, 'updating security config'); + } +}; + +export const getSecurityConfig = async (_req: Request, res: Response) => { + const logger = container.get(LoggerService); + const storageService = container.get(MeetStorageService); + + logger.verbose('Getting security config'); + + try { + const config = await storageService.getGlobalConfig(); + const securityConfig = config.securityConfig; + return res.status(200).json(securityConfig); + } catch (error) { + handleError(res, error, 'getting security config'); + } +}; diff --git a/backend/src/controllers/global-config/webhook-config.controller.ts b/backend/src/controllers/global-config/webhook-config.controller.ts new file mode 100644 index 0000000..60b451a --- /dev/null +++ b/backend/src/controllers/global-config/webhook-config.controller.ts @@ -0,0 +1,59 @@ +import { WebhookConfig } from '@typings-ce'; +import { Request, Response } from 'express'; +import { container } from '../../config/index.js'; +import { handleError } from '../../models/error.model.js'; +import { LoggerService, MeetStorageService, OpenViduWebhookService } from '../../services/index.js'; + +export const updateWebhookConfig = async (req: Request, res: Response) => { + const logger = container.get(LoggerService); + const storageService = container.get(MeetStorageService); + + logger.info(`Updating webhooks config: ${JSON.stringify(req.body)}`); + const webhookConfig = req.body as WebhookConfig; + + try { + const globalConfig = await storageService.getGlobalConfig(); + + // TODO: Validate the URL if webhooks are enabled by making a test request + globalConfig.webhooksConfig = { + enabled: webhookConfig.enabled, + url: webhookConfig.url === undefined ? globalConfig.webhooksConfig.url : webhookConfig.url + }; + + await storageService.saveGlobalConfig(globalConfig); + + return res.status(200).json({ message: 'Webhooks config updated successfully' }); + } catch (error) { + handleError(res, error, 'updating webhooks config'); + } +}; + +export const getWebhookConfig = async (_req: Request, res: Response) => { + const logger = container.get(LoggerService); + const storageService = container.get(MeetStorageService); + + logger.verbose('Getting webhooks config'); + + try { + const config = await storageService.getGlobalConfig(); + return res.status(200).json(config.webhooksConfig); + } catch (error) { + handleError(res, error, 'getting webhooks config'); + } +}; + +export const testWebhook = async (req: Request, res: Response) => { + const logger = container.get(LoggerService); + const webhookService = container.get(OpenViduWebhookService); + + logger.verbose(`Testing webhook URL: ${req.body.url}`); + const url = req.body.url; + + try { + await webhookService.testWebhookUrl(url); + logger.info(`Webhook URL '${url}' is valid`); + return res.status(200).json({ message: 'Webhook URL is valid' }); + } catch (error) { + handleError(res, error, 'testing webhook URL'); + } +}; diff --git a/backend/src/controllers/global-preferences/appearance-preferences.controller.ts b/backend/src/controllers/global-preferences/appearance-preferences.controller.ts deleted file mode 100644 index c5de6ad..0000000 --- a/backend/src/controllers/global-preferences/appearance-preferences.controller.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Request, Response } from 'express'; -import { errorProFeature, rejectRequestFromMeetError } from '../../models/error.model.js'; - -export const updateAppearancePreferences = async (_req: Request, res: Response) => { - const error = errorProFeature('update appearance preferences'); - rejectRequestFromMeetError(res, error); -}; - -export const getAppearancePreferences = async (_req: Request, res: Response) => { - const error = errorProFeature('get appearance preferences'); - rejectRequestFromMeetError(res, error); -}; diff --git a/backend/src/controllers/global-preferences/security-preferences.controller.ts b/backend/src/controllers/global-preferences/security-preferences.controller.ts deleted file mode 100644 index 92a5c87..0000000 --- a/backend/src/controllers/global-preferences/security-preferences.controller.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { SecurityPreferences } from '@typings-ce'; -import { Request, Response } from 'express'; -import { container } from '../../config/index.js'; -import { handleError } from '../../models/error.model.js'; -import { LoggerService, MeetStorageService } from '../../services/index.js'; - -export const updateSecurityPreferences = async (req: Request, res: Response) => { - const logger = container.get(LoggerService); - const globalPrefService = container.get(MeetStorageService); - - logger.verbose(`Updating security preferences: ${JSON.stringify(req.body)}`); - const securityPreferences = req.body as SecurityPreferences; - - try { - const globalPreferences = await globalPrefService.getGlobalPreferences(); - const currentAuth = globalPreferences.securityPreferences.authentication; - const newAuth = securityPreferences.authentication; - - currentAuth.authMethod = newAuth.authMethod; - currentAuth.authModeToAccessRoom = newAuth.authModeToAccessRoom; - await globalPrefService.saveGlobalPreferences(globalPreferences); - - return res.status(200).json({ message: 'Security preferences updated successfully' }); - } catch (error) { - handleError(res, error, 'updating security preferences'); - } -}; - -export const getSecurityPreferences = async (_req: Request, res: Response) => { - const logger = container.get(LoggerService); - const preferenceService = container.get(MeetStorageService); - - logger.verbose('Getting security preferences'); - - try { - const preferences = await preferenceService.getGlobalPreferences(); - const securityPreferences = preferences.securityPreferences; - return res.status(200).json(securityPreferences); - } catch (error) { - handleError(res, error, 'getting security preferences'); - } -}; diff --git a/backend/src/controllers/global-preferences/webhook-preferences.controller.ts b/backend/src/controllers/global-preferences/webhook-preferences.controller.ts deleted file mode 100644 index 2886343..0000000 --- a/backend/src/controllers/global-preferences/webhook-preferences.controller.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { WebhookPreferences } from '@typings-ce'; -import { Request, Response } from 'express'; -import { container } from '../../config/index.js'; -import { handleError } from '../../models/error.model.js'; -import { LoggerService, MeetStorageService, OpenViduWebhookService } from '../../services/index.js'; - -export const updateWebhookPreferences = async (req: Request, res: Response) => { - const logger = container.get(LoggerService); - const globalPrefService = container.get(MeetStorageService); - - logger.info(`Updating webhooks preferences: ${JSON.stringify(req.body)}`); - const webhookPreferences = req.body as WebhookPreferences; - - try { - const globalPreferences = await globalPrefService.getGlobalPreferences(); - - // TODO: Validate the URL if webhooks are enabled by making a test request - globalPreferences.webhooksPreferences = { - enabled: webhookPreferences.enabled, - url: - webhookPreferences.url === undefined - ? globalPreferences.webhooksPreferences.url - : webhookPreferences.url - }; - - await globalPrefService.saveGlobalPreferences(globalPreferences); - - return res.status(200).json({ message: 'Webhooks preferences updated successfully' }); - } catch (error) { - handleError(res, error, 'updating webhooks preferences'); - } -}; - -export const getWebhookPreferences = async (_req: Request, res: Response) => { - const logger = container.get(LoggerService); - const preferenceService = container.get(MeetStorageService); - - logger.verbose('Getting webhooks preferences'); - - try { - const preferences = await preferenceService.getGlobalPreferences(); - return res.status(200).json(preferences.webhooksPreferences); - } catch (error) { - handleError(res, error, 'getting webhooks preferences'); - } -}; - -export const testWebhook = async (req: Request, res: Response) => { - const logger = container.get(LoggerService); - const webhookService = container.get(OpenViduWebhookService); - - logger.verbose(`Testing webhook URL: ${req.body.url}`); - const url = req.body.url; - - try { - await webhookService.testWebhookUrl(url); - logger.info(`Webhook URL '${url}' is valid`); - return res.status(200).json({ message: 'Webhook URL is valid' }); - } catch (error) { - handleError(res, error, 'testing webhook URL'); - } -}; diff --git a/backend/src/controllers/index.ts b/backend/src/controllers/index.ts index 940361c..6da156f 100644 --- a/backend/src/controllers/index.ts +++ b/backend/src/controllers/index.ts @@ -6,6 +6,6 @@ export * from './participant.controller.js'; export * from './recording.controller.js'; export * from './livekit-webhook.controller.js'; -export * from './global-preferences/appearance-preferences.controller.js'; -export * from './global-preferences/webhook-preferences.controller.js'; -export * from './global-preferences/security-preferences.controller.js'; +export * from './global-config/appearance-config.controller.js'; +export * from './global-config/webhook-config.controller.js'; +export * from './global-config/security-config.controller.js'; diff --git a/backend/src/environment.ts b/backend/src/environment.ts index 2d5ec23..9d9213a 100644 --- a/backend/src/environment.ts +++ b/backend/src/environment.ts @@ -50,7 +50,7 @@ export const { LIVEKIT_API_KEY = 'devkey', LIVEKIT_API_SECRET = 'secret', - MEET_PREFERENCES_STORAGE_MODE = 's3', // Options: 's3', 'abs' + MEET_BLOB_STORAGE_MODE = 's3', // Options: 's3', 'abs' // S3 configuration MEET_S3_BUCKET = 'openvidu-appdata', @@ -108,12 +108,12 @@ export const logEnvVars = () => { console.log('SERVICE NAME ID: ', text(MEET_NAME_ID)); console.log('CORS ORIGIN:', text(SERVER_CORS_ORIGIN)); console.log('MEET LOG LEVEL: ', text(MEET_LOG_LEVEL)); - console.log('MEET PREFERENCES STORAGE:', text(MEET_PREFERENCES_STORAGE_MODE)); + console.log('MEET BLOB STORAGE MODE:', text(MEET_BLOB_STORAGE_MODE)); console.log('MEET INITIAL ADMIN USER: ', credential('****' + MEET_INITIAL_ADMIN_USER.slice(-3))); console.log('MEET INITIAL ADMIN PASSWORD: ', credential('****' + MEET_INITIAL_ADMIN_PASSWORD.slice(-3))); if (!MEET_INITIAL_API_KEY) { - console.log(chalk.red('MEET INITIAL_API_KEY: none')); + console.log(chalk.red('MEET INITIAL API KEY: none')); } else { console.log('MEET INITIAL API KEY: ', credential('****' + MEET_INITIAL_API_KEY.slice(-3))); } @@ -133,7 +133,7 @@ export const logEnvVars = () => { console.log('LIVEKIT API KEY: ', credential('****' + LIVEKIT_API_KEY.slice(-3))); console.log('---------------------------------------------------------'); - if (MEET_PREFERENCES_STORAGE_MODE === 's3') { + if (MEET_BLOB_STORAGE_MODE === 's3') { console.log('S3 Configuration'); console.log('---------------------------------------------------------'); console.log('MEET S3 BUCKET:', text(MEET_S3_BUCKET)); @@ -143,7 +143,7 @@ export const logEnvVars = () => { console.log('MEET AWS REGION:', text(MEET_AWS_REGION)); console.log('MEET S3 WITH PATH STYLE ACCESS:', text(MEET_S3_WITH_PATH_STYLE_ACCESS)); console.log('---------------------------------------------------------'); - } else if (MEET_PREFERENCES_STORAGE_MODE === 'abs') { + } else if (MEET_BLOB_STORAGE_MODE === 'abs') { console.log('Azure Blob Storage Configuration'); console.log('---------------------------------------------------------'); console.log('MEET AZURE ACCOUNT NAME:', text(MEET_AZURE_ACCOUNT_NAME)); diff --git a/backend/src/middlewares/index.ts b/backend/src/middlewares/index.ts index a4b159e..85fdae9 100644 --- a/backend/src/middlewares/index.ts +++ b/backend/src/middlewares/index.ts @@ -9,4 +9,4 @@ export * from './request-validators/user-validator.middleware.js'; export * from './request-validators/room-validator.middleware.js'; export * from './request-validators/participant-validator.middleware.js'; export * from './request-validators/recording-validator.middleware.js'; -export * from './request-validators/preferences-validator.middleware.js'; +export * from './request-validators/config-validator.middleware.js'; diff --git a/backend/src/middlewares/participant.middleware.ts b/backend/src/middlewares/participant.middleware.ts index df31f87..73e5859 100644 --- a/backend/src/middlewares/participant.middleware.ts +++ b/backend/src/middlewares/participant.middleware.ts @@ -13,7 +13,7 @@ import { allowAnonymous, tokenAndRoleValidator, withAuth } from './auth.middlewa * - Otherwise, allow anonymous access. */ export const configureParticipantTokenAuth = async (req: Request, res: Response, next: NextFunction) => { - const globalPrefService = container.get(MeetStorageService); + const storageService = container.get(MeetStorageService); const roomService = container.get(RoomService); let role: ParticipantRole; @@ -28,10 +28,10 @@ export const configureParticipantTokenAuth = async (req: Request, res: Response, let authModeToAccessRoom: AuthMode; try { - const { securityPreferences } = await globalPrefService.getGlobalPreferences(); - authModeToAccessRoom = securityPreferences.authentication.authModeToAccessRoom; + const { securityConfig } = await storageService.getGlobalConfig(); + authModeToAccessRoom = securityConfig.authentication.authModeToAccessRoom; } catch (error) { - return handleError(res, error, 'checking authentication preferences'); + return handleError(res, error, 'checking authentication config'); } const authValidators = []; diff --git a/backend/src/middlewares/request-validators/preferences-validator.middleware.ts b/backend/src/middlewares/request-validators/config-validator.middleware.ts similarity index 71% rename from backend/src/middlewares/request-validators/preferences-validator.middleware.ts rename to backend/src/middlewares/request-validators/config-validator.middleware.ts index 5bdae4d..43d7a9b 100644 --- a/backend/src/middlewares/request-validators/preferences-validator.middleware.ts +++ b/backend/src/middlewares/request-validators/config-validator.middleware.ts @@ -1,17 +1,17 @@ import { - AuthenticationPreferences, + AuthenticationConfig, AuthMode, AuthType, - SecurityPreferences, + SecurityConfig, SingleUserAuth, ValidAuthMethod, - WebhookPreferences + WebhookConfig } from '@typings-ce'; import { NextFunction, Request, Response } from 'express'; import { z } from 'zod'; import { rejectUnprocessableRequest } from '../../models/error.model.js'; -const WebhookPreferencesSchema: z.ZodType = z +const WebhookConfigSchema: z.ZodType = z .object({ enabled: z.boolean(), url: z @@ -48,17 +48,17 @@ const SingleUserAuthSchema: z.ZodType = z.object({ const ValidAuthMethodSchema: z.ZodType = SingleUserAuthSchema; -const AuthenticationPreferencesSchema: z.ZodType = z.object({ +const AuthenticationConfigSchema: z.ZodType = z.object({ authMethod: ValidAuthMethodSchema, authModeToAccessRoom: AuthModeSchema }); -const SecurityPreferencesSchema: z.ZodType = z.object({ - authentication: AuthenticationPreferencesSchema +const SecurityConfigSchema: z.ZodType = z.object({ + authentication: AuthenticationConfigSchema }); -export const validateWebhookPreferences = (req: Request, res: Response, next: NextFunction) => { - const { success, error, data } = WebhookPreferencesSchema.safeParse(req.body); +export const validateWebhookConfig = (req: Request, res: Response, next: NextFunction) => { + const { success, error, data } = WebhookConfigSchema.safeParse(req.body); if (!success) { return rejectUnprocessableRequest(res, error); @@ -79,8 +79,8 @@ export const withValidWebhookTestRequest = (req: Request, res: Response, next: N next(); }; -export const validateSecurityPreferences = (req: Request, res: Response, next: NextFunction) => { - const { success, error, data } = SecurityPreferencesSchema.safeParse(req.body); +export const validateSecurityConfig = (req: Request, res: Response, next: NextFunction) => { + const { success, error, data } = SecurityConfigSchema.safeParse(req.body); if (!success) { return rejectUnprocessableRequest(res, error); diff --git a/backend/src/middlewares/room.middleware.ts b/backend/src/middlewares/room.middleware.ts index 925872a..95beb1d 100644 --- a/backend/src/middlewares/room.middleware.ts +++ b/backend/src/middlewares/room.middleware.ts @@ -77,10 +77,10 @@ export const configureRecordingTokenAuth = async (req: Request, res: Response, n let authModeToAccessRoom: AuthMode; try { - const { securityPreferences } = await storageService.getGlobalPreferences(); - authModeToAccessRoom = securityPreferences.authentication.authModeToAccessRoom; + const { securityConfig } = await storageService.getGlobalConfig(); + authModeToAccessRoom = securityConfig.authentication.authModeToAccessRoom; } catch (error) { - return handleError(res, error, 'checking authentication preferences'); + return handleError(res, error, 'checking authentication config'); } const authValidators = []; diff --git a/backend/src/models/redis.model.ts b/backend/src/models/redis.model.ts index 509c430..04aa4f7 100644 --- a/backend/src/models/redis.model.ts +++ b/backend/src/models/redis.model.ts @@ -3,7 +3,7 @@ export const enum RedisKeyPrefix { } export const enum RedisKeyName { - GLOBAL_PREFERENCES = `${RedisKeyPrefix.BASE}global_preferences`, + GLOBAL_CONFIG = `${RedisKeyPrefix.BASE}global_config`, ROOM = `${RedisKeyPrefix.BASE}room:`, RECORDING = `${RedisKeyPrefix.BASE}recording:`, RECORDING_SECRETS = `${RedisKeyPrefix.BASE}recording_secrets:`, diff --git a/backend/src/routes/global-config.routes.ts b/backend/src/routes/global-config.routes.ts new file mode 100644 index 0000000..5ac9947 --- /dev/null +++ b/backend/src/routes/global-config.routes.ts @@ -0,0 +1,48 @@ +import { UserRole } from '@typings-ce'; +import bodyParser from 'body-parser'; +import { Router } from 'express'; +import * as appearanceConfigCtrl from '../controllers/global-config/appearance-config.controller.js'; +import * as securityConfigCtrl from '../controllers/global-config/security-config.controller.js'; +import * as webhookConfigCtrl from '../controllers/global-config/webhook-config.controller.js'; +import { + tokenAndRoleValidator, + validateSecurityConfig, + validateWebhookConfig, + withAuth, + withValidWebhookTestRequest +} from '../middlewares/index.js'; + +export const configRouter = Router(); +configRouter.use(bodyParser.urlencoded({ extended: true })); +configRouter.use(bodyParser.json()); + +// Webhook config +configRouter.put( + '/webhooks', + withAuth(tokenAndRoleValidator(UserRole.ADMIN)), + validateWebhookConfig, + webhookConfigCtrl.updateWebhookConfig +); +configRouter.get('/webhooks', withAuth(tokenAndRoleValidator(UserRole.ADMIN)), webhookConfigCtrl.getWebhookConfig); +configRouter.post('/webhooks/test', withValidWebhookTestRequest, webhookConfigCtrl.testWebhook); + +// Security config +configRouter.put( + '/security', + withAuth(tokenAndRoleValidator(UserRole.ADMIN)), + validateSecurityConfig, + securityConfigCtrl.updateSecurityConfig +); +configRouter.get('/security', securityConfigCtrl.getSecurityConfig); + +// Appearance config +configRouter.put( + '/appearance', + withAuth(tokenAndRoleValidator(UserRole.ADMIN)), + appearanceConfigCtrl.updateAppearanceConfig +); +configRouter.get( + '/appearance', + withAuth(tokenAndRoleValidator(UserRole.ADMIN)), + appearanceConfigCtrl.getAppearanceConfig +); diff --git a/backend/src/routes/global-preferences.routes.ts b/backend/src/routes/global-preferences.routes.ts deleted file mode 100644 index 8b7d1ad..0000000 --- a/backend/src/routes/global-preferences.routes.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { UserRole } from '@typings-ce'; -import bodyParser from 'body-parser'; -import { Router } from 'express'; -import * as appearancePrefCtrl from '../controllers/global-preferences/appearance-preferences.controller.js'; -import * as securityPrefCtrl from '../controllers/global-preferences/security-preferences.controller.js'; -import * as webhookPrefCtrl from '../controllers/global-preferences/webhook-preferences.controller.js'; -import { - tokenAndRoleValidator, - validateSecurityPreferences, - validateWebhookPreferences, - withAuth, - withValidWebhookTestRequest -} from '../middlewares/index.js'; - -export const preferencesRouter = Router(); -preferencesRouter.use(bodyParser.urlencoded({ extended: true })); -preferencesRouter.use(bodyParser.json()); - -// Webhook preferences -preferencesRouter.put( - '/webhooks', - withAuth(tokenAndRoleValidator(UserRole.ADMIN)), - validateWebhookPreferences, - webhookPrefCtrl.updateWebhookPreferences -); -preferencesRouter.get( - '/webhooks', - withAuth(tokenAndRoleValidator(UserRole.ADMIN)), - webhookPrefCtrl.getWebhookPreferences -); -preferencesRouter.post('/webhooks/test', withValidWebhookTestRequest, webhookPrefCtrl.testWebhook); - -// Security preferences -preferencesRouter.put( - '/security', - withAuth(tokenAndRoleValidator(UserRole.ADMIN)), - validateSecurityPreferences, - securityPrefCtrl.updateSecurityPreferences -); -preferencesRouter.get('/security', securityPrefCtrl.getSecurityPreferences); - -// Appearance preferences -preferencesRouter.put( - '/appearance', - withAuth(tokenAndRoleValidator(UserRole.ADMIN)), - appearancePrefCtrl.updateAppearancePreferences -); -preferencesRouter.get( - '/appearance', - withAuth(tokenAndRoleValidator(UserRole.ADMIN)), - appearancePrefCtrl.getAppearancePreferences -); diff --git a/backend/src/routes/index.ts b/backend/src/routes/index.ts index f2abe31..e087c3d 100644 --- a/backend/src/routes/index.ts +++ b/backend/src/routes/index.ts @@ -1,4 +1,4 @@ -export * from './global-preferences.routes.js'; +export * from './global-config.routes.js'; export * from './auth.routes.js'; export * from './user.routes.js'; export * from './room.routes.js'; diff --git a/backend/src/server.ts b/backend/src/server.ts index 9fc940e..c65a1c6 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -8,12 +8,12 @@ import { SERVER_CORS_ORIGIN, SERVER_PORT, logEnvVars } from './environment.js'; import { jsonSyntaxErrorHandler } from './middlewares/index.js'; import { authRouter, + configRouter, internalMeetingRouter, internalParticipantRouter, internalRecordingRouter, internalRoomRouter, livekitWebhookRouter, - preferencesRouter, recordingRouter, roomRouter, userRouter @@ -62,7 +62,7 @@ const createApp = () => { app.use(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/meetings`, internalMeetingRouter); app.use(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/participants`, internalParticipantRouter); app.use(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/recordings`, internalRecordingRouter); - app.use(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/preferences`, preferencesRouter); + app.use(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config`, configRouter); app.use('/health', (_req: Request, res: Response) => res.status(200).send('OK')); diff --git a/backend/src/services/openvidu-webhook.service.ts b/backend/src/services/openvidu-webhook.service.ts index 0eb1770..46d62c7 100644 --- a/backend/src/services/openvidu-webhook.service.ts +++ b/backend/src/services/openvidu-webhook.service.ts @@ -5,7 +5,7 @@ import { MeetWebhookEvent, MeetWebhookEventType, MeetWebhookPayload, - WebhookPreferences + WebhookConfig } from '@typings-ce'; import crypto from 'crypto'; import { inject, injectable } from 'inversify'; @@ -20,7 +20,7 @@ import { AuthService, LoggerService, MeetStorageService } from './index.js'; export class OpenViduWebhookService { constructor( @inject(LoggerService) protected logger: LoggerService, - @inject(MeetStorageService) protected globalPrefService: MeetStorageService, + @inject(MeetStorageService) protected storageService: MeetStorageService, @inject(AuthService) protected authService: AuthService ) {} @@ -153,9 +153,9 @@ export class OpenViduWebhookService { } protected async sendWebhookEvent(event: MeetWebhookEventType, payload: MeetWebhookPayload) { - const webhookPreferences = await this.getWebhookPreferences(); + const webhookConfig = await this.getWebhookConfig(); - if (!webhookPreferences.enabled) return; + if (!webhookConfig.enabled) return; const creationDate = Date.now(); const data: MeetWebhookEvent = { @@ -169,7 +169,7 @@ export class OpenViduWebhookService { try { const signature = await this.generateWebhookSignature(creationDate, data); - await this.fetchWithRetry(webhookPreferences.url!, { + await this.fetchWithRetry(webhookConfig.url!, { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -179,7 +179,7 @@ export class OpenViduWebhookService { body: JSON.stringify(data) }); } catch (error) { - this.logger.error(`Error sending webhook event ${data.event} to '${webhookPreferences.url}':`, error); + this.logger.error(`Error sending webhook event ${data.event} to '${webhookConfig.url}':`, error); throw error; } } @@ -309,12 +309,12 @@ export class OpenViduWebhookService { } } - protected async getWebhookPreferences(): Promise { + protected async getWebhookConfig(): Promise { try { - const { webhooksPreferences } = await this.globalPrefService.getGlobalPreferences(); - return webhooksPreferences; + const { webhooksConfig } = await this.storageService.getGlobalConfig(); + return webhooksConfig; } catch (error) { - this.logger.error('Error getting webhook preferences:', error); + this.logger.error('Error getting webhook config:', error); throw error; } } diff --git a/backend/src/services/storage/providers/s3/s3-storage-key.builder.ts b/backend/src/services/storage/providers/s3/s3-storage-key.builder.ts index 68737c3..babf185 100644 --- a/backend/src/services/storage/providers/s3/s3-storage-key.builder.ts +++ b/backend/src/services/storage/providers/s3/s3-storage-key.builder.ts @@ -3,8 +3,8 @@ import { RecordingHelper } from '../../../../helpers/recording.helper.js'; import { StorageKeyBuilder } from '../../storage.interface.js'; export class S3KeyBuilder implements StorageKeyBuilder { - buildGlobalPreferencesKey(): string { - return `global-preferences.json`; + buildGlobalConfigKey(): string { + return `global-config.json`; } buildMeetRoomKey(roomId: string): string { diff --git a/backend/src/services/storage/storage.factory.ts b/backend/src/services/storage/storage.factory.ts index d78c1b1..631e562 100644 --- a/backend/src/services/storage/storage.factory.ts +++ b/backend/src/services/storage/storage.factory.ts @@ -1,14 +1,14 @@ import { inject, injectable } from 'inversify'; +import { container, STORAGE_TYPES } from '../../config/dependency-injector.config.js'; import { LoggerService } from '../index.js'; import { StorageKeyBuilder, StorageProvider } from './storage.interface.js'; -import { container, STORAGE_TYPES } from '../../config/dependency-injector.config.js'; /** * Factory class responsible for creating the appropriate basic storage provider * based on configuration. * * This factory determines which basic storage implementation to use based on the - * `MEET_PREFERENCES_STORAGE_MODE` environment variable. It creates providers that + * `MEET_BLOB_STORAGE_MODE` environment variable. It creates providers that * handle only basic CRUD operations, following the Single Responsibility Principle. * * Domain-specific logic should be handled in the MeetStorageService layer. diff --git a/backend/src/services/storage/storage.interface.ts b/backend/src/services/storage/storage.interface.ts index 8ce1367..f4906ce 100644 --- a/backend/src/services/storage/storage.interface.ts +++ b/backend/src/services/storage/storage.interface.ts @@ -109,9 +109,9 @@ export interface StorageProvider { */ export interface StorageKeyBuilder { /** - * Builds the key for global preferences storage. + * Builds the key for global config storage. */ - buildGlobalPreferencesKey(): string; + buildGlobalConfigKey(): string; /** * Builds the key for a specific room. diff --git a/backend/src/services/storage/storage.service.ts b/backend/src/services/storage/storage.service.ts index 8090aff..d8bce00 100644 --- a/backend/src/services/storage/storage.service.ts +++ b/backend/src/services/storage/storage.service.ts @@ -1,13 +1,4 @@ -import { - AuthMode, - AuthType, - GlobalPreferences, - MeetApiKey, - MeetRecordingInfo, - MeetRoom, - User, - UserRole -} from '@typings-ce'; +import { AuthMode, AuthType, GlobalConfig, MeetApiKey, MeetRecordingInfo, MeetRoom, User, UserRole } from '@typings-ce'; import { inject, injectable } from 'inversify'; import ms from 'ms'; import { Readable } from 'stream'; @@ -35,21 +26,21 @@ import { StorageKeyBuilder, StorageProvider } from './storage.interface.js'; /** * Domain-specific storage service for OpenVidu Meet. * - * This service handles all domain-specific logic for rooms, recordings, and preferences, + * This service handles all domain-specific logic for rooms, recordings, and global config, * while delegating basic storage operations to the StorageProvider. * * This architecture follows the Single Responsibility Principle: * - StorageProvider: Handles only basic CRUD operations * - MeetStorageService: Handles domain-specific business logic * - * @template GPrefs - Type for global preferences, extends GlobalPreferences + * @template GConfig - Type for global config, extends GlobalConfig * @template MRoom - Type for room data, extends MeetRoom * @template MRec - Type for recording data, extends MeetRecordingInfo * @template MUser - Type for user data, extends User */ @injectable() export class MeetStorageService< - GPrefs extends GlobalPreferences = GlobalPreferences, + GConfig extends GlobalConfig = GlobalConfig, MRoom extends MeetRoom = MeetRoom, MRec extends MeetRecordingInfo = MeetRecordingInfo, MUser extends User = User @@ -104,7 +95,7 @@ export class MeetStorageService< /** * Initializes the storage with default data and initial environment variables if not already initialized. - * This includes global preferences, admin user and API key. + * This includes global config, admin user and API key. */ async initializeStorage(): Promise { try { @@ -127,7 +118,7 @@ export class MeetStorageService< this.logger.info('Storage not initialized or different project detected, proceeding with initialization'); - await this.initializeGlobalPreferences(); + await this.initializeGlobalConfig(); await this.initializeAdminUser(); await this.initializeApiKey(); @@ -139,32 +130,32 @@ export class MeetStorageService< } // ========================================== - // GLOBAL PREFERENCES DOMAIN LOGIC + // GLOBAL CONFIG DOMAIN LOGIC // ========================================== - async getGlobalPreferences(): Promise { - const redisKey = RedisKeyName.GLOBAL_PREFERENCES; - const storageKey = this.keyBuilder.buildGlobalPreferencesKey(); + async getGlobalConfig(): Promise { + const redisKey = RedisKeyName.GLOBAL_CONFIG; + const storageKey = this.keyBuilder.buildGlobalConfigKey(); - const preferences = await this.getFromCacheAndStorage(redisKey, storageKey); + const config = await this.getFromCacheAndStorage(redisKey, storageKey); - if (preferences) return preferences; + if (config) return config; - // Build and save default preferences if not found in cache or storage - await this.initializeGlobalPreferences(); - return this.getDefaultPreferences(); + // Build and save default config if not found in cache or storage + await this.initializeGlobalConfig(); + return this.getDefaultConfig(); } /** - * Saves global preferences to the storage provider. - * @param {GPrefs} preferences - The global preferences to save. - * @returns {Promise} The saved global preferences. + * Saves global config to the storage provider. + * @param {GConfig} config - The global config to save. + * @returns {Promise} The saved global config. */ - async saveGlobalPreferences(preferences: GPrefs): Promise { - this.logger.info('Saving global preferences'); - const redisKey = RedisKeyName.GLOBAL_PREFERENCES; - const storageKey = this.keyBuilder.buildGlobalPreferencesKey(); - return await this.saveCacheAndStorage(redisKey, storageKey, preferences); + async saveGlobalConfig(config: GConfig): Promise { + this.logger.info('Saving global config'); + const redisKey = RedisKeyName.GLOBAL_CONFIG; + const storageKey = this.keyBuilder.buildGlobalConfigKey(); + return await this.saveCacheAndStorage(redisKey, storageKey, config); } // ========================================== @@ -643,24 +634,24 @@ export class MeetStorageService< // ========================================== /** - * Checks if storage is already initialized by verifying that global preferences exist + * Checks if storage is already initialized by verifying that global config exist * and belong to the current project. * @returns {Promise} True if storage is already initialized for this project */ protected async checkStorageInitialization(): Promise { try { - const redisKey = RedisKeyName.GLOBAL_PREFERENCES; - const storageKey = this.keyBuilder.buildGlobalPreferencesKey(); + const redisKey = RedisKeyName.GLOBAL_CONFIG; + const storageKey = this.keyBuilder.buildGlobalConfigKey(); - const existing = await this.getFromCacheAndStorage(redisKey, storageKey); + const existing = await this.getFromCacheAndStorage(redisKey, storageKey); if (!existing) { - this.logger.verbose('No global preferences found, storage needs initialization'); + this.logger.verbose('No global config found, storage needs initialization'); return false; } // Check if it's from the same project - const existingProjectId = (existing as GlobalPreferences)?.projectId; + const existingProjectId = (existing as GlobalConfig)?.projectId; const currentProjectId = MEET_NAME_ID; if (existingProjectId !== currentProjectId) { @@ -679,26 +670,26 @@ export class MeetStorageService< } /** - * Initializes default global preferences if not already present. + * Initializes default global config if not already present. */ - protected async initializeGlobalPreferences(): Promise { - const preferences = this.getDefaultPreferences(); - await this.saveGlobalPreferences(preferences); - this.logger.info('Global preferences initialized with default values'); + protected async initializeGlobalConfig(): Promise { + const config = this.getDefaultConfig(); + await this.saveGlobalConfig(config); + this.logger.info('Global config initialized with default values'); } /** - * Returns the default global preferences. - * @returns {GPrefs} + * Returns the default global config. + * @returns {GConfig} */ - protected getDefaultPreferences(): GPrefs { + protected getDefaultConfig(): GConfig { return { projectId: MEET_NAME_ID, - webhooksPreferences: { + webhooksConfig: { enabled: MEET_INITIAL_WEBHOOK_ENABLED === 'true' && MEET_INITIAL_API_KEY, url: MEET_INITIAL_WEBHOOK_URL }, - securityPreferences: { + securityConfig: { authentication: { authMethod: { type: AuthType.SINGLE_USER @@ -706,7 +697,7 @@ export class MeetStorageService< authModeToAccessRoom: AuthMode.NONE } } - } as GPrefs; + } as GConfig; } /** diff --git a/backend/tests/helpers/request-helpers.ts b/backend/tests/helpers/request-helpers.ts index 03b6250..61d46e6 100644 --- a/backend/tests/helpers/request-helpers.ts +++ b/backend/tests/helpers/request-helpers.ts @@ -26,7 +26,7 @@ import { MeetRoomDeletionPolicyWithRecordings, MeetRoomOptions, ParticipantRole, - WebhookPreferences + WebhookConfig } from '../../src/typings/ce/index.js'; const CREDENTIALS = { @@ -77,47 +77,47 @@ export const getApiKeys = async () => { return response; }; -export const getAppearancePreferences = async () => { +export const getAppearanceConfig = async () => { checkAppIsRunning(); const adminCookie = await loginUser(); const response = await request(app) - .get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/preferences/appearance`) + .get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/appearance`) .set('Cookie', adminCookie) .send(); return response; }; -export const updateAppearancePreferences = async (preferences: any) => { +export const updateAppearanceConfig = async (config: any) => { checkAppIsRunning(); const adminCookie = await loginUser(); const response = await request(app) - .put(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/preferences/appearance`) + .put(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/appearance`) .set('Cookie', adminCookie) - .send(preferences); + .send(config); return response; }; -export const getWebbhookPreferences = async () => { +export const getWebbhookConfig = async () => { checkAppIsRunning(); const adminCookie = await loginUser(); const response = await request(app) - .get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/preferences/webhooks`) + .get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/webhooks`) .set('Cookie', adminCookie) .send(); return response; }; -export const updateWebbhookPreferences = async (preferences: WebhookPreferences) => { +export const updateWebbhookConfig = async (config: WebhookConfig) => { checkAppIsRunning(); const adminCookie = await loginUser(); const response = await request(app) - .put(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/preferences/webhooks`) + .put(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/webhooks`) .set('Cookie', adminCookie) - .send(preferences); + .send(config); return response; }; @@ -126,35 +126,35 @@ export const testWebhookUrl = async (url: string) => { checkAppIsRunning(); const response = await request(app) - .post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/preferences/webhooks/test`) + .post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/webhooks/test`) .send({ url }); return response; }; -export const getSecurityPreferences = async () => { +export const getSecurityConfig = async () => { checkAppIsRunning(); const adminCookie = await loginUser(); const response = await request(app) - .get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/preferences/security`) + .get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/security`) .set('Cookie', adminCookie) .send(); return response; }; -export const updateSecurityPreferences = async (preferences: any) => { +export const updateSecurityConfig = async (config: any) => { checkAppIsRunning(); const adminCookie = await loginUser(); const response = await request(app) - .put(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/preferences/security`) + .put(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/security`) .set('Cookie', adminCookie) - .send(preferences); + .send(config); return response; }; -export const changeSecurityPreferences = async (authMode: AuthMode) => { - const response = await updateSecurityPreferences({ +export const changeSecurityConfig = async (authMode: AuthMode) => { + const response = await updateSecurityConfig({ authentication: { authMethod: { type: AuthType.SINGLE_USER @@ -376,7 +376,7 @@ export const generateParticipantToken = async (participantOptions: any, cookie?: checkAppIsRunning(); // Disable authentication to generate the token - await changeSecurityPreferences(AuthMode.NONE); + await changeSecurityConfig(AuthMode.NONE); // Generate the participant token const response = await request(app) @@ -418,7 +418,7 @@ export const refreshParticipantToken = async (participantOptions: any, cookie: s checkAppIsRunning(); // Disable authentication to generate the token - await changeSecurityPreferences(AuthMode.NONE); + await changeSecurityConfig(AuthMode.NONE); const response = await request(app) .post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/participants/token/refresh`) @@ -580,7 +580,7 @@ export const generateRecordingToken = async (roomId: string, secret: string) => checkAppIsRunning(); // Disable authentication to generate the token - await changeSecurityPreferences(AuthMode.NONE); + await changeSecurityConfig(AuthMode.NONE); const response = await request(app) .post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/rooms/${roomId}/recording-token`) diff --git a/backend/tests/integration/api/global-preferences/appearance.test.ts b/backend/tests/integration/api/global-config/appearance.test.ts similarity index 54% rename from backend/tests/integration/api/global-preferences/appearance.test.ts rename to backend/tests/integration/api/global-config/appearance.test.ts index f36a562..f9dad97 100644 --- a/backend/tests/integration/api/global-preferences/appearance.test.ts +++ b/backend/tests/integration/api/global-config/appearance.test.ts @@ -1,25 +1,21 @@ import { beforeAll, describe, expect, it } from '@jest/globals'; -import { - getAppearancePreferences, - startTestServer, - updateAppearancePreferences -} from '../../../helpers/request-helpers.js'; +import { getAppearanceConfig, startTestServer, updateAppearanceConfig } from '../../../helpers/request-helpers.js'; describe('Appearance API Tests', () => { beforeAll(() => { startTestServer(); }); - describe('Get Appearance Preferences', () => { + describe('Get Appearance Config', () => { it('should return 402 status code as it is a PRO feature', async () => { - const response = await getAppearancePreferences(); + const response = await getAppearanceConfig(); expect(response.status).toBe(402); }); }); - describe('Update Appearance Preferences', () => { + describe('Update Appearance Config', () => { it('should return 402 status code as it is a PRO feature', async () => { - const response = await updateAppearancePreferences({}); + const response = await updateAppearanceConfig({}); expect(response.status).toBe(402); }); }); diff --git a/backend/tests/integration/api/global-preferences/security.test.ts b/backend/tests/integration/api/global-config/security.test.ts similarity index 61% rename from backend/tests/integration/api/global-preferences/security.test.ts rename to backend/tests/integration/api/global-config/security.test.ts index 1a37a1b..5afdf0f 100644 --- a/backend/tests/integration/api/global-preferences/security.test.ts +++ b/backend/tests/integration/api/global-config/security.test.ts @@ -3,13 +3,9 @@ import { container } from '../../../../src/config/dependency-injector.config.js' import { MeetStorageService } from '../../../../src/services/index.js'; import { AuthMode, AuthType } from '../../../../src/typings/ce/index.js'; import { expectValidationError } from '../../../helpers/assertion-helpers.js'; -import { - getSecurityPreferences, - startTestServer, - updateSecurityPreferences -} from '../../../helpers/request-helpers.js'; +import { getSecurityConfig, startTestServer, updateSecurityConfig } from '../../../helpers/request-helpers.js'; -const defaultPreferences = { +const defaultConfig = { authentication: { authMethod: { type: AuthType.SINGLE_USER @@ -18,23 +14,23 @@ const defaultPreferences = { } }; -const restoreDefaultGlobalPreferences = async () => { - const defaultPref = await container.get(MeetStorageService)['getDefaultPreferences'](); - await container.get(MeetStorageService).saveGlobalPreferences(defaultPref); +const restoreDefaultGlobalConfig = async () => { + const defaultGlobalConfig = await container.get(MeetStorageService)['getDefaultConfig'](); + await container.get(MeetStorageService).saveGlobalConfig(defaultGlobalConfig); }; -describe('Security Preferences API Tests', () => { +describe('Security Config API Tests', () => { beforeAll(async () => { startTestServer(); }); afterEach(async () => { - await restoreDefaultGlobalPreferences(); + await restoreDefaultGlobalConfig(); }); - describe('Update security preferences', () => { - it('should update security preferences with valid complete data', async () => { - const validPreferences = { + describe('Update security config', () => { + it('should update security config with valid complete data', async () => { + const validConfig = { authentication: { authMethod: { type: AuthType.SINGLE_USER @@ -42,20 +38,20 @@ describe('Security Preferences API Tests', () => { authModeToAccessRoom: AuthMode.ALL_USERS } }; - let response = await updateSecurityPreferences(validPreferences); + let response = await updateSecurityConfig(validConfig); expect(response.status).toBe(200); - expect(response.body.message).toBe('Security preferences updated successfully'); + expect(response.body.message).toBe('Security config updated successfully'); - response = await getSecurityPreferences(); + response = await getSecurityConfig(); expect(response.status).toBe(200); - expect(response.body).toEqual(validPreferences); + expect(response.body).toEqual(validConfig); }); }); - describe('Update security preferences validation', () => { + describe('Update security config validation', () => { it('should reject when authModeToAccessRoom is not a valid enum value', async () => { - const response = await updateSecurityPreferences({ + const response = await updateSecurityConfig({ authentication: { authMethod: { type: AuthType.SINGLE_USER @@ -72,7 +68,7 @@ describe('Security Preferences API Tests', () => { }); it('should reject when authType is not a valid enum value', async () => { - const response = await updateSecurityPreferences({ + const response = await updateSecurityConfig({ authentication: { authMethod: { type: 'invalid' @@ -89,14 +85,14 @@ describe('Security Preferences API Tests', () => { }); it('should reject when authModeToAccessRoom or authMethod are not provided', async () => { - let response = await updateSecurityPreferences({ + let response = await updateSecurityConfig({ authentication: { authMode: AuthMode.NONE } }); expectValidationError(response, 'authentication.authMethod', 'Required'); - response = await updateSecurityPreferences({ + response = await updateSecurityConfig({ authentication: { method: { type: AuthType.SINGLE_USER @@ -107,7 +103,7 @@ describe('Security Preferences API Tests', () => { }); it('should reject when authentication is not an object', async () => { - const response = await updateSecurityPreferences({ + const response = await updateSecurityConfig({ authentication: 'invalid' }); @@ -115,12 +111,12 @@ describe('Security Preferences API Tests', () => { }); }); - describe('Get security preferences', () => { - it('should return security preferences when authenticated as admin', async () => { - const response = await getSecurityPreferences(); + describe('Get security config', () => { + it('should return security config when authenticated as admin', async () => { + const response = await getSecurityConfig(); expect(response.status).toBe(200); - expect(response.body).toEqual(defaultPreferences); + expect(response.body).toEqual(defaultConfig); }); }); }); diff --git a/backend/tests/integration/api/global-preferences/webhook.test.ts b/backend/tests/integration/api/global-config/webhook.test.ts similarity index 63% rename from backend/tests/integration/api/global-preferences/webhook.test.ts rename to backend/tests/integration/api/global-config/webhook.test.ts index 9d01097..bae4aab 100644 --- a/backend/tests/integration/api/global-preferences/webhook.test.ts +++ b/backend/tests/integration/api/global-config/webhook.test.ts @@ -5,78 +5,78 @@ import { MEET_INITIAL_WEBHOOK_ENABLED, MEET_INITIAL_WEBHOOK_URL } from '../../.. import { MeetStorageService } from '../../../../src/services/index.js'; import { expectValidationError } from '../../../helpers/assertion-helpers.js'; import { - getWebbhookPreferences, + getWebbhookConfig, startTestServer, testWebhookUrl, - updateWebbhookPreferences + updateWebbhookConfig } from '../../../helpers/request-helpers.js'; import { startWebhookServer, stopWebhookServer } from '../../../helpers/test-scenarios.js'; -describe('Webhook Preferences API Tests', () => { +describe('Webhook Config API Tests', () => { beforeAll(() => { startTestServer(); }); afterEach(async () => { const storageService = container.get(MeetStorageService); - await storageService['initializeGlobalPreferences'](); + await storageService['initializeGlobalConfig'](); }); - describe('Update webhook preferences', () => { - it('should update webhook preferences with valid data', async () => { - const validPreferences = { + describe('Update webhook config', () => { + it('should update webhook config with valid data', async () => { + const validConfig = { enabled: true, url: 'https://example.com/webhook' }; - let response = await updateWebbhookPreferences(validPreferences); + let response = await updateWebbhookConfig(validConfig); expect(response.status).toBe(200); - expect(response.body.message).toBe('Webhooks preferences updated successfully'); + expect(response.body.message).toBe('Webhooks config updated successfully'); - response = await getWebbhookPreferences(); + response = await getWebbhookConfig(); expect(response.status).toBe(200); expect(response.body.enabled).toBe(true); - expect(response.body.url).toBe(validPreferences.url); - expect(response.body).toEqual(validPreferences); + expect(response.body.url).toBe(validConfig.url); + expect(response.body).toEqual(validConfig); }); it('should allow disabling webhooks', async () => { - const oldWebhookPreferences = await getWebbhookPreferences(); - expect(oldWebhookPreferences.status).toBe(200); + const oldWebhookConfig = await getWebbhookConfig(); + expect(oldWebhookConfig.status).toBe(200); - let response = await updateWebbhookPreferences({ + let response = await updateWebbhookConfig({ enabled: false }); expect(response.status).toBe(200); - expect(response.body.message).toBe('Webhooks preferences updated successfully'); + expect(response.body.message).toBe('Webhooks config updated successfully'); - response = await getWebbhookPreferences(); + response = await getWebbhookConfig(); expect(response.status).toBe(200); expect(response.body.enabled).toBe(false); - expect(response.body.url).toBe(oldWebhookPreferences.body.url); + expect(response.body.url).toBe(oldWebhookConfig.body.url); }); it('should update URL even when disabling webhooks', async () => { - const preference = { + const config = { enabled: false, url: 'https://newurl.com/webhook' }; - const response = await updateWebbhookPreferences(preference); + const response = await updateWebbhookConfig(config); expect(response.status).toBe(200); - expect(response.body.message).toBe('Webhooks preferences updated successfully'); + expect(response.body.message).toBe('Webhooks config updated successfully'); - const preferencesResponse = await getWebbhookPreferences(); - expect(preferencesResponse.status).toBe(200); - expect(preferencesResponse.body.enabled).toBe(preference.enabled); - expect(preferencesResponse.body.url).toBe(preference.url); + const configResponse = await getWebbhookConfig(); + expect(configResponse.status).toBe(200); + expect(configResponse.body.enabled).toBe(config.enabled); + expect(configResponse.body.url).toBe(config.url); }); }); - describe('Update webhook preferences validation', () => { + describe('Update webhook config validation', () => { it('should reject invalid webhook URL', async () => { - const response = await updateWebbhookPreferences({ + const response = await updateWebbhookConfig({ enabled: true, url: 'invalid-url' }); @@ -86,14 +86,14 @@ describe('Webhook Preferences API Tests', () => { }); it('should reject missing URL when webhooks are enabled', async () => { - const response = await updateWebbhookPreferences({ enabled: true }); + const response = await updateWebbhookConfig({ enabled: true }); expect(response.status).toBe(422); expectValidationError(response, 'url', 'URL is required when webhooks are enabled'); }); it('should reject non-http(s) URLs', async () => { - const response = await updateWebbhookPreferences({ + const response = await updateWebbhookConfig({ enabled: true, url: 'ftp://example.com/webhook' }); @@ -103,9 +103,9 @@ describe('Webhook Preferences API Tests', () => { }); }); - describe('Get webhook preferences', () => { - it('should return webhook preferences when authenticated as admin', async () => { - const response = await getWebbhookPreferences(); + describe('Get webhook config', () => { + it('should return webhook config when authenticated as admin', async () => { + const response = await getWebbhookConfig(); expect(response.status).toBe(200); expect(response.body).toEqual({ diff --git a/backend/tests/integration/api/rooms/get-room-preferences.test.ts b/backend/tests/integration/api/rooms/get-room-preferences.test.ts index 3b47741..801f116 100644 --- a/backend/tests/integration/api/rooms/get-room-preferences.test.ts +++ b/backend/tests/integration/api/rooms/get-room-preferences.test.ts @@ -34,7 +34,7 @@ describe('Room API Tests', () => { it('should retrieve custom room config', async () => { const payload = { - roomName: 'custom-prefs', + roomName: 'custom-config', config: { recording: { enabled: true, diff --git a/backend/tests/integration/api/rooms/get-room.test.ts b/backend/tests/integration/api/rooms/get-room.test.ts index 3b560b5..3ba4059 100644 --- a/backend/tests/integration/api/rooms/get-room.test.ts +++ b/backend/tests/integration/api/rooms/get-room.test.ts @@ -34,7 +34,7 @@ describe('Room API Tests', () => { it('should retrieve a room with custom config', async () => { const payload = { - roomName: 'custom-prefs', + roomName: 'custom-config', config: { recording: { enabled: true, @@ -50,7 +50,7 @@ describe('Room API Tests', () => { // Retrieve the room by its ID const response = await getRoom(roomId); - expectSuccessRoomResponse(response, 'custom-prefs', undefined, payload.config); + expectSuccessRoomResponse(response, 'custom-config', undefined, payload.config); }); it('should retrieve only specified fields when using fields parameter', async () => { diff --git a/backend/tests/integration/api/rooms/update-room-preferences.test.ts b/backend/tests/integration/api/rooms/update-room-preferences.test.ts index 60507b3..573899a 100644 --- a/backend/tests/integration/api/rooms/update-room-preferences.test.ts +++ b/backend/tests/integration/api/rooms/update-room-preferences.test.ts @@ -77,7 +77,7 @@ describe('Room API Tests', () => { expect(getResponse.body.config).toEqual(updatedConfig); }); - it('should allow partial preference updates', async () => { + it('should allow partial config updates', async () => { // Create a room first with all config enabled const createdRoom = await createRoom({ roomName: 'partial-update', @@ -91,7 +91,7 @@ describe('Room API Tests', () => { } }); - // Update only one preference + // Update only one config field const partialConfig = { recording: { enabled: false, diff --git a/backend/tests/integration/api/security/participant-security.test.ts b/backend/tests/integration/api/security/participant-security.test.ts index e08fc61..e7bc342 100644 --- a/backend/tests/integration/api/security/participant-security.test.ts +++ b/backend/tests/integration/api/security/participant-security.test.ts @@ -4,7 +4,7 @@ import request from 'supertest'; import INTERNAL_CONFIG from '../../../../src/config/internal-config.js'; import { AuthMode } from '../../../../src/typings/ce/index.js'; import { - changeSecurityPreferences, + changeSecurityConfig, deleteAllRooms, disconnectFakeParticipants, loginUser, @@ -39,7 +39,7 @@ describe('Participant API Security Tests', () => { }); it('should succeed when no authentication is required and participant is speaker', async () => { - await changeSecurityPreferences(AuthMode.NONE); + await changeSecurityConfig(AuthMode.NONE); const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({ roomId: roomData.room.roomId, @@ -50,7 +50,7 @@ describe('Participant API Security Tests', () => { }); it('should succeed when no authentication is required and participant is moderator', async () => { - await changeSecurityPreferences(AuthMode.NONE); + await changeSecurityConfig(AuthMode.NONE); const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({ roomId: roomData.room.roomId, @@ -61,7 +61,7 @@ describe('Participant API Security Tests', () => { }); it('should succeed when authentication is required for moderator and participant is speaker', async () => { - await changeSecurityPreferences(AuthMode.MODERATORS_ONLY); + await changeSecurityConfig(AuthMode.MODERATORS_ONLY); const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({ roomId: roomData.room.roomId, @@ -72,7 +72,7 @@ describe('Participant API Security Tests', () => { }); it('should succeed when authentication is required for moderator, participant is moderator and authenticated', async () => { - await changeSecurityPreferences(AuthMode.MODERATORS_ONLY); + await changeSecurityConfig(AuthMode.MODERATORS_ONLY); const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).set('Cookie', adminCookie).send({ roomId: roomData.room.roomId, @@ -83,7 +83,7 @@ describe('Participant API Security Tests', () => { }); it('should fail when authentication is required for moderator and participant is moderator but not authenticated', async () => { - await changeSecurityPreferences(AuthMode.MODERATORS_ONLY); + await changeSecurityConfig(AuthMode.MODERATORS_ONLY); const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({ roomId: roomData.room.roomId, @@ -94,7 +94,7 @@ describe('Participant API Security Tests', () => { }); it('should succeed when authentication is required for all users, participant is speaker and authenticated', async () => { - await changeSecurityPreferences(AuthMode.ALL_USERS); + await changeSecurityConfig(AuthMode.ALL_USERS); const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).set('Cookie', adminCookie).send({ roomId: roomData.room.roomId, @@ -105,7 +105,7 @@ describe('Participant API Security Tests', () => { }); it('should fail when authentication is required for all users and participant is speaker but not authenticated', async () => { - await changeSecurityPreferences(AuthMode.ALL_USERS); + await changeSecurityConfig(AuthMode.ALL_USERS); const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({ roomId: roomData.room.roomId, @@ -116,7 +116,7 @@ describe('Participant API Security Tests', () => { }); it('should succeed when authentication is required for all users, participant is moderator and authenticated', async () => { - await changeSecurityPreferences(AuthMode.ALL_USERS); + await changeSecurityConfig(AuthMode.ALL_USERS); const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).set('Cookie', adminCookie).send({ roomId: roomData.room.roomId, @@ -127,7 +127,7 @@ describe('Participant API Security Tests', () => { }); it('should fail when authentication is required for all users and participant is moderator but not authenticated', async () => { - await changeSecurityPreferences(AuthMode.ALL_USERS); + await changeSecurityConfig(AuthMode.ALL_USERS); const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({ roomId: roomData.room.roomId, @@ -154,7 +154,7 @@ describe('Participant API Security Tests', () => { }); it('should succeed when no authentication is required and participant is speaker', async () => { - await changeSecurityPreferences(AuthMode.NONE); + await changeSecurityConfig(AuthMode.NONE); const response = await request(app) .post(`${PARTICIPANTS_PATH}/token/refresh`) @@ -169,7 +169,7 @@ describe('Participant API Security Tests', () => { }); it('should succeed when no authentication is required and participant is moderator', async () => { - await changeSecurityPreferences(AuthMode.NONE); + await changeSecurityConfig(AuthMode.NONE); const response = await request(app) .post(`${PARTICIPANTS_PATH}/token/refresh`) @@ -184,7 +184,7 @@ describe('Participant API Security Tests', () => { }); it('should succeed when authentication is required for moderator and participant is speaker', async () => { - await changeSecurityPreferences(AuthMode.MODERATORS_ONLY); + await changeSecurityConfig(AuthMode.MODERATORS_ONLY); const response = await request(app) .post(`${PARTICIPANTS_PATH}/token/refresh`) @@ -199,7 +199,7 @@ describe('Participant API Security Tests', () => { }); it('should succeed when authentication is required for moderator, participant is moderator and authenticated', async () => { - await changeSecurityPreferences(AuthMode.MODERATORS_ONLY); + await changeSecurityConfig(AuthMode.MODERATORS_ONLY); const response = await request(app) .post(`${PARTICIPANTS_PATH}/token/refresh`) @@ -214,7 +214,7 @@ describe('Participant API Security Tests', () => { }); it('should fail when authentication is required for moderator and participant is moderator but not authenticated', async () => { - await changeSecurityPreferences(AuthMode.MODERATORS_ONLY); + await changeSecurityConfig(AuthMode.MODERATORS_ONLY); const response = await request(app) .post(`${PARTICIPANTS_PATH}/token/refresh`) @@ -229,7 +229,7 @@ describe('Participant API Security Tests', () => { }); it('should succeed when authentication is required for all users, participant is speaker and authenticated', async () => { - await changeSecurityPreferences(AuthMode.ALL_USERS); + await changeSecurityConfig(AuthMode.ALL_USERS); const response = await request(app) .post(`${PARTICIPANTS_PATH}/token/refresh`) @@ -244,7 +244,7 @@ describe('Participant API Security Tests', () => { }); it('should fail when authentication is required for all users and participant is speaker but not authenticated', async () => { - await changeSecurityPreferences(AuthMode.ALL_USERS); + await changeSecurityConfig(AuthMode.ALL_USERS); const response = await request(app) .post(`${PARTICIPANTS_PATH}/token/refresh`) @@ -259,7 +259,7 @@ describe('Participant API Security Tests', () => { }); it('should succeed when authentication is required for all users, participant is moderator and authenticated', async () => { - await changeSecurityPreferences(AuthMode.ALL_USERS); + await changeSecurityConfig(AuthMode.ALL_USERS); const response = await request(app) .post(`${PARTICIPANTS_PATH}/token/refresh`) @@ -274,7 +274,7 @@ describe('Participant API Security Tests', () => { }); it('should fail when authentication is required for all users and participant is moderator but not authenticated', async () => { - await changeSecurityPreferences(AuthMode.ALL_USERS); + await changeSecurityConfig(AuthMode.ALL_USERS); const response = await request(app) .post(`${PARTICIPANTS_PATH}/token/refresh`) diff --git a/backend/tests/integration/api/security/preferences-security.test.ts b/backend/tests/integration/api/security/preferences-security.test.ts index 2198143..26b9beb 100644 --- a/backend/tests/integration/api/security/preferences-security.test.ts +++ b/backend/tests/integration/api/security/preferences-security.test.ts @@ -6,9 +6,9 @@ import { MEET_INITIAL_API_KEY } from '../../../../src/environment.js'; import { AuthMode, AuthType } from '../../../../src/typings/ce/index.js'; import { loginUser, startTestServer } from '../../../helpers/request-helpers.js'; -const PREFERENCES_PATH = `${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/preferences`; +const CONFIG_PATH = `${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config`; -describe('Global Preferences API Security Tests', () => { +describe('Global Config API Security Tests', () => { let app: Express; let adminCookie: string; @@ -17,55 +17,55 @@ describe('Global Preferences API Security Tests', () => { adminCookie = await loginUser(); }); - describe('Update Webhook Preferences Tests', () => { - const webhookPreferences = { + describe('Update Webhook Config Tests', () => { + const webhookConfig = { enabled: true, url: 'https://example.com/webhook' }; it('should fail when request includes API key', async () => { const response = await request(app) - .put(`${PREFERENCES_PATH}/webhooks`) + .put(`${CONFIG_PATH}/webhooks`) .set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY) - .send(webhookPreferences); + .send(webhookConfig); expect(response.status).toBe(401); }); it('should succeed when user is authenticated as admin', async () => { const response = await request(app) - .put(`${PREFERENCES_PATH}/webhooks`) + .put(`${CONFIG_PATH}/webhooks`) .set('Cookie', adminCookie) - .send(webhookPreferences); + .send(webhookConfig); expect(response.status).toBe(200); }); it('should fail when user is not authenticated', async () => { - const response = await request(app).put(`${PREFERENCES_PATH}/webhooks`).send(webhookPreferences); + const response = await request(app).put(`${CONFIG_PATH}/webhooks`).send(webhookConfig); expect(response.status).toBe(401); }); }); - describe('Get Webhook Preferences Tests', () => { + describe('Get Webhook Config Tests', () => { it('should fail when request includes API key', async () => { const response = await request(app) - .get(`${PREFERENCES_PATH}/webhooks`) + .get(`${CONFIG_PATH}/webhooks`) .set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY); expect(response.status).toBe(401); }); it('should succeed when user is authenticated as admin', async () => { - const response = await request(app).get(`${PREFERENCES_PATH}/webhooks`).set('Cookie', adminCookie); + const response = await request(app).get(`${CONFIG_PATH}/webhooks`).set('Cookie', adminCookie); expect(response.status).toBe(200); }); it('should fail when user is not authenticated', async () => { - const response = await request(app).get(`${PREFERENCES_PATH}/webhooks`); + const response = await request(app).get(`${CONFIG_PATH}/webhooks`); expect(response.status).toBe(401); }); }); - describe('Update Security Preferences Tests', () => { - const securityPreferences = { + describe('Update Security Config Tests', () => { + const securityConfig = { authentication: { authMethod: { type: AuthType.SINGLE_USER @@ -76,71 +76,68 @@ describe('Global Preferences API Security Tests', () => { it('should fail when request includes API key', async () => { const response = await request(app) - .put(`${PREFERENCES_PATH}/security`) + .put(`${CONFIG_PATH}/security`) .set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY) - .send(securityPreferences); + .send(securityConfig); expect(response.status).toBe(401); }); it('should succeed when user is authenticated as admin', async () => { const response = await request(app) - .put(`${PREFERENCES_PATH}/security`) + .put(`${CONFIG_PATH}/security`) .set('Cookie', adminCookie) - .send(securityPreferences); + .send(securityConfig); expect(response.status).toBe(200); }); it('should fail when user is not authenticated', async () => { - const response = await request(app).put(`${PREFERENCES_PATH}/security`).send(securityPreferences); + const response = await request(app).put(`${CONFIG_PATH}/security`).send(securityConfig); expect(response.status).toBe(401); }); }); - describe('Get Security Preferences Tests', () => { + describe('Get Security Config Tests', () => { it('should succeed when user is not authenticated', async () => { - const response = await request(app).get(`${PREFERENCES_PATH}/security`); + const response = await request(app).get(`${CONFIG_PATH}/security`); expect(response.status).toBe(200); }); }); - describe('Update Appearance Preferences Tests', () => { + describe('Update Appearance Config Tests', () => { it('should fail when request includes API key', async () => { const response = await request(app) - .put(`${PREFERENCES_PATH}/appearance`) + .put(`${CONFIG_PATH}/appearance`) .set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY) .send({}); expect(response.status).toBe(401); }); it('should succeed when user is authenticated as admin', async () => { - const response = await request(app) - .put(`${PREFERENCES_PATH}/appearance`) - .set('Cookie', adminCookie) - .send({}); + const response = await request(app).put(`${CONFIG_PATH}/appearance`).set('Cookie', adminCookie).send({}); expect(response.status).toBe(402); // Assuming 402 is the expected status code for this case }); it('should fail when user is not authenticated', async () => { - const response = await request(app).put(`${PREFERENCES_PATH}/appearance`).send({}); + const response = await request(app).put(`${CONFIG_PATH}/appearance`).send({}); expect(response.status).toBe(401); }); }); - describe('Get Appearance Preferences Tests', () => { + describe('Get Appearance Config Tests', () => { it('should fail when request includes API key', async () => { const response = await request(app) - .get(`${PREFERENCES_PATH}/appearance`) + .get(`${CONFIG_PATH}/appearance`) .set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY); expect(response.status).toBe(401); }); it('should succeed when user is authenticated as admin', async () => { - const response = await request(app).get(`${PREFERENCES_PATH}/appearance`).set('Cookie', adminCookie); + const response = await request(app).get(`${CONFIG_PATH}/appearance`).set('Cookie', adminCookie); expect(response.status).toBe(402); // Assuming 402 is the expected status code for this case }); it('should fail when user is not authenticated', async () => { - const response = await request(app).get(`${PREFERENCES_PATH}/appearance`); + const response = await request(app).get(`${CONFIG_PATH}/appearance`); expect(response.status).toBe(401); }); }); diff --git a/backend/tests/integration/api/security/room-security.test.ts b/backend/tests/integration/api/security/room-security.test.ts index e486c56..ea593db 100644 --- a/backend/tests/integration/api/security/room-security.test.ts +++ b/backend/tests/integration/api/security/room-security.test.ts @@ -5,7 +5,7 @@ import INTERNAL_CONFIG from '../../../../src/config/internal-config.js'; import { MEET_INITIAL_API_KEY } from '../../../../src/environment.js'; import { AuthMode, MeetRecordingAccess, ParticipantRole } from '../../../../src/typings/ce/index.js'; import { - changeSecurityPreferences, + changeSecurityConfig, createRoom, deleteAllRecordings, deleteAllRooms, @@ -323,7 +323,7 @@ describe('Room API Security Tests', () => { }); it('should succeed when no authentication is required and participant is speaker', async () => { - await changeSecurityPreferences(AuthMode.NONE); + await changeSecurityConfig(AuthMode.NONE); const response = await request(app) .post(`${INTERNAL_ROOMS_PATH}/${roomData.room.roomId}/recording-token`) @@ -332,7 +332,7 @@ describe('Room API Security Tests', () => { }); it('should succeed when no authentication is required and participant is moderator', async () => { - await changeSecurityPreferences(AuthMode.NONE); + await changeSecurityConfig(AuthMode.NONE); const response = await request(app) .post(`${INTERNAL_ROOMS_PATH}/${roomData.room.roomId}/recording-token`) @@ -341,7 +341,7 @@ describe('Room API Security Tests', () => { }); it('should succeed when authentication is required for moderator and participant is speaker', async () => { - await changeSecurityPreferences(AuthMode.MODERATORS_ONLY); + await changeSecurityConfig(AuthMode.MODERATORS_ONLY); const response = await request(app) .post(`${INTERNAL_ROOMS_PATH}/${roomData.room.roomId}/recording-token`) @@ -350,7 +350,7 @@ describe('Room API Security Tests', () => { }); it('should succeed when authentication is required for moderator, participant is moderator and authenticated', async () => { - await changeSecurityPreferences(AuthMode.MODERATORS_ONLY); + await changeSecurityConfig(AuthMode.MODERATORS_ONLY); const response = await request(app) .post(`${INTERNAL_ROOMS_PATH}/${roomData.room.roomId}/recording-token`) @@ -360,7 +360,7 @@ describe('Room API Security Tests', () => { }); it('should fail when authentication is required for moderator and participant is moderator but not authenticated', async () => { - await changeSecurityPreferences(AuthMode.MODERATORS_ONLY); + await changeSecurityConfig(AuthMode.MODERATORS_ONLY); const response = await request(app) .post(`${INTERNAL_ROOMS_PATH}/${roomData.room.roomId}/recording-token`) @@ -369,7 +369,7 @@ describe('Room API Security Tests', () => { }); it('should succeed when authentication is required for all users, participant is speaker and authenticated', async () => { - await changeSecurityPreferences(AuthMode.ALL_USERS); + await changeSecurityConfig(AuthMode.ALL_USERS); const response = await request(app) .post(`${INTERNAL_ROOMS_PATH}/${roomData.room.roomId}/recording-token`) @@ -379,7 +379,7 @@ describe('Room API Security Tests', () => { }); it('should fail when authentication is required for all users and participant is speaker but not authenticated', async () => { - await changeSecurityPreferences(AuthMode.ALL_USERS); + await changeSecurityConfig(AuthMode.ALL_USERS); const response = await request(app) .post(`${INTERNAL_ROOMS_PATH}/${roomData.room.roomId}/recording-token`) @@ -388,7 +388,7 @@ describe('Room API Security Tests', () => { }); it('should succeed when authentication is required for all users, participant is moderator and authenticated', async () => { - await changeSecurityPreferences(AuthMode.ALL_USERS); + await changeSecurityConfig(AuthMode.ALL_USERS); const response = await request(app) .post(`${INTERNAL_ROOMS_PATH}/${roomData.room.roomId}/recording-token`) @@ -398,7 +398,7 @@ describe('Room API Security Tests', () => { }); it('should fail when authentication is required for all users and participant is moderator but not authenticated', async () => { - await changeSecurityPreferences(AuthMode.ALL_USERS); + await changeSecurityConfig(AuthMode.ALL_USERS); const response = await request(app) .post(`${INTERNAL_ROOMS_PATH}/${roomData.room.roomId}/recording-token`) diff --git a/backend/tests/integration/webhooks/webhook.test.ts b/backend/tests/integration/webhooks/webhook.test.ts index d1b5d48..8950ef7 100644 --- a/backend/tests/integration/webhooks/webhook.test.ts +++ b/backend/tests/integration/webhooks/webhook.test.ts @@ -13,7 +13,7 @@ import { endMeeting, sleep, startTestServer, - updateWebbhookPreferences + updateWebbhookConfig } from '../../helpers/request-helpers.js'; import { setupSingleRoom, @@ -41,8 +41,8 @@ describe('Webhook Integration Tests', () => { beforeEach(async () => { receivedWebhooks = []; - // Enable webhooks in global preferences - await updateWebbhookPreferences({ + // Enable webhooks in global config + await updateWebbhookConfig({ enabled: true, url: `http://localhost:5080/webhook` }); @@ -50,14 +50,14 @@ describe('Webhook Integration Tests', () => { afterAll(async () => { await stopWebhookServer(); - await storageService['initializeGlobalPreferences'](); + await storageService['initializeGlobalConfig'](); await disconnectFakeParticipants(); await Promise.all([deleteAllRooms(), deleteAllRecordings()]); }); it('should not send webhooks when disabled', async () => { - await updateWebbhookPreferences({ + await updateWebbhookConfig({ enabled: false }); diff --git a/frontend/projects/shared-meet-components/src/lib/components/dialogs/delete-room-dialog/delete-room-dialog.component.ts b/frontend/projects/shared-meet-components/src/lib/components/dialogs/delete-room-dialog/delete-room-dialog.component.ts index 39a09fa..e0bd709 100644 --- a/frontend/projects/shared-meet-components/src/lib/components/dialogs/delete-room-dialog/delete-room-dialog.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/components/dialogs/delete-room-dialog/delete-room-dialog.component.ts @@ -14,7 +14,7 @@ import type { DeleteRoomDialogOptions } from '@lib/models'; import { MeetRoomDeletionPolicyWithMeeting, MeetRoomDeletionPolicyWithRecordings } from '@lib/typings/ce'; @Component({ - selector: 'ov-dialog', + selector: 'ov-delete-room-dialog', standalone: true, imports: [ FormsModule, diff --git a/frontend/projects/shared-meet-components/src/lib/components/recording-lists/recording-lists.component.ts b/frontend/projects/shared-meet-components/src/lib/components/recording-lists/recording-lists.component.ts index 10f7888..85c938e 100644 --- a/frontend/projects/shared-meet-components/src/lib/components/recording-lists/recording-lists.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/components/recording-lists/recording-lists.component.ts @@ -14,9 +14,9 @@ import { MatSelectModule } from '@angular/material/select'; import { MatTableModule } from '@angular/material/table'; import { MatToolbarModule } from '@angular/material/toolbar'; import { MatTooltipModule } from '@angular/material/tooltip'; +import { ViewportService } from '@lib/services'; import { MeetRecordingInfo, MeetRecordingStatus } from '@lib/typings/ce'; import { formatBytes, formatDurationToHMS } from '@lib/utils'; -import { ViewportService } from '@lib/services'; export interface RecordingTableAction { recordings: MeetRecordingInfo[]; diff --git a/frontend/projects/shared-meet-components/src/lib/components/share-meeting-link/share-meeting-link.component.ts b/frontend/projects/shared-meet-components/src/lib/components/share-meeting-link/share-meeting-link.component.ts index 3c65647..a440069 100644 --- a/frontend/projects/shared-meet-components/src/lib/components/share-meeting-link/share-meeting-link.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/components/share-meeting-link/share-meeting-link.component.ts @@ -1,20 +1,20 @@ -import { Component, Input, Output, EventEmitter } from '@angular/core'; -import { MatButtonModule, MatIconButton } from '@angular/material/button'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; @Component({ selector: 'ov-share-meeting-link', standalone: true, - imports: [MatButtonModule, MatIconModule, MatIconButton], + imports: [MatButtonModule, MatIconModule], templateUrl: './share-meeting-link.component.html', styleUrl: './share-meeting-link.component.scss' }) export class ShareMeetingLinkComponent { - @Input() meetingUrl!: string; - @Input() title: string = 'Invite others with this meeting link'; - @Input() titleSize: 'sm' | 'md' | 'lg' | 'xl' = 'sm'; - @Input() titleWeight: 'light' | 'semibold' | 'bold' | 'normal' = 'normal'; - @Input() subtitle?: string; - @Input() additionalInfo?: string; - @Output() copyClicked = new EventEmitter(); + @Input() meetingUrl!: string; + @Input() title: string = 'Invite others with this meeting link'; + @Input() titleSize: 'sm' | 'md' | 'lg' | 'xl' = 'sm'; + @Input() titleWeight: 'light' | 'semibold' | 'bold' | 'normal' = 'normal'; + @Input() subtitle?: string; + @Input() additionalInfo?: string; + @Output() copyClicked = new EventEmitter(); } diff --git a/frontend/projects/shared-meet-components/src/lib/guards/auth.guard.ts b/frontend/projects/shared-meet-components/src/lib/guards/auth.guard.ts index 7bf2337..b081a66 100644 --- a/frontend/projects/shared-meet-components/src/lib/guards/auth.guard.ts +++ b/frontend/projects/shared-meet-components/src/lib/guards/auth.guard.ts @@ -3,7 +3,7 @@ import { ActivatedRouteSnapshot, CanActivateFn, RouterStateSnapshot } from '@ang import { ErrorReason } from '@lib/models'; import { AuthService, - GlobalPreferencesService, + GlobalConfigService, NavigationService, ParticipantService, RecordingService, @@ -53,7 +53,7 @@ export const checkParticipantRoleAndAuthGuard: CanActivateFn = async ( ) => { const navigationService = inject(NavigationService); const authService = inject(AuthService); - const preferencesService = inject(GlobalPreferencesService); + const configService = inject(GlobalConfigService); const roomService = inject(RoomService); const participantService = inject(ParticipantService); @@ -81,7 +81,7 @@ export const checkParticipantRoleAndAuthGuard: CanActivateFn = async ( } } - const authMode = await preferencesService.getAuthModeToAccessRoom(); + const authMode = await configService.getAuthModeToAccessRoom(); // If the user is a moderator and the room requires authentication for moderators only, // or if the room requires authentication for all users, diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/console.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/console/console.component.ts index 075e9af..431e473 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/console.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/console.component.ts @@ -4,7 +4,7 @@ import { ConsoleNavLink } from '@lib/models'; import { AuthService } from '@lib/services'; @Component({ - selector: 'app-console', + selector: 'ov-console', standalone: true, imports: [ConsoleNavComponent], templateUrl: './console.component.html', diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/developers/developers.component.html b/frontend/projects/shared-meet-components/src/lib/pages/console/embedded/embedded.component.html similarity index 100% rename from frontend/projects/shared-meet-components/src/lib/pages/console/developers/developers.component.html rename to frontend/projects/shared-meet-components/src/lib/pages/console/embedded/embedded.component.html diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/developers/developers.component.scss b/frontend/projects/shared-meet-components/src/lib/pages/console/embedded/embedded.component.scss similarity index 100% rename from frontend/projects/shared-meet-components/src/lib/pages/console/developers/developers.component.scss rename to frontend/projects/shared-meet-components/src/lib/pages/console/embedded/embedded.component.scss diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/developers/developers.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/console/embedded/embedded.component.ts similarity index 86% rename from frontend/projects/shared-meet-components/src/lib/pages/console/developers/developers.component.ts rename to frontend/projects/shared-meet-components/src/lib/pages/console/embedded/embedded.component.ts index 7964cb5..640ab52 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/developers/developers.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/embedded/embedded.component.ts @@ -9,11 +9,11 @@ import { MatInputModule } from '@angular/material/input'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; import { MatTooltipModule } from '@angular/material/tooltip'; -import { AuthService, GlobalPreferencesService, NotificationService } from '@lib/services'; +import { AuthService, GlobalConfigService, NotificationService } from '@lib/services'; import { MeetApiKey } from '@lib/typings/ce'; @Component({ - selector: 'ov-developers-settings', + selector: 'ov-embedded', standalone: true, imports: [ MatCardModule, @@ -26,10 +26,10 @@ import { MeetApiKey } from '@lib/typings/ce'; ReactiveFormsModule, MatProgressSpinnerModule ], - templateUrl: './developers.component.html', - styleUrl: './developers.component.scss' + templateUrl: './embedded.component.html', + styleUrl: './embedded.component.scss' }) -export class DevelopersSettingsComponent implements OnInit { +export class EmbeddedComponent implements OnInit { isLoading = signal(true); hasWebhookChanges = signal(false); @@ -51,7 +51,7 @@ export class DevelopersSettingsComponent implements OnInit { constructor( protected authService: AuthService, - protected preferencesService: GlobalPreferencesService, + protected configService: GlobalConfigService, protected notificationService: NotificationService, protected clipboard: Clipboard ) { @@ -164,16 +164,16 @@ export class DevelopersSettingsComponent implements OnInit { private async loadWebhookConfig() { try { - const webhookPreferences = await this.preferencesService.getWebhookPreferences(); + const webhookConfig = await this.configService.getWebhookConfig(); this.webhookForm.patchValue({ - isEnabled: webhookPreferences.enabled, - url: webhookPreferences.url - // roomCreated: webhookPreferences.events.roomCreated, - // roomDeleted: webhookPreferences.events.roomDeleted, - // participantJoined: webhookPreferences.events.participantJoined, - // participantLeft: webhookPreferences.events.participantLeft, - // recordingStarted: webhookPreferences.events.recordingStarted, - // recordingFinished: webhookPreferences.events.recordingFinished + isEnabled: webhookConfig.enabled, + url: webhookConfig.url + // roomCreated: webhookConfig.events.roomCreated, + // roomDeleted: webhookConfig.events.roomDeleted, + // participantJoined: webhookConfig.events.participantJoined, + // participantLeft: webhookConfig.events.participantLeft, + // recordingStarted: webhookConfig.events.recordingStarted, + // recordingFinished: webhookConfig.events.recordingFinished }); // Store initial values after loading @@ -199,7 +199,7 @@ export class DevelopersSettingsComponent implements OnInit { if (!this.webhookForm.valid) return; const formValue = this.webhookForm.value; - const webhookPreferences = { + const webhookConfig = { enabled: formValue.isEnabled!, url: formValue.url ?? undefined // events: { @@ -213,7 +213,7 @@ export class DevelopersSettingsComponent implements OnInit { }; try { - await this.preferencesService.saveWebhookPreferences(webhookPreferences); + await this.configService.saveWebhookConfig(webhookConfig); this.notificationService.showSnackbar('Webhook configuration saved successfully'); // Update initial values after successful save @@ -229,7 +229,7 @@ export class DevelopersSettingsComponent implements OnInit { const url = this.webhookForm.get('url')?.value; if (url) { try { - await this.preferencesService.testWebhookUrl(url); + await this.configService.testWebhookUrl(url); this.notificationService.showSnackbar('Test webhook sent successfully. Your URL is reachable.'); } catch (error: any) { const errorMessage = error.error?.message || error.message || 'Unknown error'; diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.html b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.html index cad976e..5ec5e63 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.html +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.html @@ -53,7 +53,7 @@ @switch (currentStep()?.id) { @case ('roomDetails') { - + } @case ('recording') { diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/recording-layout/recording-layout.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/recording-layout/recording-layout.component.ts index 3940b4a..5eb5691 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/recording-layout/recording-layout.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/recording-layout/recording-layout.component.ts @@ -39,7 +39,7 @@ export class RecordingLayoutComponent implements OnDestroy { description: 'Highlight the active speaker with other participants below', imageUrl: './assets/layouts/speaker.png', isPro: true, - disabled: true, + disabled: true // recommended: true }, { diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/recording-trigger/recording-trigger.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/recording-trigger/recording-trigger.component.ts index fc4f569..2da9b14 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/recording-trigger/recording-trigger.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/recording-trigger/recording-trigger.component.ts @@ -31,7 +31,7 @@ export class RecordingTriggerComponent implements OnDestroy { id: 'manual', title: 'Manual Recording', description: 'Start recording manually when needed', - icon: 'touch_app', + icon: 'touch_app' // recommended: true }, { diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-config/room-config.component.html b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-config/room-config.component.html index 33f3377..972ec16 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-config/room-config.component.html +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-config/room-config.component.html @@ -14,7 +14,7 @@
- +
@@ -38,7 +38,7 @@ - +
diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-config/room-config.component.scss b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-config/room-config.component.scss index 3bc46b8..03114a8 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-config/room-config.component.scss +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-config/room-config.component.scss @@ -59,7 +59,7 @@ } } - .preference-card { + .config-card { @include ov-card; border: 2px solid var(--ov-meet-border-secondary); transition: all 0.2s ease-in-out; @@ -155,7 +155,7 @@ grid-template-columns: 1fr; } - .preference-card { + .config-card { .card-header { flex-direction: column; align-items: flex-start; @@ -171,7 +171,7 @@ @media (max-width: 480px) { .room-config-step { - .preference-card { + .config-card { .card-header { .icon-title-group { .title-group { @@ -187,4 +187,4 @@ } } } -} \ No newline at end of file +} diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.ts index f87e0a0..5eb6e4f 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.ts @@ -18,7 +18,7 @@ import { import { Subject, takeUntil } from 'rxjs'; @Component({ - selector: 'ov-room-wizard-room-details', + selector: 'ov-room-details', standalone: true, imports: [ ReactiveFormsModule, diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/rooms.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/rooms.component.ts index 4b53541..a22f9b6 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/rooms.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/rooms.component.ts @@ -31,7 +31,7 @@ import { import { ILogger, LoggerService } from 'openvidu-components-angular'; @Component({ - selector: 'ov-room-config', + selector: 'ov-rooms', standalone: true, imports: [ MatListModule, diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/users-permissions/users-permissions.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/console/users-permissions/users-permissions.component.ts index 1f342b6..3cc423f 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/users-permissions/users-permissions.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/users-permissions/users-permissions.component.ts @@ -18,11 +18,11 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatSelectModule } from '@angular/material/select'; import { MatTooltipModule } from '@angular/material/tooltip'; import { ProFeatureBadgeComponent } from '@lib/components'; -import { AuthService, GlobalPreferencesService, NotificationService } from '@lib/services'; +import { AuthService, GlobalConfigService, NotificationService } from '@lib/services'; import { AuthMode } from '@lib/typings/ce'; @Component({ - selector: 'ov-preferences', + selector: 'ov-users-permissions', standalone: true, imports: [ MatCardModule, @@ -68,7 +68,7 @@ export class UsersPermissionsComponent implements OnInit { private initialAccessSettingsFormValue: any = null; constructor( - private preferencesService: GlobalPreferencesService, + private configService: GlobalConfigService, private authService: AuthService, private notificationService: NotificationService ) { @@ -129,15 +129,15 @@ export class UsersPermissionsComponent implements OnInit { private async loadAccessSettings() { try { - const authMode = await this.preferencesService.getAuthModeToAccessRoom(); + const authMode = await this.configService.getAuthModeToAccessRoom(); this.accessSettingsForm.get('authModeToAccessRoom')?.setValue(authMode); // Store initial values after loading this.initialAccessSettingsFormValue = this.accessSettingsForm.value; this.hasAccessSettingsChanges.set(false); } catch (error) { - console.error('Error loading security preferences:', error); - this.notificationService.showSnackbar('Failed to load security preferences'); + console.error('Error loading security config:', error); + this.notificationService.showSnackbar('Failed to load security config'); } } @@ -220,10 +220,10 @@ export class UsersPermissionsComponent implements OnInit { const formData = this.accessSettingsForm.value; try { - const securityPrefs = await this.preferencesService.getSecurityPreferences(); - securityPrefs.authentication.authModeToAccessRoom = formData.authModeToAccessRoom!; + const securityConfig = await this.configService.getSecurityConfig(); + securityConfig.authentication.authModeToAccessRoom = formData.authModeToAccessRoom!; - await this.preferencesService.saveSecurityPreferences(securityPrefs); + await this.configService.saveSecurityConfig(securityConfig); this.notificationService.showSnackbar('Access & Permissions settings saved successfully'); // Update initial values after successful save diff --git a/frontend/projects/shared-meet-components/src/lib/pages/index.ts b/frontend/projects/shared-meet-components/src/lib/pages/index.ts index 18f198c..8852c6d 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/index.ts +++ b/frontend/projects/shared-meet-components/src/lib/pages/index.ts @@ -1,6 +1,6 @@ export * from './console/console.component'; export * from './console/about/about.component'; -export * from './console/developers/developers.component'; +export * from './console/embedded/embedded.component'; export * from './console/overview/overview.component'; export * from './console/recordings/recordings.component'; export * from './console/rooms/rooms.component'; diff --git a/frontend/projects/shared-meet-components/src/lib/pages/meeting/meeting.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/meeting/meeting.component.ts index 81eeb32..59bdec7 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/meeting/meeting.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/pages/meeting/meeting.component.ts @@ -61,7 +61,7 @@ import { import { combineLatest, Subject, takeUntil } from 'rxjs'; @Component({ - selector: 'app-meeting', + selector: 'ov-meeting', templateUrl: './meeting.component.html', styleUrls: ['./meeting.component.scss'], standalone: true, diff --git a/frontend/projects/shared-meet-components/src/lib/pages/room-recordings/room-recordings.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/room-recordings/room-recordings.component.ts index e01d8f2..2dc6c92 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/room-recordings/room-recordings.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/pages/room-recordings/room-recordings.component.ts @@ -10,7 +10,7 @@ import { MeetRecordingFilters, MeetRecordingInfo } from '@lib/typings/ce'; import { ILogger, LoggerService } from 'openvidu-components-angular'; @Component({ - selector: 'app-room-recordings', + selector: 'ov-room-recordings', templateUrl: './room-recordings.component.html', styleUrls: ['./room-recordings.component.scss'], standalone: true, diff --git a/frontend/projects/shared-meet-components/src/lib/routes/base-routes.ts b/frontend/projects/shared-meet-components/src/lib/routes/base-routes.ts index 9213120..de9a9dd 100644 --- a/frontend/projects/shared-meet-components/src/lib/routes/base-routes.ts +++ b/frontend/projects/shared-meet-components/src/lib/routes/base-routes.ts @@ -13,7 +13,7 @@ import { } from '@lib/guards'; import { ConsoleComponent, - DevelopersSettingsComponent, + EmbeddedComponent, EndMeetingComponent, ErrorComponent, LoginComponent, @@ -96,7 +96,7 @@ export const baseRoutes: Routes = [ }, { path: 'embedded', - component: DevelopersSettingsComponent + component: EmbeddedComponent }, { path: 'users-permissions', diff --git a/frontend/projects/shared-meet-components/src/lib/services/feature-configuration.service.ts b/frontend/projects/shared-meet-components/src/lib/services/feature-configuration.service.ts index 943ee8b..bbe5174 100644 --- a/frontend/projects/shared-meet-components/src/lib/services/feature-configuration.service.ts +++ b/frontend/projects/shared-meet-components/src/lib/services/feature-configuration.service.ts @@ -128,7 +128,7 @@ export class FeatureConfigurationService { * Core logic to calculate features based on all configurations */ protected calculateFeatures( - roomPrefs?: MeetRoomConfig, + roomConfig?: MeetRoomConfig, participantPerms?: ParticipantPermissions, role?: ParticipantRole, recordingPerms?: RecordingPermissions @@ -137,10 +137,10 @@ export class FeatureConfigurationService { const features: ApplicationFeatures = { ...DEFAULT_FEATURES }; // Apply room configurations - if (roomPrefs) { - features.showRecordingPanel = roomPrefs.recording.enabled; - features.showChat = roomPrefs.chat.enabled; - features.showBackgrounds = roomPrefs.virtualBackground.enabled; + if (roomConfig) { + features.showRecordingPanel = roomConfig.recording.enabled; + features.showChat = roomConfig.chat.enabled; + features.showBackgrounds = roomConfig.virtualBackground.enabled; } // Apply participant permissions (these can restrict enabled features) diff --git a/frontend/projects/shared-meet-components/src/lib/services/global-config.service.ts b/frontend/projects/shared-meet-components/src/lib/services/global-config.service.ts new file mode 100644 index 0000000..0a441f1 --- /dev/null +++ b/frontend/projects/shared-meet-components/src/lib/services/global-config.service.ts @@ -0,0 +1,68 @@ +import { Injectable } from '@angular/core'; +import { HttpService } from '@lib/services'; +import { AuthMode, SecurityConfig, WebhookConfig } from '@lib/typings/ce'; +import { LoggerService } from 'openvidu-components-angular'; + +@Injectable({ + providedIn: 'root' +}) +export class GlobalConfigService { + protected readonly GLOBAL_CONFIG_API = `${HttpService.INTERNAL_API_PATH_PREFIX}/config`; + + protected securityConfig?: SecurityConfig; + + protected log; + + constructor( + protected loggerService: LoggerService, + protected httpService: HttpService + ) { + this.log = this.loggerService.get('OpenVidu Meet - GlobalConfigService'); + } + + async getSecurityConfig(forceRefresh = false): Promise { + if (this.securityConfig && !forceRefresh) { + return this.securityConfig; + } + + try { + const path = `${this.GLOBAL_CONFIG_API}/security`; + this.securityConfig = await this.httpService.getRequest(path); + return this.securityConfig; + } catch (error) { + this.log.e('Error fetching security config:', error); + throw error; + } + } + + async getAuthModeToAccessRoom(): Promise { + await this.getSecurityConfig(); + return this.securityConfig!.authentication.authModeToAccessRoom; + } + + async saveSecurityConfig(config: SecurityConfig) { + const path = `${this.GLOBAL_CONFIG_API}/security`; + await this.httpService.putRequest(path, config); + this.securityConfig = config; + } + + async getWebhookConfig(): Promise { + try { + const path = `${this.GLOBAL_CONFIG_API}/webhooks`; + return await this.httpService.getRequest(path); + } catch (error) { + this.log.e('Error fetching webhook config:', error); + throw error; + } + } + + async saveWebhookConfig(config: WebhookConfig) { + const path = `${this.GLOBAL_CONFIG_API}/webhooks`; + await this.httpService.putRequest(path, config); + } + + async testWebhookUrl(url: string): Promise { + const path = `${this.GLOBAL_CONFIG_API}/webhooks/test`; + await this.httpService.postRequest(path, { url }); + } +} diff --git a/frontend/projects/shared-meet-components/src/lib/services/global-preferences.service.ts b/frontend/projects/shared-meet-components/src/lib/services/global-preferences.service.ts deleted file mode 100644 index 19fddfc..0000000 --- a/frontend/projects/shared-meet-components/src/lib/services/global-preferences.service.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpService } from '@lib/services'; -import { AuthMode, SecurityPreferences, WebhookPreferences } from '@lib/typings/ce'; -import { LoggerService } from 'openvidu-components-angular'; - -@Injectable({ - providedIn: 'root' -}) -export class GlobalPreferencesService { - protected readonly PREFERENCES_API = `${HttpService.INTERNAL_API_PATH_PREFIX}/preferences`; - - protected securityPreferences?: SecurityPreferences; - - protected log; - - constructor( - protected loggerService: LoggerService, - protected httpService: HttpService - ) { - this.log = this.loggerService.get('OpenVidu Meet - GlobalPreferencesService'); - } - - async getSecurityPreferences(forceRefresh = false): Promise { - if (this.securityPreferences && !forceRefresh) { - return this.securityPreferences; - } - - try { - const path = `${this.PREFERENCES_API}/security`; - this.securityPreferences = await this.httpService.getRequest(path); - return this.securityPreferences; - } catch (error) { - this.log.e('Error fetching security preferences:', error); - throw error; - } - } - - async getAuthModeToAccessRoom(): Promise { - await this.getSecurityPreferences(); - return this.securityPreferences!.authentication.authModeToAccessRoom; - } - - async saveSecurityPreferences(preferences: SecurityPreferences) { - const path = `${this.PREFERENCES_API}/security`; - await this.httpService.putRequest(path, preferences); - this.securityPreferences = preferences; - } - - async getWebhookPreferences(): Promise { - try { - const path = `${this.PREFERENCES_API}/webhooks`; - return await this.httpService.getRequest(path); - } catch (error) { - this.log.e('Error fetching webhook preferences:', error); - throw error; - } - } - - async saveWebhookPreferences(preferences: WebhookPreferences) { - const path = `${this.PREFERENCES_API}/webhooks`; - await this.httpService.putRequest(path, preferences); - } - - async testWebhookUrl(url: string): Promise { - const path = `${this.PREFERENCES_API}/webhooks/test`; - await this.httpService.postRequest(path, { url }); - } -} diff --git a/frontend/projects/shared-meet-components/src/lib/services/index.ts b/frontend/projects/shared-meet-components/src/lib/services/index.ts index 04e0133..a1101ad 100644 --- a/frontend/projects/shared-meet-components/src/lib/services/index.ts +++ b/frontend/projects/shared-meet-components/src/lib/services/index.ts @@ -1,7 +1,7 @@ export * from './app-data.service'; export * from './http.service'; export * from './auth.service'; -export * from './global-preferences.service'; +export * from './global-config.service'; export * from './room.service'; export * from './participant.service'; export * from './meeting.service'; diff --git a/frontend/projects/shared-meet-components/src/lib/services/viewport.service.ts b/frontend/projects/shared-meet-components/src/lib/services/viewport.service.ts index 660ca22..6cb596d 100644 --- a/frontend/projects/shared-meet-components/src/lib/services/viewport.service.ts +++ b/frontend/projects/shared-meet-components/src/lib/services/viewport.service.ts @@ -1,5 +1,5 @@ -import { Injectable, signal, computed, OnDestroy } from '@angular/core'; -import { fromEvent, Subject, debounceTime, distinctUntilChanged } from 'rxjs'; +import { computed, Injectable, OnDestroy, signal } from '@angular/core'; +import { debounceTime, distinctUntilChanged, fromEvent, Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; /** @@ -256,4 +256,4 @@ export class ViewportService implements OnDestroy { this.destroy$.next(); this.destroy$.complete(); } -} \ No newline at end of file +} diff --git a/frontend/webcomponent/tests/e2e/recording-access.test.ts b/frontend/webcomponent/tests/e2e/recording-access.test.ts index 6af34b8..e9a6d38 100644 --- a/frontend/webcomponent/tests/e2e/recording-access.test.ts +++ b/frontend/webcomponent/tests/e2e/recording-access.test.ts @@ -131,7 +131,7 @@ test.describe('Recording Access Tests', () => { await prepareForJoiningRoom(page, MEET_TESTAPP_URL, roomId); await viewRecordingsAs('moderator', page); - await waitForElementInIframe(page, 'app-room-recordings', { state: 'visible' }); + await waitForElementInIframe(page, 'ov-room-recordings', { state: 'visible' }); }); test('should speaker not be able to access recording when access level is set to moderator', async ({ page }) => { @@ -155,7 +155,7 @@ test.describe('Recording Access Tests', () => { await waitForElementInIframe(page, '#view-recordings-btn', { state: 'hidden' }); }); - test('should allow moderators to access recording when access level is set to speaker', async ({ page }) => { + test('should allow moderator to access recording when access level is set to speaker', async ({ page }) => { await updateRoomConfig( roomId, { @@ -173,7 +173,7 @@ test.describe('Recording Access Tests', () => { await prepareForJoiningRoom(page, MEET_TESTAPP_URL, roomId); await viewRecordingsAs('moderator', page); - await waitForElementInIframe(page, 'app-room-recordings', { state: 'visible' }); + await waitForElementInIframe(page, 'ov-room-recordings', { state: 'visible' }); }); test('should allow speaker to access recording when access level is set to speaker', async ({ page }) => { @@ -194,6 +194,6 @@ test.describe('Recording Access Tests', () => { await prepareForJoiningRoom(page, MEET_TESTAPP_URL, roomId); await viewRecordingsAs('speaker', page); - await waitForElementInIframe(page, 'app-room-recordings', { state: 'visible' }); + await waitForElementInIframe(page, 'ov-room-recordings', { state: 'visible' }); }); }); diff --git a/typings/src/auth-preferences.ts b/typings/src/auth-config.ts similarity index 97% rename from typings/src/auth-preferences.ts rename to typings/src/auth-config.ts index 76388bb..96ea75c 100644 --- a/typings/src/auth-preferences.ts +++ b/typings/src/auth-config.ts @@ -1,4 +1,4 @@ -export interface AuthenticationPreferences { +export interface AuthenticationConfig { authMethod: ValidAuthMethod; authModeToAccessRoom: AuthMode; } diff --git a/typings/src/global-config.ts b/typings/src/global-config.ts new file mode 100644 index 0000000..fa523ad --- /dev/null +++ b/typings/src/global-config.ts @@ -0,0 +1,21 @@ +import { AuthenticationConfig } from './auth-config.js'; + +/** + * Represents global config for OpenVidu Meet. + */ +export interface GlobalConfig { + projectId: string; + securityConfig: SecurityConfig; + webhooksConfig: WebhookConfig; + // roomsConfig: MeetRoomConfig; +} + +export interface WebhookConfig { + enabled: boolean; + url?: string; + // events: WebhookEvent[]; +} + +export interface SecurityConfig { + authentication: AuthenticationConfig; +} diff --git a/typings/src/global-preferences.ts b/typings/src/global-preferences.ts deleted file mode 100644 index 80851a4..0000000 --- a/typings/src/global-preferences.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { AuthenticationPreferences } from './auth-preferences.js'; - -/** - * Represents global preferences for OpenVidu Meet. - */ -export interface GlobalPreferences { - projectId: string; - // roomFeaturesPreferences: RoomFeaturesPreferences; - webhooksPreferences: WebhookPreferences; - securityPreferences: SecurityPreferences; -} - -export interface WebhookPreferences { - enabled: boolean; - url?: string; - // events: WebhookEvent[]; -} - -export interface SecurityPreferences { - authentication: AuthenticationPreferences; -} diff --git a/typings/src/index.ts b/typings/src/index.ts index 13f4856..8744bd8 100644 --- a/typings/src/index.ts +++ b/typings/src/index.ts @@ -1,6 +1,6 @@ export * from './api-key.js'; -export * from './auth-preferences.js'; -export * from './global-preferences.js'; +export * from './auth-config.js'; +export * from './global-config.js'; export * from './permissions/livekit-permissions.js'; export * from './permissions/openvidu-permissions.js';