Compare commits
2 Commits
2934-bug-d
...
mac-instal
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2eea4c162 | ||
|
|
80321c3c75 |
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -1,2 +1,2 @@
|
||||
# All PRs to V1 must be approved by Frooodle
|
||||
* @Frooodle @reecebrowne @Ludy87 @DarioGii @ConnorYoh
|
||||
* @Frooodle @reecebrowne @Ludy87 @DarioGii
|
||||
|
||||
29
.github/pull_request_template.md
vendored
29
.github/pull_request_template.md
vendored
@@ -1,34 +1,15 @@
|
||||
# Description of Changes
|
||||
# Description
|
||||
|
||||
Please provide a summary of the changes, including:
|
||||
|
||||
- What was changed
|
||||
- Why the change was made
|
||||
- Any challenges encountered
|
||||
Please provide a summary of the changes, including relevant motivation and context.
|
||||
|
||||
Closes #(issue_number)
|
||||
|
||||
---
|
||||
|
||||
## Checklist
|
||||
|
||||
### General
|
||||
|
||||
- [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
|
||||
- [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable)
|
||||
- [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md) (if applicable)
|
||||
- [ ] I have performed a self-review of my own code
|
||||
- [ ] I have attached images of the change if it is UI based
|
||||
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||
- [ ] If my code has heavily changed functionality I have updated relevant docs on [Stirling-PDFs doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
|
||||
- [ ] My changes generate no new warnings
|
||||
|
||||
### Documentation
|
||||
|
||||
- [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed)
|
||||
- [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only)
|
||||
|
||||
### UI Changes (if applicable)
|
||||
|
||||
- [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR)
|
||||
|
||||
### Testing (if applicable)
|
||||
|
||||
- [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing) for more details.
|
||||
|
||||
6
.github/release.yml
vendored
6
.github/release.yml
vendored
@@ -1,4 +1,10 @@
|
||||
changelog:
|
||||
exclude:
|
||||
labels:
|
||||
- Documentation
|
||||
- Test
|
||||
- Github
|
||||
|
||||
categories:
|
||||
- title: Bug Fixes
|
||||
labels:
|
||||
|
||||
51
.github/scripts/check_duplicates.py
vendored
Normal file
51
.github/scripts/check_duplicates.py
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
import sys
|
||||
|
||||
|
||||
def find_duplicate_keys(file_path):
|
||||
"""
|
||||
Finds duplicate keys in a properties file and returns their occurrences.
|
||||
|
||||
This function reads a properties file, identifies any keys that occur more than
|
||||
once, and returns a dictionary with these keys and the line numbers of their occurrences.
|
||||
|
||||
Parameters:
|
||||
file_path (str): The path to the properties file to be checked.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary where each key is a duplicated key in the file, and the value is a list
|
||||
of line numbers where the key occurs.
|
||||
"""
|
||||
with open(file_path, "r", encoding="utf-8") as file:
|
||||
lines = file.readlines()
|
||||
|
||||
keys = {}
|
||||
duplicates = {}
|
||||
|
||||
for line_number, line in enumerate(lines, start=1):
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#") and "=" in line:
|
||||
key = line.split("=", 1)[0].strip()
|
||||
if key in keys:
|
||||
# If the key already exists, add the current line number
|
||||
duplicates.setdefault(key, []).append(line_number)
|
||||
# Also add the first instance of the key if not already done
|
||||
if keys[key] not in duplicates[key]:
|
||||
duplicates[key].insert(0, keys[key])
|
||||
else:
|
||||
# Store the line number of the first instance of the key
|
||||
keys[key] = line_number
|
||||
|
||||
return duplicates
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
failed = False
|
||||
for ar in sys.argv[1:]:
|
||||
duplicates = find_duplicate_keys(ar)
|
||||
if duplicates:
|
||||
for key, lines in duplicates.items():
|
||||
lines_str = ", ".join(map(str, lines))
|
||||
print(f"{key} duplicated in {ar} on lines {lines_str}")
|
||||
failed = True
|
||||
if failed:
|
||||
sys.exit(1)
|
||||
78
.github/scripts/check_language_properties.py
vendored
78
.github/scripts/check_language_properties.py
vendored
@@ -21,60 +21,25 @@ import argparse
|
||||
import re
|
||||
|
||||
|
||||
def find_duplicate_keys(file_path):
|
||||
"""
|
||||
Identifies duplicate keys in a .properties file.
|
||||
:param file_path: Path to the .properties file.
|
||||
:return: List of tuples (key, first_occurrence_line, duplicate_line).
|
||||
"""
|
||||
keys = {}
|
||||
duplicates = []
|
||||
|
||||
with open(file_path, "r", encoding="utf-8") as file:
|
||||
for line_number, line in enumerate(file, start=1):
|
||||
stripped_line = line.strip()
|
||||
|
||||
# Skip empty lines and comments
|
||||
if not stripped_line or stripped_line.startswith("#"):
|
||||
continue
|
||||
|
||||
# Split the line into key and value
|
||||
if "=" in stripped_line:
|
||||
key, _ = stripped_line.split("=", 1)
|
||||
key = key.strip()
|
||||
|
||||
# Check if the key already exists
|
||||
if key in keys:
|
||||
duplicates.append((key, keys[key], line_number))
|
||||
else:
|
||||
keys[key] = line_number
|
||||
|
||||
return duplicates
|
||||
|
||||
|
||||
# Maximum size for properties files (e.g., 200 KB)
|
||||
MAX_FILE_SIZE = 200 * 1024
|
||||
|
||||
|
||||
def parse_properties_file(file_path):
|
||||
"""
|
||||
Parses a .properties file and returns a structured list of its contents.
|
||||
:param file_path: Path to the .properties file.
|
||||
:return: List of dictionaries representing each line in the file.
|
||||
"""
|
||||
"""Parses a .properties file and returns a list of objects (including comments, empty lines, and line numbers)."""
|
||||
properties_list = []
|
||||
with open(file_path, "r", encoding="utf-8") as file:
|
||||
for line_number, line in enumerate(file, start=1):
|
||||
stripped_line = line.strip()
|
||||
|
||||
# Handle empty lines
|
||||
# Empty lines
|
||||
if not stripped_line:
|
||||
properties_list.append(
|
||||
{"line_number": line_number, "type": "empty", "content": ""}
|
||||
)
|
||||
continue
|
||||
|
||||
# Handle comments
|
||||
# Comments
|
||||
if stripped_line.startswith("#"):
|
||||
properties_list.append(
|
||||
{
|
||||
@@ -85,7 +50,7 @@ def parse_properties_file(file_path):
|
||||
)
|
||||
continue
|
||||
|
||||
# Handle key-value pairs
|
||||
# Key-value pairs
|
||||
match = re.match(r"^([^=]+)=(.*)$", line)
|
||||
if match:
|
||||
key, value = match.groups()
|
||||
@@ -102,14 +67,9 @@ def parse_properties_file(file_path):
|
||||
|
||||
|
||||
def write_json_file(file_path, updated_properties):
|
||||
"""
|
||||
Writes updated properties back to the file in their original format.
|
||||
:param file_path: Path to the .properties file.
|
||||
:param updated_properties: List of updated properties to write.
|
||||
"""
|
||||
updated_lines = {entry["line_number"]: entry for entry in updated_properties}
|
||||
|
||||
# Sort lines by their numbers and retain comments and empty lines
|
||||
# Sort by line numbers and retain comments and empty lines
|
||||
all_lines = sorted(set(updated_lines.keys()))
|
||||
|
||||
original_format = []
|
||||
@@ -128,8 +88,8 @@ def write_json_file(file_path, updated_properties):
|
||||
# Replace entries with those from the current JSON
|
||||
original_format.append(entry)
|
||||
|
||||
# Write the updated content back to the file
|
||||
with open(file_path, "w", encoding="utf-8", newline="\n") as file:
|
||||
# Write back in the original format
|
||||
with open(file_path, "w", encoding="utf-8") as file:
|
||||
for entry in original_format:
|
||||
if entry["type"] == "comment":
|
||||
file.write(f"{entry['content']}\n")
|
||||
@@ -140,12 +100,6 @@ def write_json_file(file_path, updated_properties):
|
||||
|
||||
|
||||
def update_missing_keys(reference_file, file_list, branch=""):
|
||||
"""
|
||||
Updates missing keys in the translation files based on the reference file.
|
||||
:param reference_file: Path to the reference .properties file.
|
||||
:param file_list: List of translation files to update.
|
||||
:param branch: Branch where the files are located.
|
||||
"""
|
||||
reference_properties = parse_properties_file(reference_file)
|
||||
for file_path in file_list:
|
||||
basename_current_file = os.path.basename(os.path.join(branch, file_path))
|
||||
@@ -291,24 +245,6 @@ def check_for_differences(reference_file, file_list, branch, actor):
|
||||
)
|
||||
else:
|
||||
report.append("2. **Test Status:** ✅ **_Passed_**")
|
||||
|
||||
if find_duplicate_keys(os.path.join(branch, file_path)):
|
||||
has_differences = True
|
||||
output = "\n".join(
|
||||
[
|
||||
f" - `{key}`: first at line {first}, duplicate at `line {duplicate}`"
|
||||
for key, first, duplicate in find_duplicate_keys(
|
||||
os.path.join(branch, file_path)
|
||||
)
|
||||
]
|
||||
)
|
||||
report.append("3. **Test Status:** ❌ **_Failed_**")
|
||||
report.append(" - **Issue:**")
|
||||
report.append(" - duplicate entries were found:")
|
||||
report.append(output)
|
||||
else:
|
||||
report.append("3. **Test Status:** ✅ **_Passed_**")
|
||||
|
||||
report.append("")
|
||||
report.append("---")
|
||||
report.append("")
|
||||
|
||||
85
.github/scripts/check_tabulator.py
vendored
Normal file
85
.github/scripts/check_tabulator.py
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
"""check_tabulator.py"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
|
||||
def check_tabs(file_path):
|
||||
"""
|
||||
Checks for tabs in the specified file.
|
||||
|
||||
Args:
|
||||
file_path (str): The path to the file to be checked.
|
||||
|
||||
Returns:
|
||||
bool: True if tabs are found, False otherwise.
|
||||
"""
|
||||
with open(file_path, "r", encoding="utf-8") as file:
|
||||
content = file.read()
|
||||
|
||||
if "\t" in content:
|
||||
print(f"Tab found in {file_path}")
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def replace_tabs_with_spaces(file_path, replace_with=" "):
|
||||
"""
|
||||
Replaces tabs with a specified number of spaces in the file.
|
||||
|
||||
Args:
|
||||
file_path (str): The path to the file where tabs will be replaced.
|
||||
replace_with (str): The character(s) to replace tabs with. Defaults to two spaces.
|
||||
"""
|
||||
with open(file_path, "r", encoding="utf-8") as file:
|
||||
content = file.read()
|
||||
|
||||
updated_content = content.replace("\t", replace_with)
|
||||
|
||||
with open(file_path, "w", encoding="utf-8") as file:
|
||||
file.write(updated_content)
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Main function to replace tabs with spaces in the provided files.
|
||||
The replacement character and files to check are taken from command line arguments.
|
||||
"""
|
||||
# Create ArgumentParser instance
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Replace tabs in files with specified characters."
|
||||
)
|
||||
|
||||
# Define optional argument `--replace_with`
|
||||
parser.add_argument(
|
||||
"--replace_with",
|
||||
default=" ",
|
||||
help="Character(s) to replace tabs with. Default is two spaces.",
|
||||
)
|
||||
|
||||
# Define argument for file paths
|
||||
parser.add_argument("files", metavar="FILE", nargs="+", help="Files to process.")
|
||||
|
||||
# Parse arguments
|
||||
args = parser.parse_args()
|
||||
|
||||
# Extract replacement characters and files from the parsed arguments
|
||||
replace_with = args.replace_with
|
||||
files_checked = args.files
|
||||
|
||||
error = False
|
||||
|
||||
for file_path in files_checked:
|
||||
if check_tabs(file_path):
|
||||
replace_tabs_with_spaces(file_path, replace_with)
|
||||
error = True
|
||||
|
||||
if error:
|
||||
print("Error: Originally found tabs in HTML files, now replaced.")
|
||||
sys.exit(1)
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
13
.github/workflows/PR-Demo-Comment.yml
vendored
13
.github/workflows/PR-Demo-Comment.yml
vendored
@@ -27,8 +27,7 @@ jobs:
|
||||
github.event.comment.user.login == 'LaserKaspar' ||
|
||||
github.event.comment.user.login == 'sbplat' ||
|
||||
github.event.comment.user.login == 'reecebrowne' ||
|
||||
github.event.comment.user.login == 'DarioGii' ||
|
||||
github.event.comment.user.login == 'ConnorYoh'
|
||||
github.event.comment.user.login == 'DarioGii'
|
||||
)
|
||||
outputs:
|
||||
pr_number: ${{ steps.get-pr.outputs.pr_number }}
|
||||
@@ -37,7 +36,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -82,7 +81,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -94,7 +93,7 @@ jobs:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
||||
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||
with:
|
||||
java-version: "17"
|
||||
distribution: "temurin"
|
||||
@@ -105,7 +104,7 @@ jobs:
|
||||
DOCKER_ENABLE_SECURITY: false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0
|
||||
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||
|
||||
- name: Get version number
|
||||
id: versionNumber
|
||||
@@ -120,7 +119,7 @@ jobs:
|
||||
password: ${{ secrets.DOCKER_HUB_API }}
|
||||
|
||||
- name: Build and push PR-specific image
|
||||
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6.13.0
|
||||
uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6.11.0
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
|
||||
30
.github/workflows/PR-Demo-cleanup.yml
vendored
30
.github/workflows/PR-Demo-cleanup.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Cleanup PR deployment
|
||||
id: cleanup
|
||||
run: |
|
||||
ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH'
|
||||
CLEANUP_STATUS=$(ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH'
|
||||
if [ -d "/stirling/PR-${{ github.event.pull_request.number }}" ]; then
|
||||
echo "Found PR directory, proceeding with cleanup..."
|
||||
|
||||
@@ -57,3 +57,29 @@ jobs:
|
||||
echo "NO_CLEANUP_NEEDED"
|
||||
fi
|
||||
ENDSSH
|
||||
)
|
||||
|
||||
if [[ $CLEANUP_STATUS == *"PERFORMED_CLEANUP"* ]]; then
|
||||
echo "cleanup_performed=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "cleanup_performed=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Post cleanup notice to PR
|
||||
if: steps.cleanup.outputs.cleanup_performed == 'true'
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
with:
|
||||
script: |
|
||||
const { GITHUB_REPOSITORY } = process.env;
|
||||
const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/');
|
||||
const prNumber = context.issue.number;
|
||||
|
||||
const commentBody = `## 🧹 Deployment Cleanup\n\n` +
|
||||
`The test deployment for this PR has been cleaned up.`;
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: repoOwner,
|
||||
repo: repoName,
|
||||
issue_number: prNumber,
|
||||
body: commentBody
|
||||
});
|
||||
|
||||
2
.github/workflows/auto-labeler.yml
vendored
2
.github/workflows/auto-labeler.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
51
.github/workflows/build.yml
vendored
51
.github/workflows/build.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Set up JDK ${{ matrix.jdk-version }}
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
||||
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||
with:
|
||||
java-version: ${{ matrix.jdk-version }}
|
||||
distribution: "temurin"
|
||||
@@ -58,35 +58,6 @@ jobs:
|
||||
build/reports/problems/
|
||||
retention-days: 3
|
||||
|
||||
check-licence:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
||||
with:
|
||||
java-version: "17"
|
||||
distribution: "adopt"
|
||||
|
||||
- name: check the licenses for compatibility
|
||||
run: ./gradlew clean checkLicense
|
||||
|
||||
- name: FAILED - check the licenses for compatibility
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: dependencies-without-allowed-license.json
|
||||
path: |
|
||||
build/reports/dependency-license/dependencies-without-allowed-license.json
|
||||
retention-days: 3
|
||||
|
||||
docker-compose-tests:
|
||||
# if: github.event_name == 'push' && github.ref == 'refs/heads/main' ||
|
||||
# (github.event_name == 'pull_request' &&
|
||||
@@ -106,7 +77,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -114,31 +85,31 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Set up Java 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
||||
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||
with:
|
||||
java-version: "17"
|
||||
distribution: "adopt"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0
|
||||
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||
|
||||
- name: Install Docker Compose
|
||||
run: |
|
||||
sudo curl -SL "https://github.com/docker/compose/releases/download/v2.32.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
sudo curl -SL "https://github.com/docker/compose/releases/download/v2.32.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
sudo chmod +x /usr/local/bin/docker-compose
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
||||
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
cache: 'pip' # caching pip dependencies
|
||||
|
||||
- name: Pip requirements
|
||||
run: |
|
||||
pip install --require-hashes -r ./testing/cucumber/requirements.txt
|
||||
pip install --require-hashes -r ./cucumber/requirements.txt
|
||||
|
||||
- name: Run Docker Compose Tests
|
||||
run: |
|
||||
chmod +x ./testing/test_webpages.sh
|
||||
chmod +x ./testing/test.sh
|
||||
./testing/test.sh
|
||||
chmod +x ./cucumber/test_webpages.sh
|
||||
chmod +x ./test.sh
|
||||
./test.sh
|
||||
|
||||
8
.github/workflows/check_properties.yml
vendored
8
.github/workflows/check_properties.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
||||
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
run: |
|
||||
echo "Fetching PR changed files..."
|
||||
echo "Getting list of changed files from PR..."
|
||||
gh pr view ${{ steps.get-pr-data.outputs.pr_number }} --json files -q ".files[].path" | grep -E '^src/main/resources/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$' > changed_files.txt # Filter only matching property files
|
||||
gh pr view ${{ steps.get-pr-data.outputs.pr_number }} --json files -q ".files[].path" | grep -E '^src/main/resources/messages_[a-zA-Z_]+\.properties$' > changed_files.txt # Filter only matching property files
|
||||
|
||||
- name: Determine reference file test
|
||||
id: determine-file
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
// Filter for relevant files based on the PR changes
|
||||
const changedFiles = files
|
||||
.map(file => file.filename)
|
||||
.filter(file => /^src\/main\/resources\/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$/.test(file));
|
||||
.filter(file => /^src\/main\/resources\/messages_[a-zA-Z_]+\.properties$/.test(file));
|
||||
|
||||
console.log("Changed files:", changedFiles);
|
||||
|
||||
|
||||
2
.github/workflows/dependency-review.yml
vendored
2
.github/workflows/dependency-review.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
23
.github/workflows/licenses-update.yml
vendored
23
.github/workflows/licenses-update.yml
vendored
@@ -18,39 +18,30 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Generate GitHub App Token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@136412a57a7081aa63c935a2cc2918f76c34f514 # v1.11.2
|
||||
uses: actions/create-github-app-token@c1a285145b9d317df6ced56c09f525b5c2b6f755 # v1.11.1
|
||||
with:
|
||||
app-id: ${{ secrets.GH_APP_ID }}
|
||||
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
||||
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
||||
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||
with:
|
||||
java-version: "17"
|
||||
distribution: "adopt"
|
||||
|
||||
- uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
|
||||
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
||||
|
||||
- name: check the licenses for compatibility
|
||||
run: ./gradlew clean checkLicense
|
||||
|
||||
- name: FAILED - check the licenses for compatibility
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: dependencies-without-allowed-license.json
|
||||
path: |
|
||||
build/reports/dependency-license/dependencies-without-allowed-license.json
|
||||
retention-days: 3
|
||||
- name: Run Gradle Command
|
||||
run: ./gradlew clean generateLicenseReport
|
||||
|
||||
- name: Move and Rename License File
|
||||
run: |
|
||||
|
||||
4
.github/workflows/manage-label.yml
vendored
4
.github/workflows/manage-label.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
issues: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Run Labeler
|
||||
uses: crazy-max/ghaction-github-labeler@31674a3852a9074f2086abcf1c53839d466a47e7 # v5.2.0
|
||||
uses: crazy-max/ghaction-github-labeler@b54af0c25861143e7c8813d7cbbf46d2c341680c # v5.1.0
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
yaml-file: .github/labels.yml
|
||||
|
||||
20
.github/workflows/multiOSReleases.yml
vendored
20
.github/workflows/multiOSReleases.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
versionMac: ${{ steps.versionNumberMac.outputs.versionNumberMac }}
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -51,19 +51,19 @@ jobs:
|
||||
file_suffix: ""
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
||||
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||
with:
|
||||
java-version: "21"
|
||||
distribution: "temurin"
|
||||
|
||||
- uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
|
||||
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
||||
with:
|
||||
gradle-version: 8.12
|
||||
|
||||
@@ -101,7 +101,7 @@ jobs:
|
||||
file_suffix: ""
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -139,19 +139,19 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
||||
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||
with:
|
||||
java-version: "21"
|
||||
distribution: "temurin"
|
||||
|
||||
- uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
|
||||
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
||||
with:
|
||||
gradle-version: 8.12
|
||||
|
||||
@@ -210,7 +210,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -271,7 +271,7 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
44
.github/workflows/pre_commit.yml
vendored
44
.github/workflows/pre_commit.yml
vendored
@@ -2,47 +2,29 @@ name: Pre-commit
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 0 * * 1"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
if: ${{ github.event.pull_request.user.login != 'dependabot[bot]' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Generate GitHub App Token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@136412a57a7081aa63c935a2cc2918f76c34f514 # v1.11.2
|
||||
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: 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
|
||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
||||
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
||||
with:
|
||||
python-version: 3.12
|
||||
cache: 'pip' # caching pip dependencies
|
||||
@@ -53,25 +35,25 @@ jobs:
|
||||
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"
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
- name: git add
|
||||
run: |
|
||||
git add .
|
||||
git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
|
||||
git diff --staged --quiet || git commit -m ":file_folder: pre-commit
|
||||
> Made via .github/workflows/pre_commit.yml" || echo "pre-commit: no changes"
|
||||
- name: Create Pull Request
|
||||
if: env.CHANGES_DETECTED == 'true'
|
||||
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
|
||||
with:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
commit-message: ":file_folder: pre-commit"
|
||||
committer: ${{ steps.committer.outputs.string }}
|
||||
author: ${{ steps.committer.outputs.string }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: "ci: 🤖 format everything with pre-commit"
|
||||
committer: GitHub Action <action@github.com>
|
||||
author: GitHub Action <action@github.com>
|
||||
signoff: true
|
||||
branch: pre-commit
|
||||
title: "🤖 format everything with pre-commit by <${{ steps.generate-token.outputs.app-slug }}>"
|
||||
title: "🤖 format everything with pre-commit by <github-actions[bot]>"
|
||||
body: |
|
||||
Auto-generated by [create-pull-request][1] with **${{ steps.generate-token.outputs.app-slug }}**
|
||||
Auto-generated by [create-pull-request][1]
|
||||
|
||||
[1]: https://github.com/peter-evans/create-pull-request
|
||||
draft: false
|
||||
|
||||
16
.github/workflows/push-docker.yml
vendored
16
.github/workflows/push-docker.yml
vendored
@@ -18,19 +18,19 @@ jobs:
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
||||
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||
with:
|
||||
java-version: "17"
|
||||
distribution: "temurin"
|
||||
|
||||
- uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
|
||||
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
||||
with:
|
||||
gradle-version: 8.12
|
||||
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0
|
||||
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||
|
||||
- name: Get version number
|
||||
id: versionNumber
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
password: ${{ github.token }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@4574d27a4764455b42196d70a065bc6853246a25 # v3.4.0
|
||||
uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3.3.0
|
||||
|
||||
- name: Convert repository owner to lowercase
|
||||
id: repoowner
|
||||
@@ -89,7 +89,7 @@ jobs:
|
||||
|
||||
- name: Build and push main Dockerfile
|
||||
id: build-push-regular
|
||||
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6.13.0
|
||||
uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6.11.0
|
||||
with:
|
||||
builder: ${{ steps.buildx.outputs.name }}
|
||||
context: .
|
||||
@@ -134,7 +134,7 @@ jobs:
|
||||
|
||||
- name: Build and push Dockerfile-ultra-lite
|
||||
id: build-push-lite
|
||||
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6.13.0
|
||||
uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6.11.0
|
||||
if: github.ref != 'refs/heads/main'
|
||||
with:
|
||||
context: .
|
||||
@@ -165,7 +165,7 @@ jobs:
|
||||
|
||||
- name: Build and push main Dockerfile fat
|
||||
id: build-push-fat
|
||||
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6.13.0
|
||||
uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6.11.0
|
||||
if: github.ref != 'refs/heads/main'
|
||||
with:
|
||||
builder: ${{ steps.buildx.outputs.name }}
|
||||
|
||||
10
.github/workflows/releaseArtifacts.yml
vendored
10
.github/workflows/releaseArtifacts.yml
vendored
@@ -23,19 +23,19 @@ jobs:
|
||||
version: ${{ steps.versionNumber.outputs.versionNumber }}
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
||||
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||
with:
|
||||
java-version: "17"
|
||||
distribution: "temurin"
|
||||
|
||||
- uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
|
||||
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
||||
with:
|
||||
gradle-version: 8.12
|
||||
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
file_suffix: ""
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -161,7 +161,7 @@ jobs:
|
||||
file_suffix: ""
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
4
.github/workflows/scorecards.yml
vendored
4
.github/workflows/scorecards.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -74,6 +74,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9
|
||||
uses: github/codeql-action/upload-sarif@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
62
.github/workflows/sonarqube.yml
vendored
62
.github/workflows/sonarqube.yml
vendored
@@ -1,62 +0,0 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
actions: read
|
||||
name: Run Sonarqube
|
||||
jobs:
|
||||
sonarqube:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
|
||||
|
||||
- name: Build and analyze with Gradle
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
DOCKER_ENABLE_SECURITY: true
|
||||
STIRLING_PDF_DESKTOP_UI: true
|
||||
run: |
|
||||
./gradlew clean build sonar \
|
||||
-Dsonar.projectKey=Stirling-Tools_Stirling-PDF \
|
||||
-Dsonar.organization=stirling-tools \
|
||||
-Dsonar.host.url=https://sonarcloud.io \
|
||||
-Dsonar.login=${SONAR_TOKEN} \
|
||||
-Dsonar.log.level=DEBUG \
|
||||
--info
|
||||
|
||||
- name: Upload Problems Report on Failure
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: gradle-problems-report
|
||||
path: build/reports/problems/problems-report.html
|
||||
retention-days: 7
|
||||
|
||||
- name: Upload Sonar Logs on Failure
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: sonar-logs
|
||||
path: |
|
||||
.scannerwork/report-task.txt
|
||||
build/sonar/
|
||||
retention-days: 7
|
||||
4
.github/workflows/stale.yml
vendored
4
.github/workflows/stale.yml
vendored
@@ -16,12 +16,12 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: 30 days stale issues
|
||||
uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0
|
||||
uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 30
|
||||
|
||||
6
.github/workflows/swagger.yml
vendored
6
.github/workflows/swagger.yml
vendored
@@ -14,19 +14,19 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
||||
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||
with:
|
||||
java-version: "17"
|
||||
distribution: "temurin"
|
||||
|
||||
- uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
|
||||
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
||||
|
||||
- name: Generate Swagger documentation
|
||||
run: ./gradlew generateOpenApiDocs
|
||||
|
||||
122
.github/workflows/sync_files.yml
vendored
122
.github/workflows/sync_files.yml
vendored
@@ -1,145 +1,63 @@
|
||||
name: Sync Files
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "build.gradle"
|
||||
- "README.md"
|
||||
- "src/main/resources/messages_*.properties"
|
||||
- "src/main/resources/static/3rdPartyLicenses.json"
|
||||
- "scripts/ignore_translation.toml"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
read_bot_entries:
|
||||
sync-readme:
|
||||
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 }}
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Generate GitHub App Token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@136412a57a7081aa63c935a2cc2918f76c34f514 # v1.11.2
|
||||
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:
|
||||
needs: ["read_bot_entries"]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Generate GitHub App Token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@136412a57a7081aa63c935a2cc2918f76c34f514 # v1.11.2
|
||||
with:
|
||||
app-id: ${{ vars.GH_APP_ID }}
|
||||
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
||||
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
cache: 'pip' # caching pip dependencies
|
||||
|
||||
- name: Sync translation property files
|
||||
run: |
|
||||
python .github/scripts/check_language_properties.py --reference-file "src/main/resources/messages_en_GB.properties" --branch main
|
||||
|
||||
- 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: |
|
||||
git add src/main/resources/messages_*.properties
|
||||
git diff --staged --quiet || git commit -m ":memo: Sync translation files" || echo "no changes"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install --require-hashes -r ./.github/scripts/requirements_sync_readme.txt
|
||||
|
||||
- name: Sync README.md
|
||||
- name: Sync README
|
||||
run: python scripts/counter_translation.py
|
||||
- name: Set up git config
|
||||
run: |
|
||||
python scripts/counter_translation.py
|
||||
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
- name: Run git add
|
||||
run: |
|
||||
git add README.md
|
||||
git diff --staged --quiet || git commit -m ":memo: Sync README.md" || echo "no changes"
|
||||
|
||||
git add .
|
||||
git diff --staged --quiet || git commit -m ":memo: Sync README
|
||||
> Made via sync_files.yml" || echo "no changes"
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
|
||||
with:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: Update files
|
||||
committer: ${{ needs.read_bot_entries.outputs.committer }}
|
||||
author: ${{ needs.read_bot_entries.outputs.committer }}
|
||||
committer: GitHub Action <action@github.com>
|
||||
author: GitHub Action <action@github.com>
|
||||
signoff: true
|
||||
branch: sync_readme
|
||||
title: ":globe_with_meridians: Sync Translations + Update README Progress Table"
|
||||
title: ":memo: Update README: Translation Progress Table"
|
||||
body: |
|
||||
### Description of Changes
|
||||
|
||||
This Pull Request was automatically generated to synchronize updates to translation files and documentation. Below are the details of the changes made:
|
||||
|
||||
#### **1. Synchronization of Translation Files**
|
||||
- Updated translation files (`messages_*.properties`) to reflect changes in the reference file `messages_en_GB.properties`.
|
||||
- Ensured consistency and synchronization across all supported language files.
|
||||
- Highlighted any missing or incomplete translations.
|
||||
|
||||
#### **2. Update README.md**
|
||||
- Generated the translation progress table in `README.md`.
|
||||
- Added a summary of the current translation status for all supported languages.
|
||||
- Included up-to-date statistics on translation coverage.
|
||||
|
||||
#### **Why these changes are necessary**
|
||||
- Keeps translation files aligned with the latest reference updates.
|
||||
- Ensures the documentation reflects the current translation progress.
|
||||
|
||||
---
|
||||
|
||||
Auto-generated by [create-pull-request][1].
|
||||
Auto-generated by [create-pull-request][1]
|
||||
|
||||
[1]: https://github.com/peter-evans/create-pull-request
|
||||
draft: false
|
||||
delete-branch: true
|
||||
labels: github-actions
|
||||
labels: Documentation,Translation,github-actions
|
||||
sign-commits: true
|
||||
add-paths: |
|
||||
README.md
|
||||
src/main/resources/messages_*.properties
|
||||
|
||||
16
.github/workflows/testdriver.yml
vendored
16
.github/workflows/testdriver.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
||||
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
DOCKER_ENABLE_SECURITY: false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0
|
||||
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||
|
||||
- name: Get version number
|
||||
id: versionNumber
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
password: ${{ secrets.DOCKER_HUB_API }}
|
||||
|
||||
- name: Build and push test image
|
||||
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6.13.0
|
||||
uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6.11.0
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
@@ -105,14 +105,14 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Run TestDriver.ai
|
||||
uses: testdriverai/action@f0d0f45fdd684db628baa843fe9313f3ca3a8aa8 #1.1.3
|
||||
uses: testdriverai/action@47e87c5d50beeeb3da624b2d9b5c1391269d6d22 #1.0.0
|
||||
with:
|
||||
key: ${{secrets.TESTDRIVER_API_KEY}}
|
||||
prerun: |
|
||||
@@ -122,7 +122,7 @@ jobs:
|
||||
Start-Process "C:/Program Files/Google/Chrome/Application/chrome.exe" -ArgumentList "--start-maximized", "--load-extension=$(pwd)/node_modules/dashcam-chrome/build", "http://${{ secrets.VPS_HOST }}:1337"
|
||||
Start-Sleep -Seconds 20
|
||||
prompt: |
|
||||
1. /run testing/testdriver/test.yml
|
||||
1. /run testdriver/test.yml
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
FORCE_COLOR: "3"
|
||||
@@ -134,7 +134,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
73
.github/workflows/update-translations.yml
vendored
Normal file
73
.github/workflows/update-translations.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
name: Update Translations
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: ["main"]
|
||||
paths:
|
||||
- "src/main/resources/messages_en_GB.properties"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
update-translations-main:
|
||||
if: github.event_name == 'push'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Run Python script to check files
|
||||
id: run-check
|
||||
run: |
|
||||
echo "Running Python script to check files..."
|
||||
python .github/scripts/check_language_properties.py \
|
||||
--reference-file src/main/resources/messages_en_GB.properties \
|
||||
--branch main
|
||||
|
||||
- name: Set up git config
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Add translation keys
|
||||
run: |
|
||||
git add src/main/resources/messages_*.properties
|
||||
git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
|
||||
|
||||
- name: Create Pull Request
|
||||
id: cpr
|
||||
if: env.CHANGES_DETECTED == 'true'
|
||||
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: "Update translation files"
|
||||
committer: GitHub Action <action@github.com>
|
||||
author: GitHub Action <action@github.com>
|
||||
signoff: true
|
||||
branch: update_translation_files
|
||||
title: "Update translation files"
|
||||
add-paths: |
|
||||
src/main/resources/messages_*.properties
|
||||
body: |
|
||||
Auto-generated by [create-pull-request][1]
|
||||
|
||||
[1]: https://github.com/peter-evans/create-pull-request
|
||||
draft: false
|
||||
delete-branch: true
|
||||
labels: Translation,github-actions
|
||||
sign-commits: true
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -25,7 +25,6 @@ clientWebUI/
|
||||
!cucumber/
|
||||
!cucumber/exampleFiles/
|
||||
!cucumber/exampleFiles/example_html.zip
|
||||
exampleYmlFiles/stirling/
|
||||
|
||||
# Gradle
|
||||
.gradle
|
||||
@@ -140,7 +139,6 @@ venv.bak/
|
||||
# VS Code
|
||||
/.vscode/**/*
|
||||
!/.vscode/settings.json
|
||||
!/.vscode/extensions.json
|
||||
|
||||
# IntelliJ IDEA
|
||||
.idea/
|
||||
|
||||
@@ -6,10 +6,10 @@ repos:
|
||||
args:
|
||||
- --fix
|
||||
- --line-length=127
|
||||
files: ^((\.github/scripts|scripts)/.+)?[^/]+\.py$
|
||||
files: ^((.github/scripts|scripts)/.+)?[^/]+\.py$
|
||||
exclude: (split_photos.py)
|
||||
- id: ruff-format
|
||||
files: ^((\.github/scripts|scripts)/.+)?[^/]+\.py$
|
||||
files: ^((.github/scripts|scripts)/.+)?[^/]+\.py$
|
||||
exclude: (split_photos.py)
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.3.0
|
||||
@@ -19,18 +19,39 @@ repos:
|
||||
- --ignore-words-list=
|
||||
- --skip="./.*,*.csv,*.json,*.ambr"
|
||||
- --quiet-level=2
|
||||
files: \.(html|css|js|py|md)$
|
||||
files: \.(properties|html|css|js|py|md)$
|
||||
exclude: (.vscode|.devcontainer|src/main/resources|Dockerfile|.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js)
|
||||
- repo: https://github.com/gitleaks/gitleaks
|
||||
rev: v8.22.0
|
||||
hooks:
|
||||
- id: gitleaks
|
||||
- repo: https://github.com/jumanjihouse/pre-commit-hooks
|
||||
rev: 3.0.0
|
||||
hooks:
|
||||
- id: shellcheck
|
||||
files: ^.*(\.bash|\.sh|\.ksh|\.zsh)$
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
hooks:
|
||||
- id: end-of-file-fixer
|
||||
files: ^.*(\.js|\.java|\.py|\.yml)$
|
||||
exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js|\.github/workflows/.*$)
|
||||
exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js$)
|
||||
- id: trailing-whitespace
|
||||
files: ^.*(\.js|\.java|\.py|\.yml)$
|
||||
exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js|\.github/workflows/.*$)
|
||||
exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js$)
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: check-duplicate-properties-keys
|
||||
name: Check Duplicate Properties Keys
|
||||
entry: python .github/scripts/check_duplicates.py
|
||||
language: python
|
||||
files: ^(src)/.+\.properties$
|
||||
- id: check-html-tabs
|
||||
name: Check HTML for tabs
|
||||
description: Ensures HTML/CSS/JS files do not contain tab characters
|
||||
# args: ["--replace_with= "]
|
||||
entry: python .github/scripts/check_tabulator.py
|
||||
language: python
|
||||
exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js$)
|
||||
files: ^.*(\.html|\.css|\.js)$
|
||||
24
.vscode/extensions.json
vendored
24
.vscode/extensions.json
vendored
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"elagil.pre-commit-helper", // Support for pre-commit hooks to enforce code quality
|
||||
"josevseb.google-java-format-for-vs-code", // Google Java code formatter to follow the Google Java Style Guide
|
||||
"ms-python.black-formatter", // Python code formatter using Black
|
||||
"ms-python.flake8", // Flake8 linter for Python to enforce code quality
|
||||
"ms-python.python", // Official Microsoft Python extension with IntelliSense, debugging, and Jupyter support
|
||||
// "ms-vscode-remote.remote-containers", // Support for remote development with containers (Docker, Dev Containers)
|
||||
// "ms-vscode-remote.vscode-remote-extensionpack", // Remote Development Pack for SSH, WSL, and Containers
|
||||
"Oracle.oracle-java", // Oracle Java extension with additional features for Java development
|
||||
"redhat.java", // Java support by Red Hat with IntelliSense, debugging, and code navigation
|
||||
"shengchen.vscode-checkstyle", // Checkstyle integration for Java code quality checks
|
||||
"streetsidesoftware.code-spell-checker", // Spell checker for code to avoid typos
|
||||
"vmware.vscode-boot-dev-pack", // Developer tools for Spring Boot by VMware
|
||||
"vmware.vscode-spring-boot", // Spring Boot tools by VMware for enhanced Spring development
|
||||
"vscjava.vscode-gradle", // Gradle extension for build and automation support
|
||||
"vscjava.vscode-java-debug", // Debugging support for Java projects
|
||||
"vscjava.vscode-java-dependency", // Java dependency management within VS Code
|
||||
"vscjava.vscode-java-pack", // Java Extension Pack with essential Java tools for VS Code
|
||||
"vscjava.vscode-java-test", // Java test framework for running and debugging tests in VS Code
|
||||
"vscjava.vscode-spring-boot-dashboard", // Spring Boot dashboard for managing and visualizing Spring Boot applications
|
||||
"vscjava.vscode-spring-initializr" // Support for Spring Initializr to create new Spring projects
|
||||
]
|
||||
}
|
||||
@@ -39,16 +39,6 @@ Stirling-PDF is built using:
|
||||
2. Install Docker and JDK17 if not already installed.
|
||||
|
||||
3. Install a recommended Java IDE such as Eclipse, IntelliJ, or VSCode
|
||||
1. Only VSCode
|
||||
1. Open VS Code.
|
||||
2. When prompted, install the recommended extensions.
|
||||
3. Alternatively, open the command palette (`Ctrl + Shift + P` or `Cmd + Shift + P` on macOS) and run:
|
||||
|
||||
```sh
|
||||
Extensions: Show Recommended Extensions
|
||||
```
|
||||
|
||||
4. Install the required extensions from the list.
|
||||
|
||||
4. Lombok Setup
|
||||
Stirling-PDF uses Lombok to reduce boilerplate code. Some IDEs, like Eclipse, don't support Lombok out of the box. To set up Lombok in your development environment:
|
||||
@@ -585,3 +575,42 @@ In your Thymeleaf templates, use the `#{key}` syntax to reference the new transl
|
||||
```
|
||||
|
||||
Remember, never hard-code text in your templates or Java code. Always use translation keys to ensure proper localization.
|
||||
|
||||
|
||||
## Managing Dependencies
|
||||
|
||||
When adding new dependencies or updating existing ones in Stirling-PDF, follow these steps to ensure proper verification and security:
|
||||
|
||||
1. Update the dependency in `build.gradle`:
|
||||
```groovy
|
||||
dependencies {
|
||||
// Add or update your dependency
|
||||
implementation "com.example:new-library:1.2.3"
|
||||
}
|
||||
```
|
||||
|
||||
2. Generate new verification metadata and keys:
|
||||
```bash
|
||||
# Generate verification metadata with signatures and checksums
|
||||
./gradlew clean dependencies buildEnvironment --write-verification-metadata sha256,pgp
|
||||
|
||||
# Export the .keys file
|
||||
./gradlew --export-keys
|
||||
```
|
||||
|
||||
3. Files to commit:
|
||||
- `build.gradle` - Your dependency changes
|
||||
- `gradle/verification-metadata.xml` - Contains verification rules and checksums
|
||||
- `gradle/verification-keyring.keys` - Contains PGP keys in text format
|
||||
|
||||
4. Verify the build works with the new verification:
|
||||
```bash
|
||||
./gradlew build
|
||||
```
|
||||
|
||||
5. Before committing, check:
|
||||
- Verify any new BOM files are properly handled in verification metadata
|
||||
- Review the changes in `verification-metadata.xml` to ensure they match your dependency updates
|
||||
|
||||
This ensures dependencies are properly verified and secure while maintaining transparency in the repository.
|
||||
|
||||
|
||||
64
Dockerfile
64
Dockerfile
@@ -25,13 +25,7 @@ LABEL org.opencontainers.image.keywords="PDF, manipulation, merge, split, conver
|
||||
# Set Environment Variables
|
||||
ENV DOCKER_ENABLE_SECURITY=false \
|
||||
VERSION_TAG=$VERSION_TAG \
|
||||
JAVA_TOOL_OPTIONS="-XX:+UnlockExperimentalVMOptions \
|
||||
-XX:MaxRAMPercentage=75 \
|
||||
-XX:InitiatingHeapOccupancyPercent=20 \
|
||||
-XX:+G1PeriodicGCInvokesConcurrent \
|
||||
-XX:G1PeriodicGCInterval=10000 \
|
||||
-XX:+UseStringDeduplication \
|
||||
-XX:G1PeriodicGCSystemLoadThreshold=70" \
|
||||
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
|
||||
HOME=/home/stirlingpdfuser \
|
||||
PUID=1000 \
|
||||
PGID=1000 \
|
||||
@@ -39,43 +33,41 @@ ENV DOCKER_ENABLE_SECURITY=false \
|
||||
|
||||
|
||||
# JDK for app
|
||||
RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
||||
echo "@community https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
|
||||
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
||||
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
|
||||
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
|
||||
apk upgrade --no-cache -a && \
|
||||
apk add --no-cache \
|
||||
ca-certificates \
|
||||
tzdata \
|
||||
tini \
|
||||
bash \
|
||||
curl \
|
||||
qpdf \
|
||||
shadow \
|
||||
su-exec \
|
||||
openssl \
|
||||
openssl-dev \
|
||||
openjdk21-jre \
|
||||
# Doc conversion
|
||||
gcompat \
|
||||
libc6-compat \
|
||||
libreoffice \
|
||||
# pdftohtml
|
||||
poppler-utils \
|
||||
# OCR MY PDF (unpaper for descew and other advanced features)
|
||||
tesseract-ocr-data-eng \
|
||||
# CV
|
||||
py3-opencv \
|
||||
python3 \
|
||||
py3-unoconv@testing \
|
||||
py3-pillow@testing \
|
||||
py3-pdf2image@testing \
|
||||
weasyprint@community && \
|
||||
ca-certificates \
|
||||
tzdata \
|
||||
tini \
|
||||
bash \
|
||||
curl \
|
||||
qpdf \
|
||||
shadow \
|
||||
su-exec \
|
||||
openssl \
|
||||
openssl-dev \
|
||||
openjdk21-jre \
|
||||
# Doc conversion
|
||||
libreoffice \
|
||||
# pdftohtml
|
||||
poppler-utils \
|
||||
# OCR MY PDF (unpaper for descew and other advanced features)
|
||||
tesseract-ocr-data-eng \
|
||||
# CV
|
||||
py3-opencv \
|
||||
# python3/pip
|
||||
python3 \
|
||||
py3-pip && \
|
||||
# uno unoconv and HTML
|
||||
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint pdf2image pillow && \
|
||||
mv /usr/share/tessdata /usr/share/tessdata-original && \
|
||||
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
|
||||
fc-cache -f -v && \
|
||||
chmod +x /scripts/* && \
|
||||
chmod +x /scripts/init.sh && \
|
||||
# User permissions
|
||||
# User permissions
|
||||
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
|
||||
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
|
||||
chown stirlingpdfuser:stirlingpdfgroup /app.jar
|
||||
|
||||
@@ -9,7 +9,7 @@ COPY . .
|
||||
|
||||
# Build the application with DOCKER_ENABLE_SECURITY=false
|
||||
RUN DOCKER_ENABLE_SECURITY=true \
|
||||
./gradlew clean build
|
||||
./gradlew clean build
|
||||
|
||||
# Main stage
|
||||
FROM alpine:3.21.2@sha256:56fa17d2a7e7f168a043a2712e63aed1f8543aeafdcee47c58dcffe38ed51099
|
||||
@@ -25,13 +25,7 @@ ARG VERSION_TAG
|
||||
# Set Environment Variables
|
||||
ENV DOCKER_ENABLE_SECURITY=false \
|
||||
VERSION_TAG=$VERSION_TAG \
|
||||
JAVA_TOOL_OPTIONS="-XX:+UnlockExperimentalVMOptions \
|
||||
-XX:MaxRAMPercentage=75 \
|
||||
-XX:InitiatingHeapOccupancyPercent=20 \
|
||||
-XX:+G1PeriodicGCInvokesConcurrent \
|
||||
-XX:G1PeriodicGCInterval=10000 \
|
||||
-XX:+UseStringDeduplication \
|
||||
-XX:G1PeriodicGCSystemLoadThreshold=70" \
|
||||
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
|
||||
HOME=/home/stirlingpdfuser \
|
||||
PUID=1000 \
|
||||
PGID=1000 \
|
||||
@@ -41,46 +35,42 @@ ENV DOCKER_ENABLE_SECURITY=false \
|
||||
|
||||
|
||||
# JDK for app
|
||||
RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
||||
echo "@community https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
|
||||
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
||||
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
|
||||
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
|
||||
apk upgrade --no-cache -a && \
|
||||
apk add --no-cache \
|
||||
ca-certificates \
|
||||
tzdata \
|
||||
tini \
|
||||
bash \
|
||||
curl \
|
||||
shadow \
|
||||
su-exec \
|
||||
openssl \
|
||||
openssl-dev \
|
||||
openjdk21-jre \
|
||||
# Doc conversion
|
||||
gcompat \
|
||||
libc6-compat \
|
||||
libreoffice \
|
||||
# pdftohtml
|
||||
poppler-utils \
|
||||
# OCR MY PDF (unpaper for descew and other advanced featues)
|
||||
qpdf \
|
||||
tesseract-ocr-data-eng \
|
||||
font-terminus font-dejavu font-noto font-noto-cjk font-awesome font-noto-extra \
|
||||
# CV
|
||||
py3-opencv \
|
||||
# python3/pip
|
||||
python3 \
|
||||
py3-unoconv@testing \
|
||||
py3-pillow@testing \
|
||||
py3-pdf2image@testing \
|
||||
weasyprint@community && \
|
||||
# uno unoconv and HTML
|
||||
ca-certificates \
|
||||
tzdata \
|
||||
tini \
|
||||
bash \
|
||||
curl \
|
||||
shadow \
|
||||
su-exec \
|
||||
openssl \
|
||||
openssl-dev \
|
||||
openjdk21-jre \
|
||||
# Doc conversion
|
||||
libreoffice \
|
||||
# pdftohtml
|
||||
poppler-utils \
|
||||
# OCR MY PDF (unpaper for descew and other advanced featues)
|
||||
qpdf \
|
||||
tesseract-ocr-data-eng \
|
||||
font-terminus font-dejavu font-noto font-noto-cjk font-awesome font-noto-extra \
|
||||
# CV
|
||||
py3-opencv \
|
||||
# python3/pip
|
||||
python3 \
|
||||
py3-pip && \
|
||||
# uno unoconv and HTML
|
||||
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint pdf2image pillow && \
|
||||
mv /usr/share/tessdata /usr/share/tessdata-original && \
|
||||
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
|
||||
fc-cache -f -v && \
|
||||
chmod +x /scripts/* && \
|
||||
chmod +x /scripts/init.sh && \
|
||||
# User permissions
|
||||
# User permissions
|
||||
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
|
||||
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
|
||||
chown stirlingpdfuser:stirlingpdfgroup /app.jar
|
||||
|
||||
@@ -7,13 +7,7 @@ ARG VERSION_TAG
|
||||
ENV DOCKER_ENABLE_SECURITY=false \
|
||||
HOME=/home/stirlingpdfuser \
|
||||
VERSION_TAG=$VERSION_TAG \
|
||||
JAVA_TOOL_OPTIONS="-XX:+UnlockExperimentalVMOptions \
|
||||
-XX:MaxRAMPercentage=75 \
|
||||
-XX:InitiatingHeapOccupancyPercent=20 \
|
||||
-XX:+G1PeriodicGCInvokesConcurrent \
|
||||
-XX:G1PeriodicGCInterval=10000 \
|
||||
-XX:+UseStringDeduplication \
|
||||
-XX:G1PeriodicGCSystemLoadThreshold=70" \
|
||||
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
|
||||
PUID=1000 \
|
||||
PGID=1000 \
|
||||
UMASK=022
|
||||
|
||||
@@ -18,7 +18,9 @@ Any SVG flags are fine; most of the current ones were sourced from [here](https:
|
||||
For example, to add Polish, you would add:
|
||||
|
||||
```html
|
||||
<a th:if="${#lists.isEmpty(@languages) or #lists.contains(@languages, 'pl_PL')}" class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pl_PL"> <img th:src="@{'/images/flags/pl.svg'}" alt="icon" width="20" height="15"> Polski</a>
|
||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pl_PL">
|
||||
<img src="images/flags/pl.svg" alt="icon" width="20" height="15"> Polski
|
||||
</a>
|
||||
```
|
||||
|
||||
The `data-bs-language-code` is the code used to reference the file in the next step.
|
||||
|
||||
69
README.md
69
README.md
@@ -113,50 +113,49 @@ Visit our comprehensive documentation at [docs.stirlingpdf.com](https://docs.sti
|
||||
|
||||
## Supported Languages
|
||||
|
||||
Stirling-PDF currently supports 39 languages!
|
||||
Stirling-PDF currently supports 38 languages!
|
||||
|
||||
| Language | Progress |
|
||||
| -------------------------------------------- | -------------------------------------- |
|
||||
| Arabic (العربية) (ar_AR) |  |
|
||||
| Azerbaijani (Azərbaycan Dili) (az_AZ) |  |
|
||||
| Arabic (العربية) (ar_AR) |  |
|
||||
| Azerbaijani (Azərbaycan Dili) (az_AZ) |  |
|
||||
| Basque (Euskara) (eu_ES) |  |
|
||||
| Bulgarian (Български) (bg_BG) |  |
|
||||
| Catalan (Català) (ca_CA) |  |
|
||||
| Croatian (Hrvatski) (hr_HR) |  |
|
||||
| Czech (Česky) (cs_CZ) |  |
|
||||
| Danish (Dansk) (da_DK) |  |
|
||||
| Dutch (Nederlands) (nl_NL) |  |
|
||||
| Bulgarian (Български) (bg_BG) |  |
|
||||
| Catalan (Català) (ca_CA) |  |
|
||||
| Croatian (Hrvatski) (hr_HR) |  |
|
||||
| Czech (Česky) (cs_CZ) |  |
|
||||
| Danish (Dansk) (da_DK) |  |
|
||||
| Dutch (Nederlands) (nl_NL) |  |
|
||||
| English (English) (en_GB) |  |
|
||||
| English (US) (en_US) |  |
|
||||
| French (Français) (fr_FR) |  |
|
||||
| German (Deutsch) (de_DE) |  |
|
||||
| Greek (Ελληνικά) (el_GR) |  |
|
||||
| Hindi (हिंदी) (hi_IN) |  |
|
||||
| Hungarian (Magyar) (hu_HU) |  |
|
||||
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
||||
| Irish (Gaeilge) (ga_IE) |  |
|
||||
| French (Français) (fr_FR) |  |
|
||||
| German (Deutsch) (de_DE) |  |
|
||||
| Greek (Ελληνικά) (el_GR) |  |
|
||||
| Hindi (हिंदी) (hi_IN) |  |
|
||||
| Hungarian (Magyar) (hu_HU) |  |
|
||||
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
||||
| Irish (Gaeilge) (ga_IE) |  |
|
||||
| Italian (Italiano) (it_IT) |  |
|
||||
| Japanese (日本語) (ja_JP) |  |
|
||||
| Korean (한국어) (ko_KR) |  |
|
||||
| Norwegian (Norsk) (no_NB) |  |
|
||||
| Persian (فارسی) (fa_IR) |  |
|
||||
| Polish (Polski) (pl_PL) |  |
|
||||
| Portuguese (Português) (pt_PT) |  |
|
||||
| Japanese (日本語) (ja_JP) |  |
|
||||
| Korean (한국어) (ko_KR) |  |
|
||||
| Norwegian (Norsk) (no_NB) |  |
|
||||
| Persian (فارسی) (fa_IR) |  |
|
||||
| Polish (Polski) (pl_PL) |  |
|
||||
| Portuguese (Português) (pt_PT) |  |
|
||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||
| Romanian (Română) (ro_RO) |  |
|
||||
| Russian (Русский) (ru_RU) |  |
|
||||
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||
| Romanian (Română) (ro_RO) |  |
|
||||
| Russian (Русский) (ru_RU) |  |
|
||||
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||
| Slovakian (Slovensky) (sk_SK) |  |
|
||||
| Slovenian (Slovenščina) (sl_SI) |  |
|
||||
| Spanish (Español) (es_ES) |  |
|
||||
| Swedish (Svenska) (sv_SE) |  |
|
||||
| Thai (ไทย) (th_TH) |  |
|
||||
| Tibetan (བོད་ཡིག་) (zh_BO) |  |
|
||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||
| Turkish (Türkçe) (tr_TR) |  |
|
||||
| Ukrainian (Українська) (uk_UA) |  |
|
||||
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
||||
| Slovakian (Slovensky) (sk_SK) |  |
|
||||
| Spanish (Español) (es_ES) |  |
|
||||
| Swedish (Svenska) (sv_SE) |  |
|
||||
| Thai (ไทย) (th_TH) |  |
|
||||
| Tibetan (བོད་ཡིག་) (zh_BO) |  |
|
||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||
| Turkish (Türkçe) (tr_TR) |  |
|
||||
| Ukrainian (Українська) (uk_UA) |  |
|
||||
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
||||
|
||||
|
||||
## Stirling PDF Enterprise
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
{
|
||||
"allowedLicenses": [
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "BSD License"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "The BSD License"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "BSD-2-Clause"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "BSD 2-Clause License"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "The 2-Clause BSD License"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "BSD-3-Clause"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "The BSD 3-Clause License (BSD3)"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "BSD-4 License"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "MIT"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "MIT License"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "The MIT License"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.github.jai-imageio:jai-imageio-core",
|
||||
"moduleLicense": "LICENSE.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.github.jai-imageio:jai-imageio-jpeg2000",
|
||||
"moduleLicense": "LICENSE-JJ2000.txt, LICENSE-Sun.txt"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "Apache 2"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "Apache 2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "Apache-2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "Apache-2.0 License"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "Apache License 2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "Apache License Version 2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "Apache License, Version 2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "The Apache License, Version 2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "The Apache Software License, Version 2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.nimbusds:oauth2-oidc-sdk",
|
||||
"moduleLicense": "\"Apache License, version 2.0\";link=\"https://www.apache.org/licenses/LICENSE-2.0.html\""
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "MPL 2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "UnboundID SCIM2 SDK Free Use License"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "GPL2 w/ CPE"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "GPLv2+CE"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "GNU GENERAL PUBLIC LICENSE, Version 2 + Classpath Exception"
|
||||
},
|
||||
{
|
||||
"moduleName": "com.martiansoftware:jsap",
|
||||
"moduleLicense": "LGPL"
|
||||
},
|
||||
{
|
||||
"moduleName": "org.hibernate.orm:hibernate-core",
|
||||
"moduleLicense": "GNU Library General Public License v2.1 or later"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "Eclipse Public License - v 1.0"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "Eclipse Public License v. 2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "Eclipse Public License - v 2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "Eclipse Public License - Version 2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "Eclipse Public License, Version 2.0"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "Ubuntu Font Licence 1.0"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "Bouncy Castle Licence"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "Public Domain, per Creative Commons CC0"
|
||||
},
|
||||
{
|
||||
"moduleName": ".*",
|
||||
"moduleLicense": "The W3C License"
|
||||
}
|
||||
]
|
||||
}
|
||||
101
build.gradle
101
build.gradle
@@ -5,28 +5,28 @@ plugins {
|
||||
id "org.springdoc.openapi-gradle-plugin" version "1.8.0"
|
||||
id "io.swagger.swaggerhub" version "1.3.2"
|
||||
id "edu.sc.seis.launch4j" version "3.0.6"
|
||||
id "com.diffplug.spotless" version "7.0.2"
|
||||
id "com.diffplug.spotless" version "7.0.1"
|
||||
id "com.github.jk1.dependency-license-report" version "2.9"
|
||||
//id "nebula.lint" version "19.0.3"
|
||||
id("org.panteleyev.jpackageplugin") version "1.6.1"
|
||||
id "org.sonarqube" version "6.0.1.5171"
|
||||
//id "nebula.lint" version "19.0.3"
|
||||
id("org.panteleyev.jpackageplugin") version "1.6.0"
|
||||
}
|
||||
|
||||
import com.github.jk1.license.render.*
|
||||
|
||||
ext {
|
||||
springBootVersion = "3.4.1"
|
||||
pdfboxVersion = "3.0.4"
|
||||
pdfboxVersion = "3.0.3"
|
||||
logbackVersion = "1.5.7"
|
||||
imageioVersion = "3.12.0"
|
||||
lombokVersion = "1.18.36"
|
||||
bouncycastleVersion = "1.80"
|
||||
bouncycastleVersion = "1.79"
|
||||
springSecuritySamlVersion = "6.4.2"
|
||||
openSamlVersion = "4.3.2"
|
||||
}
|
||||
|
||||
group = "stirling.software"
|
||||
version = "0.41.0"
|
||||
version = "0.37.1"
|
||||
|
||||
|
||||
java {
|
||||
// 17 is lowest but we support and recommend 21
|
||||
@@ -35,13 +35,14 @@ java {
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url = "https://build.shibboleth.net/maven/releases" }
|
||||
maven { url = "https://maven.pkg.github.com/jcefmaven/jcefmaven" }
|
||||
maven { url "https://jitpack.io" }
|
||||
maven { url "https://build.shibboleth.net/maven/releases" }
|
||||
maven { url "https://maven.pkg.github.com/jcefmaven/jcefmaven" }
|
||||
|
||||
}
|
||||
|
||||
licenseReport {
|
||||
renderers = [new JsonReportRenderer()]
|
||||
allowedLicensesFile = new File("$projectDir/allowed-licenses.json")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
@@ -65,7 +66,7 @@ sourceSets {
|
||||
}
|
||||
|
||||
if (System.getenv("STIRLING_PDF_DESKTOP_UI") == "false") {
|
||||
exclude "stirling/software/SPDF/UI/impl/**"
|
||||
exclude "stirling/software/SPDF/UI/impl/**"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -137,10 +138,10 @@ jpackage {
|
||||
|
||||
// Windows-specific configuration
|
||||
windows {
|
||||
launcherAsService = false
|
||||
appVersion = project.version
|
||||
launcherAsService = false
|
||||
appVersion = project.version
|
||||
|
||||
winConsole = false
|
||||
winConsole = false
|
||||
winMenu = true // Creates start menu entry
|
||||
winShortcut = true // Creates desktop shortcut
|
||||
winShortcutPrompt = true // Lets user choose whether to create shortcuts
|
||||
@@ -156,7 +157,7 @@ jpackage {
|
||||
|
||||
// macOS-specific configuration
|
||||
mac {
|
||||
appVersion = getMacVersion(project.version.toString())
|
||||
appVersion = getMacVersion(project.version.toString())
|
||||
icon = "src/main/resources/static/favicon.icns"
|
||||
type = "dmg"
|
||||
macPackageIdentifier = "com.stirling.software.pdf"
|
||||
@@ -180,7 +181,7 @@ jpackage {
|
||||
|
||||
// Linux-specific configuration
|
||||
linux {
|
||||
appVersion = project.version
|
||||
appVersion = project.version
|
||||
icon = "src/main/resources/static/favicon.png"
|
||||
type = "deb" // Can also use "rpm" for Red Hat-based systems
|
||||
|
||||
@@ -228,9 +229,9 @@ launch4j {
|
||||
outfile="Stirling-PDF.exe"
|
||||
|
||||
if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') {
|
||||
headerType = "gui"
|
||||
headerType = "gui"
|
||||
} else {
|
||||
headerType = "console"
|
||||
headerType = "console"
|
||||
}
|
||||
jarTask = tasks.bootJar
|
||||
|
||||
@@ -238,11 +239,13 @@ launch4j {
|
||||
downloadUrl="https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe"
|
||||
|
||||
if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') {
|
||||
variables=["BROWSER_OPEN=true", "STIRLING_PDF_DESKTOP_UI=true"]
|
||||
variables=["BROWSER_OPEN=true", "STIRLING_PDF_DESKTOP_UI=true"]
|
||||
} else {
|
||||
variables=["BROWSER_OPEN=true"]
|
||||
variables=["BROWSER_OPEN=true"]
|
||||
}
|
||||
|
||||
|
||||
|
||||
jreMinVersion="17"
|
||||
|
||||
mutexName="Stirling-PDF"
|
||||
@@ -264,22 +267,11 @@ spotless {
|
||||
importOrder("java", "javax", "org", "com", "net", "io")
|
||||
toggleOffOn()
|
||||
trimTrailingWhitespace()
|
||||
leadingTabsToSpaces()
|
||||
indentWithSpaces()
|
||||
endWithNewline()
|
||||
}
|
||||
}
|
||||
|
||||
sonar {
|
||||
properties {
|
||||
property "sonar.projectKey", "Stirling-Tools_Stirling-PDF"
|
||||
property "sonar.organization", "stirling-tools"
|
||||
|
||||
property "sonar.exclusions", "**/build-wrapper-dump.json, src/main/java/org/apache/**, src/main/resources/static/pdfjs/**, src/main/resources/static/pdfjs-legacy/**, src/main/resources/static/js/thirdParty/**"
|
||||
property "sonar.coverage.exclusions", "src/main/java/org/apache/**, src/main/resources/static/pdfjs/**, src/main/resources/static/pdfjs-legacy/**, src/main/resources/static/js/thirdParty/**"
|
||||
property "sonar.cpd.exclusions", "src/main/java/org/apache/**, src/main/resources/static/pdfjs/**, src/main/resources/static/pdfjs-legacy/**, src/main/resources/static/js/thirdParty/**"
|
||||
}
|
||||
}
|
||||
|
||||
//gradleLint {
|
||||
// rules=['unused-dependency']
|
||||
// }
|
||||
@@ -294,23 +286,26 @@ configurations.all {
|
||||
}
|
||||
dependencies {
|
||||
|
||||
if (System.getenv("STIRLING_PDF_DESKTOP_UI") != "false") {
|
||||
implementation "me.friwi:jcefmaven:127.3.1"
|
||||
implementation "org.openjfx:javafx-controls:21"
|
||||
implementation "org.openjfx:javafx-swing:21"
|
||||
if (System.getenv("STIRLING_PDF_DESKTOP_UI") != "false") {
|
||||
implementation "me.friwi:jcefmaven:127.3.1"
|
||||
implementation "org.openjfx:javafx-controls:21"
|
||||
implementation "org.openjfx:javafx-swing:21"
|
||||
}
|
||||
|
||||
//security updates
|
||||
implementation "org.springframework:spring-webmvc:6.2.2"
|
||||
implementation "org.springframework:spring-webmvc:6.2.1"
|
||||
|
||||
implementation("io.github.pixee:java-security-toolkit:1.2.1")
|
||||
|
||||
// implementation "org.yaml:snakeyaml:2.2"
|
||||
implementation 'com.github.Carleslc.Simple-YAML:Simple-Yaml:1.8.4'
|
||||
|
||||
// Exclude Tomcat and include Jetty
|
||||
implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
|
||||
implementation "org.springframework.boot:spring-boot-starter-jetty:$springBootVersion"
|
||||
|
||||
implementation "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion"
|
||||
implementation 'com.posthog.java:posthog:1.2.0'
|
||||
implementation 'com.posthog.java:posthog:1.1.1'
|
||||
implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1'
|
||||
|
||||
|
||||
@@ -320,20 +315,20 @@ dependencies {
|
||||
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
|
||||
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
|
||||
|
||||
implementation "org.springframework.session:spring-session-core:$springBootVersion"
|
||||
implementation "org.springframework:spring-jdbc:6.2.2"
|
||||
implementation "org.springframework.session:spring-session-core:$springBootVersion"
|
||||
implementation "org.springframework:spring-jdbc:6.2.1"
|
||||
|
||||
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
|
||||
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
|
||||
// Don't upgrade h2database
|
||||
runtimeOnly "com.h2database:h2:2.3.232"
|
||||
runtimeOnly "org.postgresql:postgresql:42.7.5"
|
||||
runtimeOnly "org.postgresql:postgresql:42.7.4"
|
||||
constraints {
|
||||
implementation "org.opensaml:opensaml-core:$openSamlVersion"
|
||||
implementation "org.opensaml:opensaml-saml-api:$openSamlVersion"
|
||||
implementation "org.opensaml:opensaml-saml-impl:$openSamlVersion"
|
||||
}
|
||||
implementation "org.springframework.security:spring-security-saml2-service-provider:$springSecuritySamlVersion"
|
||||
// implementation 'org.springframework.security:spring-security-core:$springSecuritySamlVersion'
|
||||
// implementation 'org.springframework.security:spring-security-core:$springSecuritySamlVersion'
|
||||
implementation 'com.coveo:saml-client:5.0.0'
|
||||
|
||||
|
||||
@@ -377,8 +372,6 @@ dependencies {
|
||||
implementation ("org.apache.pdfbox:pdfbox:$pdfboxVersion") {
|
||||
exclude group: "commons-logging", module: "commons-logging"
|
||||
}
|
||||
implementation "org.apache.pdfbox:preflight:$pdfboxVersion"
|
||||
|
||||
|
||||
implementation ("org.apache.pdfbox:xmpbox:$pdfboxVersion") {
|
||||
exclude group: "commons-logging", module: "commons-logging"
|
||||
@@ -405,8 +398,8 @@ dependencies {
|
||||
implementation "com.bucket4j:bucket4j_jdk17-core:8.14.0"
|
||||
implementation "com.fathzer:javaluator:3.0.5"
|
||||
|
||||
implementation 'com.vladsch.flexmark:flexmark-html2md-converter:0.64.8'
|
||||
|
||||
implementation 'org.jsoup:jsoup:1.18.3'
|
||||
|
||||
developmentOnly("org.springframework.boot:spring-boot-devtools:$springBootVersion")
|
||||
compileOnly "org.projectlombok:lombok:$lombokVersion"
|
||||
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
|
||||
@@ -430,13 +423,13 @@ task writeVersion {
|
||||
}
|
||||
|
||||
swaggerhubUpload {
|
||||
// dependsOn = generateOpenApiDocs // Depends on your task generating Swagger docs
|
||||
api = "Stirling-PDF" // The name of your API on SwaggerHub
|
||||
owner = "Frooodle" // Your SwaggerHub username (or organization name)
|
||||
version = project.version // The version of your API
|
||||
inputFile = "./SwaggerDoc.json" // The path to your Swagger docs
|
||||
token = "${System.getenv("SWAGGERHUB_API_KEY")}" // Your SwaggerHub API key, passed as an environment variable
|
||||
oas = "3.0.0" // The version of the OpenAPI Specification you"re using
|
||||
//dependsOn generateOpenApiDocs // Depends on your task generating Swagger docs
|
||||
api "Stirling-PDF" // The name of your API on SwaggerHub
|
||||
owner "Frooodle" // Your SwaggerHub username (or organization name)
|
||||
version project.version // The version of your API
|
||||
inputFile "./SwaggerDoc.json" // The path to your Swagger docs
|
||||
token "${System.getenv("SWAGGERHUB_API_KEY")}" // Your SwaggerHub API key, passed as an environment variable
|
||||
oas "3.0.0" // The version of the OpenAPI Specification you"re using
|
||||
}
|
||||
|
||||
jar {
|
||||
|
||||
@@ -204,12 +204,4 @@ Feature: API Validation
|
||||
Then the response status code should be 200
|
||||
And the response file should have size greater than 100
|
||||
And the response file should have extension ".pdf"
|
||||
|
||||
Scenario: Convert PDF to Markdown format
|
||||
Given I generate a PDF file as "fileInput"
|
||||
And the pdf contains 3 pages with random text
|
||||
When I send the API request to the endpoint "/api/v1/convert/pdf/markdown"
|
||||
Then the response status code should be 200
|
||||
And the response file should have size greater than 100
|
||||
And the response file should have extension ".md"
|
||||
|
||||
@@ -2,16 +2,17 @@
|
||||
|
||||
# Function to check a single webpage
|
||||
check_webpage() {
|
||||
local url=$(echo "$1" | tr -d '\r') # Remove carriage returns
|
||||
local base_url=$(echo "$2" | tr -d '\r')
|
||||
local url=$1
|
||||
local base_url=${2:-"http://localhost:8080"}
|
||||
local full_url="${base_url}${url}"
|
||||
local timeout=10
|
||||
|
||||
echo -n "Testing $full_url ... "
|
||||
|
||||
# Use curl to fetch the page with timeout
|
||||
response=$(curl -s -w "\n%{http_code}" --max-time $timeout "$full_url")
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "FAILED - Connection error or timeout $full_url "
|
||||
echo "FAILED - Connection error or timeout"
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -26,7 +27,7 @@ check_webpage() {
|
||||
fi
|
||||
|
||||
# Check if response contains HTML
|
||||
if ! printf '%s' "$BODY" | grep -q "<!DOCTYPE html>\|<html"; then
|
||||
if ! echo "$BODY" | grep -q "<!DOCTYPE html>\|<html"; then
|
||||
echo "FAILED - Response is not HTML"
|
||||
return 1
|
||||
fi
|
||||
@@ -45,12 +46,11 @@ test_all_urls() {
|
||||
|
||||
echo "Starting webpage tests..."
|
||||
echo "Base URL: $base_url"
|
||||
echo "Number of lines: $(wc -l < "$url_file")"
|
||||
echo "----------------------------------------"
|
||||
|
||||
|
||||
while IFS= read -r url || [ -n "$url" ]; do
|
||||
# Skip empty lines and comments
|
||||
[[ -z "$url" || "$url" =~ ^#.*$ ]] && continue
|
||||
# Skip empty lines
|
||||
[ -z "$url" ] && continue
|
||||
|
||||
((total_count++))
|
||||
if ! check_webpage "$url" "$base_url"; then
|
||||
@@ -60,7 +60,7 @@ test_all_urls() {
|
||||
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
|
||||
|
||||
echo "----------------------------------------"
|
||||
echo "Test Summary:"
|
||||
echo "Total tests: $total_count"
|
||||
@@ -71,44 +71,18 @@ test_all_urls() {
|
||||
return $failed_count
|
||||
}
|
||||
|
||||
# Print usage information
|
||||
usage() {
|
||||
echo "Usage: $0 [-f url_file] [-b base_url]"
|
||||
echo "Options:"
|
||||
echo " -f url_file Path to file containing URLs to test (required)"
|
||||
echo " -b base_url Base URL to prepend to test URLs (default: http://localhost:8080)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
local url_file=""
|
||||
local base_url="http://localhost:8080"
|
||||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local url_file="${script_dir}/webpage_urls.txt"
|
||||
|
||||
# Parse command line options
|
||||
while getopts ":f:b:h" opt; do
|
||||
case $opt in
|
||||
f) url_file="$OPTARG" ;;
|
||||
b) base_url="$OPTARG" ;;
|
||||
h) usage ;;
|
||||
\?) echo "Invalid option -$OPTARG" >&2; usage ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Check if URL file is provided
|
||||
if [ -z "$url_file" ]; then
|
||||
echo "Error: URL file is required"
|
||||
usage
|
||||
fi
|
||||
|
||||
# Check if URL file exists
|
||||
if [ ! -f "$url_file" ]; then
|
||||
echo "Error: URL list file not found: $url_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run tests using the URL list
|
||||
if test_all_urls "$url_file" "$base_url"; then
|
||||
if test_all_urls "$url_file"; then
|
||||
echo "All webpage tests passed!"
|
||||
exit 0
|
||||
else
|
||||
@@ -12,6 +12,7 @@
|
||||
/extract-page
|
||||
/pdf-to-single-page
|
||||
/img-to-pdf
|
||||
/markdown-to-pdf
|
||||
/pdf-to-img
|
||||
/pdf-to-text
|
||||
/pdf-to-csv
|
||||
BIN
docs/stirling-pdf.png
Normal file
BIN
docs/stirling-pdf.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
1
docs/stirling-transparent.svg
Normal file
1
docs/stirling-transparent.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 9.4 KiB |
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
stirling-pdf:
|
||||
container_name: Stirling-PDF-Security-Fat-with-login
|
||||
container_name: Stirling-PDF-Security-Fat
|
||||
image: stirlingtools/stirling-pdf:latest-fat
|
||||
deploy:
|
||||
resources:
|
||||
|
||||
6568
gradle/verification-keyring.keys
Normal file
6568
gradle/verification-keyring.keys
Normal file
File diff suppressed because it is too large
Load Diff
477
gradle/verification-metadata.xml
Normal file
477
gradle/verification-metadata.xml
Normal file
@@ -0,0 +1,477 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<verification-metadata xmlns="https://schema.gradle.org/dependency-verification" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://schema.gradle.org/dependency-verification https://schema.gradle.org/dependency-verification/dependency-verification-1.3.xsd">
|
||||
<configuration>
|
||||
<verify-metadata>true</verify-metadata>
|
||||
<verify-signatures>true</verify-signatures>
|
||||
<keyring-format>armored</keyring-format>
|
||||
<trusted-artifacts>
|
||||
<trust group="io.dropwizard.metrics" name="metrics-bom" reason="BOM file, safe to trust"/>
|
||||
<trust group="io.dropwizard.metrics" name="metrics-parent" reason="BOM parent, https://github.com/gradle/gradle/issues/20194"/>
|
||||
<trust group="org.springframework" name="spring-framework-bom" reason="Spring BOM file, safe to trust"/>
|
||||
</trusted-artifacts>
|
||||
<trusted-keys>
|
||||
<trusted-key id="015479E1055341431B4545AB72475FD306B9CAB7" group="com.googlecode.javaewah" name="JavaEWAH" version="1.2.3"/>
|
||||
<trusted-key id="042B29E928995B9DB963C636C7CA19B7B620D787" group="com.github.stephenc.jcip" name="jcip-annotations" version="1.0-1"/>
|
||||
<trusted-key id="04543577D6A9CC626239C50C7ECBD740FF06AEB5">
|
||||
<trusting group="org.glassfish.jaxb"/>
|
||||
<trusting group="^com[.]sun($|([.].*))" regex="true"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="050A37A2E0577F4BAA095B52602EC18D20C4661C">
|
||||
<trusting group="com.thoughtworks.xstream"/>
|
||||
<trusting group="io.github.x-stream"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="077E8893A6DCC33DD4A4D5B256E73BA9A0B592D0" group="^org[.]apache[.]logging($|([.].*))" regex="true"/>
|
||||
<trusted-key id="0785B3EFF60B1B1BEA94E0BB7C25280EAE63EBE5" group="^org[.]apache[.]httpcomponents($|([.].*))" regex="true"/>
|
||||
<trusted-key id="07E20F0103D9DFC697C490D0368557390486F2C5">
|
||||
<trusting group="io.rest-assured"/>
|
||||
<trusting group="org.awaitility"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="08F0AAB4D0C1A4BDDE340765B341DDB020FCB6AB" group="org.bouncycastle"/>
|
||||
<trusted-key id="0A60B3F1FCB211175300EC206E50BB68CC1699A6" group="com.github.jai-imageio"/>
|
||||
<trusted-key id="0B1B71E813C226033B16D8C5F0D228D8FF31B515" group="^io[.]zipkin($|([.].*))" regex="true"/>
|
||||
<trusted-key id="0B743A794876D3C78AB542A118D239B1CBCD2236" group="org.glassfish.jersey" name="jersey-bom"/>
|
||||
<trusted-key id="0CC641C3A62453AB390066C4A41F13C999945293" group="commons-collections" name="commons-collections" version="3.2.2"/>
|
||||
<trusted-key id="0CDE80149711EB46DFF17AE421A24B3F8B0F594A" group="org.apache" name="apache" version="16"/>
|
||||
<trusted-key id="0CFA413799E2464C7D7E26220A4B343F2A55FDAE" group="com.h2database" name="h2" version="2.3.232"/>
|
||||
<trusted-key id="0D35D3F60078655126908E8AF3D1600878E85A3D" group="io.netty" name="netty-bom"/>
|
||||
<trusted-key id="0E0CA56D354132B5E646C25F49A1796B9B494CB8" group="org.opensaml"/>
|
||||
<trusted-key id="0E9BD9062B021BBA50F41EEB9549F6CB1E679A56" group="org.locationtech.jts"/>
|
||||
<trusted-key id="10F3C7A02ECA55E502BADCF3991EFB94DB91127D" group="org.ow2" name="ow2" version="1.5.1"/>
|
||||
<trusted-key id="1452F35849B50750F6A3BBB4B54011358B352F85" group="org.hibernate.orm" name="hibernate-core" version="6.6.4.Final"/>
|
||||
<trusted-key id="147B691A19097624902F4EA9689CBE64F4BC997F" group="org.mockito"/>
|
||||
<trusted-key id="190D5A957FF22273E601F7A7C92C5FEC70161C62" group="org.apache" name="apache" version="18"/>
|
||||
<trusted-key id="19BEAB2D799C020F17C69126B16698A4ADF4D638" group="org.checkerframework" name="checker-qual"/>
|
||||
<trusted-key id="1AA8CF92D409A73393D0B736BFF2EE42C8282E76" group="org.apache.activemq" name="activemq-bom" version="6.1.4"/>
|
||||
<trusted-key id="1D04A424F505394DBED15D451D0690E353BE126D" group="net.minidev"/>
|
||||
<trusted-key id="1D2C7EF8ADA0F794B58C7C63436902AF59EDF60E">
|
||||
<trusting group="dev.equo.ide" name="solstice" version="1.7.5"/>
|
||||
<trusting group="dev.equo.ide" name="solstice" version="1.8.0"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="20FC6EC5F628F0EB66F157B8DC97B815CAC4E847" group="io.github.pixee" name="java-security-toolkit" version="1.2.1"/>
|
||||
<trusted-key id="2518174F4111F02779592A6F9757D7E7E06DD2AC" group="io.prometheus"/>
|
||||
<trusted-key id="2655176F748FD83725B4805FF2A01147D830C125" group="org.testcontainers" name="testcontainers-bom"/>
|
||||
<trusted-key id="28118C070CB22A0175A2E8D43D12CA2AC19F3181" group="^com[.]fasterxml($|([.].*))" regex="true"/>
|
||||
<trusted-key id="28417C95E8906D108392822354A43F3254868410" group="org.apache.activemq"/>
|
||||
<trusted-key id="2B1DD4CE9223D4E19C73531E5657B51F13E59DBE" group="com.unboundid.product.scim2"/>
|
||||
<trusted-key id="2B34821418CF19CF1F2A8352953E02E4F573B46F" group="jakarta.platform"/>
|
||||
<trusted-key id="2BCBDD0F23EA1CAFCC11D4860374CF2E8DD1BDFD" group="net.java"/>
|
||||
<trusted-key id="2DB4F1EF0FA761ECC4EA935C86FDC7E2A11262CB">
|
||||
<trusting group="commons-beanutils" name="commons-beanutils" version="1.10.0"/>
|
||||
<trusting group="commons-codec"/>
|
||||
<trusting group="commons-io"/>
|
||||
<trusting group="commons-logging"/>
|
||||
<trusting group="org.apache.commons"/>
|
||||
<trusting group="xml-apis"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="2DC48CBB4352B4953AF6F803D433B437192A0FD1" group="com.datastax.oss" name="java-driver-bom" version="4.15.0"/>
|
||||
<trusted-key id="2E3A1AFFE42B5F53AF19F780BCF4173966770193" group="org.jetbrains" name="annotations" version="13.0"/>
|
||||
<trusted-key id="2FC53E6B1F681184F4CCD637F5C81DE10A0B8ECC" group="org.yaml" name="snakeyaml" version="2.3"/>
|
||||
<trusted-key id="3262A061C42FC4C7BBB5C25C1CF0293FA53CA458" group="org.apache.tomcat.embed"/>
|
||||
<trusted-key id="34441E504A937F43EB0DAEF96A65176A0FB1CD0B" group="org.apache.groovy" name="groovy-bom"/>
|
||||
<trusted-key id="3690C240CE51B4670D30AD1C38EE757D69184620" group="org.tukaani" name="xz" version="1.9"/>
|
||||
<trusted-key id="3750777B9C4B7D233B9D0C40307A96FBA0292109" group="org.postgresql" name="postgresql" version="42.7.4"/>
|
||||
<trusted-key id="38319E05F62674572CDF886170B2EBE96C112CC9" group="org.cryptacular" name="cryptacular" version="1.2.5"/>
|
||||
<trusted-key id="3E61D8C230332482009D7F0EDB901B24CAD38BC4" group="io.swagger.core.v3"/>
|
||||
<trusted-key id="3F05DDA9F317301E927136D417A27CE7A60FF5F0" group="io.opentelemetry" name="opentelemetry-bom"/>
|
||||
<trusted-key id="4021EEEAFF5DE8404DCD0A270AA3E5C3D232E79B">
|
||||
<trusting group="jakarta.enterprise"/>
|
||||
<trusting group="jakarta.inject"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="41D266DB4427983A1A4AFB0C3684155E9365C30E" group="com.jayway.jsonpath" name="json-path" version="2.9.0"/>
|
||||
<trusted-key id="44FBDBBC1A00FE414F1C1873586654072EAD6677" group="org.sonatype.oss" name="oss-parent" version="9"/>
|
||||
<trusted-key id="453EA31328DE7D8AAA55AD4ED56C721C1CFF1424" group="^com[.]twelvemonkeys($|([.].*))" regex="true"/>
|
||||
<trusted-key id="475F3B8E59E6E63AA78067482C7B12F2A511E325" group="org.slf4j"/>
|
||||
<trusted-key id="477E62A656AD5475A1882855C809CA3C41BA6E96" group="jakarta.validation" name="jakarta.validation-api" version="3.0.2"/>
|
||||
<trusted-key id="4797B4F5DCC46CEA61059071A1AE06236CA2BA62" group="^com[.]diffplug($|([.].*))" regex="true"/>
|
||||
<trusted-key id="47EF0EC60C210BC6DFAA5819B7AE15C15C321C44" group="jakarta.transaction" name="jakarta.transaction-api" version="2.0.1"/>
|
||||
<trusted-key id="47FF105DF431FF5416B821FEAECDB81D38EA9C89" group="org.commonmark"/>
|
||||
<trusted-key id="482C52BC305FB31063CD19D67BEFA2F0A9C24E7D" group="net.sf.launch4j" name="launch4j" version="3.50"/>
|
||||
<trusted-key id="48B086A7D843CFA258E83286928FBF39003C0425">
|
||||
<trusting group="io.micrometer"/>
|
||||
<trusting group="io.projectreactor"/>
|
||||
<trusting group="io.spring.gradle"/>
|
||||
<trusting group="^org[.]springframework($|([.].*))" regex="true"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="498AAC354AA5CB36FAAB7608B6E83A2D2E447E56" group="org.apache.cassandra" name="java-driver-bom" version="4.18.1"/>
|
||||
<trusted-key id="4F7E32D440EF90A83011A8FC6425559C47CC79C4">
|
||||
<trusting group="com.sun.activation"/>
|
||||
<trusting group="javax.activation"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="53C935821AA6A755BD337DB53595395EB3D8E1BA" group="org.apache.logging.log4j" name="log4j-bom" version="2.20.0"/>
|
||||
<trusted-key id="5719E50EAC5A4B1DD390B72C2A742740E08E7F8D" group="org.antlr"/>
|
||||
<trusted-key id="57312C37B064EE0FDAB0130490D5CE79E1DE6A2C" group="com.querydsl" name="querydsl-bom"/>
|
||||
<trusted-key id="5989BAF76217B843D66BE55B2D0E1FB8FE4B68B4" group="^org[.]eclipse[.]jetty($|([.].*))" regex="true"/>
|
||||
<trusted-key id="59A8E169739301FD48139CA00E325BECB6962A24" group="jakarta.annotation" name="jakarta.annotation-api" version="2.1.1"/>
|
||||
<trusted-key id="5C9A30FF22B2C02F30261C305B93F1DF7CDB6DEA" group="org.apache.xmlgraphics"/>
|
||||
<trusted-key id="60200AC4AE761F1614D6C46766D68DAA073BE985">
|
||||
<trusting group="ch.qos.logback"/>
|
||||
<trusting group="org.slf4j"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="694621A7227D8D5289699830ABE9F3126BB741C1" group="com.google.guava" name="guava-parent" version="26.0-android"/>
|
||||
<trusted-key id="6DD3B8C64EF75253BEB2C53AD908A43FB7EC07AC" group="jakarta.activation" name="jakarta.activation-api" version="2.1.3"/>
|
||||
<trusted-key id="6E13156C0EE653F0B984663AB95BBD3FA43C4492" group="org.apache" name="apache" version="3"/>
|
||||
<trusted-key id="6F538074CCEBF35F28AF9B066A0975F8B1127B83" group="org.jetbrains.kotlin"/>
|
||||
<trusted-key id="70CD19BFD9F6C330027D6F260315BFB7970A144F" group="javax.xml.bind"/>
|
||||
<trusted-key id="71EBF1CA4125B10AAB1E17CDB7DC526C17E3608B" group="jakarta.persistence" name="jakarta.persistence-api" version="3.1.0"/>
|
||||
<trusted-key id="7464550A61C90BA385FC97A76D9567281201E5E3" group="jakarta.servlet" name="jakarta.servlet-api" version="6.0.0"/>
|
||||
<trusted-key id="7616EB882DAF57A11477AAF559A252FB1199D873" group="com.google.code.findbugs" name="jsr305" version="3.0.2"/>
|
||||
<trusted-key id="798E2DA37E70DAE0EA9E498CA388C395AAFB80F8" group="io.dropwizard.metrics"/>
|
||||
<trusted-key id="7A1D848E7C2AF85EEBA69C99E7BF252CF360097E" group="org.latencyutils" name="LatencyUtils" version="2.0.3"/>
|
||||
<trusted-key id="7B121B76A7ED6CE6E60AD51784E913A8E3A748C0" group="org.bouncycastle"/>
|
||||
<trusted-key id="7C669810892CBD3148FA92995B05CCDE140C2876" group="org.eclipse.jgit"/>
|
||||
<trusted-key id="808D78B17A5A2D7C3668E31FBFFC9B54721244AD" group="org.apache.commons" name="commons-parent" version="39"/>
|
||||
<trusted-key id="80F6D6B0D90C6747753344CAB5A9E81B565E89E0" group="org.tomlj" name="tomlj" version="1.0.0"/>
|
||||
<trusted-key id="81BE0C38ACE8AEDC7735A05F4C2AFF633F3A7223" group="org.seleniumhq.selenium" name="selenium-bom"/>
|
||||
<trusted-key id="81CCDC71C7D61C179B27002D6A9FBE152D4C64D1" group="org.openjfx"/>
|
||||
<trusted-key id="82F0964816AD7319CB0CCCF93EFD9D223D715E9A" group="com.nimbusds"/>
|
||||
<trusted-key id="82F94BBDF95C247BBD21396B9A0B94DEC0FFA7EE" group="org.webjars" name="swagger-ui" version="5.2.0"/>
|
||||
<trusted-key id="839323A4780D5BF9A6978970152888E10EF880B3">
|
||||
<trusting group="org.attoparser"/>
|
||||
<trusting group="org.unbescape"/>
|
||||
<trusting group="^org[.]thymeleaf($|([.].*))" regex="true"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="84789D24DF77A32433CE1F079EB80E92EB2135B1" group="org.apache" name="apache"/>
|
||||
<trusted-key id="8756C4F765C9AC3CB6B85D62379CE192D401AB61" group="com.diffplug.durian"/>
|
||||
<trusted-key id="894F14D98D7F20D5E82645E3DFE102108BF9381F" group="org.hibernate.search" name="hibernate-search-bom" version="7.1.2.Final"/>
|
||||
<trusted-key id="94976E17E18DD3201447286954963C3E875A56AE" group="io.smallrye"/>
|
||||
<trusted-key id="9579802DC3E15DE9C389239FC0D48A119CE7EE7B" group="com.zaxxer" name="HikariCP" version="5.1.0"/>
|
||||
<trusted-key id="9790B1EC52577244529621F38C77ED250E495230" group="com.bucket4j" name="bucket4j_jdk17-core" version="8.14.0"/>
|
||||
<trusted-key id="982C26A0C156D986CC2AD19E3FBA8E8E719022D7" group="org.jboss" name="jboss-parent" version="39"/>
|
||||
<trusted-key id="9B32CBC0F3F6BA4C13D611FC21871D2A9AB66A31" group="io.rsocket" name="rsocket-bom" version="1.1.3"/>
|
||||
<trusted-key id="9E3044071B758EBCB7E45673700E4F39BC05364B">
|
||||
<trusting group="org.eclipse.platform" name="org.eclipse.osgi" version="3.18.300"/>
|
||||
<trusting group="org.eclipse.platform" name="org.eclipse.osgi" version="3.18.500"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="A41A5960555F8CBBC7D8B2D7787F3A057B828D36" group="org.springdoc"/>
|
||||
<trusted-key id="A5BD02B93E7A40482EB1D66A5F69AD087600B22C" group="org.ow2.asm"/>
|
||||
<trusted-key id="A602970FE1BF5C9C8A9491B97A3C9FE21DFDBF44" group="org.apache.pdfbox"/>
|
||||
<trusted-key id="A654E2E6D97BE4219A4909415B15A33991BEA5A8" group="me.friwi"/>
|
||||
<trusted-key id="A6D6C97108B8585F91B158748671A8DF71296252" group="com.squareup.okhttp3" name="okhttp-bom" version="4.10.0"/>
|
||||
<trusted-key id="A7892505CF1A58076453E52D7999BEFBA1039E8B" group="net.bytebuddy"/>
|
||||
<trusted-key id="A9789342F598AD5B1175EF357EB97D110DFADD60" group="com.googlecode.concurrent-trees" name="concurrent-trees" version="2.6.1"/>
|
||||
<trusted-key id="AA70C7C433D501636392EC02153E7A3C2B4E5118" group="org.eclipse.ee4j" name="project"/>
|
||||
<trusted-key id="AB1DC33940689C44669107094989E0E939C2999B">
|
||||
<trusting group="com.opencsv" name="opencsv" version="5.10"/>
|
||||
<trusting group="com.opencsv" name="opencsv" version="5.9"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="B1F250C1F371EBF0E31E86E30E31BBB30C940D01" group="com.posthog.java" name="posthog" version="1.1.1"/>
|
||||
<trusted-key id="B6E73D84EA4FCC47166087253FAAD2CD5ECBB314">
|
||||
<trusting group="commons-beanutils"/>
|
||||
<trusting group="org.apache.commons"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="BA926F64CA647B6D853A38672E2010F8A7FF4A41" group="org.apache" name="apache" version="7"/>
|
||||
<trusted-key id="BB785E0400E71390977E4D1ADF3CC7C64D56297B" group="jakarta.interceptor" name="jakarta.interceptor-api" version="2.1.0"/>
|
||||
<trusted-key id="BCA1F17506AF088F3A964A9C0459A2B383ED8C11" group="org.eclipse.angus"/>
|
||||
<trusted-key id="BDB5FA4FE719D787FB3D3197F6D4A1D411E9D1AE" group="^com[.]google($|([.].*))" regex="true"/>
|
||||
<trusted-key id="BE685132AFD2740D9095F9040CC0B712FEE75827" group="org.assertj"/>
|
||||
<trusted-key id="C1D1ADA83198AA7FEAD102483FFE64C7506FCCC9" group="com.coveo" name="saml-client" version="5.0.0"/>
|
||||
<trusted-key id="C663D2F64DA2CA09DB28D9ABD3FA67D522C55256" group="org.apache.pulsar" name="pulsar-bom" version="3.3.3"/>
|
||||
<trusted-key id="C7BE5BCC9FEC15518CFDA882B0F3710FA64900E7" group="com.google.code.gson"/>
|
||||
<trusted-key id="C89074FC8BE681B7C7EAAB6E4C5EED3C53B75933" group="org.skyscreamer" name="jsonassert" version="1.5.3"/>
|
||||
<trusted-key id="CA62ED130E4053944406DF640181B45EA58677BC" group="org.apache.logging" name="logging-parent" version="7"/>
|
||||
<trusted-key id="CC57399D74CD7E4768ED6FA4CA62973FBF0451C0" group="com.vaadin.external.google" name="android-json" version="0.0.20131108.vaadin1"/>
|
||||
<trusted-key id="CD5464315F0B98C77E6E8ECD9DAADC1C9FCC82D0" group="commons-cli" name="commons-cli" version="1.4"/>
|
||||
<trusted-key id="CE3285F320685193D11FEA01F6CE9695C9318406" group="com.google.zxing"/>
|
||||
<trusted-key id="CE4439C1BEF3DA83B1832F9DBEFEEF227A98B809" group="org.apache.velocity"/>
|
||||
<trusted-key id="CE8075A251547BEE249BC151A2115AE15F6B8B72">
|
||||
<trusting group="org.apache.commons"/>
|
||||
<trusting group="org.xmlunit"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="D421D1DF4570BFB13E485D0BF95ADD0A28D2F139" group="org.projectlombok" name="lombok" version="1.18.36"/>
|
||||
<trusted-key id="D54A395B5CF3F86EB45F6E426B1B008864323B92" group="org.antlr"/>
|
||||
<trusted-key id="DB45ECD19B97514F727105AE67BF80B10AD53983" group="org.apache.santuario" name="xmlsec" version="2.3.4"/>
|
||||
<trusted-key id="DBD744ACE7ADE6AA50DD591F66B50994442D2D40" group="^com[.]squareup($|([.].*))" regex="true"/>
|
||||
<trusted-key id="DBFBFF8DA2F1571ACC6F63AB905CF8FC70CC1444" group="org.aspectj" name="aspectjweaver" version="1.9.22.1"/>
|
||||
<trusted-key id="DCAA15007BED9DE690CD9523378B845402277962">
|
||||
<trusting group="org.opensaml"/>
|
||||
<trusting group="^net[.]shibboleth($|([.].*))" regex="true"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="E01AAB301618D23B39DBD41002DE09238A0E4D34" group="com.drewnoakes" name="metadata-extractor" version="2.19.0"/>
|
||||
<trusted-key id="E113159331A1F87BFC2A93D0960D2E8635A91268" group="org.hdrhistogram" name="HdrHistogram" version="2.2.2"/>
|
||||
<trusted-key id="E2ACB037933CDEAAB7BF77D49A2C7A98E457C53D">
|
||||
<trusting group="io.projectreactor"/>
|
||||
<trusting group="^org[.]springframework($|([.].*))" regex="true"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="E3A9F95079E84CE201F7CF60BEDE11EAF1164480" group="org.hamcrest" name="hamcrest"/>
|
||||
<trusted-key id="E7DC75FC24FB3C8DFE8086AD3D5839A2262CBBFB" group="org.jetbrains.kotlinx"/>
|
||||
<trusted-key id="E85AED155021AF8A6C6B7A4A7C7D8456294423BA" group="org.objenesis"/>
|
||||
<trusted-key id="EE0CA873074092F806F59B65D364ABAA39A47320">
|
||||
<trusting group="com.google.errorprone"/>
|
||||
<trusting group="com.google.googlejavaformat"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="EED29BAB8D4FD882D62308CD72D1B04BC7E6AA04" group="me.friwi"/>
|
||||
<trusted-key id="EF5214AD654CD05F0DA91609ECEAC3B11AD0E0A0" group="com.adobe.xmp" name="xmpcore" version="6.1.11"/>
|
||||
<trusted-key id="F046369B06B761AC86D9849F71B329993BFFCFDD" group="com.oracle.database.jdbc" name="ojdbc-bom" version="21.9.0.0"/>
|
||||
<trusted-key id="F0E31196852A34F8855710BD4A6CE7EBC7F4F54B" group="io.prometheus"/>
|
||||
<trusted-key id="F1232CDCD94176E7FBA9CFE289A2C76A5EE16E57" group="technology.tabula" name="tabula" version="1.0.5"/>
|
||||
<trusted-key id="F3184BCD55F4D016E30D4C9BF42E87F9665015C9" group="org.jsoup" name="jsoup" version="1.18.3"/>
|
||||
<trusted-key id="F55EF5BB19F52A250FEDC0DF39450183608E49D4" group="com.googlecode.owasp-java-html-sanitizer"/>
|
||||
<trusted-key id="F5FEBA84EB26C56457B2CF819E31AB27445478DB" group="org.infinispan"/>
|
||||
<trusted-key id="F60649A7F36F9FBEE21D9AA08AC0378EC753063D" group="com.fathzer"/>
|
||||
<trusted-key id="F674EBA7B6EC777BDB58942DE0E92C40A43A012A" group="jakarta.websocket"/>
|
||||
<trusted-key id="FA77DCFEF2EE6EB2DEBEDD2C012579464D01C06A" group="org.apache" name="apache"/>
|
||||
<trusted-key id="FA7929F83AD44C4590F6CC6815C71C0A4E0B8EDD" group="net.java.dev.jna"/>
|
||||
<trusted-key id="FC411CD3CB7DCB0ABC9801058118B3BCDB1A5000" group="jakarta.xml.bind"/>
|
||||
<trusted-key id="FF6E2C001948C5F2F38B0CC385911F425EC61B51">
|
||||
<trusting group="org.apiguardian"/>
|
||||
<trusting group="org.opentest4j"/>
|
||||
<trusting group="^org[.]junit($|([.].*))" regex="true"/>
|
||||
</trusted-key>
|
||||
</trusted-keys>
|
||||
</configuration>
|
||||
<components>
|
||||
<component group="com.diffplug.spotless" name="com.diffplug.spotless.gradle.plugin" version="6.25.0">
|
||||
<artifact name="com.diffplug.spotless.gradle.plugin-6.25.0.pom">
|
||||
<sha256 value="f45c82b12faacd85acd474eba699322fa5dea88408b247d0e4bde9412908223a" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.diffplug.spotless" name="com.diffplug.spotless.gradle.plugin" version="7.0.1">
|
||||
<artifact name="com.diffplug.spotless.gradle.plugin-7.0.1.pom">
|
||||
<sha256 value="d967a0f74c203ddcc5700947aab40f4be2a5a9f7b8d32aab7fc412b2030e7dfc" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.Carleslc.Simple-YAML" name="Simple-Configuration" version="1.8.4">
|
||||
<artifact name="Simple-Configuration-1.8.4.jar">
|
||||
<sha256 value="2b960f4840ac68bb1815d937ca2d58eb9b04c05e6a9b769a4e870c52a4728156" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="Simple-Configuration-1.8.4.pom">
|
||||
<sha256 value="698e378e816a220edfcb754fd4c4f7d9a8fd38716b9081f63f9878d4bbf3cdd5" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.Carleslc.Simple-YAML" name="Simple-YAML-Parent" version="1.8.4">
|
||||
<artifact name="Simple-YAML-Parent-1.8.4.pom">
|
||||
<sha256 value="b9298b875185bd13b4e301187eeb234d3a1a4b1a871dd4a7461f2e7775121357" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.Carleslc.Simple-YAML" name="Simple-Yaml" version="1.8.4">
|
||||
<artifact name="Simple-Yaml-1.8.4.jar">
|
||||
<sha256 value="d558ca57927d4bc393e9522aac0cf60cc632a9f6f60cd6724aa94b7005e1fd18" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="Simple-Yaml-1.8.4.pom">
|
||||
<sha256 value="47f1003cd91eb6c11b2c941bf89e72428aed92e6bfef327b18935dda28eb4072" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.jk1" name="gradle-license-report" version="2.9">
|
||||
<artifact name="gradle-license-report-2.9.jar">
|
||||
<sha256 value="ebfd6da851654c53216eea9eda1485c12e0cd6de5a9919bf5da9735a021f32af" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="gradle-license-report-2.9.module">
|
||||
<sha256 value="4139a508481c369ae0f2627fa8387f1e20e58600f2037cdc1cdaa164e056f235" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.jk1.dependency-license-report" name="com.github.jk1.dependency-license-report.gradle.plugin" version="2.9">
|
||||
<artifact name="com.github.jk1.dependency-license-report.gradle.plugin-2.9.pom">
|
||||
<sha256 value="a79ca4dfe069d737faf075c8f4b6c6471c2e5cea8e1546946ae333d747fddf02" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.psxpaul" name="gradle-execfork-plugin" version="0.2.0">
|
||||
<artifact name="gradle-execfork-plugin-0.2.0.jar">
|
||||
<sha256 value="eb4f73df13ee24fb1952e0a9054c5618ef07f0d62386bfad1a04990df0cb3a65" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="gradle-execfork-plugin-0.2.0.module">
|
||||
<sha256 value="7b239eb029b2e4cab00dddf1df204ef4bbf88e78a43619c26fbb1e49bc53c642" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.google.guava" name="guava-parent" version="33.3.1-jre">
|
||||
<artifact name="guava-parent-33.3.1-jre.pom">
|
||||
<sha256 value="55441db27e8869dfefe053059bdf478bdc7e95585642bf391f0023345fd56287" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.martiansoftware" name="jsap" version="2.1">
|
||||
<artifact name="jsap-2.1.jar">
|
||||
<sha256 value="331746fa62cfbc3368260c5a2e660936ad11be612308c120a044e120361d474e" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="jsap-2.1.pom">
|
||||
<sha256 value="9acf56a8579c05bedd819d99232363e2bf327e8f73c67598dbd9885a845a3c69" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="commons-logging" name="commons-logging" version="1.0.4">
|
||||
<artifact name="commons-logging-1.0.4.pom">
|
||||
<sha256 value="65d310509352b5425118225ee600a01f83ba72142d035014b5d164bc04b2d284" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="edu.sc.seis.launch4j" name="edu.sc.seis.launch4j.gradle.plugin" version="3.0.6">
|
||||
<artifact name="edu.sc.seis.launch4j.gradle.plugin-3.0.6.pom">
|
||||
<sha256 value="62a4f6752190b9ebf30869e092e4154e41a2c5cd96048ae98a01916f2684465a" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="edu.sc.seis.launch4j" name="launch4j" version="3.0.6">
|
||||
<artifact name="launch4j-3.0.6.jar">
|
||||
<sha256 value="6a8f000c6fda2eb17406b516ec0be28cdac900cbba03319e57bd3c2f1b1afa02" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="launch4j-3.0.6.module">
|
||||
<sha256 value="0a38e1daab79a32b56790db458088148c97be021764e2d2dce259b9a87fec048" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.dropwizard.metrics" name="metrics-bom" version="4.2.25">
|
||||
<artifact name="metrics-bom-4.2.25.pom">
|
||||
<sha256 value="825ad37b8380f992b515050bbd95452f85466feae7b856d5c150d4e5f716a8e9" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.dropwizard.metrics" name="metrics-parent" version="4.2.25">
|
||||
<artifact name="metrics-parent-4.2.25.pom">
|
||||
<sha256 value="df7b6371f9b15698e123d9861f2099ca32c9ec966d9f0c60755a2a34ccbfabc2" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.spring.dependency-management" name="io.spring.dependency-management.gradle.plugin" version="1.1.7">
|
||||
<artifact name="io.spring.dependency-management.gradle.plugin-1.1.7.pom">
|
||||
<sha256 value="19bb16ab5d6359bff88ce95c80b01e7e3445157faa1d74ae5cf03a467cea1e04" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.swagger" name="swaggerhub" version="1.3.2">
|
||||
<artifact name="swaggerhub-1.3.2.jar">
|
||||
<sha256 value="703a61e96b23af81b2ceeba4a081bb3212ec00211ae300748b3e7ccb1f33bd32" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="swaggerhub-1.3.2.module">
|
||||
<sha256 value="bd5ccd6e48224cab88bbd79e880ff011ee4fa711490f410f7810b75a2cb9c3c0" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.swagger.swaggerhub" name="io.swagger.swaggerhub.gradle.plugin" version="1.3.2">
|
||||
<artifact name="io.swagger.swaggerhub.gradle.plugin-1.3.2.pom">
|
||||
<sha256 value="69069eee12440c521662057334ac4acaea0ce6534ca4fd8b1bc264de930ad2d0" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="net.java" name="jvnet-parent" version="5">
|
||||
<artifact name="jvnet-parent-5.pom">
|
||||
<sha256 value="1af699f8d9ddab67f9a0d202fbd7915eb0362a5a6dfd5ffc54cafa3465c9cb0a" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="net.shibboleth" name="parent" version="11.3.5">
|
||||
<artifact name="parent-11.3.5.pom">
|
||||
<pgp value="0E0CA56D354132B5E646C25F49A1796B9B494CB8"/>
|
||||
<sha256 value="7a24e2700485eea087370f1dca6fe0291d7893d38c11aabfe977784fd93b808c" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.apache" name="apache" version="27">
|
||||
<artifact name="apache-27.pom">
|
||||
<sha256 value="b2b0fc69e22a650c3892f1c366d77076f29575c6738df4c7a70a44844484cdf9" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.apache" name="apache" version="33">
|
||||
<artifact name="apache-33.pom">
|
||||
<sha256 value="d78bd8524c5f8380a190a6525686629a95dfe512df21111383a6d8c0923a4415" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.apache.commons" name="commons-parent" version="78">
|
||||
<artifact name="commons-parent-78.pom">
|
||||
<sha256 value="022d202e655edd04f2a10ecbe453d92977924d38380a4ca8c359f1817a80320e" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.hibernate.common" name="hibernate-commons-annotations" version="7.0.3.Final">
|
||||
<artifact name="hibernate-commons-annotations-7.0.3.Final.jar">
|
||||
<sha256 value="0db2fd57d5e43688ac6ed5cdf36deaf05d84340dcc24c2dd2a2114de38e5175d" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="hibernate-commons-annotations-7.0.3.Final.module">
|
||||
<sha256 value="b1aa7202fc3f67d22066903d3e1eb7052ee10f47322a1cb925fa2f449f25aee3" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="hibernate-commons-annotations-7.0.3.Final.pom">
|
||||
<sha256 value="66f6e607b30740e391989825a5ae076a6c877a99b78eb054a8146650aaff72eb" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jboss" name="jboss-parent" version="42">
|
||||
<artifact name="jboss-parent-42.pom">
|
||||
<sha256 value="e41276efe3509054cba4197b3d6360c51dd57bc640dde48cf37dafaa45a09c3b" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jboss" name="jboss-parent" version="43">
|
||||
<artifact name="jboss-parent-43.pom">
|
||||
<sha256 value="3c3ade76fb883acdb9a8a03355d1df4066ffb9c8c78f09b219e9c0fc2a3f4317" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jboss.logging" name="jboss-logging" version="3.6.1.Final">
|
||||
<artifact name="jboss-logging-3.6.1.Final.jar">
|
||||
<sha256 value="5e08a4b092dc85b337f0910a740571d8720cfa565fabd880a8caf94a657ca416" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="jboss-logging-3.6.1.Final.pom">
|
||||
<sha256 value="27cd88ab8e5946b8a7aa92644eb3732e35be281439ab07af71f898453ee7540d" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jboss.logging" name="logging-parent" version="1.0.3.Final">
|
||||
<artifact name="logging-parent-1.0.3.Final.pom">
|
||||
<sha256 value="9972c894749cda355766217d43ded7009b1eeb26e0301c30914a2db253dd685b" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit" name="junit-bom" version="5.11.2">
|
||||
<artifact name="junit-bom-5.11.2.pom">
|
||||
<sha256 value="f48e88538aac145eb3ae0345a9ebd055b28f329a35dce8d1e9281325ca9b0ea2" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.opensaml" name="opensaml-bom" version="4.3.0">
|
||||
<artifact name="opensaml-bom-4.3.0.pom">
|
||||
<sha256 value="4dfcc7cd96a2645c6e28df9f166f0e5b2b1a44aa109b3100cdb0ee17e01e02d2" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.opensaml" name="opensaml-parent" version="4.3.0">
|
||||
<artifact name="opensaml-parent-4.3.0.pom">
|
||||
<sha256 value="5e9db2f2dc3938835a76f5334997d79c8781511c8b68c1f6df6b384306900319" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.ow2" name="ow2" version="1.5.1">
|
||||
<artifact name="ow2-1.5.1.pom">
|
||||
<sha256 value="321ddbb7ee6fe4f53dea6b4cd6db74154d6bfa42391c1f763b361b9f485acf05" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.panteleyev" name="jpackage-gradle-plugin" version="1.6.0">
|
||||
<artifact name="jpackage-gradle-plugin-1.6.0.jar">
|
||||
<sha256 value="a8a588ff44a62db1aee62d3da117d2632a7f9a107709ca201da2a59dcb500175" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="jpackage-gradle-plugin-1.6.0.module">
|
||||
<sha256 value="a572bc67a0bcce5eb8c50a0ae2659fba850dae5b0188f53045635c9276545179" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.panteleyev.jpackageplugin" name="org.panteleyev.jpackageplugin.gradle.plugin" version="1.6.0">
|
||||
<artifact name="org.panteleyev.jpackageplugin.gradle.plugin-1.6.0.pom">
|
||||
<sha256 value="82bff05e70c9f7f5c3d4a8c3958b3842dea970ac1378e306051e66cf98a8f340" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.sonatype.oss" name="oss-parent" version="5">
|
||||
<artifact name="oss-parent-5.pom">
|
||||
<pgp value="2BCBDD0F23EA1CAFCC11D4860374CF2E8DD1BDFD"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.sonatype.oss" name="oss-parent" version="7">
|
||||
<artifact name="oss-parent-7.pom">
|
||||
<sha256 value="b51f8867c92b6a722499557fc3a1fdea77bdf9ef574722fe90ce436a29559454" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.springdoc" name="springdoc-openapi-gradle-plugin" version="1.8.0">
|
||||
<artifact name="springdoc-openapi-gradle-plugin-1.8.0.jar">
|
||||
<sha256 value="94075aa01757a0c1d573ade9145c098963f084feefd31dc95d65606c503585f4" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="springdoc-openapi-gradle-plugin-1.8.0.module">
|
||||
<sha256 value="6f2d828807961169293f4f5b897f7c3ee76da06dc6bb9d94acb3d5f2418e998c" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.springdoc.openapi-gradle-plugin" name="org.springdoc.openapi-gradle-plugin.gradle.plugin" version="1.8.0">
|
||||
<artifact name="org.springdoc.openapi-gradle-plugin.gradle.plugin-1.8.0.pom">
|
||||
<sha256 value="2d117343231e29be22e489bc1f4825e1d4bbef545905e793244e95221957154f" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.springframework" name="spring-framework-bom" version="5.3.34">
|
||||
<artifact name="spring-framework-bom-5.3.34.pom">
|
||||
<sha256 value="6d0616e2544d7115dc249817dd758a34dfa677329182b42e17542e133e55732d" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.springframework.boot" name="org.springframework.boot.gradle.plugin" version="3.4.1">
|
||||
<artifact name="org.springframework.boot.gradle.plugin-3.4.1.pom">
|
||||
<sha256 value="f4d1acf98aa55a44b1a23b1c2b5c75aaa84c4408bea955bd81efb38acd68f38d" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="xml-apis" name="xml-apis-ext" version="1.3.04">
|
||||
<artifact name="xml-apis-ext-1.3.04.jar">
|
||||
<sha256 value="d0b4887dc34d57de49074a58affad439a013d0baffa1a8034f8ef2a5ea191646" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="xml-apis-ext-1.3.04.pom">
|
||||
<sha256 value="1b5939a9310a59c0df0c03726721d5fc9521e87d6c203bfa7220bae82a30d9e8" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="xmlpull" name="xmlpull" version="1.1.3.1">
|
||||
<artifact name="xmlpull-1.1.3.1.jar">
|
||||
<sha256 value="34e08ee62116071cbb69c0ed70d15a7a5b208d62798c59f2120bb8929324cb63" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="xmlpull-1.1.3.1.pom">
|
||||
<sha256 value="8f10ffd8df0d3e9819c8cc8402709c6b248bc53a954ef6e45470d9ae3a5735fb" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
</components>
|
||||
</verification-metadata>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 242 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 145 KiB |
@@ -75,7 +75,7 @@ def write_readme(progress_list: list[tuple[str, int]]) -> None:
|
||||
f"",
|
||||
)
|
||||
|
||||
with open("README.md", "w", encoding="utf-8", newline="\n") as file:
|
||||
with open("README.md", "w", encoding="utf-8") as file:
|
||||
file.writelines(content)
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ def compare_files(
|
||||
)
|
||||
)
|
||||
ignore_translation = convert_to_multiline(sort_ignore_translation)
|
||||
with open(ignore_translation_file, "w", encoding="utf-8", newline="\n") as file:
|
||||
with open(ignore_translation_file, "w", encoding="utf-8") as file:
|
||||
file.write(tomlkit.dumps(ignore_translation))
|
||||
|
||||
unique_data = list(set(result_list))
|
||||
|
||||
@@ -24,6 +24,7 @@ ignore = [
|
||||
[cs_CZ]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
'pipeline.header',
|
||||
'text',
|
||||
]
|
||||
|
||||
@@ -210,11 +211,6 @@ ignore = [
|
||||
'watermark.type.1',
|
||||
]
|
||||
|
||||
[sl_SI]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
]
|
||||
|
||||
[sr_LATN_RS]
|
||||
ignore = [
|
||||
'language.direction',
|
||||
|
||||
@@ -4,7 +4,6 @@ import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -75,11 +74,6 @@ public class AppConfig {
|
||||
: "null";
|
||||
}
|
||||
|
||||
@Bean(name = "languages")
|
||||
public List<String> languages() {
|
||||
return applicationProperties.getUi().getLanguages();
|
||||
}
|
||||
|
||||
@Bean(name = "navBarText")
|
||||
public String navBarText() {
|
||||
String defaultNavBar =
|
||||
|
||||
@@ -9,200 +9,135 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.simpleyaml.configuration.comments.CommentType;
|
||||
import org.simpleyaml.configuration.file.YamlFile;
|
||||
import org.simpleyaml.configuration.implementation.SimpleYamlImplementation;
|
||||
import org.simpleyaml.configuration.implementation.snakeyaml.lib.DumperOptions;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* the merged content actually differs.
|
||||
*/
|
||||
@Slf4j
|
||||
public class ConfigInitializer {
|
||||
|
||||
public void ensureConfigExists() throws IOException, URISyntaxException {
|
||||
// 1) If settings file doesn't exist, create from template
|
||||
// Define the path to the external config directory
|
||||
Path destPath = Paths.get(InstallationPathConfig.getSettingsPath());
|
||||
|
||||
// Check if the file already exists
|
||||
if (Files.notExists(destPath)) {
|
||||
// Ensure the destination directory exists
|
||||
Files.createDirectories(destPath.getParent());
|
||||
|
||||
// Copy the resource from classpath to the external directory
|
||||
try (InputStream in =
|
||||
getClass().getClassLoader().getResourceAsStream("settings.yml.template")) {
|
||||
if (in == null) {
|
||||
if (in != null) {
|
||||
Files.copy(in, destPath);
|
||||
} else {
|
||||
throw new FileNotFoundException(
|
||||
"Resource file not found: settings.yml.template");
|
||||
}
|
||||
Files.copy(in, destPath);
|
||||
}
|
||||
log.info("Created settings file from template");
|
||||
} else {
|
||||
// 2) Merge existing file with the template
|
||||
|
||||
// Define the path to the config settings file
|
||||
Path settingsPath = Paths.get(InstallationPathConfig.getSettingsPath());
|
||||
URL templateResource = getClass().getClassLoader().getResource("settings.yml.template");
|
||||
if (templateResource == null) {
|
||||
// Load the template resource
|
||||
URL settingsTemplateResource =
|
||||
getClass().getClassLoader().getResource("settings.yml.template");
|
||||
if (settingsTemplateResource == null) {
|
||||
throw new IOException("Resource not found: settings.yml.template");
|
||||
}
|
||||
|
||||
// Copy template to a temp location so we can read lines
|
||||
// Create a temporary file to copy the resource content
|
||||
Path tempTemplatePath = Files.createTempFile("settings.yml", ".template");
|
||||
try (InputStream in = templateResource.openStream()) {
|
||||
|
||||
try (InputStream in = settingsTemplateResource.openStream()) {
|
||||
Files.copy(in, tempTemplatePath, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
// 2a) Read lines from both files
|
||||
List<String> templateLines = Files.readAllLines(tempTemplatePath);
|
||||
List<String> mainLines = Files.readAllLines(settingsPath);
|
||||
final YamlFile settingsTemplateFile = new YamlFile(tempTemplatePath.toFile());
|
||||
DumperOptions yamlOptionsSettingsTemplateFile =
|
||||
((SimpleYamlImplementation) settingsTemplateFile.getImplementation())
|
||||
.getDumperOptions();
|
||||
yamlOptionsSettingsTemplateFile.setSplitLines(false);
|
||||
settingsTemplateFile.loadWithComments();
|
||||
|
||||
// 2b) Merge lines
|
||||
List<String> mergedLines = mergeYamlLinesWithTemplate(templateLines, mainLines);
|
||||
final YamlFile settingsFile = new YamlFile(settingsPath.toFile());
|
||||
DumperOptions yamlOptionsSettingsFile =
|
||||
((SimpleYamlImplementation) settingsFile.getImplementation())
|
||||
.getDumperOptions();
|
||||
yamlOptionsSettingsFile.setSplitLines(false);
|
||||
settingsFile.loadWithComments();
|
||||
|
||||
// 2c) Only write if there's an actual difference
|
||||
if (!mergedLines.equals(mainLines)) {
|
||||
Files.write(settingsPath, mergedLines);
|
||||
log.info("Settings file updated based on template changes.");
|
||||
} else {
|
||||
log.info("No changes detected; settings file left as-is.");
|
||||
// Load headers and comments
|
||||
String header = settingsTemplateFile.getHeader();
|
||||
|
||||
// Create a new file for temporary settings
|
||||
final YamlFile tempSettingFile = new YamlFile(settingsPath.toFile());
|
||||
DumperOptions yamlOptionsTempSettingFile =
|
||||
((SimpleYamlImplementation) tempSettingFile.getImplementation())
|
||||
.getDumperOptions();
|
||||
yamlOptionsTempSettingFile.setSplitLines(false);
|
||||
tempSettingFile.createNewFile(true);
|
||||
tempSettingFile.setHeader(header);
|
||||
|
||||
// Get all keys from the template
|
||||
List<String> keys =
|
||||
Arrays.asList(settingsTemplateFile.getKeys(true).toArray(new String[0]));
|
||||
|
||||
for (String key : keys) {
|
||||
if (!key.contains(".")) {
|
||||
// Add blank lines and comments to specific sections
|
||||
tempSettingFile
|
||||
.path(key)
|
||||
.comment(settingsTemplateFile.getComment(key))
|
||||
.blankLine();
|
||||
continue;
|
||||
}
|
||||
// Copy settings from the template to the settings.yml file
|
||||
changeConfigItemFromCommentToKeyValue(
|
||||
settingsTemplateFile, settingsFile, tempSettingFile, key);
|
||||
}
|
||||
|
||||
Files.deleteIfExists(tempTemplatePath);
|
||||
// Save the settings.yml file
|
||||
tempSettingFile.save();
|
||||
}
|
||||
|
||||
// 3) Ensure custom settings file exists
|
||||
// Create custom settings file if it doesn't exist
|
||||
Path customSettingsPath = Paths.get(InstallationPathConfig.getCustomSettingsPath());
|
||||
if (!Files.exists(customSettingsPath)) {
|
||||
Files.createFile(customSettingsPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge logic that: - Reads the template lines block-by-block (where a "block" = a key and all
|
||||
* the lines that belong to it), - If the main file has that key, we keep the main file's block
|
||||
* (preserving whitespace + inline comments). - Otherwise, we insert the template's block. - We
|
||||
* also remove keys from main that no longer exist in the template.
|
||||
*
|
||||
* @param templateLines lines from settings.yml.template
|
||||
* @param mainLines lines from the existing settings.yml
|
||||
* @return merged lines
|
||||
*/
|
||||
private List<String> mergeYamlLinesWithTemplate(
|
||||
List<String> templateLines, List<String> mainLines) {
|
||||
|
||||
// 1) Parse template lines into an ordered map: path -> Block
|
||||
LinkedHashMap<String, Block> templateBlocks = parseYamlBlocks(templateLines);
|
||||
|
||||
// 2) Parse main lines into a map: path -> Block
|
||||
LinkedHashMap<String, Block> mainBlocks = parseYamlBlocks(mainLines);
|
||||
|
||||
// 3) Build the final list by iterating template blocks in order
|
||||
List<String> merged = new ArrayList<>();
|
||||
for (Map.Entry<String, Block> entry : templateBlocks.entrySet()) {
|
||||
String path = entry.getKey();
|
||||
Block templateBlock = entry.getValue();
|
||||
|
||||
if (mainBlocks.containsKey(path)) {
|
||||
// If main has the same block, prefer main's lines
|
||||
merged.addAll(mainBlocks.get(path).lines);
|
||||
} else {
|
||||
// Otherwise, add the template block
|
||||
merged.addAll(templateBlock.lines);
|
||||
}
|
||||
private void changeConfigItemFromCommentToKeyValue(
|
||||
final YamlFile settingsTemplateFile,
|
||||
final YamlFile settingsFile,
|
||||
final YamlFile tempSettingFile,
|
||||
String path) {
|
||||
if (settingsFile.get(path) == null && settingsTemplateFile.get(path) != null) {
|
||||
// If the key is only in the template, add it to the temporary settings with comments
|
||||
tempSettingFile
|
||||
.path(path)
|
||||
.set(settingsTemplateFile.get(path))
|
||||
.comment(settingsTemplateFile.getComment(path, CommentType.BLOCK))
|
||||
.commentSide(settingsTemplateFile.getComment(path, CommentType.SIDE));
|
||||
} else if (settingsFile.get(path) != null && settingsTemplateFile.get(path) != null) {
|
||||
// If the key is in both, update the temporary settings with the main settings' value
|
||||
// and comments
|
||||
tempSettingFile
|
||||
.path(path)
|
||||
.set(settingsFile.get(path))
|
||||
.comment(settingsTemplateFile.getComment(path, CommentType.BLOCK))
|
||||
.commentSide(settingsTemplateFile.getComment(path, CommentType.SIDE));
|
||||
} else {
|
||||
// Log if the key is not found in both YAML files
|
||||
log.info("Key not found in both YAML files: " + path);
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a list of lines into a map of "path -> Block" where "Block" is all lines that belong to
|
||||
* that key (including subsequent indented lines). Very naive approach that may not work with
|
||||
* advanced YAML.
|
||||
*/
|
||||
private LinkedHashMap<String, Block> parseYamlBlocks(List<String> lines) {
|
||||
LinkedHashMap<String, Block> blocks = new LinkedHashMap<>();
|
||||
|
||||
Block currentBlock = null;
|
||||
String currentPath = null;
|
||||
|
||||
for (String line : lines) {
|
||||
if (isLikelyKeyLine(line)) {
|
||||
// Found a new "key: ..." line
|
||||
if (currentBlock != null && currentPath != null) {
|
||||
blocks.put(currentPath, currentBlock);
|
||||
}
|
||||
currentBlock = new Block();
|
||||
currentBlock.lines.add(line);
|
||||
currentPath = computePathForLine(line);
|
||||
} else {
|
||||
// Continuation of current block (comments, blank lines, sub-lines)
|
||||
if (currentBlock == null) {
|
||||
// If file starts with comments/blank lines, treat as "header block" with path
|
||||
// ""
|
||||
currentBlock = new Block();
|
||||
currentPath = "";
|
||||
}
|
||||
currentBlock.lines.add(line);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentBlock != null && currentPath != null) {
|
||||
blocks.put(currentPath, currentBlock);
|
||||
}
|
||||
|
||||
return blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the line is likely "key:" or "key: value", ignoring comments/blank. Skips lines
|
||||
* starting with "-" or "#".
|
||||
*/
|
||||
private boolean isLikelyKeyLine(String line) {
|
||||
String trimmed = line.trim();
|
||||
if (trimmed.isEmpty() || trimmed.startsWith("#") || trimmed.startsWith("-")) {
|
||||
return false;
|
||||
}
|
||||
int colonIdx = trimmed.indexOf(':');
|
||||
return (colonIdx > 0); // someKey:
|
||||
}
|
||||
|
||||
// For a line like "security: ", returns "security" or "security.enableLogin"
|
||||
// by looking at indentation. Very naive.
|
||||
private static final Deque<String> pathStack = new ArrayDeque<>();
|
||||
private static int currentIndentLevel = 0;
|
||||
|
||||
private String computePathForLine(String line) {
|
||||
// count leading spaces
|
||||
int leadingSpaces = 0;
|
||||
for (char c : line.toCharArray()) {
|
||||
if (c == ' ') leadingSpaces++;
|
||||
else break;
|
||||
}
|
||||
// assume 2 spaces = 1 indent
|
||||
int indentLevel = leadingSpaces / 2;
|
||||
|
||||
String trimmed = line.trim();
|
||||
int colonIdx = trimmed.indexOf(':');
|
||||
String keyName = trimmed.substring(0, colonIdx).trim();
|
||||
|
||||
// pop stack until we match the new indent level
|
||||
while (currentIndentLevel >= indentLevel && !pathStack.isEmpty()) {
|
||||
pathStack.pop();
|
||||
currentIndentLevel--;
|
||||
}
|
||||
|
||||
// push the new key
|
||||
pathStack.push(keyName);
|
||||
currentIndentLevel = indentLevel;
|
||||
|
||||
// build path by reversing the stack
|
||||
String[] arr = pathStack.toArray(new String[0]);
|
||||
List<String> reversed = Arrays.asList(arr);
|
||||
Collections.reverse(reversed);
|
||||
return String.join(".", reversed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple holder for the lines that comprise a "block" (i.e. a key and its subsequent lines).
|
||||
*/
|
||||
private static class Block {
|
||||
List<String> lines = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,6 @@ public class EndpointConfiguration {
|
||||
addEndpointToGroup("Convert", "url-to-pdf");
|
||||
addEndpointToGroup("Convert", "markdown-to-pdf");
|
||||
addEndpointToGroup("Convert", "pdf-to-csv");
|
||||
addEndpointToGroup("Convert", "pdf-to-markdown");
|
||||
|
||||
// Adding endpoints to "Security" group
|
||||
addEndpointToGroup("Security", "add-password");
|
||||
@@ -244,7 +243,6 @@ public class EndpointConfiguration {
|
||||
addEndpointToGroup("Java", REMOVE_BLANKS);
|
||||
addEndpointToGroup("Java", "pdf-to-text");
|
||||
addEndpointToGroup("Java", "remove-image-pdf");
|
||||
addEndpointToGroup("Java", "pdf-to-markdown");
|
||||
|
||||
// Javascript
|
||||
addEndpointToGroup("Javascript", "pdf-organizer");
|
||||
@@ -260,11 +258,12 @@ public class EndpointConfiguration {
|
||||
// Weasyprint dependent endpoints
|
||||
addEndpointToGroup("Weasyprint", "html-to-pdf");
|
||||
addEndpointToGroup("Weasyprint", "url-to-pdf");
|
||||
addEndpointToGroup("Weasyprint", "markdown-to-pdf");
|
||||
|
||||
// Pdftohtml dependent endpoints
|
||||
addEndpointToGroup("Pdftohtml", "pdf-to-html");
|
||||
addEndpointToGroup("Pdftohtml", "pdf-to-markdown");
|
||||
|
||||
// disabled for now while we resolve issues
|
||||
disableEndpoint("pdf-to-pdfa");
|
||||
}
|
||||
|
||||
private void processEnvironmentConfigs() {
|
||||
|
||||
@@ -7,10 +7,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
import com.posthog.java.PostHog;
|
||||
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class PostHogConfig {
|
||||
|
||||
@Value("${posthog.api.key}")
|
||||
@@ -23,11 +21,7 @@ public class PostHogConfig {
|
||||
|
||||
@Bean
|
||||
public PostHog postHogClient() {
|
||||
postHogClient =
|
||||
new PostHog.Builder(posthogApiKey)
|
||||
.host(posthogHost)
|
||||
.logger(new PostHogLoggerImpl())
|
||||
.build();
|
||||
postHogClient = new PostHog.Builder(posthogApiKey).host(posthogHost).build();
|
||||
return postHogClient;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
package stirling.software.SPDF.config;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.posthog.java.PostHogLogger;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class PostHogLoggerImpl implements PostHogLogger {
|
||||
|
||||
@Override
|
||||
public void debug(String message) {
|
||||
log.debug(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String message) {
|
||||
log.info(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String message) {
|
||||
log.warn(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String message) {
|
||||
log.error(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String message, Throwable throwable) {
|
||||
if (message.contains("Error sending events to PostHog")) {
|
||||
log.warn(
|
||||
"Error sending metrics, Likely caused by no internet connection. Non Blocking");
|
||||
} else {
|
||||
log.error(message, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,7 @@ package stirling.software.SPDF.controller.api;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -28,14 +26,11 @@ public class AdditionalLanguageJsController {
|
||||
@Hidden
|
||||
@GetMapping(value = "/additionalLanguageCode.js", produces = "application/javascript")
|
||||
public void generateAdditionalLanguageJs(HttpServletResponse response) throws IOException {
|
||||
Set<String> supportedLanguages = languageService.getSupportedLanguages();
|
||||
List<String> supportedLanguages = languageService.getSupportedLanguages();
|
||||
response.setContentType("application/javascript");
|
||||
PrintWriter writer = response.getWriter();
|
||||
// Erstelle das JavaScript dynamisch
|
||||
writer.println(
|
||||
"const supportedLanguages = "
|
||||
+ toJsonArray(new ArrayList<>(supportedLanguages))
|
||||
+ ";");
|
||||
writer.println("const supportedLanguages = " + toJsonArray(supportedLanguages) + ";");
|
||||
// Generiere die `getDetailedLanguageCode`-Funktion
|
||||
writer.println(
|
||||
"""
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
package stirling.software.SPDF.controller.api;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.pdfbox.Loader;
|
||||
import org.apache.pdfbox.cos.COSName;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageTree;
|
||||
import org.apache.pdfbox.pdmodel.encryption.PDEncryption;
|
||||
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
|
||||
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import stirling.software.SPDF.model.api.PDFFile;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/analysis")
|
||||
@Tag(name = "Analysis", description = "Analysis APIs")
|
||||
public class AnalysisController {
|
||||
|
||||
@PostMapping(value = "/page-count", consumes = "multipart/form-data")
|
||||
@Operation(
|
||||
summary = "Get PDF page count",
|
||||
description = "Returns total number of pages in PDF. Input:PDF Output:JSON Type:SISO")
|
||||
public Map<String, Integer> getPageCount(@ModelAttribute PDFFile file) throws IOException {
|
||||
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
|
||||
return Map.of("pageCount", document.getNumberOfPages());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/basic-info", consumes = "multipart/form-data")
|
||||
@Operation(
|
||||
summary = "Get basic PDF information",
|
||||
description = "Returns page count, version, file size. Input:PDF Output:JSON Type:SISO")
|
||||
public Map<String, Object> getBasicInfo(@ModelAttribute PDFFile file) throws IOException {
|
||||
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
|
||||
Map<String, Object> info = new HashMap<>();
|
||||
info.put("pageCount", document.getNumberOfPages());
|
||||
info.put("pdfVersion", document.getVersion());
|
||||
info.put("fileSize", file.getFileInput().getSize());
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/document-properties", consumes = "multipart/form-data")
|
||||
@Operation(
|
||||
summary = "Get PDF document properties",
|
||||
description = "Returns title, author, subject, etc. Input:PDF Output:JSON Type:SISO")
|
||||
public Map<String, String> getDocumentProperties(@ModelAttribute PDFFile file)
|
||||
throws IOException {
|
||||
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
|
||||
PDDocumentInformation info = document.getDocumentInformation();
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("title", info.getTitle());
|
||||
properties.put("author", info.getAuthor());
|
||||
properties.put("subject", info.getSubject());
|
||||
properties.put("keywords", info.getKeywords());
|
||||
properties.put("creator", info.getCreator());
|
||||
properties.put("producer", info.getProducer());
|
||||
properties.put("creationDate", info.getCreationDate().toString());
|
||||
properties.put("modificationDate", info.getModificationDate().toString());
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/page-dimensions", consumes = "multipart/form-data")
|
||||
@Operation(
|
||||
summary = "Get page dimensions for all pages",
|
||||
description = "Returns width and height of each page. Input:PDF Output:JSON Type:SISO")
|
||||
public List<Map<String, Float>> getPageDimensions(@ModelAttribute PDFFile file)
|
||||
throws IOException {
|
||||
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
|
||||
List<Map<String, Float>> dimensions = new ArrayList<>();
|
||||
PDPageTree pages = document.getPages();
|
||||
|
||||
for (PDPage page : pages) {
|
||||
Map<String, Float> pageDim = new HashMap<>();
|
||||
pageDim.put("width", page.getBBox().getWidth());
|
||||
pageDim.put("height", page.getBBox().getHeight());
|
||||
dimensions.add(pageDim);
|
||||
}
|
||||
return dimensions;
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/form-fields", consumes = "multipart/form-data")
|
||||
@Operation(
|
||||
summary = "Get form field information",
|
||||
description =
|
||||
"Returns count and details of form fields. Input:PDF Output:JSON Type:SISO")
|
||||
public Map<String, Object> getFormFields(@ModelAttribute PDFFile file) throws IOException {
|
||||
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
|
||||
Map<String, Object> formInfo = new HashMap<>();
|
||||
PDAcroForm form = document.getDocumentCatalog().getAcroForm();
|
||||
|
||||
if (form != null) {
|
||||
formInfo.put("fieldCount", form.getFields().size());
|
||||
formInfo.put("hasXFA", form.hasXFA());
|
||||
formInfo.put("isSignaturesExist", form.isSignaturesExist());
|
||||
} else {
|
||||
formInfo.put("fieldCount", 0);
|
||||
formInfo.put("hasXFA", false);
|
||||
formInfo.put("isSignaturesExist", false);
|
||||
}
|
||||
return formInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/annotation-info", consumes = "multipart/form-data")
|
||||
@Operation(
|
||||
summary = "Get annotation information",
|
||||
description = "Returns count and types of annotations. Input:PDF Output:JSON Type:SISO")
|
||||
public Map<String, Object> getAnnotationInfo(@ModelAttribute PDFFile file) throws IOException {
|
||||
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
|
||||
Map<String, Object> annotInfo = new HashMap<>();
|
||||
int totalAnnotations = 0;
|
||||
Map<String, Integer> annotationTypes = new HashMap<>();
|
||||
|
||||
for (PDPage page : document.getPages()) {
|
||||
for (PDAnnotation annot : page.getAnnotations()) {
|
||||
totalAnnotations++;
|
||||
String subType = annot.getSubtype();
|
||||
annotationTypes.merge(subType, 1, Integer::sum);
|
||||
}
|
||||
}
|
||||
|
||||
annotInfo.put("totalCount", totalAnnotations);
|
||||
annotInfo.put("typeBreakdown", annotationTypes);
|
||||
return annotInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/font-info", consumes = "multipart/form-data")
|
||||
@Operation(
|
||||
summary = "Get font information",
|
||||
description =
|
||||
"Returns list of fonts used in the document. Input:PDF Output:JSON Type:SISO")
|
||||
public Map<String, Object> getFontInfo(@ModelAttribute PDFFile file) throws IOException {
|
||||
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
|
||||
Map<String, Object> fontInfo = new HashMap<>();
|
||||
Set<String> fontNames = new HashSet<>();
|
||||
|
||||
for (PDPage page : document.getPages()) {
|
||||
for (COSName font : page.getResources().getFontNames()) {
|
||||
fontNames.add(font.getName());
|
||||
}
|
||||
}
|
||||
|
||||
fontInfo.put("fontCount", fontNames.size());
|
||||
fontInfo.put("fonts", fontNames);
|
||||
return fontInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/security-info", consumes = "multipart/form-data")
|
||||
@Operation(
|
||||
summary = "Get security information",
|
||||
description =
|
||||
"Returns encryption and permission details. Input:PDF Output:JSON Type:SISO")
|
||||
public Map<String, Object> getSecurityInfo(@ModelAttribute PDFFile file) throws IOException {
|
||||
try (PDDocument document = Loader.loadPDF(file.getFileInput().getBytes())) {
|
||||
Map<String, Object> securityInfo = new HashMap<>();
|
||||
PDEncryption encryption = document.getEncryption();
|
||||
|
||||
if (encryption != null) {
|
||||
securityInfo.put("isEncrypted", true);
|
||||
securityInfo.put("keyLength", encryption.getLength());
|
||||
|
||||
// Get permissions
|
||||
Map<String, Boolean> permissions = new HashMap<>();
|
||||
permissions.put("canPrint", document.getCurrentAccessPermission().canPrint());
|
||||
permissions.put("canModify", document.getCurrentAccessPermission().canModify());
|
||||
permissions.put(
|
||||
"canExtractContent",
|
||||
document.getCurrentAccessPermission().canExtractContent());
|
||||
permissions.put(
|
||||
"canModifyAnnotations",
|
||||
document.getCurrentAccessPermission().canModifyAnnotations());
|
||||
|
||||
securityInfo.put("permissions", permissions);
|
||||
} else {
|
||||
securityInfo.put("isEncrypted", false);
|
||||
}
|
||||
|
||||
return securityInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,8 +100,6 @@ public class SplitPdfBySectionsController {
|
||||
|
||||
if (sectionNum == horiz * verti) pageNum++;
|
||||
}
|
||||
|
||||
zipOut.finish();
|
||||
data = Files.readAllBytes(zipFile);
|
||||
return WebResponseUtils.bytesToWebResponse(
|
||||
data, filename + "_split.zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||
|
||||
@@ -13,7 +13,6 @@ import io.github.pixee.security.Filenames;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest;
|
||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
||||
import stirling.software.SPDF.utils.FileToPdf;
|
||||
@@ -28,23 +27,19 @@ public class ConvertHtmlToPDF {
|
||||
|
||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
||||
|
||||
private final ApplicationProperties applicationProperties;
|
||||
|
||||
@Autowired
|
||||
public ConvertHtmlToPDF(
|
||||
CustomPDDocumentFactory pdfDocumentFactory,
|
||||
@Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled,
|
||||
ApplicationProperties applicationProperties) {
|
||||
@Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled) {
|
||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||
this.bookAndHtmlFormatsInstalled = bookAndHtmlFormatsInstalled;
|
||||
this.applicationProperties = applicationProperties;
|
||||
}
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/html/pdf")
|
||||
@Operation(
|
||||
summary = "Convert an HTML or ZIP (containing HTML and CSS) to PDF",
|
||||
description =
|
||||
"This endpoint takes an HTML or ZIP file input and converts it to a PDF format. Input:HTML Output:PDF Type:SISO")
|
||||
"This endpoint takes an HTML or ZIP file input and converts it to a PDF format.")
|
||||
public ResponseEntity<byte[]> HtmlToPdf(@ModelAttribute HTMLToPdfRequest request)
|
||||
throws Exception {
|
||||
MultipartFile fileInput = request.getFileInput();
|
||||
@@ -59,17 +54,12 @@ public class ConvertHtmlToPDF {
|
||||
|| (!originalFilename.endsWith(".html") && !originalFilename.endsWith(".zip"))) {
|
||||
throw new IllegalArgumentException("File must be either .html or .zip format.");
|
||||
}
|
||||
|
||||
boolean disableSanitize =
|
||||
Boolean.TRUE.equals(applicationProperties.getSystem().getDisableSanitize());
|
||||
|
||||
byte[] pdfBytes =
|
||||
FileToPdf.convertHtmlToPdf(
|
||||
request,
|
||||
fileInput.getBytes(),
|
||||
originalFilename,
|
||||
bookAndHtmlFormatsInstalled,
|
||||
disableSanitize);
|
||||
bookAndHtmlFormatsInstalled);
|
||||
|
||||
pdfBytes = pdfDocumentFactory.createNewBytesBasedOnOldDocument(pdfBytes);
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import io.github.pixee.security.Filenames;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.model.api.GeneralFile;
|
||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
||||
import stirling.software.SPDF.utils.FileToPdf;
|
||||
@@ -38,16 +37,12 @@ public class ConvertMarkdownToPdf {
|
||||
|
||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
||||
|
||||
private final ApplicationProperties applicationProperties;
|
||||
|
||||
@Autowired
|
||||
public ConvertMarkdownToPdf(
|
||||
CustomPDDocumentFactory pdfDocumentFactory,
|
||||
@Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled,
|
||||
ApplicationProperties applicationProperties) {
|
||||
@Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled) {
|
||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||
this.bookAndHtmlFormatsInstalled = bookAndHtmlFormatsInstalled;
|
||||
this.applicationProperties = applicationProperties;
|
||||
}
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/markdown/pdf")
|
||||
@@ -81,16 +76,12 @@ public class ConvertMarkdownToPdf {
|
||||
|
||||
String htmlContent = renderer.render(document);
|
||||
|
||||
boolean disableSanitize =
|
||||
Boolean.TRUE.equals(applicationProperties.getSystem().getDisableSanitize());
|
||||
|
||||
byte[] pdfBytes =
|
||||
FileToPdf.convertHtmlToPdf(
|
||||
null,
|
||||
htmlContent.getBytes(),
|
||||
"converted.html",
|
||||
bookAndHtmlFormatsInstalled,
|
||||
disableSanitize);
|
||||
bookAndHtmlFormatsInstalled);
|
||||
pdfBytes = pdfDocumentFactory.createNewBytesBasedOnOldDocument(pdfBytes);
|
||||
String outputFilename =
|
||||
originalFilename.replaceFirst("[.][^.]+$", "")
|
||||
|
||||
@@ -73,8 +73,8 @@ public class ConvertPDFToPDFA {
|
||||
// Determine PDF/A filter based on requested format
|
||||
String pdfFilter =
|
||||
"pdfa".equals(outputFormat)
|
||||
? "pdf:writer_pdf_Export:{\"SelectPdfVersion\":{\"type\":\"long\",\"value\":\"2\"}}"
|
||||
: "pdf:writer_pdf_Export:{\"SelectPdfVersion\":{\"type\":\"long\",\"value\":\"1\"}}";
|
||||
? "writer_pdf_Export:{'SelectPdfVersion':{'Value':'2'}}:writer_pdf_Export"
|
||||
: "writer_pdf_Export:{'SelectPdfVersion':{'Value':'1'}}:writer_pdf_Export";
|
||||
|
||||
// Prepare LibreOffice command
|
||||
List<String> command =
|
||||
@@ -84,7 +84,7 @@ public class ConvertPDFToPDFA {
|
||||
"--headless",
|
||||
"--nologo",
|
||||
"--convert-to",
|
||||
pdfFilter,
|
||||
"pdf:" + pdfFilter,
|
||||
"--outdir",
|
||||
tempOutputDir.toString(),
|
||||
tempInputFile.toString()));
|
||||
|
||||
@@ -8,9 +8,7 @@ import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
@@ -43,12 +41,8 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||
public class AutoSplitPdfController {
|
||||
|
||||
private static final Set<String> VALID_QR_CONTENTS =
|
||||
new HashSet<>(
|
||||
Set.of(
|
||||
"https://github.com/Stirling-Tools/Stirling-PDF",
|
||||
"https://github.com/Frooodle/Stirling-PDF",
|
||||
"https://stirlingpdf.com"));
|
||||
private static final String QR_CONTENT = "https://github.com/Stirling-Tools/Stirling-PDF";
|
||||
private static final String QR_CONTENT_OLD = "https://github.com/Frooodle/Stirling-PDF";
|
||||
|
||||
private final CustomPDDocumentFactory pdfDocumentFactory;
|
||||
|
||||
@@ -126,14 +120,13 @@ public class AutoSplitPdfController {
|
||||
for (int page = 0; page < document.getNumberOfPages(); ++page) {
|
||||
BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 150);
|
||||
String result = decodeQRCode(bim);
|
||||
|
||||
boolean isValidQrCode = VALID_QR_CONTENTS.contains(result);
|
||||
log.debug("detected qr code {}, code is vale={}", result, isValidQrCode);
|
||||
if (isValidQrCode && page != 0) {
|
||||
if ((QR_CONTENT.equals(result) || QR_CONTENT_OLD.equals(result)) && page != 0) {
|
||||
splitDocuments.add(new PDDocument());
|
||||
}
|
||||
|
||||
if (!splitDocuments.isEmpty() && !isValidQrCode) {
|
||||
if (!splitDocuments.isEmpty()
|
||||
&& !QR_CONTENT.equals(result)
|
||||
&& !QR_CONTENT_OLD.equals(result)) {
|
||||
splitDocuments.get(splitDocuments.size() - 1).addPage(document.getPage(page));
|
||||
} else if (page == 0) {
|
||||
PDDocument firstDocument = new PDDocument();
|
||||
@@ -142,7 +135,7 @@ public class AutoSplitPdfController {
|
||||
}
|
||||
|
||||
// If duplexMode is true and current page is a divider, then skip next page
|
||||
if (duplexMode && isValidQrCode) {
|
||||
if (duplexMode && (QR_CONTENT.equals(result) || QR_CONTENT_OLD.equals(result))) {
|
||||
page++;
|
||||
}
|
||||
}
|
||||
@@ -175,9 +168,6 @@ public class AutoSplitPdfController {
|
||||
|
||||
return WebResponseUtils.bytesToWebResponse(
|
||||
data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||
} catch (Exception e) {
|
||||
log.error("Error in auto split", e);
|
||||
throw e;
|
||||
} finally {
|
||||
// Clean up resources
|
||||
if (document != null) {
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -95,9 +94,7 @@ public class CompressController {
|
||||
}
|
||||
}
|
||||
}
|
||||
Path tempOutput = Files.createTempFile("output_", ".pdf");
|
||||
doc.save(tempOutput.toString());
|
||||
Files.move(tempOutput, pdfFile, StandardCopyOption.REPLACE_EXISTING);
|
||||
doc.save(pdfFile.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +188,7 @@ public class CompressController {
|
||||
optimizeLevel =
|
||||
incrementOptimizeLevel(
|
||||
optimizeLevel, outputFileSize, expectedOutputSize);
|
||||
if (autoMode && optimizeLevel >= 9) {
|
||||
if (autoMode && optimizeLevel > 9) {
|
||||
log.info("Maximum compression level reached in auto mode");
|
||||
sizeMet = true;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class ExtractImagesController {
|
||||
@Operation(
|
||||
summary = "Extract images from a PDF file",
|
||||
description =
|
||||
"This endpoint extracts images from a given PDF file and returns them in a zip file. Users can specify the output image format. Input:PDF Output:IMAGE/ZIP Type:SIMO")
|
||||
"This endpoint extracts images from a given PDF file and returns them in a zip file. Users can specify the output image format. Input: PDF Output: IMAGE/ZIP Type: SIMO")
|
||||
public ResponseEntity<byte[]> extractImages(@ModelAttribute PDFExtractImagesRequest request)
|
||||
throws IOException, InterruptedException, ExecutionException {
|
||||
MultipartFile file = request.getFileInput();
|
||||
|
||||
@@ -46,7 +46,7 @@ public class FlattenController {
|
||||
@Operation(
|
||||
summary = "Flatten PDF form fields or full page",
|
||||
description =
|
||||
"Flattening just PDF form fields or converting each page to images to make text unselectable. Input:PDF, Output:PDF. Type:SISO")
|
||||
"Flattening just PDF form fields or converting each page to images to make text unselectable. Input: PDF, Output: PDF. Type: SISO")
|
||||
public ResponseEntity<byte[]> flatten(@ModelAttribute FlattenRequest request) throws Exception {
|
||||
MultipartFile file = request.getFileInput();
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import io.github.pixee.security.BoundedLineReader;
|
||||
import io.github.pixee.security.Filenames;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -66,10 +65,6 @@ public class OCRController {
|
||||
}
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/ocr-pdf")
|
||||
@Operation(
|
||||
summary = "Process PDF files with OCR using Tesseract",
|
||||
description =
|
||||
"Takes a PDF file as input, performs OCR using specified languages and OCR type (skip-text/force-ocr), and returns the processed PDF. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> processPdfWithOCR(
|
||||
@ModelAttribute ProcessPdfWithOcrRequest request)
|
||||
throws IOException, InterruptedException {
|
||||
|
||||
@@ -25,7 +25,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.model.PipelineConfig;
|
||||
import stirling.software.SPDF.model.PipelineResult;
|
||||
import stirling.software.SPDF.model.api.HandleDataRequest;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
@@ -59,8 +58,7 @@ public class PipelineController {
|
||||
if (inputFiles == null || inputFiles.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
PipelineResult result = processor.runPipelineAgainstFiles(inputFiles, config);
|
||||
List<Resource> outputFiles = result.getOutputFiles();
|
||||
List<Resource> outputFiles = processor.runPipelineAgainstFiles(inputFiles, config);
|
||||
if (outputFiles != null && outputFiles.size() == 1) {
|
||||
// If there is only one file, return it directly
|
||||
Resource singleFile = outputFiles.get(0);
|
||||
|
||||
@@ -27,7 +27,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||
import stirling.software.SPDF.model.PipelineConfig;
|
||||
import stirling.software.SPDF.model.PipelineOperation;
|
||||
import stirling.software.SPDF.model.PipelineResult;
|
||||
import stirling.software.SPDF.utils.FileMonitor;
|
||||
|
||||
@Service
|
||||
@@ -144,64 +143,19 @@ public class PipelineDirectoryProcessor {
|
||||
|
||||
private File[] collectFilesForProcessing(Path dir, Path jsonFile, PipelineOperation operation)
|
||||
throws IOException {
|
||||
|
||||
List<String> inputExtensions =
|
||||
apiDocService.getExtensionTypes(false, operation.getOperation());
|
||||
log.info(
|
||||
"Allowed extensions for operation {}: {}",
|
||||
operation.getOperation(),
|
||||
inputExtensions);
|
||||
|
||||
boolean allowAllFiles = inputExtensions.contains("ALL");
|
||||
|
||||
try (Stream<Path> paths = Files.list(dir)) {
|
||||
File[] files =
|
||||
paths.filter(
|
||||
path -> {
|
||||
if (Files.isDirectory(path)) {
|
||||
return false;
|
||||
}
|
||||
if (path.equals(jsonFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get file extension
|
||||
String filename = path.getFileName().toString();
|
||||
String extension =
|
||||
filename.contains(".")
|
||||
? filename.substring(
|
||||
filename.lastIndexOf(".")
|
||||
+ 1)
|
||||
.toLowerCase()
|
||||
: "";
|
||||
|
||||
// Check against allowed extensions
|
||||
boolean isAllowed =
|
||||
allowAllFiles
|
||||
|| inputExtensions.contains(extension);
|
||||
if (!isAllowed) {
|
||||
log.info(
|
||||
"Skipping file with unsupported extension: {} ({})",
|
||||
filename,
|
||||
extension);
|
||||
}
|
||||
return isAllowed;
|
||||
})
|
||||
.filter(
|
||||
path -> {
|
||||
boolean isReady =
|
||||
fileMonitor.isFileReadyForProcessing(path);
|
||||
if (!isReady) {
|
||||
log.info(
|
||||
"File not ready for processing (locked/created last 5s): {}",
|
||||
path);
|
||||
}
|
||||
return isReady;
|
||||
})
|
||||
.map(Path::toFile)
|
||||
.toArray(File[]::new);
|
||||
log.info("Collected {} files for processing", files.length);
|
||||
return files;
|
||||
if ("automated".equals(operation.getParameters().get("fileInput"))) {
|
||||
return paths.filter(
|
||||
path ->
|
||||
!Files.isDirectory(path)
|
||||
&& !path.equals(jsonFile)
|
||||
&& fileMonitor.isFileReadyForProcessing(path))
|
||||
.map(Path::toFile)
|
||||
.toArray(File[]::new);
|
||||
} else {
|
||||
String fileInput = (String) operation.getParameters().get("fileInput");
|
||||
return new File[] {new File(fileInput)};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,37 +198,19 @@ public class PipelineDirectoryProcessor {
|
||||
try {
|
||||
List<Resource> inputFiles =
|
||||
processor.generateInputFiles(filesToProcess.toArray(new File[0]));
|
||||
if (inputFiles == null || inputFiles.isEmpty()) {
|
||||
if (inputFiles == null || inputFiles.size() == 0) {
|
||||
return;
|
||||
}
|
||||
PipelineResult result = processor.runPipelineAgainstFiles(inputFiles, config);
|
||||
|
||||
if (result.isHasErrors()) {
|
||||
log.error("Errors occurred during processing, retaining original files");
|
||||
moveToErrorDirectory(filesToProcess, dir);
|
||||
} else {
|
||||
moveAndRenameFiles(result.getOutputFiles(), config, dir);
|
||||
deleteOriginalFiles(filesToProcess, processingDir);
|
||||
}
|
||||
List<Resource> outputFiles = processor.runPipelineAgainstFiles(inputFiles, config);
|
||||
if (outputFiles == null) return;
|
||||
moveAndRenameFiles(outputFiles, config, dir);
|
||||
deleteOriginalFiles(filesToProcess, processingDir);
|
||||
} catch (Exception e) {
|
||||
log.error("Error during processing", e);
|
||||
log.error("error during processing", e);
|
||||
moveFilesBack(filesToProcess, processingDir);
|
||||
}
|
||||
}
|
||||
|
||||
private void moveToErrorDirectory(List<File> files, Path originalDir) throws IOException {
|
||||
Path errorDir = originalDir.resolve("error");
|
||||
if (!Files.exists(errorDir)) {
|
||||
Files.createDirectories(errorDir);
|
||||
}
|
||||
|
||||
for (File file : files) {
|
||||
Path target = errorDir.resolve(file.getName());
|
||||
Files.move(file.toPath(), target);
|
||||
log.info("Moved failed file to error directory for investigation: {}", target);
|
||||
}
|
||||
}
|
||||
|
||||
private void moveAndRenameFiles(List<Resource> resources, PipelineConfig config, Path dir)
|
||||
throws IOException {
|
||||
for (Resource resource : resources) {
|
||||
|
||||
@@ -33,7 +33,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.SPDFApplication;
|
||||
import stirling.software.SPDF.model.PipelineConfig;
|
||||
import stirling.software.SPDF.model.PipelineOperation;
|
||||
import stirling.software.SPDF.model.PipelineResult;
|
||||
import stirling.software.SPDF.model.Role;
|
||||
|
||||
@Service
|
||||
@@ -85,10 +84,8 @@ public class PipelineProcessor {
|
||||
return "http://localhost:" + port + contextPath + "/";
|
||||
}
|
||||
|
||||
PipelineResult runPipelineAgainstFiles(List<Resource> outputFiles, PipelineConfig config)
|
||||
List<Resource> runPipelineAgainstFiles(List<Resource> outputFiles, PipelineConfig config)
|
||||
throws Exception {
|
||||
PipelineResult result = new PipelineResult();
|
||||
|
||||
ByteArrayOutputStream logStream = new ByteArrayOutputStream();
|
||||
PrintStream logPrintStream = new PrintStream(logStream);
|
||||
boolean hasErrors = false;
|
||||
@@ -133,8 +130,7 @@ public class PipelineProcessor {
|
||||
if (operation.startsWith("filter-")
|
||||
&& (response.getBody() == null
|
||||
|| response.getBody().length == 0)) {
|
||||
result.setFiltersApplied(true);
|
||||
log.info("Skipping file due to filtering {}", operation);
|
||||
log.info("Skipping file due to failing {}", operation);
|
||||
continue;
|
||||
}
|
||||
if (!response.getStatusCode().equals(HttpStatus.OK)) {
|
||||
@@ -212,10 +208,7 @@ public class PipelineProcessor {
|
||||
if (hasErrors) {
|
||||
log.error("Errors occurred during processing. Log: {}", logStream.toString());
|
||||
}
|
||||
result.setHasErrors(hasErrors);
|
||||
result.setFiltersApplied(hasErrors);
|
||||
result.setOutputFiles(outputFiles);
|
||||
return result;
|
||||
return outputFiles;
|
||||
}
|
||||
|
||||
private ResponseEntity<byte[]> sendWebRequest(String url, MultiValueMap<String, Object> body) {
|
||||
|
||||
@@ -40,7 +40,8 @@ public class RemoveCertSignController {
|
||||
@Operation(
|
||||
summary = "Remove digital signature from PDF",
|
||||
description =
|
||||
"This endpoint accepts a PDF file and returns the PDF file without the digital signature. Input:PDF, Output:PDF Type:SISO")
|
||||
"This endpoint accepts a PDF file and returns the PDF file without the digital signature."
|
||||
+ " Input: PDF, Output: PDF")
|
||||
public ResponseEntity<byte[]> removeCertSignPDF(@ModelAttribute PDFFile request)
|
||||
throws Exception {
|
||||
MultipartFile pdf = request.getFileInput();
|
||||
|
||||
@@ -44,13 +44,6 @@ public class ConverterWebController {
|
||||
return "convert/markdown-to-pdf";
|
||||
}
|
||||
|
||||
@GetMapping("/pdf-to-markdown")
|
||||
@Hidden
|
||||
public String convertPdfToMarkdownForm(Model model) {
|
||||
model.addAttribute("currentPage", "pdf-to-markdown");
|
||||
return "convert/pdf-to-markdown";
|
||||
}
|
||||
|
||||
@GetMapping("/url-to-pdf")
|
||||
@Hidden
|
||||
public String convertURLToPdfForm(Model model) {
|
||||
|
||||
@@ -36,9 +36,8 @@ public class DatabaseWebController {
|
||||
}
|
||||
List<FileInfo> backupList = databaseService.getBackupList();
|
||||
model.addAttribute("backupFiles", backupList);
|
||||
String dbVersion = databaseService.getH2Version();
|
||||
model.addAttribute("databaseVersion", dbVersion);
|
||||
if ("Unknown".equalsIgnoreCase(dbVersion)) {
|
||||
model.addAttribute("databaseVersion", databaseService.getH2Version());
|
||||
if ("Unknown".equalsIgnoreCase(databaseService.getH2Version())) {
|
||||
model.addAttribute("infoMessage", "notSupported");
|
||||
}
|
||||
return "database";
|
||||
|
||||
@@ -74,12 +74,6 @@ public class HomeWebController {
|
||||
return "redirect:/";
|
||||
}
|
||||
|
||||
@GetMapping("/home-legacy")
|
||||
public String homeLegacy(Model model) {
|
||||
model.addAttribute("currentPage", "home-legacy");
|
||||
return "home-legacy";
|
||||
}
|
||||
|
||||
@GetMapping(value = "/robots.txt", produces = MediaType.TEXT_PLAIN_VALUE)
|
||||
@ResponseBody
|
||||
@Hidden
|
||||
|
||||
@@ -265,8 +265,7 @@ public class ApplicationProperties {
|
||||
return getKeycloak();
|
||||
default:
|
||||
throw new UnsupportedProviderException(
|
||||
"Logout from the provider is not supported? Report it at"
|
||||
+ " https://github.com/Stirling-Tools/Stirling-PDF/issues");
|
||||
"Logout from the provider is not supported? Report it at https://github.com/Stirling-Tools/Stirling-PDF/issues");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -284,7 +283,6 @@ public class ApplicationProperties {
|
||||
private Boolean enableAlphaFunctionality;
|
||||
private String enableAnalytics;
|
||||
private Datasource datasource;
|
||||
private Boolean disableSanitize;
|
||||
}
|
||||
|
||||
@Data
|
||||
@@ -314,10 +312,10 @@ public class ApplicationProperties {
|
||||
@Override
|
||||
public String toString() {
|
||||
return """
|
||||
Driver {
|
||||
driverName='%s'
|
||||
}
|
||||
"""
|
||||
Driver {
|
||||
driverName='%s'
|
||||
}
|
||||
"""
|
||||
.formatted(driverName);
|
||||
}
|
||||
}
|
||||
@@ -327,7 +325,6 @@ public class ApplicationProperties {
|
||||
private String appName;
|
||||
private String homeDescription;
|
||||
private String appNameNavbar;
|
||||
private List<String> languages;
|
||||
|
||||
public String getAppName() {
|
||||
return appName != null && appName.trim().length() > 0 ? appName : null;
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package stirling.software.SPDF.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PipelineResult {
|
||||
private List<Resource> outputFiles;
|
||||
private boolean hasErrors;
|
||||
private boolean filtersApplied;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package stirling.software.SPDF.model.api.converters;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import stirling.software.SPDF.model.api.PDFFile;
|
||||
import stirling.software.SPDF.utils.PDFToFile;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "Convert", description = "Convert APIs")
|
||||
@RequestMapping("/api/v1/convert")
|
||||
public class ConvertPDFToMarkdown {
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf/markdown")
|
||||
@Operation(
|
||||
summary = "Convert PDF to Markdown",
|
||||
description =
|
||||
"This endpoint converts a PDF file to Markdown format. Input:PDF Output:Markdown Type:SISO")
|
||||
public ResponseEntity<byte[]> processPdfToMarkdown(@ModelAttribute PDFFile request)
|
||||
throws Exception {
|
||||
MultipartFile inputFile = request.getFileInput();
|
||||
PDFToFile pdfToFile = new PDFToFile();
|
||||
return pdfToFile.processPdfToMarkdown(inputFile);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +1,41 @@
|
||||
package stirling.software.SPDF.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class LanguageService {
|
||||
|
||||
private final ApplicationProperties applicationProperties;
|
||||
private final PathMatchingResourcePatternResolver resourcePatternResolver =
|
||||
new PathMatchingResourcePatternResolver();
|
||||
|
||||
public LanguageService(ApplicationProperties applicationProperties) {
|
||||
this.applicationProperties = applicationProperties;
|
||||
}
|
||||
public List<String> getSupportedLanguages() {
|
||||
List<String> supportedLanguages = new ArrayList<>();
|
||||
|
||||
public Set<String> getSupportedLanguages() {
|
||||
try {
|
||||
Resource[] resources =
|
||||
resourcePatternResolver.getResources("classpath*:messages_*.properties");
|
||||
|
||||
return Arrays.stream(resources)
|
||||
.map(Resource::getFilename)
|
||||
.filter(
|
||||
filename ->
|
||||
filename != null
|
||||
&& filename.startsWith("messages_")
|
||||
&& filename.endsWith(".properties"))
|
||||
.map(filename -> filename.replace("messages_", "").replace(".properties", ""))
|
||||
.filter(
|
||||
languageCode -> {
|
||||
Set<String> allowedLanguages =
|
||||
new HashSet<>(applicationProperties.getUi().getLanguages());
|
||||
return allowedLanguages.isEmpty()
|
||||
|| allowedLanguages.contains(languageCode)
|
||||
|| "en_GB".equals(languageCode);
|
||||
})
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
for (Resource resource : resources) {
|
||||
if (resource.exists() && resource.isReadable()) {
|
||||
String filename = resource.getFilename();
|
||||
if (filename != null
|
||||
&& filename.startsWith("messages_")
|
||||
&& filename.endsWith(".properties")) {
|
||||
String languageCode =
|
||||
filename.replace("messages_", "").replace(".properties", "");
|
||||
supportedLanguages.add(languageCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Error retrieving supported languages", e);
|
||||
return new HashSet<>();
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return supportedLanguages;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class MetricsAggregatorService {
|
||||
if (method == null || uri == null) {
|
||||
return;
|
||||
}
|
||||
if (!"GET".equals(method) && !"POST".equals(method)) {
|
||||
if (!method.equals("GET") && !method.equals("POST")) {
|
||||
return;
|
||||
}
|
||||
// Skip URIs that are 2 characters or shorter
|
||||
|
||||
@@ -26,8 +26,7 @@ public class FileToPdf {
|
||||
HTMLToPdfRequest request,
|
||||
byte[] fileBytes,
|
||||
String fileName,
|
||||
boolean htmlFormatsInstalled,
|
||||
boolean disableSanitize)
|
||||
boolean htmlFormatsInstalled)
|
||||
throws IOException, InterruptedException {
|
||||
|
||||
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
|
||||
@@ -37,13 +36,12 @@ public class FileToPdf {
|
||||
if (fileName.endsWith(".html")) {
|
||||
tempInputFile = Files.createTempFile("input_", ".html");
|
||||
String sanitizedHtml =
|
||||
sanitizeHtmlContent(
|
||||
new String(fileBytes, StandardCharsets.UTF_8), disableSanitize);
|
||||
sanitizeHtmlContent(new String(fileBytes, StandardCharsets.UTF_8));
|
||||
Files.write(tempInputFile, sanitizedHtml.getBytes(StandardCharsets.UTF_8));
|
||||
} else if (fileName.endsWith(".zip")) {
|
||||
tempInputFile = Files.createTempFile("input_", ".zip");
|
||||
Files.write(tempInputFile, fileBytes);
|
||||
sanitizeHtmlFilesInZip(tempInputFile, disableSanitize);
|
||||
sanitizeHtmlFilesInZip(tempInputFile);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported file format: " + fileName);
|
||||
}
|
||||
@@ -91,12 +89,11 @@ public class FileToPdf {
|
||||
return pdfBytes;
|
||||
}
|
||||
|
||||
private static String sanitizeHtmlContent(String htmlContent, boolean disableSanitize) {
|
||||
return (!disableSanitize) ? CustomHtmlSanitizer.sanitize(htmlContent) : htmlContent;
|
||||
private static String sanitizeHtmlContent(String htmlContent) {
|
||||
return CustomHtmlSanitizer.sanitize(htmlContent);
|
||||
}
|
||||
|
||||
private static void sanitizeHtmlFilesInZip(Path zipFilePath, boolean disableSanitize)
|
||||
throws IOException {
|
||||
private static void sanitizeHtmlFilesInZip(Path zipFilePath) throws IOException {
|
||||
Path tempUnzippedDir = Files.createTempDirectory("unzipped_");
|
||||
try (ZipInputStream zipIn =
|
||||
ZipSecurity.createHardenedInputStream(
|
||||
@@ -109,7 +106,7 @@ public class FileToPdf {
|
||||
if (entry.getName().toLowerCase().endsWith(".html")
|
||||
|| entry.getName().toLowerCase().endsWith(".htm")) {
|
||||
String content = new String(zipIn.readAllBytes(), StandardCharsets.UTF_8);
|
||||
String sanitizedContent = sanitizeHtmlContent(content, disableSanitize);
|
||||
String sanitizedContent = sanitizeHtmlContent(content);
|
||||
Files.write(filePath, sanitizedContent.getBytes(StandardCharsets.UTF_8));
|
||||
} else {
|
||||
Files.copy(zipIn, filePath);
|
||||
|
||||
@@ -9,17 +9,15 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.simpleyaml.configuration.file.YamlFile;
|
||||
import org.simpleyaml.configuration.file.YamlFileWrapper;
|
||||
import org.simpleyaml.configuration.implementation.SimpleYamlImplementation;
|
||||
import org.simpleyaml.configuration.implementation.snakeyaml.lib.DumperOptions;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.fathzer.soft.javaluator.DoubleEvaluator;
|
||||
@@ -287,10 +285,7 @@ public class GeneralUtils {
|
||||
String[] rangeParts = part.split("-");
|
||||
try {
|
||||
int start = Integer.parseInt(rangeParts[0]);
|
||||
int end =
|
||||
(rangeParts.length > 1 && !rangeParts[1].isEmpty())
|
||||
? Integer.parseInt(rangeParts[1])
|
||||
: totalPages;
|
||||
int end = Integer.parseInt(rangeParts[1]);
|
||||
for (int i = start; i <= end; i++) {
|
||||
if (i >= 1 && i <= totalPages) {
|
||||
partResult.add(i - 1 + offset);
|
||||
@@ -348,208 +343,41 @@ public class GeneralUtils {
|
||||
|
||||
public static void saveKeyToConfig(String id, String key, boolean autoGenerated)
|
||||
throws IOException {
|
||||
doSaveKeyToConfig(id, (key == null ? "" : key), autoGenerated);
|
||||
Path path =
|
||||
Paths.get(
|
||||
InstallationPathConfig
|
||||
.getSettingsPath()); // Target the configs/settings.yml
|
||||
|
||||
final YamlFile settingsYml = new YamlFile(path.toFile());
|
||||
DumperOptions yamlOptionssettingsYml =
|
||||
((SimpleYamlImplementation) settingsYml.getImplementation()).getDumperOptions();
|
||||
yamlOptionssettingsYml.setSplitLines(false);
|
||||
|
||||
settingsYml.loadWithComments();
|
||||
|
||||
YamlFileWrapper writer = settingsYml.path(id).set(key);
|
||||
if (autoGenerated) {
|
||||
writer.comment("# Automatically Generated Settings (Do Not Edit Directly)");
|
||||
}
|
||||
settingsYml.save();
|
||||
}
|
||||
|
||||
public static void saveKeyToConfig(String id, boolean key, boolean autoGenerated)
|
||||
throws IOException {
|
||||
doSaveKeyToConfig(id, String.valueOf(key), autoGenerated);
|
||||
}
|
||||
Path path = Paths.get(InstallationPathConfig.getSettingsPath());
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* Internal Implementation Details *
|
||||
*------------------------------------------------------------------------*/
|
||||
final YamlFile settingsYml = new YamlFile(path.toFile());
|
||||
DumperOptions yamlOptionssettingsYml =
|
||||
((SimpleYamlImplementation) settingsYml.getImplementation()).getDumperOptions();
|
||||
yamlOptionssettingsYml.setSplitLines(false);
|
||||
|
||||
/**
|
||||
* Actually performs the line-based update for the given path (e.g. "security.csrfDisabled") to
|
||||
* a new string value (e.g. "true"), possibly marking it as auto-generated.
|
||||
*/
|
||||
private static void doSaveKeyToConfig(String fullPath, String newValue, boolean autoGenerated)
|
||||
throws IOException {
|
||||
// 1) Load the file (settings.yml)
|
||||
Path settingsPath = Paths.get(InstallationPathConfig.getSettingsPath());
|
||||
if (!Files.exists(settingsPath)) {
|
||||
log.warn("Settings file not found at {}, creating a new empty file...", settingsPath);
|
||||
Files.createDirectories(settingsPath.getParent());
|
||||
Files.createFile(settingsPath);
|
||||
}
|
||||
List<String> lines = Files.readAllLines(settingsPath);
|
||||
settingsYml.loadWithComments();
|
||||
|
||||
// 2) Build a map of "nestedKeyPath -> lineIndex" by parsing indentation
|
||||
// Also track each line's indentation so we can preserve it when rewriting.
|
||||
Map<String, LineInfo> pathToLine = parseNestedYamlKeys(lines);
|
||||
|
||||
// 3) If the path is found, rewrite its line. Else, append at the bottom (no indentation).
|
||||
boolean changed = false;
|
||||
if (pathToLine.containsKey(fullPath)) {
|
||||
// Rewrite existing line
|
||||
LineInfo info = pathToLine.get(fullPath);
|
||||
String oldLine = lines.get(info.lineIndex);
|
||||
String newLine =
|
||||
rewriteLine(oldLine, info.indentSpaces, fullPath, newValue, autoGenerated);
|
||||
if (!newLine.equals(oldLine)) {
|
||||
lines.set(info.lineIndex, newLine);
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
// Append a new line at the bottom, with zero indentation
|
||||
String appended = fullPath + ": " + newValue;
|
||||
if (autoGenerated) {
|
||||
appended += " # Automatically Generated Settings (Do Not Edit Directly)";
|
||||
}
|
||||
lines.add(appended);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// 4) If changed, write back to file
|
||||
if (changed) {
|
||||
Files.write(settingsPath, lines);
|
||||
log.info(
|
||||
"Updated '{}' to '{}' (autoGenerated={}) in {}",
|
||||
fullPath,
|
||||
newValue,
|
||||
autoGenerated,
|
||||
settingsPath);
|
||||
} else {
|
||||
log.info("No changes for '{}' (already set to '{}').", fullPath, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
/** A small record-like class that holds: - lineIndex - indentSpaces */
|
||||
private static class LineInfo {
|
||||
int lineIndex;
|
||||
int indentSpaces;
|
||||
|
||||
public LineInfo(int lineIndex, int indentSpaces) {
|
||||
this.lineIndex = lineIndex;
|
||||
this.indentSpaces = indentSpaces;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the YAML lines to build a map: "full.nested.key" -> (lineIndex, indentSpaces). We do a
|
||||
* naive indentation-based path stacking: - 2 spaces = 1 indent level - lines that start with
|
||||
* fewer or equal indentation pop the stack - lines that look like "key:" or "key: value" cause
|
||||
* a push
|
||||
*/
|
||||
private static Map<String, LineInfo> parseNestedYamlKeys(List<String> lines) {
|
||||
Map<String, LineInfo> result = new HashMap<>();
|
||||
|
||||
// We'll maintain a stack of (keyName, indentLevel).
|
||||
// Each line that looks like "myKey:" or "myKey: value" is a new "child" of the top of the
|
||||
// stack if indent is deeper.
|
||||
Deque<String> pathStack = new ArrayDeque<>();
|
||||
Deque<Integer> indentStack = new ArrayDeque<>();
|
||||
indentStack.push(-1); // sentinel
|
||||
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
String line = lines.get(i);
|
||||
String trimmed = line.trim();
|
||||
|
||||
// skip blank lines, comment lines, or list items
|
||||
if (trimmed.isEmpty() || trimmed.startsWith("#") || trimmed.startsWith("-")) {
|
||||
continue;
|
||||
}
|
||||
// check if there's a colon
|
||||
int colonIdx = trimmed.indexOf(':');
|
||||
if (colonIdx <= 0) { // must have at least one char before ':'
|
||||
continue;
|
||||
}
|
||||
// parse out key
|
||||
String keyPart = trimmed.substring(0, colonIdx).trim();
|
||||
if (keyPart.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// count leading spaces for indentation
|
||||
int leadingSpaces = countLeadingSpaces(line);
|
||||
int indentLevel = leadingSpaces / 2; // assume 2 spaces per level
|
||||
|
||||
// pop from stack until we get to a shallower indentation
|
||||
while (indentStack.peek() != null && indentStack.peek() >= indentLevel) {
|
||||
indentStack.pop();
|
||||
pathStack.pop();
|
||||
}
|
||||
|
||||
// push the new key
|
||||
pathStack.push(keyPart);
|
||||
indentStack.push(indentLevel);
|
||||
|
||||
// build the full path
|
||||
String[] arr = pathStack.toArray(new String[0]);
|
||||
List<String> reversed = Arrays.asList(arr);
|
||||
Collections.reverse(reversed);
|
||||
String fullPath = String.join(".", reversed);
|
||||
|
||||
// store line info
|
||||
result.put(fullPath, new LineInfo(i, leadingSpaces));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite a single line to set a new value, preserving indentation and (optionally) the
|
||||
* existing or auto-generated inline comment.
|
||||
*
|
||||
* <p>For example, oldLine might be: " csrfDisabled: false # set to 'true' to disable CSRF
|
||||
* protection" newValue = "true" autoGenerated = false
|
||||
*
|
||||
* <p>We'll produce something like: " csrfDisabled: true # set to 'true' to disable CSRF
|
||||
* protection"
|
||||
*/
|
||||
private static String rewriteLine(
|
||||
String oldLine, int indentSpaces, String path, String newValue, boolean autoGenerated) {
|
||||
// We'll keep the exact leading indentation (indentSpaces).
|
||||
// Then "key: newValue". We'll try to preserve any existing inline comment unless
|
||||
// autoGenerated is true.
|
||||
|
||||
// 1) Extract leading spaces from the old line (just in case they differ from indentSpaces).
|
||||
int actualLeadingSpaces = countLeadingSpaces(oldLine);
|
||||
String leading = oldLine.substring(0, actualLeadingSpaces);
|
||||
|
||||
// 2) Remove leading spaces from the rest
|
||||
String trimmed = oldLine.substring(actualLeadingSpaces);
|
||||
|
||||
// 3) Check for existing comment
|
||||
int hashIndex = trimmed.indexOf('#');
|
||||
String lineWithoutComment =
|
||||
(hashIndex >= 0) ? trimmed.substring(0, hashIndex).trim() : trimmed.trim();
|
||||
String oldComment = (hashIndex >= 0) ? trimmed.substring(hashIndex).trim() : "";
|
||||
|
||||
// 4) Rebuild "key: newValue"
|
||||
// The "key" here is everything before ':' in lineWithoutComment
|
||||
int colonIdx = lineWithoutComment.indexOf(':');
|
||||
String existingKey =
|
||||
(colonIdx >= 0)
|
||||
? lineWithoutComment.substring(0, colonIdx).trim()
|
||||
: path; // fallback if line is malformed
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(leading); // restore original leading spaces
|
||||
|
||||
// "key: newValue"
|
||||
sb.append(existingKey).append(": ").append(newValue);
|
||||
|
||||
// 5) If autoGenerated, add/replace comment
|
||||
YamlFileWrapper writer = settingsYml.path(id).set(key);
|
||||
if (autoGenerated) {
|
||||
sb.append(" # Automatically Generated Settings (Do Not Edit Directly)");
|
||||
} else {
|
||||
// preserve the old comment if it exists
|
||||
if (!oldComment.isEmpty()) {
|
||||
sb.append(" ").append(oldComment);
|
||||
}
|
||||
writer.comment("# Automatically Generated Settings (Do Not Edit Directly)");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static int countLeadingSpaces(String line) {
|
||||
int count = 0;
|
||||
for (char c : line.toCharArray()) {
|
||||
if (c == ' ') count++;
|
||||
else break;
|
||||
}
|
||||
return count;
|
||||
settingsYml.save();
|
||||
}
|
||||
|
||||
public static String generateMachineFingerprint() {
|
||||
@@ -587,7 +415,9 @@ public class GeneralUtils {
|
||||
for (byte b : hash) {
|
||||
fingerprint.append(String.format("%02x", b));
|
||||
}
|
||||
|
||||
return fingerprint.toString();
|
||||
|
||||
} catch (Exception e) {
|
||||
return "GenericID";
|
||||
}
|
||||
|
||||
@@ -20,9 +20,6 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter;
|
||||
import com.vladsch.flexmark.util.data.MutableDataSet;
|
||||
|
||||
import io.github.pixee.security.Filenames;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -31,123 +28,6 @@ import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||
@Slf4j
|
||||
public class PDFToFile {
|
||||
|
||||
public ResponseEntity<byte[]> processPdfToMarkdown(MultipartFile inputFile)
|
||||
throws IOException, InterruptedException {
|
||||
if (!"application/pdf".equals(inputFile.getContentType())) {
|
||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
MutableDataSet options =
|
||||
new MutableDataSet()
|
||||
.set(
|
||||
FlexmarkHtmlConverter.MAX_BLANK_LINES,
|
||||
2) // Control max consecutive blank lines
|
||||
.set(
|
||||
FlexmarkHtmlConverter.MAX_TRAILING_BLANK_LINES,
|
||||
1) // Control trailing blank lines
|
||||
.set(
|
||||
FlexmarkHtmlConverter.SETEXT_HEADINGS,
|
||||
true) // Use Setext headings for h1 and h2
|
||||
.set(
|
||||
FlexmarkHtmlConverter.OUTPUT_UNKNOWN_TAGS,
|
||||
false) // Don't output HTML for unknown tags
|
||||
.set(
|
||||
FlexmarkHtmlConverter.TYPOGRAPHIC_QUOTES,
|
||||
true) // Convert quotation marks
|
||||
.set(
|
||||
FlexmarkHtmlConverter.BR_AS_PARA_BREAKS,
|
||||
true) // Convert <br> to paragraph breaks
|
||||
.set(FlexmarkHtmlConverter.CODE_INDENT, " "); // Indent for code blocks
|
||||
|
||||
FlexmarkHtmlConverter htmlToMarkdownConverter =
|
||||
FlexmarkHtmlConverter.builder(options).build();
|
||||
|
||||
String originalPdfFileName = Filenames.toSimpleFileName(inputFile.getOriginalFilename());
|
||||
String pdfBaseName = originalPdfFileName;
|
||||
if (originalPdfFileName.contains(".")) {
|
||||
pdfBaseName = originalPdfFileName.substring(0, originalPdfFileName.lastIndexOf('.'));
|
||||
}
|
||||
|
||||
Path tempInputFile = null;
|
||||
Path tempOutputDir = null;
|
||||
byte[] fileBytes;
|
||||
String fileName = "temp.file";
|
||||
|
||||
try {
|
||||
tempInputFile = Files.createTempFile("input_", ".pdf");
|
||||
inputFile.transferTo(tempInputFile);
|
||||
tempOutputDir = Files.createTempDirectory("output_");
|
||||
|
||||
List<String> command =
|
||||
new ArrayList<>(
|
||||
Arrays.asList(
|
||||
"pdftohtml",
|
||||
"-s",
|
||||
"-noframes",
|
||||
"-c",
|
||||
tempInputFile.toString(),
|
||||
pdfBaseName));
|
||||
|
||||
ProcessExecutorResult returnCode =
|
||||
ProcessExecutor.getInstance(ProcessExecutor.Processes.PDFTOHTML)
|
||||
.runCommandWithOutputHandling(command, tempOutputDir.toFile());
|
||||
// Process HTML files to Markdown
|
||||
File[] outputFiles = Objects.requireNonNull(tempOutputDir.toFile().listFiles());
|
||||
List<File> markdownFiles = new ArrayList<>();
|
||||
|
||||
// Convert HTML files to Markdown
|
||||
for (File outputFile : outputFiles) {
|
||||
if (outputFile.getName().endsWith(".html")) {
|
||||
String html = Files.readString(outputFile.toPath());
|
||||
String markdown = htmlToMarkdownConverter.convert(html);
|
||||
|
||||
String mdFileName = outputFile.getName().replace(".html", ".md");
|
||||
File mdFile = new File(tempOutputDir.toFile(), mdFileName);
|
||||
Files.writeString(mdFile.toPath(), markdown);
|
||||
markdownFiles.add(mdFile);
|
||||
}
|
||||
}
|
||||
|
||||
// If there's only one markdown file, return it directly
|
||||
if (markdownFiles.size() == 1) {
|
||||
fileName = pdfBaseName + ".md";
|
||||
fileBytes = Files.readAllBytes(markdownFiles.get(0).toPath());
|
||||
} else {
|
||||
// Multiple files - create a zip
|
||||
fileName = pdfBaseName + "ToMarkdown.zip";
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
|
||||
try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) {
|
||||
// Add markdown files
|
||||
for (File mdFile : markdownFiles) {
|
||||
ZipEntry mdEntry = new ZipEntry(mdFile.getName());
|
||||
zipOutputStream.putNextEntry(mdEntry);
|
||||
Files.copy(mdFile.toPath(), zipOutputStream);
|
||||
zipOutputStream.closeEntry();
|
||||
}
|
||||
|
||||
// Add images and other assets
|
||||
for (File file : outputFiles) {
|
||||
if (!file.getName().endsWith(".html") && !file.getName().endsWith(".md")) {
|
||||
ZipEntry assetEntry = new ZipEntry(file.getName());
|
||||
zipOutputStream.putNextEntry(assetEntry);
|
||||
Files.copy(file.toPath(), zipOutputStream);
|
||||
zipOutputStream.closeEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileBytes = byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
|
||||
} finally {
|
||||
if (tempInputFile != null) Files.deleteIfExists(tempInputFile);
|
||||
if (tempOutputDir != null) FileUtils.deleteDirectory(tempOutputDir.toFile());
|
||||
}
|
||||
return WebResponseUtils.bytesToWebResponse(
|
||||
fileBytes, fileName, MediaType.APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
|
||||
public ResponseEntity<byte[]> processPdfToHtml(MultipartFile inputFile)
|
||||
throws IOException, InterruptedException {
|
||||
if (!"application/pdf".equals(inputFile.getContentType())) {
|
||||
|
||||
@@ -218,9 +218,6 @@ public class ProcessExecutor {
|
||||
errorReaderThread.join();
|
||||
outputReaderThread.join();
|
||||
|
||||
boolean isQpdf =
|
||||
command != null && !command.isEmpty() && command.get(0).contains("qpdf");
|
||||
|
||||
if (outputLines.size() > 0) {
|
||||
String outputMessage = String.join("\n", outputLines);
|
||||
messages += outputMessage;
|
||||
@@ -236,28 +233,20 @@ public class ProcessExecutor {
|
||||
log.warn("Command error output:\n" + errorMessage);
|
||||
}
|
||||
if (exitCode != 0) {
|
||||
if (isQpdf && exitCode == 3) {
|
||||
log.warn("qpdf succeeded with warnings: {}", messages);
|
||||
} else {
|
||||
throw new IOException(
|
||||
"Command process failed with exit code "
|
||||
+ exitCode
|
||||
+ ". Error message: "
|
||||
+ errorMessage);
|
||||
}
|
||||
throw new IOException(
|
||||
"Command process failed with exit code "
|
||||
+ exitCode
|
||||
+ ". Error message: "
|
||||
+ errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
if (exitCode != 0) {
|
||||
if (isQpdf && exitCode == 3) {
|
||||
log.warn("qpdf succeeded with warnings: {}", messages);
|
||||
} else {
|
||||
throw new IOException(
|
||||
"Command process failed with exit code "
|
||||
+ exitCode
|
||||
+ "\nLogs: "
|
||||
+ messages);
|
||||
}
|
||||
throw new IOException(
|
||||
"Command process failed with exit code "
|
||||
+ exitCode
|
||||
+ "\nLogs: "
|
||||
+ messages);
|
||||
}
|
||||
} finally {
|
||||
semaphore.release();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user