mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-06-23 16:05:09 +00:00
Compare commits
1 Commits
9b448d99cb
...
33c0b74b1f
Author | SHA1 | Date | |
---|---|---|---|
![]() |
33c0b74b1f |
33
.github/actions/setup-bot/action.yml
vendored
33
.github/actions/setup-bot/action.yml
vendored
@ -1,33 +0,0 @@
|
|||||||
name: 'Setup GitHub App Bot'
|
|
||||||
description: 'Generates a GitHub App Token and configures Git for a bot'
|
|
||||||
inputs:
|
|
||||||
app-id:
|
|
||||||
description: 'GitHub App ID'
|
|
||||||
required: True
|
|
||||||
private-key:
|
|
||||||
description: 'GitHub App Private Key'
|
|
||||||
required: True
|
|
||||||
outputs:
|
|
||||||
token:
|
|
||||||
description: 'Generated GitHub App Token'
|
|
||||||
value: ${{ steps.generate-token.outputs.token }}
|
|
||||||
committer:
|
|
||||||
description: 'Committer string for Git'
|
|
||||||
value: "${{ steps.generate-token.outputs.app-slug }}[bot] <${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com>"
|
|
||||||
app-slug:
|
|
||||||
description: 'GitHub App slug'
|
|
||||||
value: ${{ steps.generate-token.outputs.app-slug }}
|
|
||||||
runs:
|
|
||||||
using: 'composite'
|
|
||||||
steps:
|
|
||||||
- name: Generate a GitHub App Token
|
|
||||||
id: generate-token
|
|
||||||
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
|
|
||||||
with:
|
|
||||||
app-id: ${{ inputs.app-id }}
|
|
||||||
private-key: ${{ inputs.private-key }}
|
|
||||||
- name: Configure Git
|
|
||||||
run: |
|
|
||||||
git config --global user.name "${{ steps.generate-token.outputs.app-slug }}[bot]"
|
|
||||||
git config --global user.email "${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com"
|
|
||||||
shell: bash
|
|
12
.github/workflows/check_properties.yml
vendored
12
.github/workflows/check_properties.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
issues: write # Allow posting comments on issues/PRs
|
issues: write # Allow posting comments on issues/PRs
|
||||||
pull-requests: write # Allow writing to pull requests
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
|
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
|
||||||
@ -25,12 +25,10 @@ jobs:
|
|||||||
- name: Checkout main branch first
|
- name: Checkout main branch first
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Setup GitHub App Bot
|
- name: Set up Python
|
||||||
id: setup-bot
|
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||||
uses: ./.github/actions/setup-bot
|
|
||||||
with:
|
with:
|
||||||
app-id: ${{ secrets.GH_APP_ID }}
|
python-version: "3.12"
|
||||||
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Get PR data
|
- name: Get PR data
|
||||||
id: get-pr-data
|
id: get-pr-data
|
||||||
@ -221,7 +219,7 @@ jobs:
|
|||||||
const comment = comments.data.find(c => c.body.includes("## 🚀 Translation Verification Summary"));
|
const comment = comments.data.find(c => c.body.includes("## 🚀 Translation Verification Summary"));
|
||||||
|
|
||||||
// Only update or create comments by the action user
|
// Only update or create comments by the action user
|
||||||
const expectedActor = "${{ steps.setup-bot.outputs.app-slug }}[bot]";
|
const expectedActor = "github-actions[bot]";
|
||||||
|
|
||||||
if (comment && comment.user.login === expectedActor) {
|
if (comment && comment.user.login === expectedActor) {
|
||||||
// Update existing comment
|
// Update existing comment
|
||||||
|
44
.github/workflows/licenses-update.yml
vendored
44
.github/workflows/licenses-update.yml
vendored
@ -16,50 +16,52 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
repository-projects: write # Required for enabling automerge
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
|
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- name: Check out code
|
- name: Generate GitHub App Token
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
id: generate-token
|
||||||
with:
|
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Setup GitHub App Bot
|
|
||||||
id: setup-bot
|
|
||||||
uses: ./.github/actions/setup-bot
|
|
||||||
with:
|
with:
|
||||||
app-id: ${{ secrets.GH_APP_ID }}
|
app-id: ${{ secrets.GH_APP_ID }}
|
||||||
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
||||||
|
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Set up JDK 17
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
|
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
|
||||||
with:
|
with:
|
||||||
java-version: "17"
|
java-version: "17"
|
||||||
distribution: "adopt"
|
distribution: "adopt"
|
||||||
|
|
||||||
- name: Setup Gradle
|
- uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0
|
||||||
uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0
|
|
||||||
|
|
||||||
- name: Check licenses for compatibility
|
- name: check the licenses for compatibility
|
||||||
run: ./gradlew clean checkLicense
|
run: ./gradlew clean checkLicense
|
||||||
|
|
||||||
- name: Upload artifact on failure
|
- name: FAILED - check the licenses for compatibility
|
||||||
if: failure()
|
if: failure()
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||||
with:
|
with:
|
||||||
name: dependencies-without-allowed-license.json
|
name: dependencies-without-allowed-license.json
|
||||||
path: build/reports/dependency-license/dependencies-without-allowed-license.json
|
path: |
|
||||||
|
build/reports/dependency-license/dependencies-without-allowed-license.json
|
||||||
retention-days: 3
|
retention-days: 3
|
||||||
|
|
||||||
- name: Move and rename license file
|
- name: Move and Rename License File
|
||||||
run: |
|
run: |
|
||||||
mv build/reports/dependency-license/index.json src/main/resources/static/3rdPartyLicenses.json
|
mv build/reports/dependency-license/index.json src/main/resources/static/3rdPartyLicenses.json
|
||||||
|
|
||||||
- name: Commit changes
|
- name: Set up git config
|
||||||
|
run: |
|
||||||
|
git config --global user.name "stirlingbot[bot]"
|
||||||
|
git config --global user.email "1113334+stirlingbot[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
|
- name: Run git add
|
||||||
run: |
|
run: |
|
||||||
git add src/main/resources/static/3rdPartyLicenses.json
|
git add src/main/resources/static/3rdPartyLicenses.json
|
||||||
git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
|
git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
|
||||||
@ -69,15 +71,15 @@ jobs:
|
|||||||
if: env.CHANGES_DETECTED == 'true'
|
if: env.CHANGES_DETECTED == 'true'
|
||||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
||||||
with:
|
with:
|
||||||
token: ${{ steps.setup-bot.outputs.token }}
|
token: ${{ steps.generate-token.outputs.token }}
|
||||||
commit-message: "Update 3rd Party Licenses"
|
commit-message: "Update 3rd Party Licenses"
|
||||||
committer: ${{ steps.setup-bot.outputs.committer }}
|
committer: "stirlingbot[bot] <1113334+stirlingbot[bot]@users.noreply.github.com>"
|
||||||
author: ${{ steps.setup-bot.outputs.committer }}
|
author: "stirlingbot[bot] <1113334+stirlingbot[bot]@users.noreply.github.com>"
|
||||||
signoff: true
|
signoff: true
|
||||||
branch: update-3rd-party-licenses
|
branch: update-3rd-party-licenses
|
||||||
title: "Update 3rd Party Licenses"
|
title: "Update 3rd Party Licenses"
|
||||||
body: |
|
body: |
|
||||||
Auto-generated by ${{ steps.setup-bot.outputs.app-slug }}[bot]
|
Auto-generated by StirlingBot
|
||||||
labels: licenses,github-actions
|
labels: licenses,github-actions
|
||||||
draft: false
|
draft: false
|
||||||
delete-branch: true
|
delete-branch: true
|
||||||
@ -87,4 +89,4 @@ jobs:
|
|||||||
if: steps.cpr.outputs.pull-request-operation == 'created'
|
if: steps.cpr.outputs.pull-request-operation == 'created'
|
||||||
run: gh pr merge --squash --auto "${{ steps.cpr.outputs.pull-request-number }}"
|
run: gh pr merge --squash --auto "${{ steps.cpr.outputs.pull-request-number }}"
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ steps.setup-bot.outputs.token }}
|
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||||
|
43
.github/workflows/pre_commit.yml
vendored
43
.github/workflows/pre_commit.yml
vendored
@ -20,49 +20,58 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Generate GitHub App Token
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
id: generate-token
|
||||||
with:
|
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Setup GitHub App Bot
|
|
||||||
id: setup-bot
|
|
||||||
uses: ./.github/actions/setup-bot
|
|
||||||
with:
|
with:
|
||||||
app-id: ${{ secrets.GH_APP_ID }}
|
app-id: ${{ secrets.GH_APP_ID }}
|
||||||
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
||||||
|
|
||||||
|
- name: Get GitHub App User ID
|
||||||
|
id: get-user-id
|
||||||
|
run: echo "user-id=$(gh api "/users/${{ steps.generate-token.outputs.app-slug }}[bot]" --jq .id)" >> $GITHUB_OUTPUT
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||||
|
|
||||||
|
- id: committer
|
||||||
|
run: |
|
||||||
|
echo "string=${{ steps.generate-token.outputs.app-slug }}[bot] <${{ steps.get-user-id.outputs.user-id }}+${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com>" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||||
with:
|
with:
|
||||||
python-version: 3.12
|
python-version: 3.12
|
||||||
cache: 'pip' # caching pip dependencies
|
cache: 'pip' # caching pip dependencies
|
||||||
|
|
||||||
- name: Run Pre-Commit Hooks
|
- name: Run Pre-Commit Hooks
|
||||||
run: |
|
run: |
|
||||||
pip install --require-hashes -r ./.github/scripts/requirements_pre_commit.txt
|
pip install --require-hashes -r ./.github/scripts/requirements_pre_commit.txt
|
||||||
|
|
||||||
- run: pre-commit run --all-files -c .pre-commit-config.yaml
|
- run: pre-commit run --all-files -c .pre-commit-config.yaml
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
- name: Set up git config
|
||||||
|
run: |
|
||||||
|
git config --global user.name ${{ steps.generate-token.outputs.app-slug }}[bot]
|
||||||
|
git config --global user.email "${{ steps.get-user-id.outputs.user-id }}+${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com"
|
||||||
- name: git add
|
- name: git add
|
||||||
run: |
|
run: |
|
||||||
git add .
|
git add .
|
||||||
git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
|
git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
if: env.CHANGES_DETECTED == 'true'
|
if: env.CHANGES_DETECTED == 'true'
|
||||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
||||||
with:
|
with:
|
||||||
token: ${{ steps.setup-bot.outputs.token }}
|
token: ${{ steps.generate-token.outputs.token }}
|
||||||
commit-message: ":file_folder: pre-commit"
|
commit-message: ":file_folder: pre-commit"
|
||||||
committer: ${{ steps.setup-bot.outputs.committer }}
|
committer: ${{ steps.committer.outputs.string }}
|
||||||
author: ${{ steps.setup-bot.outputs.committer }}
|
author: ${{ steps.committer.outputs.string }}
|
||||||
signoff: true
|
signoff: true
|
||||||
branch: pre-commit
|
branch: pre-commit
|
||||||
title: "🤖 format everything with pre-commit by ${{ steps.setup-bot.outputs.app-slug }}"
|
title: "🤖 format everything with pre-commit by <${{ steps.generate-token.outputs.app-slug }}>"
|
||||||
body: |
|
body: |
|
||||||
Auto-generated by [create-pull-request][1] with **${{ steps.setup-bot.outputs.app-slug }}**
|
Auto-generated by [create-pull-request][1] with **${{ steps.generate-token.outputs.app-slug }}**
|
||||||
|
|
||||||
[1]: https://github.com/peter-evans/create-pull-request
|
[1]: https://github.com/peter-evans/create-pull-request
|
||||||
draft: false
|
draft: false
|
||||||
|
67
.github/workflows/sync_files.yml
vendored
67
.github/workflows/sync_files.yml
vendored
@ -16,7 +16,44 @@ permissions:
|
|||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
read_bot_entries:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
userName: ${{ steps.get-user-id.outputs.user_name }}
|
||||||
|
userEmail: ${{ steps.get-user-id.outputs.user_email }}
|
||||||
|
committer: ${{ steps.committer.outputs.committer }}
|
||||||
|
steps:
|
||||||
|
- name: Harden Runner
|
||||||
|
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
|
||||||
|
- name: Generate GitHub App Token
|
||||||
|
id: generate-token
|
||||||
|
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
|
||||||
|
with:
|
||||||
|
app-id: ${{ secrets.GH_APP_ID }}
|
||||||
|
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
||||||
|
|
||||||
|
- name: Get GitHub App User ID
|
||||||
|
id: get-user-id
|
||||||
|
run: |
|
||||||
|
USER_NAME="${{ steps.generate-token.outputs.app-slug }}[bot]"
|
||||||
|
USER_ID=$(gh api "/users/$USER_NAME" --jq .id)
|
||||||
|
USER_EMAIL="$USER_ID+$USER_NAME@users.noreply.github.com"
|
||||||
|
echo "user_name=$USER_NAME" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "user_email=$USER_EMAIL" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "user-id=$USER_ID" >> "$GITHUB_OUTPUT"
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||||
|
|
||||||
|
- id: committer
|
||||||
|
run: |
|
||||||
|
COMMITTER="${{ steps.get-user-id.outputs.user_name }} <${{ steps.get-user-id.outputs.user_email }}>"
|
||||||
|
echo "committer=$COMMITTER" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
sync-files:
|
sync-files:
|
||||||
|
needs: ["read_bot_entries"]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
@ -24,29 +61,34 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- name: Generate GitHub App Token
|
||||||
|
id: generate-token
|
||||||
- name: Setup GitHub App Bot
|
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
|
||||||
id: setup-bot
|
|
||||||
uses: ./.github/actions/setup-bot
|
|
||||||
with:
|
with:
|
||||||
app-id: ${{ vars.GH_APP_ID }}
|
app-id: ${{ vars.GH_APP_ID }}
|
||||||
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
||||||
|
|
||||||
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
cache: "pip" # caching pip dependencies
|
cache: 'pip' # caching pip dependencies
|
||||||
|
|
||||||
- name: Sync translation property files
|
- name: Sync translation property files
|
||||||
run: |
|
run: |
|
||||||
python .github/scripts/check_language_properties.py --reference-file "src/main/resources/messages_en_GB.properties" --branch main
|
python .github/scripts/check_language_properties.py --reference-file "src/main/resources/messages_en_GB.properties" --branch main
|
||||||
|
|
||||||
- name: Commit translation files
|
- name: Set up git config
|
||||||
|
run: |
|
||||||
|
git config --global user.name ${{ needs.read_bot_entries.outputs.userName }}
|
||||||
|
git config --global user.email ${{ needs.read_bot_entries.outputs.userEmail }}
|
||||||
|
|
||||||
|
- name: Run git add
|
||||||
run: |
|
run: |
|
||||||
git add src/main/resources/messages_*.properties
|
git add src/main/resources/messages_*.properties
|
||||||
git diff --staged --quiet || git commit -m ":memo: Sync translation files" || echo "No changes detected"
|
git diff --staged --quiet || git commit -m ":memo: Sync translation files" || echo "no changes"
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pip install --require-hashes -r ./.github/scripts/requirements_sync_readme.txt
|
run: pip install --require-hashes -r ./.github/scripts/requirements_sync_readme.txt
|
||||||
@ -58,16 +100,15 @@ jobs:
|
|||||||
- name: Run git add
|
- name: Run git add
|
||||||
run: |
|
run: |
|
||||||
git add README.md
|
git add README.md
|
||||||
git diff --staged --quiet || git commit -m ":memo: Sync README.md" || echo "No changes detected"
|
git diff --staged --quiet || git commit -m ":memo: Sync README.md" || echo "no changes"
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
if: always()
|
|
||||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
||||||
with:
|
with:
|
||||||
token: ${{ steps.setup-bot.outputs.token }}
|
token: ${{ steps.generate-token.outputs.token }}
|
||||||
commit-message: Update files
|
commit-message: Update files
|
||||||
committer: ${{ steps.setup-bot.outputs.committer }}
|
committer: ${{ needs.read_bot_entries.outputs.committer }}
|
||||||
author: ${{ steps.setup-bot.outputs.committer }}
|
author: ${{ needs.read_bot_entries.outputs.committer }}
|
||||||
signoff: true
|
signoff: true
|
||||||
branch: sync_readme
|
branch: sync_readme
|
||||||
title: ":globe_with_meridians: Sync Translations + Update README Progress Table"
|
title: ":globe_with_meridians: Sync Translations + Update README Progress Table"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.11.11
|
rev: v0.11.6
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff
|
||||||
args:
|
args:
|
||||||
@ -22,7 +22,7 @@ repos:
|
|||||||
files: \.(html|css|js|py|md)$
|
files: \.(html|css|js|py|md)$
|
||||||
exclude: (.vscode|.devcontainer|src/main/resources|Dockerfile|.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js)
|
exclude: (.vscode|.devcontainer|src/main/resources|Dockerfile|.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js)
|
||||||
- repo: https://github.com/gitleaks/gitleaks
|
- repo: https://github.com/gitleaks/gitleaks
|
||||||
rev: v8.26.0
|
rev: v8.24.3
|
||||||
hooks:
|
hooks:
|
||||||
- id: gitleaks
|
- id: gitleaks
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -10,7 +10,7 @@
|
|||||||
"java.configuration.updateBuildConfiguration": "interactive",
|
"java.configuration.updateBuildConfiguration": "interactive",
|
||||||
"java.format.enabled": true,
|
"java.format.enabled": true,
|
||||||
"java.format.settings.profile": "GoogleStyle",
|
"java.format.settings.profile": "GoogleStyle",
|
||||||
"java.format.settings.google.version": "1.27.0",
|
"java.format.settings.google.version": "1.26.0",
|
||||||
"java.format.settings.google.extra": "--aosp --skip-sorting-imports --skip-javadoc-formatting",
|
"java.format.settings.google.extra": "--aosp --skip-sorting-imports --skip-javadoc-formatting",
|
||||||
// (DE) Aktiviert Kommentare im Java-Format.
|
// (DE) Aktiviert Kommentare im Java-Format.
|
||||||
// (EN) Enables comments in Java formatting.
|
// (EN) Enables comments in Java formatting.
|
||||||
|
24
AGENTS.md
24
AGENTS.md
@ -1,24 +0,0 @@
|
|||||||
# Codex Contribution Guidelines for Stirling-PDF
|
|
||||||
|
|
||||||
This file provides high-level instructions for Codex when modifying any files within this repository. Follow these rules to ensure changes remain consistent with the existing project structure.
|
|
||||||
|
|
||||||
## 1. Code Style and Formatting
|
|
||||||
- Respect the `.editorconfig` settings located in the repository root. Java files use 4 spaces; HTML, JS, and Python generally use 2 spaces. Lines should end with `LF`.
|
|
||||||
- Format Java code with `./gradlew spotlessApply` before committing.
|
|
||||||
- Review `DeveloperGuide.md` for project structure and design details before making significant changes.
|
|
||||||
|
|
||||||
## 2. Testing
|
|
||||||
- Run `./gradlew build` before committing changes to ensure the project compiles.
|
|
||||||
- If the build cannot complete due to environment restrictions, DO NOT COMMIT THE CHANGE
|
|
||||||
|
|
||||||
## 3. Commits
|
|
||||||
- Keep commits focused. Group related changes together and provide concise commit messages.
|
|
||||||
- Ensure the working tree is clean (`git status`) before concluding your work.
|
|
||||||
|
|
||||||
## 4. Pull Requests
|
|
||||||
- Summarize what was changed and why. Include build results from `./gradlew build` in the PR description.
|
|
||||||
- Note that the code was generated with the assistance of AI.
|
|
||||||
|
|
||||||
## 5. Translations
|
|
||||||
- Only modify `messages_en_GB.properties` when adding or updating translations.
|
|
||||||
|
|
@ -128,7 +128,7 @@ Stirling-PDF currently supports 40 languages!
|
|||||||
| English (English) (en_GB) |  |
|
| English (English) (en_GB) |  |
|
||||||
| English (US) (en_US) |  |
|
| English (US) (en_US) |  |
|
||||||
| French (Français) (fr_FR) |  |
|
| French (Français) (fr_FR) |  |
|
||||||
| German (Deutsch) (de_DE) |  |
|
| German (Deutsch) (de_DE) |  |
|
||||||
| Greek (Ελληνικά) (el_GR) |  |
|
| Greek (Ελληνικά) (el_GR) |  |
|
||||||
| Hindi (हिंदी) (hi_IN) |  |
|
| Hindi (हिंदी) (hi_IN) |  |
|
||||||
| Hungarian (Magyar) (hu_HU) |  |
|
| Hungarian (Magyar) (hu_HU) |  |
|
||||||
@ -143,9 +143,9 @@ Stirling-PDF currently supports 40 languages!
|
|||||||
| Portuguese (Português) (pt_PT) |  |
|
| Portuguese (Português) (pt_PT) |  |
|
||||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||||
| Romanian (Română) (ro_RO) |  |
|
| Romanian (Română) (ro_RO) |  |
|
||||||
| Russian (Русский) (ru_RU) |  |
|
| Russian (Русский) (ru_RU) |  |
|
||||||
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||||
| Slovakian (Slovensky) (sk_SK) |  |
|
| Slovakian (Slovensky) (sk_SK) |  |
|
||||||
| Slovenian (Slovenščina) (sl_SI) |  |
|
| Slovenian (Slovenščina) (sl_SI) |  |
|
||||||
| Spanish (Español) (es_ES) |  |
|
| Spanish (Español) (es_ES) |  |
|
||||||
@ -154,7 +154,7 @@ Stirling-PDF currently supports 40 languages!
|
|||||||
| Tibetan (བོད་ཡིག་) (zh_BO) |  |
|
| Tibetan (བོད་ཡིག་) (zh_BO) |  |
|
||||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||||
| Turkish (Türkçe) (tr_TR) |  |
|
| Turkish (Türkçe) (tr_TR) |  |
|
||||||
| Ukrainian (Українська) (uk_UA) |  |
|
| Ukrainian (Українська) (uk_UA) |  |
|
||||||
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
||||||
| Malayalam (മലയാളം) (ml_ML) |  |
|
| Malayalam (മലയാളം) (ml_ML) |  |
|
||||||
|
|
||||||
|
17
build.gradle
17
build.gradle
@ -1,7 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "java"
|
id "java"
|
||||||
id 'jacoco'
|
id 'jacoco'
|
||||||
id "org.springframework.boot" version "3.5.0"
|
id "org.springframework.boot" version "3.4.5"
|
||||||
id "io.spring.dependency-management" version "1.1.7"
|
id "io.spring.dependency-management" version "1.1.7"
|
||||||
id "org.springdoc.openapi-gradle-plugin" version "1.9.0"
|
id "org.springdoc.openapi-gradle-plugin" version "1.9.0"
|
||||||
id "io.swagger.swaggerhub" version "1.3.2"
|
id "io.swagger.swaggerhub" version "1.3.2"
|
||||||
@ -19,7 +19,7 @@ import java.nio.file.Files
|
|||||||
import java.time.Year
|
import java.time.Year
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
springBootVersion = "3.5.0"
|
springBootVersion = "3.4.5"
|
||||||
pdfboxVersion = "3.0.5"
|
pdfboxVersion = "3.0.5"
|
||||||
imageioVersion = "3.12.0"
|
imageioVersion = "3.12.0"
|
||||||
lombokVersion = "1.18.38"
|
lombokVersion = "1.18.38"
|
||||||
@ -376,7 +376,7 @@ spotless {
|
|||||||
java {
|
java {
|
||||||
target project.fileTree('src').include('**/*.java')
|
target project.fileTree('src').include('**/*.java')
|
||||||
|
|
||||||
googleJavaFormat("1.27.0").aosp().reorderImports(false)
|
googleJavaFormat("1.26.0").aosp().reorderImports(false)
|
||||||
|
|
||||||
importOrder("java", "javax", "org", "com", "net", "io", "jakarta", "lombok", "me", "stirling")
|
importOrder("java", "javax", "org", "com", "net", "io", "jakarta", "lombok", "me", "stirling")
|
||||||
toggleOffOn()
|
toggleOffOn()
|
||||||
@ -413,14 +413,13 @@ configurations.all {
|
|||||||
// Exclude Tomcat
|
// Exclude Tomcat
|
||||||
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
|
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':common')
|
|
||||||
|
|
||||||
//tmp for security bumps
|
//tmp for security bumps
|
||||||
implementation 'ch.qos.logback:logback-core:1.5.18'
|
implementation 'ch.qos.logback:logback-core:1.5.18'
|
||||||
implementation 'ch.qos.logback:logback-classic:1.5.18'
|
implementation 'ch.qos.logback:logback-classic:1.5.18'
|
||||||
|
|
||||||
|
|
||||||
// Exclude vulnerable BouncyCastle version used in tableau
|
// Exclude vulnerable BouncyCastle version used in tableau
|
||||||
configurations.all {
|
configurations.all {
|
||||||
exclude group: 'org.bouncycastle', module: 'bcpkix-jdk15on'
|
exclude group: 'org.bouncycastle', module: 'bcpkix-jdk15on'
|
||||||
@ -449,6 +448,8 @@ dependencies {
|
|||||||
|
|
||||||
|
|
||||||
if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") {
|
if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") {
|
||||||
|
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
||||||
implementation 'io.micrometer:micrometer-registry-prometheus'
|
implementation 'io.micrometer:micrometer-registry-prometheus'
|
||||||
|
|
||||||
implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion"
|
||||||
@ -457,7 +458,7 @@ dependencies {
|
|||||||
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
|
||||||
implementation "org.springframework.boot:spring-boot-starter-mail:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-mail:$springBootVersion"
|
||||||
|
|
||||||
implementation "org.springframework.session:spring-session-core:3.5.0"
|
implementation "org.springframework.session:spring-session-core:3.4.3"
|
||||||
implementation "org.springframework:spring-jdbc:6.2.7"
|
implementation "org.springframework:spring-jdbc:6.2.7"
|
||||||
|
|
||||||
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
|
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
|
||||||
@ -543,7 +544,9 @@ dependencies {
|
|||||||
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
|
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
|
||||||
|
|
||||||
// Mockito (core)
|
// Mockito (core)
|
||||||
testImplementation 'org.mockito:mockito-core:5.18.0'
|
testImplementation 'org.mockito:mockito-core:5.17.0'
|
||||||
|
|
||||||
|
|
||||||
testRuntimeOnly 'org.mockito:mockito-inline:5.2.0'
|
testRuntimeOnly 'org.mockito:mockito-inline:5.2.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
196
common/.gitignore
vendored
196
common/.gitignore
vendored
@ -1,196 +0,0 @@
|
|||||||
### Eclipse ###
|
|
||||||
.metadata
|
|
||||||
bin/
|
|
||||||
tmp/
|
|
||||||
*.tmp
|
|
||||||
*.bak
|
|
||||||
*.exe
|
|
||||||
*.swp
|
|
||||||
*~.nib
|
|
||||||
local.properties
|
|
||||||
.settings/
|
|
||||||
.loadpath
|
|
||||||
.recommenders
|
|
||||||
.classpath
|
|
||||||
.project
|
|
||||||
version.properties
|
|
||||||
|
|
||||||
#### Stirling-PDF Files ###
|
|
||||||
pipeline/watchedFolders/
|
|
||||||
pipeline/finishedFolders/
|
|
||||||
customFiles/
|
|
||||||
configs/
|
|
||||||
watchedFolders/
|
|
||||||
clientWebUI/
|
|
||||||
!cucumber/
|
|
||||||
!cucumber/exampleFiles/
|
|
||||||
!cucumber/exampleFiles/example_html.zip
|
|
||||||
exampleYmlFiles/stirling/
|
|
||||||
/testing/file_snapshots
|
|
||||||
SwaggerDoc.json
|
|
||||||
|
|
||||||
# Gradle
|
|
||||||
.gradle
|
|
||||||
.lock
|
|
||||||
|
|
||||||
# External tool builders
|
|
||||||
.externalToolBuilders/
|
|
||||||
|
|
||||||
# Locally stored "Eclipse launch configurations"
|
|
||||||
*.launch
|
|
||||||
|
|
||||||
# PyDev specific (Python IDE for Eclipse)
|
|
||||||
*.pydevproject
|
|
||||||
|
|
||||||
# CDT-specific (C/C++ Development Tooling)
|
|
||||||
.cproject
|
|
||||||
|
|
||||||
# CDT- autotools
|
|
||||||
.autotools
|
|
||||||
|
|
||||||
# Java annotation processor (APT)
|
|
||||||
.factorypath
|
|
||||||
|
|
||||||
# PDT-specific (PHP Development Tools)
|
|
||||||
.buildpath
|
|
||||||
|
|
||||||
# sbteclipse plugin
|
|
||||||
.target
|
|
||||||
|
|
||||||
# Tern plugin
|
|
||||||
.tern-project
|
|
||||||
|
|
||||||
# TeXlipse plugin
|
|
||||||
.texlipse
|
|
||||||
|
|
||||||
# STS (Spring Tool Suite)
|
|
||||||
.springBeans
|
|
||||||
|
|
||||||
# Code Recommenders
|
|
||||||
.recommenders/
|
|
||||||
|
|
||||||
# Annotation Processing
|
|
||||||
.apt_generated/
|
|
||||||
.apt_generated_test/
|
|
||||||
|
|
||||||
# Scala IDE specific (Scala & Java development for Eclipse)
|
|
||||||
.cache-main
|
|
||||||
.scala_dependencies
|
|
||||||
.worksheet
|
|
||||||
|
|
||||||
# Uncomment this line if you wish to ignore the project description file.
|
|
||||||
# Typically, this file would be tracked if it contains build/dependency configurations:
|
|
||||||
#.project
|
|
||||||
|
|
||||||
### Eclipse Patch ###
|
|
||||||
# Spring Boot Tooling
|
|
||||||
.sts4-cache/
|
|
||||||
|
|
||||||
### Git ###
|
|
||||||
# Created by git for backups. To disable backups in Git:
|
|
||||||
# $ git config --global mergetool.keepBackup false
|
|
||||||
*.orig
|
|
||||||
|
|
||||||
# Created by git when using merge tools for conflicts
|
|
||||||
*.BACKUP.*
|
|
||||||
*.BASE.*
|
|
||||||
*.LOCAL.*
|
|
||||||
*.REMOTE.*
|
|
||||||
*_BACKUP_*.txt
|
|
||||||
*_BASE_*.txt
|
|
||||||
*_LOCAL_*.txt
|
|
||||||
*_REMOTE_*.txt
|
|
||||||
|
|
||||||
### Java ###
|
|
||||||
# Compiled class file
|
|
||||||
*.class
|
|
||||||
|
|
||||||
# Log file
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# BlueJ files
|
|
||||||
*.ctxt
|
|
||||||
|
|
||||||
# Mobile Tools for Java (J2ME)
|
|
||||||
.mtj.tmp/
|
|
||||||
|
|
||||||
# Package Files #
|
|
||||||
*.jar
|
|
||||||
*.war
|
|
||||||
*.nar
|
|
||||||
*.ear
|
|
||||||
*.zip
|
|
||||||
*.tar.gz
|
|
||||||
*.rar
|
|
||||||
*.db
|
|
||||||
/build
|
|
||||||
|
|
||||||
# Byte-compiled / optimized / DLL files
|
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
*.pyo
|
|
||||||
|
|
||||||
# Virtual environments
|
|
||||||
.env*
|
|
||||||
.venv*
|
|
||||||
env*/
|
|
||||||
venv*/
|
|
||||||
ENV/
|
|
||||||
env.bak/
|
|
||||||
venv.bak/
|
|
||||||
|
|
||||||
# VS Code
|
|
||||||
/.vscode/**/*
|
|
||||||
!/.vscode/settings.json
|
|
||||||
!/.vscode/extensions.json
|
|
||||||
|
|
||||||
# IntelliJ IDEA
|
|
||||||
.idea/
|
|
||||||
*.iml
|
|
||||||
out/
|
|
||||||
|
|
||||||
# Ignore Mac DS_Store files
|
|
||||||
.DS_Store
|
|
||||||
**/.DS_Store
|
|
||||||
|
|
||||||
# cucumber
|
|
||||||
/cucumber/reports/**
|
|
||||||
|
|
||||||
# Certs and Security Files
|
|
||||||
*.p12
|
|
||||||
*.pk8
|
|
||||||
*.pem
|
|
||||||
*.crt
|
|
||||||
*.cer
|
|
||||||
*.cert
|
|
||||||
*.der
|
|
||||||
*.key
|
|
||||||
*.csr
|
|
||||||
*.kdbx
|
|
||||||
*.jks
|
|
||||||
*.asc
|
|
||||||
|
|
||||||
# SSH Keys
|
|
||||||
*.pub
|
|
||||||
*.priv
|
|
||||||
id_rsa
|
|
||||||
id_rsa.pub
|
|
||||||
id_ecdsa
|
|
||||||
id_ecdsa.pub
|
|
||||||
id_ed25519
|
|
||||||
id_ed25519.pub
|
|
||||||
.ssh/
|
|
||||||
*ssh
|
|
||||||
|
|
||||||
# cache
|
|
||||||
.cache
|
|
||||||
.ruff_cache
|
|
||||||
.mypy_cache
|
|
||||||
.pytest_cache
|
|
||||||
.ipynb_checkpoints
|
|
||||||
|
|
||||||
**/jcef-bundle/
|
|
||||||
|
|
||||||
# node_modules
|
|
||||||
node_modules/
|
|
||||||
*.mjs
|
|
@ -1,52 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id 'java-library'
|
|
||||||
id 'io.spring.dependency-management' version '1.1.7'
|
|
||||||
}
|
|
||||||
|
|
||||||
group = 'stirling.software'
|
|
||||||
version = '0.46.2'
|
|
||||||
|
|
||||||
ext {
|
|
||||||
lombokVersion = "1.18.38"
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
configurations.all {
|
|
||||||
exclude group: 'commons-logging', module: 'commons-logging'
|
|
||||||
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencyManagement {
|
|
||||||
imports {
|
|
||||||
mavenBom 'org.springframework.boot:spring-boot-dependencies:3.4.5'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
|
||||||
implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1'
|
|
||||||
implementation 'com.fathzer:javaluator:3.0.6'
|
|
||||||
implementation 'com.posthog.java:posthog:1.2.0'
|
|
||||||
implementation 'io.github.pixee:java-security-toolkit:1.2.1'
|
|
||||||
implementation 'org.apache.commons:commons-lang3:3.17.0'
|
|
||||||
implementation 'com.drewnoakes:metadata-extractor:2.19.0' // Image metadata extractor
|
|
||||||
implementation 'com.vladsch.flexmark:flexmark-html2md-converter:0.64.8'
|
|
||||||
implementation "org.apache.pdfbox:pdfbox:$pdfboxVersion"
|
|
||||||
implementation 'jakarta.servlet:jakarta.servlet-api:6.0.0'
|
|
||||||
implementation 'org.snakeyaml:snakeyaml-engine:2.9'
|
|
||||||
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.6"
|
|
||||||
|
|
||||||
compileOnly "org.projectlombok:lombok:$lombokVersion"
|
|
||||||
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
|
|
||||||
|
|
||||||
testImplementation "org.springframework.boot:spring-boot-starter-test"
|
|
||||||
testRuntimeOnly 'org.mockito:mockito-inline:5.2.0'
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
package stirling.software.common.configuration.interfaces;
|
|
||||||
|
|
||||||
public interface ShowAdminInterface {
|
|
||||||
default boolean getShowUpdateOnlyAdmins() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package stirling.software.common.model;
|
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
public class PdfMetadata {
|
|
||||||
private String author;
|
|
||||||
private String producer;
|
|
||||||
private String title;
|
|
||||||
private String creator;
|
|
||||||
private String subject;
|
|
||||||
private String keywords;
|
|
||||||
private Calendar creationDate;
|
|
||||||
private Calendar modificationDate;
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package stirling.software.common.model.api;
|
|
||||||
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode
|
|
||||||
public class GeneralFile {
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The input file",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED,
|
|
||||||
format = "binary")
|
|
||||||
private MultipartFile fileInput;
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
package stirling.software.common.model.api.security;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode
|
|
||||||
public class RedactionArea {
|
|
||||||
@Schema(description = "The left edge point of the area to be redacted.")
|
|
||||||
private Double x;
|
|
||||||
|
|
||||||
@Schema(description = "The top edge point of the area to be redacted.")
|
|
||||||
private Double y;
|
|
||||||
|
|
||||||
@Schema(description = "The height of the area to be redacted.")
|
|
||||||
private Double height;
|
|
||||||
|
|
||||||
@Schema(description = "The width of the area to be redacted.")
|
|
||||||
private Double width;
|
|
||||||
|
|
||||||
@Schema(description = "The page on which the area should be redacted.")
|
|
||||||
private Integer page;
|
|
||||||
|
|
||||||
@Schema(description = "The color used to redact the specified area.")
|
|
||||||
private String color;
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
package stirling.software.common.model.enumeration;
|
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public enum Role {
|
|
||||||
|
|
||||||
// Unlimited access
|
|
||||||
ADMIN("ROLE_ADMIN", Integer.MAX_VALUE, Integer.MAX_VALUE, "adminUserSettings.admin"),
|
|
||||||
|
|
||||||
// Unlimited access
|
|
||||||
USER("ROLE_USER", Integer.MAX_VALUE, Integer.MAX_VALUE, "adminUserSettings.user"),
|
|
||||||
|
|
||||||
// 40 API calls Per Day, 40 web calls
|
|
||||||
LIMITED_API_USER("ROLE_LIMITED_API_USER", 40, 40, "adminUserSettings.apiUser"),
|
|
||||||
|
|
||||||
// 20 API calls Per Day, 20 web calls
|
|
||||||
EXTRA_LIMITED_API_USER("ROLE_EXTRA_LIMITED_API_USER", 20, 20, "adminUserSettings.extraApiUser"),
|
|
||||||
|
|
||||||
// 0 API calls per day and 20 web calls
|
|
||||||
WEB_ONLY_USER("ROLE_WEB_ONLY_USER", 0, 20, "adminUserSettings.webOnlyUser"),
|
|
||||||
|
|
||||||
INTERNAL_API_USER(
|
|
||||||
"STIRLING-PDF-BACKEND-API-USER",
|
|
||||||
Integer.MAX_VALUE,
|
|
||||||
Integer.MAX_VALUE,
|
|
||||||
"adminUserSettings.internalApiUser"),
|
|
||||||
|
|
||||||
DEMO_USER("ROLE_DEMO_USER", 100, 100, "adminUserSettings.demoUser");
|
|
||||||
|
|
||||||
private final String roleId;
|
|
||||||
private final int apiCallsPerDay;
|
|
||||||
private final int webCallsPerDay;
|
|
||||||
private final String roleName;
|
|
||||||
|
|
||||||
public static String getRoleNameByRoleId(String roleId) {
|
|
||||||
// Using the fromString method to get the Role enum based on the roleId
|
|
||||||
Role role = fromString(roleId);
|
|
||||||
// Return the roleName of the found Role enum
|
|
||||||
return role.getRoleName();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to retrieve all role IDs and role names
|
|
||||||
public static Map<String, String> getAllRoleDetails() {
|
|
||||||
// Using LinkedHashMap to preserve order
|
|
||||||
Map<String, String> roleDetails = new LinkedHashMap<>();
|
|
||||||
for (Role role : Role.values()) {
|
|
||||||
roleDetails.put(role.getRoleId(), role.getRoleName());
|
|
||||||
}
|
|
||||||
return roleDetails;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Role fromString(String roleId) {
|
|
||||||
for (Role role : Role.values()) {
|
|
||||||
if (role.getRoleId().equalsIgnoreCase(roleId)) {
|
|
||||||
return role;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("No Role defined for id: " + roleId);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
package stirling.software.common.model.exception;
|
|
||||||
|
|
||||||
public class UnsupportedClaimException extends RuntimeException {
|
|
||||||
public UnsupportedClaimException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
package stirling.software.common.util;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
public class ValidationUtils {
|
|
||||||
|
|
||||||
public static boolean isStringEmpty(String input) {
|
|
||||||
return input == null || input.isBlank();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isCollectionEmpty(Collection<String> input) {
|
|
||||||
return input == null || input.isEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
package stirling.software.common.util;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
class GeneralUtilsAdditionalTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testConvertSizeToBytes() {
|
|
||||||
assertEquals(1024L, GeneralUtils.convertSizeToBytes("1KB"));
|
|
||||||
assertEquals(1024L * 1024, GeneralUtils.convertSizeToBytes("1MB"));
|
|
||||||
assertEquals(1024L * 1024 * 1024, GeneralUtils.convertSizeToBytes("1GB"));
|
|
||||||
assertEquals(100L * 1024 * 1024, GeneralUtils.convertSizeToBytes("100"));
|
|
||||||
assertNull(GeneralUtils.convertSizeToBytes("invalid"));
|
|
||||||
assertNull(GeneralUtils.convertSizeToBytes(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testFormatBytes() {
|
|
||||||
assertEquals("512 B", GeneralUtils.formatBytes(512));
|
|
||||||
assertEquals("1.00 KB", GeneralUtils.formatBytes(1024));
|
|
||||||
assertEquals("1.00 MB", GeneralUtils.formatBytes(1024L * 1024));
|
|
||||||
assertEquals("1.00 GB", GeneralUtils.formatBytes(1024L * 1024 * 1024));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testURLHelpersAndUUID() {
|
|
||||||
assertTrue(GeneralUtils.isValidURL("https://example.com"));
|
|
||||||
assertFalse(GeneralUtils.isValidURL("htp:/bad"));
|
|
||||||
assertFalse(GeneralUtils.isURLReachable("http://localhost"));
|
|
||||||
assertFalse(GeneralUtils.isURLReachable("ftp://example.com"));
|
|
||||||
|
|
||||||
assertTrue(GeneralUtils.isValidUUID("123e4567-e89b-12d3-a456-426614174000"));
|
|
||||||
assertFalse(GeneralUtils.isValidUUID("not-a-uuid"));
|
|
||||||
|
|
||||||
assertFalse(GeneralUtils.isVersionHigher(null, "1.0"));
|
|
||||||
assertTrue(GeneralUtils.isVersionHigher("2.0", "1.9"));
|
|
||||||
assertFalse(GeneralUtils.isVersionHigher("1.0", "1.0.1"));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,125 +0,0 @@
|
|||||||
package stirling.software.common.util;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.pdfbox.cos.COSName;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDResources;
|
|
||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.mockito.Mockito;
|
|
||||||
|
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
|
||||||
import stirling.software.common.service.PdfMetadataService;
|
|
||||||
|
|
||||||
public class PdfUtilsTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testTextToPageSize() {
|
|
||||||
assertEquals(PDRectangle.A4, PdfUtils.textToPageSize("A4"));
|
|
||||||
assertEquals(PDRectangle.LETTER, PdfUtils.textToPageSize("LETTER"));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> PdfUtils.textToPageSize("INVALID"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testHasImagesOnPage() throws IOException {
|
|
||||||
// Mock a PDPage and its resources
|
|
||||||
PDPage page = Mockito.mock(PDPage.class);
|
|
||||||
PDResources resources = Mockito.mock(PDResources.class);
|
|
||||||
Mockito.when(page.getResources()).thenReturn(resources);
|
|
||||||
|
|
||||||
// Case 1: No images in resources
|
|
||||||
Mockito.when(resources.getXObjectNames()).thenReturn(Collections.emptySet());
|
|
||||||
assertFalse(PdfUtils.hasImagesOnPage(page));
|
|
||||||
|
|
||||||
// Case 2: Resources with an image
|
|
||||||
Set<COSName> xObjectNames = new HashSet<>();
|
|
||||||
COSName cosName = Mockito.mock(COSName.class);
|
|
||||||
xObjectNames.add(cosName);
|
|
||||||
|
|
||||||
PDImageXObject imageXObject = Mockito.mock(PDImageXObject.class);
|
|
||||||
Mockito.when(resources.getXObjectNames()).thenReturn(xObjectNames);
|
|
||||||
Mockito.when(resources.getXObject(cosName)).thenReturn(imageXObject);
|
|
||||||
|
|
||||||
assertTrue(PdfUtils.hasImagesOnPage(page));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testPageCountComparators() throws Exception {
|
|
||||||
PDDocument doc1 = new PDDocument();
|
|
||||||
doc1.addPage(new PDPage());
|
|
||||||
doc1.addPage(new PDPage());
|
|
||||||
doc1.addPage(new PDPage());
|
|
||||||
PdfUtils utils = new PdfUtils();
|
|
||||||
assertTrue(utils.pageCount(doc1, 2, "greater"));
|
|
||||||
|
|
||||||
PDDocument doc2 = new PDDocument();
|
|
||||||
doc2.addPage(new PDPage());
|
|
||||||
doc2.addPage(new PDPage());
|
|
||||||
doc2.addPage(new PDPage());
|
|
||||||
assertTrue(utils.pageCount(doc2, 3, "equal"));
|
|
||||||
|
|
||||||
PDDocument doc3 = new PDDocument();
|
|
||||||
doc3.addPage(new PDPage());
|
|
||||||
doc3.addPage(new PDPage());
|
|
||||||
assertTrue(utils.pageCount(doc3, 5, "less"));
|
|
||||||
|
|
||||||
PDDocument doc4 = new PDDocument();
|
|
||||||
doc4.addPage(new PDPage());
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> utils.pageCount(doc4, 1, "bad"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testPageSize() throws Exception {
|
|
||||||
PDDocument doc = new PDDocument();
|
|
||||||
PDPage page = new PDPage(PDRectangle.A4);
|
|
||||||
doc.addPage(page);
|
|
||||||
PDRectangle rect = page.getMediaBox();
|
|
||||||
String expected = rect.getWidth() + "x" + rect.getHeight();
|
|
||||||
PdfUtils utils = new PdfUtils();
|
|
||||||
assertTrue(utils.pageSize(doc, expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testOverlayImage() throws Exception {
|
|
||||||
PDDocument doc = new PDDocument();
|
|
||||||
doc.addPage(new PDPage(PDRectangle.A4));
|
|
||||||
ByteArrayOutputStream pdfOut = new ByteArrayOutputStream();
|
|
||||||
doc.save(pdfOut);
|
|
||||||
doc.close();
|
|
||||||
|
|
||||||
BufferedImage image = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB);
|
|
||||||
Graphics2D g = image.createGraphics();
|
|
||||||
g.setColor(Color.RED);
|
|
||||||
g.fillRect(0, 0, 10, 10);
|
|
||||||
g.dispose();
|
|
||||||
ByteArrayOutputStream imgOut = new ByteArrayOutputStream();
|
|
||||||
javax.imageio.ImageIO.write(image, "png", imgOut);
|
|
||||||
|
|
||||||
PdfMetadataService meta =
|
|
||||||
new PdfMetadataService(new ApplicationProperties(), "label", false, null);
|
|
||||||
CustomPDFDocumentFactory factory = new CustomPDFDocumentFactory(meta);
|
|
||||||
|
|
||||||
byte[] result =
|
|
||||||
PdfUtils.overlayImage(
|
|
||||||
factory, pdfOut.toByteArray(), imgOut.toByteArray(), 0, 0, false);
|
|
||||||
try (PDDocument resultDoc = factory.load(result)) {
|
|
||||||
assertEquals(1, resultDoc.getNumberOfPages());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,311 +0,0 @@
|
|||||||
package stirling.software.common.util;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
|
||||||
|
|
||||||
public class RequestUriUtilsTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testIsStaticResource() {
|
|
||||||
// Test static resources without context path
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource("/css/styles.css"), "CSS files should be static");
|
|
||||||
assertTrue(RequestUriUtils.isStaticResource("/js/script.js"), "JS files should be static");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource("/images/logo.png"),
|
|
||||||
"Image files should be static");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource("/public/index.html"),
|
|
||||||
"Public files should be static");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource("/pdfjs/pdf.worker.js"),
|
|
||||||
"PDF.js files should be static");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource("/api/v1/info/status"),
|
|
||||||
"API status should be static");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource("/some-path/icon.svg"),
|
|
||||||
"SVG files should be static");
|
|
||||||
assertTrue(RequestUriUtils.isStaticResource("/login"), "Login page should be static");
|
|
||||||
assertTrue(RequestUriUtils.isStaticResource("/error"), "Error page should be static");
|
|
||||||
|
|
||||||
// Test non-static resources
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isStaticResource("/api/v1/users"),
|
|
||||||
"API users should not be static");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isStaticResource("/api/v1/orders"),
|
|
||||||
"API orders should not be static");
|
|
||||||
assertFalse(RequestUriUtils.isStaticResource("/"), "Root path should not be static");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isStaticResource("/register"),
|
|
||||||
"Register page should not be static");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isStaticResource("/api/v1/products"),
|
|
||||||
"API products should not be static");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testIsStaticResourceWithContextPath() {
|
|
||||||
String contextPath = "/myapp";
|
|
||||||
|
|
||||||
// Test static resources with context path
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource(contextPath, contextPath + "/css/styles.css"),
|
|
||||||
"CSS with context path should be static");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource(contextPath, contextPath + "/js/script.js"),
|
|
||||||
"JS with context path should be static");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource(contextPath, contextPath + "/images/logo.png"),
|
|
||||||
"Images with context path should be static");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource(contextPath, contextPath + "/login"),
|
|
||||||
"Login with context path should be static");
|
|
||||||
|
|
||||||
// Test non-static resources with context path
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isStaticResource(contextPath, contextPath + "/api/v1/users"),
|
|
||||||
"API users with context path should not be static");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isStaticResource(contextPath, "/"),
|
|
||||||
"Root path with context path should not be static");
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest
|
|
||||||
@ValueSource(
|
|
||||||
strings = {
|
|
||||||
"robots.txt",
|
|
||||||
"/favicon.ico",
|
|
||||||
"/icon.svg",
|
|
||||||
"/image.png",
|
|
||||||
"/site.webmanifest",
|
|
||||||
"/app/logo.svg",
|
|
||||||
"/downloads/document.png",
|
|
||||||
"/assets/brand.ico",
|
|
||||||
"/any/path/with/image.svg",
|
|
||||||
"/deep/nested/folder/icon.png"
|
|
||||||
})
|
|
||||||
void testIsStaticResourceWithFileExtensions(String path) {
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource(path),
|
|
||||||
"Files with specific extensions should be static regardless of path");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testIsTrackableResource() {
|
|
||||||
// Test non-trackable resources (returns false)
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("/js/script.js"),
|
|
||||||
"JS files should not be trackable");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("/v1/api-docs"),
|
|
||||||
"API docs should not be trackable");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("robots.txt"),
|
|
||||||
"robots.txt should not be trackable");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("/images/logo.png"),
|
|
||||||
"Images should not be trackable");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("/styles.css"),
|
|
||||||
"CSS files should not be trackable");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("/script.js.map"),
|
|
||||||
"Map files should not be trackable");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("/icon.svg"),
|
|
||||||
"SVG files should not be trackable");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("/popularity.txt"),
|
|
||||||
"Popularity file should not be trackable");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("/script.js"),
|
|
||||||
"JS files should not be trackable");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("/swagger/index.html"),
|
|
||||||
"Swagger files should not be trackable");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("/api/v1/info/status"),
|
|
||||||
"API info should not be trackable");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("/site.webmanifest"),
|
|
||||||
"Webmanifest should not be trackable");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("/fonts/font.woff"),
|
|
||||||
"Fonts should not be trackable");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("/pdfjs/viewer.js"),
|
|
||||||
"PDF.js files should not be trackable");
|
|
||||||
|
|
||||||
// Test trackable resources (returns true)
|
|
||||||
assertTrue(RequestUriUtils.isTrackableResource("/login"), "Login page should be trackable");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isTrackableResource("/register"),
|
|
||||||
"Register page should be trackable");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isTrackableResource("/api/v1/users"),
|
|
||||||
"API users should be trackable");
|
|
||||||
assertTrue(RequestUriUtils.isTrackableResource("/"), "Root path should be trackable");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isTrackableResource("/some-other-path"),
|
|
||||||
"Other paths should be trackable");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testIsTrackableResourceWithContextPath() {
|
|
||||||
String contextPath = "/myapp";
|
|
||||||
|
|
||||||
// Test with context path
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource(contextPath, "/js/script.js"),
|
|
||||||
"JS files should not be trackable with context path");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isTrackableResource(contextPath, "/login"),
|
|
||||||
"Login page should be trackable with context path");
|
|
||||||
|
|
||||||
// Additional tests with context path
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource(contextPath, "/fonts/custom.woff"),
|
|
||||||
"Font files should not be trackable with context path");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource(contextPath, "/images/header.png"),
|
|
||||||
"Images should not be trackable with context path");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource(contextPath, "/swagger/ui.html"),
|
|
||||||
"Swagger UI should not be trackable with context path");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isTrackableResource(contextPath, "/account/profile"),
|
|
||||||
"Account page should be trackable with context path");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isTrackableResource(contextPath, "/pdf/view"),
|
|
||||||
"PDF view page should be trackable with context path");
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest
|
|
||||||
@ValueSource(
|
|
||||||
strings = {
|
|
||||||
"/js/util.js",
|
|
||||||
"/v1/api-docs/swagger.json",
|
|
||||||
"/robots.txt",
|
|
||||||
"/images/header/logo.png",
|
|
||||||
"/styles/theme.css",
|
|
||||||
"/build/app.js.map",
|
|
||||||
"/assets/icon.svg",
|
|
||||||
"/data/popularity.txt",
|
|
||||||
"/bundle.js",
|
|
||||||
"/api/swagger-ui.html",
|
|
||||||
"/api/v1/info/health",
|
|
||||||
"/site.webmanifest",
|
|
||||||
"/fonts/roboto.woff",
|
|
||||||
"/pdfjs/viewer.js"
|
|
||||||
})
|
|
||||||
void testNonTrackableResources(String path) {
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource(path),
|
|
||||||
"Resources matching patterns should not be trackable: " + path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest
|
|
||||||
@ValueSource(
|
|
||||||
strings = {
|
|
||||||
"/",
|
|
||||||
"/home",
|
|
||||||
"/login",
|
|
||||||
"/register",
|
|
||||||
"/pdf/merge",
|
|
||||||
"/pdf/split",
|
|
||||||
"/api/v1/users/1",
|
|
||||||
"/api/v1/documents/process",
|
|
||||||
"/settings",
|
|
||||||
"/account/profile",
|
|
||||||
"/dashboard",
|
|
||||||
"/help",
|
|
||||||
"/about"
|
|
||||||
})
|
|
||||||
void testTrackableResources(String path) {
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isTrackableResource(path),
|
|
||||||
"App routes should be trackable: " + path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testEdgeCases() {
|
|
||||||
// Test with empty strings
|
|
||||||
assertFalse(RequestUriUtils.isStaticResource("", ""), "Empty path should not be static");
|
|
||||||
assertTrue(RequestUriUtils.isTrackableResource("", ""), "Empty path should be trackable");
|
|
||||||
|
|
||||||
// Test with null-like behavior (would actually throw NPE in real code)
|
|
||||||
// These are not actual null tests but shows handling of odd cases
|
|
||||||
assertFalse(RequestUriUtils.isStaticResource("null"), "String 'null' should not be static");
|
|
||||||
|
|
||||||
// Test String "null" as a path
|
|
||||||
boolean isTrackable = RequestUriUtils.isTrackableResource("null");
|
|
||||||
assertTrue(isTrackable, "String 'null' should be trackable");
|
|
||||||
|
|
||||||
// Mixed case extensions test - note that Java's endsWith() is case-sensitive
|
|
||||||
// We'll check actual behavior and document it rather than asserting
|
|
||||||
|
|
||||||
// Always test the lowercase versions which should definitely work
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource("/logo.png"), "PNG (lowercase) should be static");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource("/icon.svg"), "SVG (lowercase) should be static");
|
|
||||||
|
|
||||||
// Path with query parameters
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isStaticResource("/api/users?page=1"),
|
|
||||||
"Path with query params should respect base path");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource("/images/logo.png?v=123"),
|
|
||||||
"Static resource with query params should still be static");
|
|
||||||
|
|
||||||
// Paths with fragments
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource("/css/styles.css#section1"),
|
|
||||||
"CSS with fragment should be static");
|
|
||||||
|
|
||||||
// Multiple dots in filename
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource("/js/jquery.min.js"),
|
|
||||||
"JS with multiple dots should be static");
|
|
||||||
|
|
||||||
// Special characters in path
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource("/images/user's-photo.png"),
|
|
||||||
"Path with special chars should be handled correctly");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testComplexPaths() {
|
|
||||||
// Test complex static resource paths
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource("/css/theme/dark/styles.css"),
|
|
||||||
"Nested CSS should be static");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource("/fonts/open-sans/bold/font.woff"),
|
|
||||||
"Nested font should be static");
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource("/js/vendor/jquery/3.5.1/jquery.min.js"),
|
|
||||||
"Versioned JS should be static");
|
|
||||||
|
|
||||||
// Test complex paths with context
|
|
||||||
String contextPath = "/app";
|
|
||||||
assertTrue(
|
|
||||||
RequestUriUtils.isStaticResource(
|
|
||||||
contextPath, contextPath + "/css/theme/dark/styles.css"),
|
|
||||||
"Nested CSS with context should be static");
|
|
||||||
|
|
||||||
// Test boundary cases for isTrackableResource
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("/js-framework/components"),
|
|
||||||
"Path starting with js- should not be treated as JS resource");
|
|
||||||
assertFalse(
|
|
||||||
RequestUriUtils.isTrackableResource("/fonts-selection"),
|
|
||||||
"Path starting with fonts- should not be treated as font resource");
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,5 +3,3 @@ plugins {
|
|||||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
|
id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
|
||||||
}
|
}
|
||||||
rootProject.name = 'Stirling-PDF'
|
rootProject.name = 'Stirling-PDF'
|
||||||
|
|
||||||
include 'common'
|
|
||||||
|
@ -8,10 +8,10 @@ import org.springframework.core.annotation.Order;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.EE.KeygenLicenseVerifier.License;
|
import stirling.software.SPDF.EE.KeygenLicenseVerifier.License;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.common.model.ApplicationProperties.EnterpriseEdition;
|
import stirling.software.SPDF.model.ApplicationProperties.EnterpriseEdition;
|
||||||
import stirling.software.common.model.ApplicationProperties.Premium;
|
import stirling.software.SPDF.model.ApplicationProperties.Premium;
|
||||||
import stirling.software.common.model.ApplicationProperties.Premium.ProFeatures.GoogleDrive;
|
import stirling.software.SPDF.model.ApplicationProperties.Premium.ProFeatures.GoogleDrive;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
|
@ -19,8 +19,8 @@ import com.posthog.java.shaded.org.json.JSONObject;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.common.util.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -49,8 +49,7 @@ public class KeygenLicenseVerifier {
|
|||||||
private final ApplicationProperties applicationProperties;
|
private final ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
// Shared HTTP client for connection pooling
|
// Shared HTTP client for connection pooling
|
||||||
private static final HttpClient httpClient =
|
private static final HttpClient httpClient = HttpClient.newBuilder()
|
||||||
HttpClient.newBuilder()
|
|
||||||
.version(HttpClient.Version.HTTP_2)
|
.version(HttpClient.Version.HTTP_2)
|
||||||
.connectTimeout(java.time.Duration.ofSeconds(10))
|
.connectTimeout(java.time.Duration.ofSeconds(10))
|
||||||
.build();
|
.build();
|
||||||
@ -417,9 +416,7 @@ public class KeygenLicenseVerifier {
|
|||||||
if (policyFloating) {
|
if (policyFloating) {
|
||||||
context.isFloatingLicense = true;
|
context.isFloatingLicense = true;
|
||||||
context.maxMachines = policyMaxMachines;
|
context.maxMachines = policyMaxMachines;
|
||||||
log.info(
|
log.info("Policy defines floating license with max machines: {}", context.maxMachines);
|
||||||
"Policy defines floating license with max machines: {}",
|
|
||||||
context.maxMachines);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract max users and isEnterprise from policy or metadata
|
// Extract max users and isEnterprise from policy or metadata
|
||||||
@ -477,8 +474,7 @@ public class KeygenLicenseVerifier {
|
|||||||
activateMachine(licenseKey, licenseId, machineFingerprint, context);
|
activateMachine(licenseKey, licenseId, machineFingerprint, context);
|
||||||
if (activated) {
|
if (activated) {
|
||||||
// Revalidate after activation
|
// Revalidate after activation
|
||||||
validationResponse =
|
validationResponse = validateLicense(licenseKey, machineFingerprint, context);
|
||||||
validateLicense(licenseKey, machineFingerprint, context);
|
|
||||||
isValid =
|
isValid =
|
||||||
validationResponse != null
|
validationResponse != null
|
||||||
&& validationResponse
|
&& validationResponse
|
||||||
@ -498,8 +494,8 @@ public class KeygenLicenseVerifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonNode validateLicense(
|
private JsonNode validateLicense(String licenseKey, String machineFingerprint, LicenseContext context)
|
||||||
String licenseKey, String machineFingerprint, LicenseContext context) throws Exception {
|
throws Exception {
|
||||||
String requestBody =
|
String requestBody =
|
||||||
String.format(
|
String.format(
|
||||||
"{\"meta\":{\"key\":\"%s\",\"scope\":{\"fingerprint\":\"%s\"}}}",
|
"{\"meta\":{\"key\":\"%s\",\"scope\":{\"fingerprint\":\"%s\"}}}",
|
||||||
@ -518,8 +514,7 @@ public class KeygenLicenseVerifier {
|
|||||||
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
|
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
HttpResponse<String> response =
|
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
|
||||||
log.info("ValidateLicenseResponse body: {}", response.body());
|
log.info("ValidateLicenseResponse body: {}", response.body());
|
||||||
JsonNode jsonResponse = objectMapper.readTree(response.body());
|
JsonNode jsonResponse = objectMapper.readTree(response.body());
|
||||||
if (response.statusCode() == 200) {
|
if (response.statusCode() == 200) {
|
||||||
@ -539,10 +534,8 @@ public class KeygenLicenseVerifier {
|
|||||||
context.isFloatingLicense = licenseAttrs.path("floating").asBoolean(false);
|
context.isFloatingLicense = licenseAttrs.path("floating").asBoolean(false);
|
||||||
context.maxMachines = licenseAttrs.path("maxMachines").asInt(1);
|
context.maxMachines = licenseAttrs.path("maxMachines").asInt(1);
|
||||||
|
|
||||||
log.info(
|
log.info("License floating (from license): {}, maxMachines: {}",
|
||||||
"License floating (from license): {}, maxMachines: {}",
|
context.isFloatingLicense, context.maxMachines);
|
||||||
context.isFloatingLicense,
|
|
||||||
context.maxMachines);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also check the policy for floating license support if included
|
// Also check the policy for floating license support if included
|
||||||
@ -560,8 +553,7 @@ public class KeygenLicenseVerifier {
|
|||||||
|
|
||||||
if (policyNode != null) {
|
if (policyNode != null) {
|
||||||
// Check if this is a floating license from policy
|
// Check if this is a floating license from policy
|
||||||
boolean policyFloating =
|
boolean policyFloating = policyNode.path("attributes").path("floating").asBoolean(false);
|
||||||
policyNode.path("attributes").path("floating").asBoolean(false);
|
|
||||||
int policyMaxMachines = policyNode.path("attributes").path("maxMachines").asInt(1);
|
int policyMaxMachines = policyNode.path("attributes").path("maxMachines").asInt(1);
|
||||||
|
|
||||||
// Policy takes precedence over license attributes
|
// Policy takes precedence over license attributes
|
||||||
@ -570,10 +562,8 @@ public class KeygenLicenseVerifier {
|
|||||||
context.maxMachines = policyMaxMachines;
|
context.maxMachines = policyMaxMachines;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info(
|
log.info("License floating (from policy): {}, maxMachines: {}",
|
||||||
"License floating (from policy): {}, maxMachines: {}",
|
context.isFloatingLicense, context.maxMachines);
|
||||||
context.isFloatingLicense,
|
|
||||||
context.maxMachines);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract user count, default to 1 if not specified
|
// Extract user count, default to 1 if not specified
|
||||||
@ -603,14 +593,11 @@ public class KeygenLicenseVerifier {
|
|||||||
return jsonResponse;
|
return jsonResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean activateMachine(
|
private boolean activateMachine(String licenseKey, String licenseId, String machineFingerprint,
|
||||||
String licenseKey, String licenseId, String machineFingerprint, LicenseContext context)
|
LicenseContext context) throws Exception {
|
||||||
throws Exception {
|
|
||||||
// For floating licenses, we first need to check if we need to deregister any machines
|
// For floating licenses, we first need to check if we need to deregister any machines
|
||||||
if (context.isFloatingLicense) {
|
if (context.isFloatingLicense) {
|
||||||
log.info(
|
log.info("Processing floating license activation. Max machines allowed: {}", context.maxMachines);
|
||||||
"Processing floating license activation. Max machines allowed: {}",
|
|
||||||
context.maxMachines);
|
|
||||||
|
|
||||||
// Get the current machines for this license
|
// Get the current machines for this license
|
||||||
JsonNode machinesResponse = fetchMachinesForLicense(licenseKey, licenseId);
|
JsonNode machinesResponse = fetchMachinesForLicense(licenseKey, licenseId);
|
||||||
@ -618,23 +605,17 @@ public class KeygenLicenseVerifier {
|
|||||||
JsonNode machines = machinesResponse.path("data");
|
JsonNode machines = machinesResponse.path("data");
|
||||||
int currentMachines = machines.size();
|
int currentMachines = machines.size();
|
||||||
|
|
||||||
log.info(
|
log.info("Current machine count: {}, Max allowed: {}", currentMachines, context.maxMachines);
|
||||||
"Current machine count: {}, Max allowed: {}",
|
|
||||||
currentMachines,
|
|
||||||
context.maxMachines);
|
|
||||||
|
|
||||||
// Check if the current fingerprint is already activated
|
// Check if the current fingerprint is already activated
|
||||||
boolean isCurrentMachineActivated = false;
|
boolean isCurrentMachineActivated = false;
|
||||||
String currentMachineId = null;
|
String currentMachineId = null;
|
||||||
|
|
||||||
for (JsonNode machine : machines) {
|
for (JsonNode machine : machines) {
|
||||||
if (machineFingerprint.equals(
|
if (machineFingerprint.equals(machine.path("attributes").path("fingerprint").asText())) {
|
||||||
machine.path("attributes").path("fingerprint").asText())) {
|
|
||||||
isCurrentMachineActivated = true;
|
isCurrentMachineActivated = true;
|
||||||
currentMachineId = machine.path("id").asText();
|
currentMachineId = machine.path("id").asText();
|
||||||
log.info(
|
log.info("Current machine is already activated with ID: {}", currentMachineId);
|
||||||
"Current machine is already activated with ID: {}",
|
|
||||||
currentMachineId);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -647,8 +628,7 @@ public class KeygenLicenseVerifier {
|
|||||||
|
|
||||||
// If we've reached the max machines limit, we need to deregister the oldest machine
|
// If we've reached the max machines limit, we need to deregister the oldest machine
|
||||||
if (currentMachines >= context.maxMachines) {
|
if (currentMachines >= context.maxMachines) {
|
||||||
log.info(
|
log.info("Max machines reached. Deregistering oldest machine to make room for the new machine.");
|
||||||
"Max machines reached. Deregistering oldest machine to make room for the new machine.");
|
|
||||||
|
|
||||||
// Find the oldest machine based on creation timestamp
|
// Find the oldest machine based on creation timestamp
|
||||||
if (machines.size() > 0) {
|
if (machines.size() > 0) {
|
||||||
@ -657,28 +637,23 @@ public class KeygenLicenseVerifier {
|
|||||||
java.time.Instant oldestTime = null;
|
java.time.Instant oldestTime = null;
|
||||||
|
|
||||||
for (JsonNode machine : machines) {
|
for (JsonNode machine : machines) {
|
||||||
String createdStr =
|
String createdStr = machine.path("attributes").path("created").asText(null);
|
||||||
machine.path("attributes").path("created").asText(null);
|
|
||||||
if (createdStr != null && !createdStr.isEmpty()) {
|
if (createdStr != null && !createdStr.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
java.time.Instant createdTime =
|
java.time.Instant createdTime = java.time.Instant.parse(createdStr);
|
||||||
java.time.Instant.parse(createdStr);
|
|
||||||
if (oldestTime == null || createdTime.isBefore(oldestTime)) {
|
if (oldestTime == null || createdTime.isBefore(oldestTime)) {
|
||||||
oldestTime = createdTime;
|
oldestTime = createdTime;
|
||||||
oldestMachineId = machine.path("id").asText();
|
oldestMachineId = machine.path("id").asText();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn(
|
log.warn("Could not parse creation time for machine: {}", e.getMessage());
|
||||||
"Could not parse creation time for machine: {}",
|
|
||||||
e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we couldn't determine the oldest by timestamp, use the first one
|
// If we couldn't determine the oldest by timestamp, use the first one
|
||||||
if (oldestMachineId == null) {
|
if (oldestMachineId == null) {
|
||||||
log.warn(
|
log.warn("Could not determine oldest machine by timestamp, using first machine in list");
|
||||||
"Could not determine oldest machine by timestamp, using first machine in list");
|
|
||||||
oldestMachineId = machines.path(0).path("id").asText();
|
oldestMachineId = machines.path(0).path("id").asText();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -686,15 +661,12 @@ public class KeygenLicenseVerifier {
|
|||||||
|
|
||||||
boolean deregistered = deregisterMachine(licenseKey, oldestMachineId);
|
boolean deregistered = deregisterMachine(licenseKey, oldestMachineId);
|
||||||
if (!deregistered) {
|
if (!deregistered) {
|
||||||
log.error(
|
log.error("Failed to deregister machine. Cannot proceed with activation.");
|
||||||
"Failed to deregister machine. Cannot proceed with activation.");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
log.info(
|
log.info("Machine deregistered successfully. Proceeding with activation of new machine.");
|
||||||
"Machine deregistered successfully. Proceeding with activation of new machine.");
|
|
||||||
} else {
|
} else {
|
||||||
log.error(
|
log.error("License has reached machine limit but no machines were found to deregister. This is unexpected.");
|
||||||
"License has reached machine limit but no machines were found to deregister. This is unexpected.");
|
|
||||||
// We'll still try to activate, but it might fail
|
// We'll still try to activate, but it might fail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -748,8 +720,7 @@ public class KeygenLicenseVerifier {
|
|||||||
.POST(HttpRequest.BodyPublishers.ofString(body.toString()))
|
.POST(HttpRequest.BodyPublishers.ofString(body.toString()))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
HttpResponse<String> response =
|
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
|
||||||
log.info("activateMachine Response body: " + response.body());
|
log.info("activateMachine Response body: " + response.body());
|
||||||
if (response.statusCode() == 201) {
|
if (response.statusCode() == 201) {
|
||||||
log.info("Machine activated successfully");
|
log.info("Machine activated successfully");
|
||||||
@ -777,33 +748,22 @@ public class KeygenLicenseVerifier {
|
|||||||
* @throws Exception if an error occurs during the HTTP request
|
* @throws Exception if an error occurs during the HTTP request
|
||||||
*/
|
*/
|
||||||
private JsonNode fetchMachinesForLicense(String licenseKey, String licenseId) throws Exception {
|
private JsonNode fetchMachinesForLicense(String licenseKey, String licenseId) throws Exception {
|
||||||
HttpRequest request =
|
HttpRequest request = HttpRequest.newBuilder()
|
||||||
HttpRequest.newBuilder()
|
.uri(URI.create(BASE_URL + "/" + ACCOUNT_ID + "/licenses/" + licenseId + "/machines"))
|
||||||
.uri(
|
|
||||||
URI.create(
|
|
||||||
BASE_URL
|
|
||||||
+ "/"
|
|
||||||
+ ACCOUNT_ID
|
|
||||||
+ "/licenses/"
|
|
||||||
+ licenseId
|
|
||||||
+ "/machines"))
|
|
||||||
.header("Content-Type", "application/vnd.api+json")
|
.header("Content-Type", "application/vnd.api+json")
|
||||||
.header("Accept", "application/vnd.api+json")
|
.header("Accept", "application/vnd.api+json")
|
||||||
.header("Authorization", "License " + licenseKey)
|
.header("Authorization", "License " + licenseKey)
|
||||||
.GET()
|
.GET()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
HttpResponse<String> response =
|
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
|
||||||
log.info("fetchMachinesForLicense Response body: {}", response.body());
|
log.info("fetchMachinesForLicense Response body: {}", response.body());
|
||||||
|
|
||||||
if (response.statusCode() == 200) {
|
if (response.statusCode() == 200) {
|
||||||
return objectMapper.readTree(response.body());
|
return objectMapper.readTree(response.body());
|
||||||
} else {
|
} else {
|
||||||
log.error(
|
log.error("Error fetching machines for license. Status code: {}, error: {}",
|
||||||
"Error fetching machines for license. Status code: {}, error: {}",
|
response.statusCode(), response.body());
|
||||||
response.statusCode(),
|
|
||||||
response.body());
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -817,8 +777,7 @@ public class KeygenLicenseVerifier {
|
|||||||
*/
|
*/
|
||||||
private boolean deregisterMachine(String licenseKey, String machineId) {
|
private boolean deregisterMachine(String licenseKey, String machineId) {
|
||||||
try {
|
try {
|
||||||
HttpRequest request =
|
HttpRequest request = HttpRequest.newBuilder()
|
||||||
HttpRequest.newBuilder()
|
|
||||||
.uri(URI.create(BASE_URL + "/" + ACCOUNT_ID + "/machines/" + machineId))
|
.uri(URI.create(BASE_URL + "/" + ACCOUNT_ID + "/machines/" + machineId))
|
||||||
.header("Content-Type", "application/vnd.api+json")
|
.header("Content-Type", "application/vnd.api+json")
|
||||||
.header("Accept", "application/vnd.api+json")
|
.header("Accept", "application/vnd.api+json")
|
||||||
@ -826,17 +785,14 @@ public class KeygenLicenseVerifier {
|
|||||||
.DELETE()
|
.DELETE()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
HttpResponse<String> response =
|
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
|
||||||
|
|
||||||
if (response.statusCode() == 204) {
|
if (response.statusCode() == 204) {
|
||||||
log.info("Machine {} successfully deregistered", machineId);
|
log.info("Machine {} successfully deregistered", machineId);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
log.error(
|
log.error("Error deregistering machine. Status code: {}, error: {}",
|
||||||
"Error deregistering machine. Status code: {}, error: {}",
|
response.statusCode(), response.body());
|
||||||
response.statusCode(),
|
|
||||||
response.body());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -11,8 +11,8 @@ import org.springframework.stereotype.Component;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.EE.KeygenLicenseVerifier.License;
|
import stirling.software.SPDF.EE.KeygenLicenseVerifier.License;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.common.util.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -3,11 +3,11 @@ package stirling.software.SPDF.Factories;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import stirling.software.common.model.api.misc.HighContrastColorCombination;
|
import stirling.software.SPDF.model.api.misc.HighContrastColorCombination;
|
||||||
import stirling.software.common.model.api.misc.ReplaceAndInvert;
|
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
|
||||||
import stirling.software.common.util.misc.CustomColorReplaceStrategy;
|
import stirling.software.SPDF.utils.misc.CustomColorReplaceStrategy;
|
||||||
import stirling.software.common.util.misc.InvertFullColorStrategy;
|
import stirling.software.SPDF.utils.misc.InvertFullColorStrategy;
|
||||||
import stirling.software.common.util.misc.ReplaceAndInvertColorStrategy;
|
import stirling.software.SPDF.utils.misc.ReplaceAndInvertColorStrategy;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class ReplaceAndInvertColorFactory {
|
public class ReplaceAndInvertColorFactory {
|
||||||
|
@ -31,8 +31,7 @@ public class LibreOfficeListener {
|
|||||||
log.info("waiting for listener to start");
|
log.info("waiting for listener to start");
|
||||||
try (Socket socket = new Socket()) {
|
try (Socket socket = new Socket()) {
|
||||||
socket.connect(
|
socket.connect(
|
||||||
new InetSocketAddress("localhost", LISTENER_PORT),
|
new InetSocketAddress("localhost", 2002), 1000); // Timeout after 1 second
|
||||||
1000); // Timeout after 1 second
|
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -14,8 +14,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
|
||||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
|
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
@ -27,19 +25,14 @@ import jakarta.annotation.PreDestroy;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.UI.WebBrowser;
|
import stirling.software.SPDF.UI.WebBrowser;
|
||||||
import stirling.software.common.configuration.ConfigInitializer;
|
import stirling.software.SPDF.config.ConfigInitializer;
|
||||||
import stirling.software.common.configuration.InstallationPathConfig;
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.common.util.UrlUtils;
|
import stirling.software.SPDF.utils.UrlUtils;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
@SpringBootApplication(
|
@SpringBootApplication
|
||||||
scanBasePackages = {"stirling.software.common", "stirling.software.SPDF"},
|
|
||||||
exclude = {
|
|
||||||
DataSourceAutoConfiguration.class,
|
|
||||||
DataSourceTransactionManagerAutoConfiguration.class
|
|
||||||
})
|
|
||||||
public class SPDFApplication {
|
public class SPDFApplication {
|
||||||
|
|
||||||
private static String serverPortStatic;
|
private static String serverPortStatic;
|
||||||
|
@ -43,8 +43,8 @@ import me.friwi.jcefmaven.MavenCefAppHandlerAdapter;
|
|||||||
import me.friwi.jcefmaven.impl.progress.ConsoleProgressHandler;
|
import me.friwi.jcefmaven.impl.progress.ConsoleProgressHandler;
|
||||||
|
|
||||||
import stirling.software.SPDF.UI.WebBrowser;
|
import stirling.software.SPDF.UI.WebBrowser;
|
||||||
import stirling.software.common.configuration.InstallationPathConfig;
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
import stirling.software.common.util.UIScaling;
|
import stirling.software.SPDF.utils.UIScaling;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -15,7 +15,7 @@ import io.github.pixee.security.BoundedLineReader;
|
|||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.common.util.UIScaling;
|
import stirling.software.SPDF.utils.UIScaling;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class LoadingWindow extends JDialog {
|
public class LoadingWindow extends JDialog {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package stirling.software.common.configuration;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@ -8,9 +8,7 @@ import java.util.List;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
@ -23,29 +21,21 @@ import org.springframework.core.io.ClassPathResource;
|
|||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.ResourceLoader;
|
import org.springframework.core.io.ResourceLoader;
|
||||||
import org.thymeleaf.spring6.SpringTemplateEngine;
|
import org.thymeleaf.spring6.SpringTemplateEngine;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
@Lazy
|
@Lazy
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Configuration
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
||||||
private final Environment env;
|
|
||||||
|
|
||||||
private final ApplicationProperties applicationProperties;
|
private final ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
@Getter
|
private final Environment env;
|
||||||
@Value("${baseUrl:http://localhost}")
|
|
||||||
private String baseUrl;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Value("${server.servlet.context-path:/}")
|
|
||||||
private String contextPath;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Value("${server.port:8080}")
|
|
||||||
private String serverPort;
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnProperty(name = "system.customHTMLFiles", havingValue = "true")
|
@ConditionalOnProperty(name = "system.customHTMLFiles", havingValue = "true")
|
||||||
@ -208,31 +198,6 @@ public class AppConfig {
|
|||||||
return applicationProperties.getAutomaticallyGenerated().getUUID();
|
return applicationProperties.getAutomaticallyGenerated().getUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ApplicationProperties.Security security() {
|
|
||||||
return applicationProperties.getSecurity();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ApplicationProperties.Security.OAUTH2 oAuth2() {
|
|
||||||
return applicationProperties.getSecurity().getOauth2();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ApplicationProperties.Premium premium() {
|
|
||||||
return applicationProperties.getPremium();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ApplicationProperties.System system() {
|
|
||||||
return applicationProperties.getSystem();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ApplicationProperties.Datasource datasource() {
|
|
||||||
return applicationProperties.getSystem().getDatasource();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean(name = "disablePixel")
|
@Bean(name = "disablePixel")
|
||||||
public boolean disablePixel() {
|
public boolean disablePixel() {
|
||||||
return Boolean.getBoolean(env.getProperty("DISABLE_PIXEL"));
|
return Boolean.getBoolean(env.getProperty("DISABLE_PIXEL"));
|
@ -6,7 +6,7 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
|
|
||||||
import stirling.software.SPDF.config.interfaces.ShowAdminInterface;
|
import stirling.software.SPDF.config.interfaces.ShowAdminInterface;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
class AppUpdateService {
|
class AppUpdateService {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package stirling.software.common.configuration;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -13,8 +13,6 @@ import java.util.List;
|
|||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.common.util.YamlHelper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A naive, line-based approach to merging "settings.yml" with "settings.yml.template" while
|
* A naive, line-based approach to merging "settings.yml" with "settings.yml.template" while
|
||||||
* preserving exact whitespace, blank lines, and inline comments -- but we only rewrite the file if
|
* preserving exact whitespace, blank lines, and inline comments -- but we only rewrite the file if
|
||||||
@ -78,7 +76,7 @@ public class ConfigInitializer {
|
|||||||
Path customSettingsPath = Paths.get(InstallationPathConfig.getCustomSettingsPath());
|
Path customSettingsPath = Paths.get(InstallationPathConfig.getCustomSettingsPath());
|
||||||
if (Files.notExists(customSettingsPath)) {
|
if (Files.notExists(customSettingsPath)) {
|
||||||
Files.createFile(customSettingsPath);
|
Files.createFile(customSettingsPath);
|
||||||
log.info("Created custom_settings file: {}", customSettingsPath);
|
log.info("Created custom_settings file: {}", customSettingsPath.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -12,8 +12,6 @@ import jakarta.annotation.PostConstruct;
|
|||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.common.configuration.RuntimePathConfig;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ExternalAppDepConfig {
|
public class ExternalAppDepConfig {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package stirling.software.common.configuration;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -10,11 +10,9 @@ import org.thymeleaf.IEngineConfiguration;
|
|||||||
import org.thymeleaf.templateresolver.AbstractConfigurableTemplateResolver;
|
import org.thymeleaf.templateresolver.AbstractConfigurableTemplateResolver;
|
||||||
import org.thymeleaf.templateresource.FileTemplateResource;
|
import org.thymeleaf.templateresource.FileTemplateResource;
|
||||||
import org.thymeleaf.templateresource.ITemplateResource;
|
import org.thymeleaf.templateresource.ITemplateResource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import stirling.software.common.model.InputStreamTemplateResource;
|
import stirling.software.SPDF.model.InputStreamTemplateResource;
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateResolver {
|
public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateResolver {
|
||||||
|
|
||||||
private final ResourceLoader resourceLoader;
|
private final ResourceLoader resourceLoader;
|
||||||
@ -42,8 +40,7 @@ public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateRe
|
|||||||
return new FileTemplateResource(resource.getFile().getPath(), characterEncoding);
|
return new FileTemplateResource(resource.getFile().getPath(), characterEncoding);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Log the exception to help with debugging issues loading external templates
|
|
||||||
log.warn("Unable to read template '{}' from file system", resourceName, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InputStream inputStream =
|
InputStream inputStream =
|
@ -17,8 +17,8 @@ import jakarta.annotation.PostConstruct;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.common.util.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package stirling.software.common.configuration;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
@ -50,6 +50,7 @@ public class InstallationPathConfig {
|
|||||||
return Paths.get(
|
return Paths.get(
|
||||||
System.getenv("APPDATA"), // parent path
|
System.getenv("APPDATA"), // parent path
|
||||||
"Stirling-PDF")
|
"Stirling-PDF")
|
||||||
|
.toString()
|
||||||
+ File.separator;
|
+ File.separator;
|
||||||
} else if (os.contains("mac")) {
|
} else if (os.contains("mac")) {
|
||||||
return Paths.get(
|
return Paths.get(
|
||||||
@ -57,12 +58,14 @@ public class InstallationPathConfig {
|
|||||||
"Library",
|
"Library",
|
||||||
"Application Support",
|
"Application Support",
|
||||||
"Stirling-PDF")
|
"Stirling-PDF")
|
||||||
|
.toString()
|
||||||
+ File.separator;
|
+ File.separator;
|
||||||
} else {
|
} else {
|
||||||
return Paths.get(
|
return Paths.get(
|
||||||
System.getProperty("user.home"), // parent path
|
System.getProperty("user.home"), // parent path
|
||||||
".config",
|
".config",
|
||||||
"Stirling-PDF")
|
"Stirling-PDF")
|
||||||
|
.toString()
|
||||||
+ File.separator;
|
+ File.separator;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,7 +12,7 @@ import org.springframework.web.servlet.i18n.SessionLocaleResolver;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package stirling.software.SPDF.config;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
import stirling.software.common.configuration.InstallationPathConfig;
|
|
||||||
|
|
||||||
import ch.qos.logback.core.PropertyDefinerBase;
|
import ch.qos.logback.core.PropertyDefinerBase;
|
||||||
|
|
||||||
public class LogbackPropertyLoader extends PropertyDefinerBase {
|
public class LogbackPropertyLoader extends PropertyDefinerBase {
|
||||||
|
@ -16,7 +16,7 @@ import jakarta.servlet.http.HttpSession;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.common.util.RequestUriUtils;
|
import stirling.software.SPDF.utils.RequestUriUtils;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@ -13,7 +13,7 @@ import io.swagger.v3.oas.models.security.SecurityScheme;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package stirling.software.common.configuration;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
@ -1,4 +1,4 @@
|
|||||||
package stirling.software.common.configuration;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package stirling.software.common.configuration;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@ -9,9 +9,9 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.common.model.ApplicationProperties.CustomPaths.Operations;
|
import stirling.software.SPDF.model.ApplicationProperties.CustomPaths.Operations;
|
||||||
import stirling.software.common.model.ApplicationProperties.CustomPaths.Pipeline;
|
import stirling.software.SPDF.model.ApplicationProperties.CustomPaths.Pipeline;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Configuration
|
@Configuration
|
@ -7,8 +7,6 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.common.configuration.InstallationPathConfig;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class WebMvcConfig implements WebMvcConfigurer {
|
public class WebMvcConfig implements WebMvcConfigurer {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package stirling.software.common.util;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
@ -1,6 +1,8 @@
|
|||||||
package stirling.software.common.configuration;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
||||||
import org.springframework.core.env.PropertiesPropertySource;
|
import org.springframework.core.env.PropertiesPropertySource;
|
||||||
import org.springframework.core.env.PropertySource;
|
import org.springframework.core.env.PropertySource;
|
||||||
@ -10,7 +12,8 @@ import org.springframework.core.io.support.PropertySourceFactory;
|
|||||||
public class YamlPropertySourceFactory implements PropertySourceFactory {
|
public class YamlPropertySourceFactory implements PropertySourceFactory {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) {
|
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource)
|
||||||
|
throws IOException {
|
||||||
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
||||||
factory.setResources(encodedResource.getResource());
|
factory.setResources(encodedResource.getResource());
|
||||||
Properties properties = factory.getObject();
|
Properties properties = factory.getObject();
|
@ -3,8 +3,8 @@ package stirling.software.SPDF.config.interfaces;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import stirling.software.common.model.FileInfo;
|
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
|
||||||
import stirling.software.common.model.exception.UnsupportedProviderException;
|
import stirling.software.SPDF.utils.FileInfo;
|
||||||
|
|
||||||
public interface DatabaseInterface {
|
public interface DatabaseInterface {
|
||||||
void exportDatabase() throws SQLException, UnsupportedProviderException;
|
void exportDatabase() throws SQLException, UnsupportedProviderException;
|
||||||
|
@ -9,9 +9,9 @@ import org.springframework.stereotype.Service;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.SPDF.config.interfaces.ShowAdminInterface;
|
import stirling.software.SPDF.config.interfaces.ShowAdminInterface;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.User;
|
import stirling.software.SPDF.model.User;
|
||||||
import stirling.software.SPDF.repository.UserRepository;
|
import stirling.software.SPDF.repository.UserRepository;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@ -13,7 +13,7 @@ import jakarta.servlet.http.HttpSession;
|
|||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.common.util.RequestUriUtils;
|
import stirling.software.SPDF.utils.RequestUriUtils;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class CustomAuthenticationSuccessHandler
|
public class CustomAuthenticationSuccessHandler
|
||||||
|
@ -25,11 +25,11 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import stirling.software.SPDF.SPDFApplication;
|
import stirling.software.SPDF.SPDFApplication;
|
||||||
import stirling.software.SPDF.config.security.saml2.CertificateUtils;
|
import stirling.software.SPDF.config.security.saml2.CertificateUtils;
|
||||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
|
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||||
import stirling.software.common.model.ApplicationProperties.Security.SAML2;
|
import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2;
|
||||||
import stirling.software.common.model.oauth2.KeycloakProvider;
|
import stirling.software.SPDF.model.provider.KeycloakProvider;
|
||||||
import stirling.software.common.util.UrlUtils;
|
import stirling.software.SPDF.utils.UrlUtils;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@ -20,7 +20,7 @@ import jakarta.servlet.http.HttpSession;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.User;
|
import stirling.software.SPDF.model.User;
|
||||||
import stirling.software.common.util.RequestUriUtils;
|
import stirling.software.SPDF.utils.RequestUriUtils;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
|
@ -9,7 +9,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.common.util.RequestUriUtils;
|
import stirling.software.SPDF.utils.RequestUriUtils;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class IPRateLimitingFilter implements Filter {
|
public class IPRateLimitingFilter implements Filter {
|
||||||
|
@ -11,9 +11,9 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
|
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.Role;
|
import stirling.software.SPDF.model.Role;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
|
||||||
import stirling.software.common.model.exception.UnsupportedProviderException;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
|
@ -10,8 +10,8 @@ import jakarta.annotation.PostConstruct;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.AttemptCounter;
|
import stirling.software.SPDF.model.AttemptCounter;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -37,10 +37,10 @@ import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticationFai
|
|||||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticationSuccessHandler;
|
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticationSuccessHandler;
|
||||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2ResponseAuthenticationConverter;
|
import stirling.software.SPDF.config.security.saml2.CustomSaml2ResponseAuthenticationConverter;
|
||||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.User;
|
import stirling.software.SPDF.model.User;
|
||||||
import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
|
import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
|
||||||
import stirling.software.SPDF.repository.PersistentLoginRepository;
|
import stirling.software.SPDF.repository.PersistentLoginRepository;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
|
@ -27,26 +27,27 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
||||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
||||||
import stirling.software.SPDF.model.ApiKeyAuthenticationToken;
|
import stirling.software.SPDF.model.ApiKeyAuthenticationToken;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties.Security;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2;
|
||||||
import stirling.software.SPDF.model.User;
|
import stirling.software.SPDF.model.User;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
|
||||||
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
|
|
||||||
import stirling.software.common.model.ApplicationProperties.Security.SAML2;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
public class UserAuthenticationFilter extends OncePerRequestFilter {
|
public class UserAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
private final ApplicationProperties.Security securityProp;
|
private final ApplicationProperties applicationProperties;
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
private final SessionPersistentRegistry sessionPersistentRegistry;
|
private final SessionPersistentRegistry sessionPersistentRegistry;
|
||||||
private final boolean loginEnabledValue;
|
private final boolean loginEnabledValue;
|
||||||
|
|
||||||
public UserAuthenticationFilter(
|
public UserAuthenticationFilter(
|
||||||
@Lazy ApplicationProperties.Security securityProp,
|
@Lazy ApplicationProperties applicationProperties,
|
||||||
@Lazy UserService userService,
|
@Lazy UserService userService,
|
||||||
SessionPersistentRegistry sessionPersistentRegistry,
|
SessionPersistentRegistry sessionPersistentRegistry,
|
||||||
@Qualifier("loginEnabled") boolean loginEnabledValue) {
|
@Qualifier("loginEnabled") boolean loginEnabledValue) {
|
||||||
this.securityProp = securityProp;
|
this.applicationProperties = applicationProperties;
|
||||||
this.userService = userService;
|
this.userService = userService;
|
||||||
this.sessionPersistentRegistry = sessionPersistentRegistry;
|
this.sessionPersistentRegistry = sessionPersistentRegistry;
|
||||||
this.loginEnabledValue = loginEnabledValue;
|
this.loginEnabledValue = loginEnabledValue;
|
||||||
@ -133,6 +134,7 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
// Check if the authenticated user is disabled and invalidate their session if so
|
// Check if the authenticated user is disabled and invalidate their session if so
|
||||||
if (authentication != null && authentication.isAuthenticated()) {
|
if (authentication != null && authentication.isAuthenticated()) {
|
||||||
|
|
||||||
|
Security securityProp = applicationProperties.getSecurity();
|
||||||
LoginMethod loginMethod = LoginMethod.UNKNOWN;
|
LoginMethod loginMethod = LoginMethod.UNKNOWN;
|
||||||
|
|
||||||
boolean blockRegistration = false;
|
boolean blockRegistration = false;
|
||||||
|
@ -2,13 +2,7 @@ package stirling.software.SPDF.config.security;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.springframework.context.MessageSource;
|
import org.springframework.context.MessageSource;
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
@ -31,15 +25,11 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
|
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
|
||||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
||||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
||||||
import stirling.software.SPDF.model.AuthenticationType;
|
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
|
||||||
import stirling.software.SPDF.model.Authority;
|
import stirling.software.SPDF.model.*;
|
||||||
import stirling.software.SPDF.model.Role;
|
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
|
||||||
import stirling.software.SPDF.model.User;
|
|
||||||
import stirling.software.SPDF.repository.AuthorityRepository;
|
import stirling.software.SPDF.repository.AuthorityRepository;
|
||||||
import stirling.software.SPDF.repository.UserRepository;
|
import stirling.software.SPDF.repository.UserRepository;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
|
||||||
import stirling.software.common.model.exception.UnsupportedProviderException;
|
|
||||||
import stirling.software.common.service.UserServiceInterface;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -58,7 +48,7 @@ public class UserService implements UserServiceInterface {
|
|||||||
|
|
||||||
private final DatabaseInterface databaseService;
|
private final DatabaseInterface databaseService;
|
||||||
|
|
||||||
private final ApplicationProperties.Security.OAUTH2 oAuth2;
|
private final ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void migrateOauth2ToSSO() {
|
public void migrateOauth2ToSSO() {
|
||||||
@ -421,7 +411,8 @@ public class UserService implements UserServiceInterface {
|
|||||||
} else if (principal instanceof stirling.software.SPDF.model.User domainUser) {
|
} else if (principal instanceof stirling.software.SPDF.model.User domainUser) {
|
||||||
return domainUser.getUsername();
|
return domainUser.getUsername();
|
||||||
} else if (principal instanceof OAuth2User oAuth2User) {
|
} else if (principal instanceof OAuth2User oAuth2User) {
|
||||||
return oAuth2User.getAttribute(oAuth2.getUseAsUsername());
|
return oAuth2User.getAttribute(
|
||||||
|
applicationProperties.getSecurity().getOauth2().getUseAsUsername());
|
||||||
} else if (principal instanceof CustomSaml2AuthenticatedPrincipal saml2User) {
|
} else if (principal instanceof CustomSaml2AuthenticatedPrincipal saml2User) {
|
||||||
return saml2User.name();
|
return saml2User.name();
|
||||||
} else if (principal instanceof String stringUser) {
|
} else if (principal instanceof String stringUser) {
|
||||||
|
@ -10,9 +10,9 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.common.configuration.InstallationPathConfig;
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.common.model.exception.UnsupportedProviderException;
|
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Getter
|
@Getter
|
||||||
@ -26,18 +26,18 @@ public class DatabaseConfig {
|
|||||||
public static final String DEFAULT_USERNAME = "sa";
|
public static final String DEFAULT_USERNAME = "sa";
|
||||||
public static final String POSTGRES_DRIVER = "org.postgresql.Driver";
|
public static final String POSTGRES_DRIVER = "org.postgresql.Driver";
|
||||||
|
|
||||||
private final ApplicationProperties.Datasource datasource;
|
private final ApplicationProperties applicationProperties;
|
||||||
private final boolean runningProOrHigher;
|
private final boolean runningProOrHigher;
|
||||||
|
|
||||||
public DatabaseConfig(
|
public DatabaseConfig(
|
||||||
ApplicationProperties.Datasource datasource,
|
ApplicationProperties applicationProperties,
|
||||||
@Qualifier("runningProOrHigher") boolean runningProOrHigher) {
|
@Qualifier("runningProOrHigher") boolean runningProOrHigher) {
|
||||||
DATASOURCE_DEFAULT_URL =
|
DATASOURCE_DEFAULT_URL =
|
||||||
"jdbc:h2:file:"
|
"jdbc:h2:file:"
|
||||||
+ InstallationPathConfig.getConfigPath()
|
+ InstallationPathConfig.getConfigPath()
|
||||||
+ "stirling-pdf-DB-2.3.232;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=PostgreSQL";
|
+ "stirling-pdf-DB-2.3.232;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE";
|
||||||
log.debug("Database URL: {}", DATASOURCE_DEFAULT_URL);
|
log.debug("Database URL: {}", DATASOURCE_DEFAULT_URL);
|
||||||
this.datasource = datasource;
|
this.applicationProperties = applicationProperties;
|
||||||
this.runningProOrHigher = runningProOrHigher;
|
this.runningProOrHigher = runningProOrHigher;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +58,9 @@ public class DatabaseConfig {
|
|||||||
return useDefaultDataSource(dataSourceBuilder);
|
return useDefaultDataSource(dataSourceBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ApplicationProperties.System system = applicationProperties.getSystem();
|
||||||
|
ApplicationProperties.Datasource datasource = system.getDatasource();
|
||||||
|
|
||||||
if (!datasource.isEnableCustomDatabase()) {
|
if (!datasource.isEnableCustomDatabase()) {
|
||||||
return useDefaultDataSource(dataSourceBuilder);
|
return useDefaultDataSource(dataSourceBuilder);
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,11 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
|
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.exception.BackupNotFoundException;
|
import stirling.software.SPDF.model.exception.BackupNotFoundException;
|
||||||
import stirling.software.common.configuration.InstallationPathConfig;
|
import stirling.software.SPDF.utils.FileInfo;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
|
||||||
import stirling.software.common.model.FileInfo;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ -41,14 +41,13 @@ public class DatabaseService implements DatabaseInterface {
|
|||||||
public static final String SQL_SUFFIX = ".sql";
|
public static final String SQL_SUFFIX = ".sql";
|
||||||
private final Path BACKUP_DIR;
|
private final Path BACKUP_DIR;
|
||||||
|
|
||||||
private final ApplicationProperties.Datasource datasourceProps;
|
private final ApplicationProperties applicationProperties;
|
||||||
private final DataSource dataSource;
|
private final DataSource dataSource;
|
||||||
|
|
||||||
public DatabaseService(
|
public DatabaseService(ApplicationProperties applicationProperties, DataSource dataSource) {
|
||||||
ApplicationProperties.Datasource datasourceProps, DataSource dataSource) {
|
|
||||||
this.BACKUP_DIR =
|
this.BACKUP_DIR =
|
||||||
Paths.get(InstallationPathConfig.getConfigPath(), "db", "backup").normalize();
|
Paths.get(InstallationPathConfig.getConfigPath(), "db", "backup").normalize();
|
||||||
this.datasourceProps = datasourceProps;
|
this.applicationProperties = applicationProperties;
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,12 +238,15 @@ public class DatabaseService implements DatabaseInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isH2Database() {
|
private boolean isH2Database() {
|
||||||
|
ApplicationProperties.Datasource datasource =
|
||||||
|
applicationProperties.getSystem().getDatasource();
|
||||||
|
|
||||||
boolean isTypeH2 =
|
boolean isTypeH2 =
|
||||||
datasourceProps.getType().equalsIgnoreCase(ApplicationProperties.Driver.H2.name());
|
datasource.getType().equalsIgnoreCase(ApplicationProperties.Driver.H2.name());
|
||||||
boolean isDBUrlH2 =
|
boolean isDBUrlH2 =
|
||||||
datasourceProps.getCustomDatabaseUrl().contains("h2")
|
datasource.getCustomDatabaseUrl().contains("h2")
|
||||||
|| datasourceProps.getCustomDatabaseUrl().contains("H2");
|
|| datasource.getCustomDatabaseUrl().contains("H2");
|
||||||
boolean isCustomDatabase = datasourceProps.isEnableCustomDatabase();
|
boolean isCustomDatabase = datasource.isEnableCustomDatabase();
|
||||||
|
|
||||||
if (isCustomDatabase) {
|
if (isCustomDatabase) {
|
||||||
if (isTypeH2 && !isDBUrlH2) {
|
if (isTypeH2 && !isDBUrlH2) {
|
||||||
|
@ -10,7 +10,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
|
|
||||||
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
|
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
|
||||||
import stirling.software.SPDF.controller.api.H2SQLCondition;
|
import stirling.software.SPDF.controller.api.H2SQLCondition;
|
||||||
import stirling.software.common.model.exception.UnsupportedProviderException;
|
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Conditional(H2SQLCondition.class)
|
@Conditional(H2SQLCondition.class)
|
||||||
|
@ -12,8 +12,8 @@ import jakarta.mail.internet.MimeMessage;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.api.Email;
|
import stirling.software.SPDF.model.api.Email;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service class responsible for sending emails, including those with attachments. It uses
|
* Service class responsible for sending emails, including those with attachments. It uses
|
||||||
@ -37,21 +37,8 @@ public class EmailService {
|
|||||||
*/
|
*/
|
||||||
@Async
|
@Async
|
||||||
public void sendEmailWithAttachment(Email email) throws MessagingException {
|
public void sendEmailWithAttachment(Email email) throws MessagingException {
|
||||||
MultipartFile file = email.getFileInput();
|
|
||||||
// 1) Validate recipient email address
|
|
||||||
if (email.getTo() == null || email.getTo().trim().isEmpty()) {
|
|
||||||
throw new MessagingException("Invalid Addresses");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2) Validate attachment
|
|
||||||
if (file == null
|
|
||||||
|| file.isEmpty()
|
|
||||||
|| file.getOriginalFilename() == null
|
|
||||||
|| file.getOriginalFilename().isEmpty()) {
|
|
||||||
throw new MessagingException("An attachment is required to send the email.");
|
|
||||||
}
|
|
||||||
|
|
||||||
ApplicationProperties.Mail mailProperties = applicationProperties.getMail();
|
ApplicationProperties.Mail mailProperties = applicationProperties.getMail();
|
||||||
|
MultipartFile file = email.getFileInput();
|
||||||
|
|
||||||
// Creates a MimeMessage to represent the email
|
// Creates a MimeMessage to represent the email
|
||||||
MimeMessage message = mailSender.createMimeMessage();
|
MimeMessage message = mailSender.createMimeMessage();
|
||||||
|
@ -11,7 +11,7 @@ import org.springframework.mail.javamail.JavaMailSenderImpl;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This configuration class provides the JavaMailSender bean, which is used to send emails. It reads
|
* This configuration class provides the JavaMailSender bean, which is used to send emails. It reads
|
||||||
|
@ -19,11 +19,11 @@ import lombok.RequiredArgsConstructor;
|
|||||||
|
|
||||||
import stirling.software.SPDF.config.security.LoginAttemptService;
|
import stirling.software.SPDF.config.security.LoginAttemptService;
|
||||||
import stirling.software.SPDF.config.security.UserService;
|
import stirling.software.SPDF.config.security.UserService;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||||
import stirling.software.SPDF.model.AuthenticationType;
|
import stirling.software.SPDF.model.AuthenticationType;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
|
||||||
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
|
import stirling.software.SPDF.utils.RequestUriUtils;
|
||||||
import stirling.software.common.model.exception.UnsupportedProviderException;
|
|
||||||
import stirling.software.common.util.RequestUriUtils;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class CustomOAuth2AuthenticationSuccessHandler
|
public class CustomOAuth2AuthenticationSuccessHandler
|
||||||
|
@ -15,10 +15,10 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
|
|
||||||
import stirling.software.SPDF.config.security.LoginAttemptService;
|
import stirling.software.SPDF.config.security.LoginAttemptService;
|
||||||
import stirling.software.SPDF.config.security.UserService;
|
import stirling.software.SPDF.config.security.UserService;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||||
import stirling.software.SPDF.model.User;
|
import stirling.software.SPDF.model.User;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.UsernameAttribute;
|
||||||
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
|
|
||||||
import stirling.software.common.model.enumeration.UsernameAttribute;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class CustomOAuth2UserService implements OAuth2UserService<OidcUserRequest, OidcUser> {
|
public class CustomOAuth2UserService implements OAuth2UserService<OidcUserRequest, OidcUser> {
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package stirling.software.SPDF.config.security.oauth2;
|
package stirling.software.SPDF.config.security.oauth2;
|
||||||
|
|
||||||
import static org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE;
|
import static org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE;
|
||||||
import static stirling.software.common.util.ProviderUtils.validateProvider;
|
import static stirling.software.SPDF.utils.validation.Validator.*;
|
||||||
import static stirling.software.common.util.ValidationUtils.isStringEmpty;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -26,16 +25,16 @@ import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.config.security.UserService;
|
import stirling.software.SPDF.config.security.UserService;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client;
|
||||||
import stirling.software.SPDF.model.User;
|
import stirling.software.SPDF.model.User;
|
||||||
|
import stirling.software.SPDF.model.UsernameAttribute;
|
||||||
import stirling.software.SPDF.model.exception.NoProviderFoundException;
|
import stirling.software.SPDF.model.exception.NoProviderFoundException;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.provider.GitHubProvider;
|
||||||
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
|
import stirling.software.SPDF.model.provider.GoogleProvider;
|
||||||
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2.Client;
|
import stirling.software.SPDF.model.provider.KeycloakProvider;
|
||||||
import stirling.software.common.model.enumeration.UsernameAttribute;
|
import stirling.software.SPDF.model.provider.Provider;
|
||||||
import stirling.software.common.model.oauth2.GitHubProvider;
|
|
||||||
import stirling.software.common.model.oauth2.GoogleProvider;
|
|
||||||
import stirling.software.common.model.oauth2.KeycloakProvider;
|
|
||||||
import stirling.software.common.model.oauth2.Provider;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@ -18,11 +18,11 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
|
|
||||||
import stirling.software.SPDF.config.security.LoginAttemptService;
|
import stirling.software.SPDF.config.security.LoginAttemptService;
|
||||||
import stirling.software.SPDF.config.security.UserService;
|
import stirling.software.SPDF.config.security.UserService;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2;
|
||||||
import stirling.software.SPDF.model.AuthenticationType;
|
import stirling.software.SPDF.model.AuthenticationType;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
|
||||||
import stirling.software.common.model.ApplicationProperties.Security.SAML2;
|
import stirling.software.SPDF.utils.RequestUriUtils;
|
||||||
import stirling.software.common.model.exception.UnsupportedProviderException;
|
|
||||||
import stirling.software.common.util.RequestUriUtils;
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -24,8 +24,8 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.common.model.ApplicationProperties.Security.SAML2;
|
import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -18,8 +18,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.common.model.api.PDFFile;
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/analysis")
|
@RequestMapping("/api/v1/analysis")
|
||||||
|
@ -22,8 +22,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.general.CropPdfForm;
|
import stirling.software.SPDF.model.api.general.CropPdfForm;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/general")
|
@RequestMapping("/api/v1/general")
|
||||||
|
@ -3,7 +3,6 @@ package stirling.software.SPDF.controller.api;
|
|||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.mail.MailSendException;
|
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@ -54,11 +53,6 @@ public class EmailController {
|
|||||||
// Calls the service to send the email with attachment
|
// Calls the service to send the email with attachment
|
||||||
emailService.sendEmailWithAttachment(email);
|
emailService.sendEmailWithAttachment(email);
|
||||||
return ResponseEntity.ok("Email sent successfully");
|
return ResponseEntity.ok("Email sent successfully");
|
||||||
} catch (MailSendException ex) {
|
|
||||||
// handles your "Invalid Addresses" case
|
|
||||||
String errorMsg = ex.getMessage();
|
|
||||||
log.error("MailSendException: {}", errorMsg, ex);
|
|
||||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorMsg);
|
|
||||||
} catch (MessagingException e) {
|
} catch (MessagingException e) {
|
||||||
// Catches any messaging exception (e.g., invalid email address, SMTP server issues)
|
// Catches any messaging exception (e.g., invalid email address, SMTP server issues)
|
||||||
String errorMsg = "Failed to send email: " + e.getMessage();
|
String errorMsg = "Failed to send email: " + e.getMessage();
|
||||||
|
@ -32,9 +32,9 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.general.MergePdfsRequest;
|
import stirling.software.SPDF.model.api.general.MergePdfsRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -25,8 +25,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.general.MergeMultiplePagesRequest;
|
import stirling.software.SPDF.model.api.general.MergeMultiplePagesRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/general")
|
@RequestMapping("/api/v1/general")
|
||||||
|
@ -15,10 +15,10 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.SPDF.service.PdfImageRemovalService;
|
import stirling.software.SPDF.service.PdfImageRemovalService;
|
||||||
import stirling.software.common.model.api.PDFFile;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class for handling PDF image removal requests. Provides an endpoint to remove images
|
* Controller class for handling PDF image removal requests. Provides an endpoint to remove images
|
||||||
|
@ -27,9 +27,9 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.general.OverlayPdfsRequest;
|
import stirling.software.SPDF.model.api.general.OverlayPdfsRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/general")
|
@RequestMapping("/api/v1/general")
|
||||||
|
@ -24,9 +24,9 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import stirling.software.SPDF.model.SortTypes;
|
import stirling.software.SPDF.model.SortTypes;
|
||||||
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
||||||
import stirling.software.SPDF.model.api.general.RearrangePagesRequest;
|
import stirling.software.SPDF.model.api.general.RearrangePagesRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/general")
|
@RequestMapping("/api/v1/general")
|
||||||
|
@ -19,8 +19,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.general.RotatePDFRequest;
|
import stirling.software.SPDF.model.api.general.RotatePDFRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/general")
|
@RequestMapping("/api/v1/general")
|
||||||
|
@ -26,8 +26,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.general.ScalePagesRequest;
|
import stirling.software.SPDF.model.api.general.ScalePagesRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/general")
|
@RequestMapping("/api/v1/general")
|
||||||
|
@ -17,9 +17,9 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.SPDF.config.EndpointConfiguration;
|
import stirling.software.SPDF.config.EndpointConfiguration;
|
||||||
import stirling.software.common.configuration.InstallationPathConfig;
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.common.util.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@Tag(name = "Settings", description = "Settings APIs")
|
@Tag(name = "Settings", description = "Settings APIs")
|
||||||
|
@ -28,8 +28,8 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/general")
|
@RequestMapping("/api/v1/general")
|
||||||
|
@ -31,11 +31,11 @@ import lombok.NoArgsConstructor;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.PdfMetadata;
|
||||||
import stirling.software.SPDF.model.api.SplitPdfByChaptersRequest;
|
import stirling.software.SPDF.model.api.SplitPdfByChaptersRequest;
|
||||||
import stirling.software.common.model.PdfMetadata;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.PdfMetadataService;
|
||||||
import stirling.software.common.service.PdfMetadataService;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/general")
|
@RequestMapping("/api/v1/general")
|
||||||
|
@ -32,8 +32,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.SplitPdfBySectionsRequest;
|
import stirling.software.SPDF.model.api.SplitPdfBySectionsRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/general")
|
@RequestMapping("/api/v1/general")
|
||||||
|
@ -25,9 +25,9 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.general.SplitPdfBySizeOrCountRequest;
|
import stirling.software.SPDF.model.api.general.SplitPdfBySizeOrCountRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/general")
|
@RequestMapping("/api/v1/general")
|
||||||
|
@ -21,9 +21,9 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.common.model.api.PDFFile;
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/general")
|
@RequestMapping("/api/v1/general")
|
||||||
|
@ -32,12 +32,12 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import stirling.software.SPDF.config.security.UserService;
|
import stirling.software.SPDF.config.security.UserService;
|
||||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
||||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.AuthenticationType;
|
import stirling.software.SPDF.model.AuthenticationType;
|
||||||
import stirling.software.SPDF.model.Role;
|
import stirling.software.SPDF.model.Role;
|
||||||
import stirling.software.SPDF.model.User;
|
import stirling.software.SPDF.model.User;
|
||||||
import stirling.software.SPDF.model.api.user.UsernameAndPass;
|
import stirling.software.SPDF.model.api.user.UsernameAndPass;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
|
||||||
import stirling.software.common.model.exception.UnsupportedProviderException;
|
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@Tag(name = "User", description = "User APIs")
|
@Tag(name = "User", description = "User APIs")
|
||||||
@ -172,18 +172,15 @@ public class UserController {
|
|||||||
*
|
*
|
||||||
* @param updates A map containing the settings to update. The expected structure is:
|
* @param updates A map containing the settings to update. The expected structure is:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li><b>emailNotifications</b> (optional): "true" or "false" - Enable or disable email
|
* <li><b>emailNotifications</b> (optional): "true" or "false" - Enable or disable email notifications.</li>
|
||||||
* notifications.
|
* <li><b>theme</b> (optional): "light" or "dark" - Set the user's preferred theme.</li>
|
||||||
* <li><b>theme</b> (optional): "light" or "dark" - Set the user's preferred theme.
|
* <li><b>language</b> (optional): A string representing the preferred language (e.g., "en", "fr").</li>
|
||||||
* <li><b>language</b> (optional): A string representing the preferred language (e.g.,
|
|
||||||
* "en", "fr").
|
|
||||||
* </ul>
|
* </ul>
|
||||||
* Keys not listed above will be ignored.
|
* Keys not listed above will be ignored.
|
||||||
* @param principal The currently authenticated user.
|
* @param principal The currently authenticated user.
|
||||||
* @return A redirect string to the account page after updating the settings.
|
* @return A redirect string to the account page after updating the settings.
|
||||||
* @throws SQLException If a database error occurs.
|
* @throws SQLException If a database error occurs.
|
||||||
* @throws UnsupportedProviderException If the operation is not supported for the user's
|
* @throws UnsupportedProviderException If the operation is not supported for the user's provider.
|
||||||
* provider.
|
|
||||||
*/
|
*/
|
||||||
public String updateUserSettings(@RequestBody Map<String, String> updates, Principal principal)
|
public String updateUserSettings(@RequestBody Map<String, String> updates, Principal principal)
|
||||||
throws SQLException, UnsupportedProviderException {
|
throws SQLException, UnsupportedProviderException {
|
||||||
|
@ -13,12 +13,12 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import stirling.software.common.configuration.RuntimePathConfig;
|
import stirling.software.SPDF.config.RuntimePathConfig;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.common.model.api.converters.HTMLToPdfRequest;
|
import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.FileToPdf;
|
import stirling.software.SPDF.utils.FileToPdf;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@Tag(name = "Convert", description = "Convert APIs")
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
|
@ -32,13 +32,9 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
|
|
||||||
import stirling.software.SPDF.model.api.converters.ConvertToImageRequest;
|
import stirling.software.SPDF.model.api.converters.ConvertToImageRequest;
|
||||||
import stirling.software.SPDF.model.api.converters.ConvertToPdfRequest;
|
import stirling.software.SPDF.model.api.converters.ConvertToPdfRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.CheckProgramInstall;
|
import stirling.software.SPDF.utils.*;
|
||||||
import stirling.software.common.util.GeneralUtils;
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.common.util.PdfUtils;
|
|
||||||
import stirling.software.common.util.ProcessExecutor;
|
|
||||||
import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult;
|
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/convert")
|
@RequestMapping("/api/v1/convert")
|
||||||
@ -57,7 +53,7 @@ public class ConvertImgPDFController {
|
|||||||
+ " color type, and DPI. Users can choose to get a single image or multiple"
|
+ " color type, and DPI. Users can choose to get a single image or multiple"
|
||||||
+ " images. Input:PDF Output:Image Type:SI-Conditional")
|
+ " images. Input:PDF Output:Image Type:SI-Conditional")
|
||||||
public ResponseEntity<byte[]> convertToImage(@ModelAttribute ConvertToImageRequest request)
|
public ResponseEntity<byte[]> convertToImage(@ModelAttribute ConvertToImageRequest request)
|
||||||
throws Exception {
|
throws NumberFormatException, Exception {
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
String imageFormat = request.getImageFormat();
|
String imageFormat = request.getImageFormat();
|
||||||
String singleOrMultiple = request.getSingleOrMultiple();
|
String singleOrMultiple = request.getSingleOrMultiple();
|
||||||
|
@ -23,12 +23,12 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.config.RuntimePathConfig;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.api.GeneralFile;
|
import stirling.software.SPDF.model.api.GeneralFile;
|
||||||
import stirling.software.common.configuration.RuntimePathConfig;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.utils.FileToPdf;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
import stirling.software.common.util.FileToPdf;
|
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@Tag(name = "Convert", description = "Convert APIs")
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
|
@ -23,12 +23,12 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.config.RuntimePathConfig;
|
||||||
import stirling.software.SPDF.model.api.GeneralFile;
|
import stirling.software.SPDF.model.api.GeneralFile;
|
||||||
import stirling.software.common.configuration.RuntimePathConfig;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
import stirling.software.common.util.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@Tag(name = "Convert", description = "Convert APIs")
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
|
@ -10,8 +10,8 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import stirling.software.common.model.api.PDFFile;
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
import stirling.software.common.util.PDFToFile;
|
import stirling.software.SPDF.utils.PDFToFile;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@Tag(name = "Convert", description = "Convert APIs")
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
|
@ -18,13 +18,13 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
import stirling.software.SPDF.model.api.converters.PdfToPresentationRequest;
|
import stirling.software.SPDF.model.api.converters.PdfToPresentationRequest;
|
||||||
import stirling.software.SPDF.model.api.converters.PdfToTextOrRTFRequest;
|
import stirling.software.SPDF.model.api.converters.PdfToTextOrRTFRequest;
|
||||||
import stirling.software.SPDF.model.api.converters.PdfToWordRequest;
|
import stirling.software.SPDF.model.api.converters.PdfToWordRequest;
|
||||||
import stirling.software.common.model.api.PDFFile;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.utils.PDFToFile;
|
||||||
import stirling.software.common.util.PDFToFile;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/convert")
|
@RequestMapping("/api/v1/convert")
|
||||||
|
@ -23,9 +23,9 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.converters.PdfToPdfARequest;
|
import stirling.software.SPDF.model.api.converters.PdfToPdfARequest;
|
||||||
import stirling.software.common.util.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult;
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/convert")
|
@RequestMapping("/api/v1/convert")
|
||||||
|
@ -19,14 +19,14 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.config.RuntimePathConfig;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.api.converters.UrlToPdfRequest;
|
import stirling.software.SPDF.model.api.converters.UrlToPdfRequest;
|
||||||
import stirling.software.common.configuration.RuntimePathConfig;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
import stirling.software.common.util.GeneralUtils;
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.common.util.ProcessExecutor;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult;
|
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@Tag(name = "Convert", description = "Convert APIs")
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
|
@ -30,7 +30,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
||||||
import stirling.software.SPDF.pdf.FlexibleCSVWriter;
|
import stirling.software.SPDF.pdf.FlexibleCSVWriter;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
|
|
||||||
import technology.tabula.ObjectExtractor;
|
import technology.tabula.ObjectExtractor;
|
||||||
import technology.tabula.Page;
|
import technology.tabula.Page;
|
||||||
|
@ -24,9 +24,9 @@ import stirling.software.SPDF.model.api.filter.ContainsTextRequest;
|
|||||||
import stirling.software.SPDF.model.api.filter.FileSizeRequest;
|
import stirling.software.SPDF.model.api.filter.FileSizeRequest;
|
||||||
import stirling.software.SPDF.model.api.filter.PageRotationRequest;
|
import stirling.software.SPDF.model.api.filter.PageRotationRequest;
|
||||||
import stirling.software.SPDF.model.api.filter.PageSizeRequest;
|
import stirling.software.SPDF.model.api.filter.PageSizeRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.PdfUtils;
|
import stirling.software.SPDF.utils.PdfUtils;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/filter")
|
@RequestMapping("/api/v1/filter")
|
||||||
|
@ -23,8 +23,8 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.ExtractHeaderRequest;
|
import stirling.software.SPDF.model.api.misc.ExtractHeaderRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/misc")
|
@RequestMapping("/api/v1/misc")
|
||||||
|
@ -35,8 +35,8 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.AutoSplitPdfRequest;
|
import stirling.software.SPDF.model.api.misc.AutoSplitPdfRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/misc")
|
@RequestMapping("/api/v1/misc")
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user