Compare commits

...

16 Commits

Author SHA1 Message Date
Anthony Stirling
ac1b1916d2 use /opt/venv only if docker/ else use path 2025-02-22 15:56:24 +00:00
Anthony Stirling
a36c0415b7 Merge remote-tracking branch 'origin/main' into fixPipeline 2025-02-22 01:38:52 +00:00
Anthony Stirling
dc986b5213 Allow dynamic path renaming 2025-02-22 01:37:44 +00:00
ConnorYoh
139faf4eba 2299 feature request language selection overhaul (#3017)
# Description of Changes

Please provide a summary of the changes, including:

- UI design of language drop down has changed
- too few languages were visible on the drop down
- Flags caused controversy 
- Scaling window due to size required adding some /@media CSS tags in
navbar css

Closes #(2299)

---

## Checklist

### General

- [x ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md)
(if applicable)
- [ x] 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)
- [ x] I have performed a self-review of my own code
- [x ] My changes generate no new warnings

### Documentation

- [x ] 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.

---------

Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2025-02-22 01:36:55 +00:00
Anthony Stirling
167c85e73f Update UserService.java to generate API key if empty (#3016)
# Description of Changes

Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

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
- [ ] 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.
2025-02-21 15:02:03 +00:00
Anthony Stirling
efb3b1f234 Merge remote-tracking branch 'origin/main' into fixPipeline 2025-02-21 14:33:26 +00:00
Anthony Stirling
590a3b6cbb init 2025-02-21 14:32:29 +00:00
stirlingbot[bot]
505c4bd2a7 Update 3rd Party Licenses (#2997)
Auto-generated by StirlingBot

Signed-off-by: stirlingbot[bot] <1113334+stirlingbot[bot]@users.noreply.github.com>
Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
2025-02-20 10:36:07 +00:00
dependabot[bot]
11a5b2e79f Bump actions/create-github-app-token from 1.11.2 to 1.11.3 (#2878)
Bumps
[actions/create-github-app-token](https://github.com/actions/create-github-app-token)
from 1.11.2 to 1.11.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/create-github-app-token/releases">actions/create-github-app-token's
releases</a>.</em></p>
<blockquote>
<h2>v1.11.3</h2>
<h2><a
href="https://github.com/actions/create-github-app-token/compare/v1.11.2...v1.11.3">1.11.3</a>
(2025-02-04)</h2>
<h3>Bug Fixes</h3>
<ul>
<li><strong>deps:</strong> bump the production-dependencies group with 3
updates (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/203">#203</a>)
(<a
href="8e85a3cf14">8e85a3c</a>),
closes <a
href="https://redirect.github.com/actions/create-github-app-token/issues/665">#665</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/665">#665</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/663">#663</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/662">#662</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/661">#661</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/659">#659</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/660">#660</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/658">#658</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/656">#656</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/657">#657</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/655">#655</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/731">#731</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/4016">nodejs/undici#4016</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/4017">nodejs/undici#4017</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/4018">nodejs/undici#4018</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/4008">nodejs/undici#4008</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3991">nodejs/undici#3991</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/4001">nodejs/undici#4001</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3980">nodejs/undici#3980</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/4003">nodejs/undici#4003</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3965">nodejs/undici#3965</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/4002">nodejs/undici#4002</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/4006">nodejs/undici#4006</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3956">nodejs/undici#3956</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3964">nodejs/undici#3964</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3447">nodejs/undici#3447</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/3966">#3966</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3967">nodejs/undici#3967</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3971">nodejs/undici#3971</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3954">nodejs/undici#3954</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3972">nodejs/undici#3972</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3974">nodejs/undici#3974</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3976">nodejs/undici#3976</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/3975">#3975</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3977">nodejs/undici#3977</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3978">nodejs/undici#3978</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3981">nodejs/undici#3981</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3983">nodejs/undici#3983</a>
<a
href="https://redirect.github.com/nodejs/undici/issues/3986">nodejs/undici#3986</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/4021">#4021</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/4018">#4018</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/4017">#4017</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/4016">#4016</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/4008">#4008</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/4007">#4007</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/4006">#4006</a>
<a
href="https://redirect.github.com/actions/create-github-app-token/issues/3965">#3965</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="67e27a7eb7"><code>67e27a7</code></a>
build(release): 1.11.3 [skip ci]</li>
<li><a
href="8e85a3cf14"><code>8e85a3c</code></a>
fix(deps): bump the production-dependencies group with 3 updates (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/203">#203</a>)</li>
<li>See full diff in <a
href="136412a57a...67e27a7eb7">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/create-github-app-token&package-manager=github_actions&previous-version=1.11.2&new-version=1.11.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
Co-authored-by: Ludy <Ludy87@users.noreply.github.com>
2025-02-19 22:17:42 +00:00
stirlingbot[bot]
896258f011 🌐 Sync Translations + Update README Progress Table (#2989)
### 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].

[1]: https://github.com/peter-evans/create-pull-request

Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
2025-02-19 22:10:05 +00:00
dependabot[bot]
69c6544877 Bump io.micrometer:micrometer-core from 1.14.3 to 1.14.4 (#2927)
Bumps
[io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer)
from 1.14.3 to 1.14.4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/micrometer-metrics/micrometer/releases">io.micrometer:micrometer-core's
releases</a>.</em></p>
<blockquote>
<h2>1.14.4</h2>
<h2>🐞 Bug Fixes</h2>
<ul>
<li>Log4j2Metrics does not work with multiple registries and non-root
loggers <a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/5893">#5893</a></li>
<li>Fix LongTaskTimer output for LoggingMeterRegistry <a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/5834">#5834</a></li>
<li><code>Log4j2Metrics</code> creates more <code>MetricsFilter</code>
instances than needed <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5818">#5818</a></li>
<li>Fix unit discrepancy between Timer and FunctionTimer in
LoggingMeterRegistry <a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/5816">#5816</a></li>
<li>Distribution bucket_counts sum does not equal the count <a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/4868">#4868</a></li>
</ul>
<h2>📔 Documentation</h2>
<ul>
<li>Remove obviated GraalVM native image compilation section from
Stackdriver docs <a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/5819">#5819</a></li>
<li>Update Docs with right contract of MeterFilter <a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/5480">#5480</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Bump com.netflix.spectator:spectator-reg-atlas from 1.8.3 to 1.8.4
<a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5907">#5907</a></li>
<li>Bump org.apache.httpcomponents.client5:httpclient5 from 5.4.1 to
5.4.2 <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5876">#5876</a></li>
<li>Bump io.netty:netty-bom from 4.1.116.Final to 4.1.117.Final <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5872">#5872</a></li>
<li>Bump org.postgresql:postgresql from 42.7.4 to 42.7.5 <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5871">#5871</a></li>
<li>Bump jersey3 from 3.1.9 to 3.1.10 <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5870">#5870</a></li>
<li>Bump software.amazon.awssdk:cloudwatch from 2.29.46 to 2.29.52 <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5869">#5869</a></li>
<li>Bump jetty9 from 9.4.56.v20240826 to 9.4.57.v20241219 <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5868">#5868</a></li>
<li>Bump dropwizard-metrics from 4.2.29 to 4.2.30 <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5867">#5867</a></li>
<li>Bump com.signalfx.public:signalfx-java from 1.0.48 to 1.0.49 <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5895">#5895</a></li>
<li>Bump org.apache.commons:commons-pool2 from 2.12.0 to 2.12.1 <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5865">#5865</a></li>
</ul>
<h2>📝 Tasks</h2>
<ul>
<li>Increase sleep time to avoid exemplar sampling rate limiting for
openMetricsScrapeWithExemplars() <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5908">#5908</a></li>
<li>Fix flakiness in
DynatraceMeterRegistryTest.shouldTrackPercentilesWhenDynatraceSummaryInstrumentsNotUsed()
<a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5900">#5900</a></li>
<li>Fix flakiness in
JmsInstrumentationTests.shouldInstrumentMessageListener() <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5899">#5899</a></li>
<li>Fix flakiness in JettyClientMetricsWithObservationTest.activeTimer()
<a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5894">#5894</a></li>
<li>Increase wait duration in
PushMeterRegistryTest.closeRespectsInterrupt() <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5890">#5890</a></li>
<li>Enable TimedAspectTest.pjpFunctionThrows() <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5889">#5889</a></li>
<li>Add .kotlin to .gitignore <a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/5888">#5888</a></li>
<li>Polish <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5886">#5886</a></li>
<li>Migrate to dependabot auto-merge function <a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/5874">#5874</a></li>
<li>Back-port LoggingMeterRegistry tests <a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/5833">#5833</a></li>
<li>Bump build machine image to ubuntu-2404:2024.11.1 <a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/5829">#5829</a></li>
<li>Bump build JDKs to 21.0.6, 17.0.14, 11.0.26 <a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/5828">#5828</a></li>
<li>Upgrade to Gradle Wrapper 8.12.1 <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/5823">#5823</a></li>
</ul>
<h2>❤️ Contributors</h2>
<p>Thank you to all the contributors who worked on this release:</p>
<p><a href="https://github.com/izeye"><code>@​izeye</code></a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="e387558fcc"><code>e387558</code></a>
Merge branch '1.13.x' into 1.14.x</li>
<li><a
href="f33456630e"><code>f334566</code></a>
Increase sleep time to avoid exemplar sampling rate limiting for
openMetricsS...</li>
<li><a
href="94686e8895"><code>94686e8</code></a>
Merge branch '1.13.x' into 1.14.x</li>
<li><a
href="9e4dfbf8be"><code>9e4dfbf</code></a>
Migrates post actions to java gh action</li>
<li><a
href="e44147a942"><code>e44147a</code></a>
Bump com.netflix.spectator:spectator-reg-atlas from 1.8.3 to 1.8.4 (<a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/5907">#5907</a>)</li>
<li><a
href="7c65ad6585"><code>7c65ad6</code></a>
Fix flakiness in
DynatraceMeterRegistryTest.shouldTrackPercentilesWhenDynatra...</li>
<li><a
href="f879d3abf1"><code>f879d3a</code></a>
Fix flakiness in
JmsInstrumentationTests.shouldInstrumentMessageListener() (#...</li>
<li><a
href="20d0a9ef6e"><code>20d0a9e</code></a>
Fix flakiness in JettyClientMetricsWithObservationTest.activeTimer() (<a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/5894">#5894</a>)</li>
<li><a
href="fd6d438441"><code>fd6d438</code></a>
Bump com.signalfx.public:signalfx-java from 1.0.48 to 1.0.49 (<a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/5898">#5898</a>)</li>
<li><a
href="9311c173de"><code>9311c17</code></a>
Bump com.signalfx.public:signalfx-java from 1.0.48 to 1.0.49 (<a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/5895">#5895</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/micrometer-metrics/micrometer/compare/v1.14.3...v1.14.4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=io.micrometer:micrometer-core&package-manager=gradle&previous-version=1.14.3&new-version=1.14.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-19 22:08:45 +00:00
Ludy
e145f25ba4 Enhance Java Development Configuration and Code Formatting (#2991)
# Description of Changes

Please provide a summary of the changes, including:

This PR improves Java development settings and code formatting by:
- Removing the deprecated `Checkstyle` extension from
`.vscode/extensions.json`.
- Updating `.vscode/settings.json` with:
  - Structured formatting for better readability.
  - Improved Java formatting with `google-java-format`.
  - Enhanced auto-save behavior.
  - Additional Java cleanup actions for better code quality.
  - Optimized project resource filtering.
  - More precise import sorting and ordering.
- Refining `build.gradle` to:
- Extend the `importOrder` rule to include `jakarta`, `lombok`, `me`,
and `stirling`.
  - Improve `spotless` formatting configurations.

These changes streamline the development workflow, enhance code
consistency, and improve maintainability.

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] 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)
- [x] I have performed a self-review of my own code
- [x] 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.
2025-02-19 21:41:02 +00:00
IT Creativity + Art Team
696e5ff9ca Update messages_bg_BG.properties (#2996)
BG lang strings sync


# Description of Changes

Please provide a summary of the changes, including:

- What was changed - the language strings only towards the current ones
- Why the change was made - to have an up-to-date translation
- Any challenges encountered - none


---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md)
(if applicable)
- [x]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)
- [x]I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [x]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)
- [x] 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)

- [x] 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.
2025-02-19 21:40:37 +00:00
albanobattistella
f9cf75e247 Update messages_it_IT.properties (#2993)
# Description of Changes

Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

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
- [ ] 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.
2025-02-19 12:55:15 +00:00
Anthony Stirling
5deb27cc12 view/edit PDF other langs 2025-02-18 17:46:38 +00:00
Anthony Stirling
f51c3c870a name change 2025-02-18 15:54:56 +00:00
191 changed files with 857 additions and 879 deletions

View File

@@ -24,7 +24,7 @@ jobs:
- name: Generate GitHub App Token - name: Generate GitHub App Token
id: generate-token id: generate-token
uses: actions/create-github-app-token@136412a57a7081aa63c935a2cc2918f76c34f514 # v1.11.2 uses: actions/create-github-app-token@67e27a7eb7db372a1c61a7f9bdab8699e9ee57f7 # v1.11.3
with: with:
app-id: ${{ secrets.GH_APP_ID }} app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}

View File

@@ -22,7 +22,7 @@ jobs:
- name: Generate GitHub App Token - name: Generate GitHub App Token
id: generate-token id: generate-token
uses: actions/create-github-app-token@136412a57a7081aa63c935a2cc2918f76c34f514 # v1.11.2 uses: actions/create-github-app-token@67e27a7eb7db372a1c61a7f9bdab8699e9ee57f7 # v1.11.3
with: with:
app-id: ${{ secrets.GH_APP_ID }} app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}

View File

@@ -30,7 +30,7 @@ jobs:
- name: Generate GitHub App Token - name: Generate GitHub App Token
id: generate-token id: generate-token
uses: actions/create-github-app-token@136412a57a7081aa63c935a2cc2918f76c34f514 # v1.11.2 uses: actions/create-github-app-token@67e27a7eb7db372a1c61a7f9bdab8699e9ee57f7 # v1.11.3
with: with:
app-id: ${{ secrets.GH_APP_ID }} app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
@@ -63,7 +63,7 @@ jobs:
- name: Generate GitHub App Token - name: Generate GitHub App Token
id: generate-token id: generate-token
uses: actions/create-github-app-token@136412a57a7081aa63c935a2cc2918f76c34f514 # v1.11.2 uses: actions/create-github-app-token@67e27a7eb7db372a1c61a7f9bdab8699e9ee57f7 # v1.11.3
with: with:
app-id: ${{ vars.GH_APP_ID }} app-id: ${{ vars.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}

View File

@@ -9,7 +9,6 @@
// "ms-vscode-remote.vscode-remote-extensionpack", // Remote Development Pack for SSH, WSL, and 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 "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 "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 "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-boot-dev-pack", // Developer tools for Spring Boot by VMware
"vmware.vscode-spring-boot", // Spring Boot tools by VMware for enhanced Spring development "vmware.vscode-spring-boot", // Spring Boot tools by VMware for enhanced Spring development

116
.vscode/settings.json vendored
View File

@@ -2,57 +2,147 @@
"java.compile.nullAnalysis.mode": "automatic", "java.compile.nullAnalysis.mode": "automatic",
"files.eol": "auto", "files.eol": "auto",
"java.configuration.updateBuildConfiguration": "interactive", "java.configuration.updateBuildConfiguration": "interactive",
"black-formatter.args": ["--line-length", "127"], "black-formatter.args": [
"flake8.args": ["--max-line-length", "127"], "--line-length",
"pylint.args": ["max-line-length", "127"], "127"
],
"flake8.args": [
"--max-line-length",
"127"
],
"[java]": { "[java]": {
"editor.tabSize": 4, "editor.tabSize": 4,
"editor.detectIndentation": false, "editor.detectIndentation": false,
"editor.rulers": [127] "editor.rulers": [
127
],
"editor.defaultFormatter": "josevseb.google-java-format-for-vs-code"
}, },
"[python]": { "[python]": {
"editor.tabSize": 2, "editor.tabSize": 2,
"editor.detectIndentation": false, "editor.detectIndentation": false,
"editor.rulers": [127] "editor.rulers": [
127
]
}, },
"[gradle-build]": { "[gradle-build]": {
"editor.tabSize": 4, "editor.tabSize": 4,
"editor.detectIndentation": false, "editor.detectIndentation": false,
"editor.rulers": [127] "editor.rulers": [
127
]
}, },
"[gradle]": { "[gradle]": {
"editor.tabSize": 4, "editor.tabSize": 4,
"editor.detectIndentation": false, "editor.detectIndentation": false,
"editor.rulers": [127] "editor.rulers": [
127
]
}, },
"[html]": { "[html]": {
"editor.tabSize": 2, "editor.tabSize": 2,
"editor.rulers": [127], "editor.rulers": [
127
],
"files.trimFinalNewlines": false, "files.trimFinalNewlines": false,
"files.insertFinalNewline": false "files.insertFinalNewline": false
}, },
"[javascript]": { "[javascript]": {
"editor.tabSize": 2, "editor.tabSize": 2,
"editor.rulers": [127] "editor.rulers": [
127
]
}, },
"[yaml]": { "[yaml]": {
"files.trimFinalNewlines": false, "files.trimFinalNewlines": false,
"files.insertFinalNewline": false "files.insertFinalNewline": false
}, },
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true,
"files.autoSave": "onFocusChange",
"files.autoSaveWhenNoErrors": true,
"diffEditor.maxComputationTime": 0, "diffEditor.maxComputationTime": 0,
"editor.wordSegmenterLocales": "", "editor.wordSegmenterLocales": "",
"editor.guides.bracketPairs": "active", "editor.guides.bracketPairs": "active",
"editor.guides.bracketPairsHorizontal": "active", "editor.guides.bracketPairsHorizontal": "active",
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true,
"editor.indentSize": "tabSize", "editor.indentSize": "tabSize",
"editor.stickyScroll.enabled": false, "editor.stickyScroll.enabled": false,
"editor.minimap.enabled": false, "editor.minimap.enabled": false,
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.insertSpaces": true,
"java.format.enabled": true, "java.format.enabled": true,
"java.format.settings.profile": "GoogleStyle", "java.format.settings.profile": "GoogleStyle",
"java.format.settings.google.version": "1.25.2", "java.format.settings.google.version": "1.25.2",
"java.format.settings.google.mode": "jar-file", "java.format.settings.google.mode": "jar-file",
"java.format.settings.google.extra": "--aosp --skip-sorting-imports" "java.format.settings.google.extra": "--aosp --skip-sorting-imports --skip-javadoc-formatting",
// (DE) Aktiviert Kommentare im Java-Format.
// (EN) Enables comments in Java formatting.
// "java.format.comments.enabled": true,
// (DE) Generiert automatisch Kommentare im Code.
// (EN) Automatically generates comments in code.
// "java.codeGeneration.generateComments": true,
// https://github.com/redhat-developer/vscode-java/blob/master/document/_java.learnMoreAboutCleanUps.md#java-clean-ups
"java.saveActions.cleanup": true,
"java.cleanup.actions": [
"invertEquals", // Inverts calls to Object.equals(Object) and String.equalsIgnoreCase(String) to avoid useless null pointer exception.
"instanceofPatternMatch" // Replaces instanceof checks with pattern matching.
],
// (DE) Aktiviert die Code-Vervollständigung für Java.
// (EN) Enables code completion for Java.
"java.completion.engine": "dom",
"java.completion.enabled": true,
"java.completion.importOrder": [
"java",
"javax",
"org",
"com",
"net",
"io",
"jakarta",
"lombok",
"me",
"stirling",
],
"java.project.resourceFilters": [
".devcontainer/",
".git/",
".github/",
".gradle/",
".venv/",
".venv*/",
".vscode/",
"bin/",
"build/",
"configs/",
"customFiles/",
"docs/",
"exampleYmlFiles",
"gradle/",
"images/",
"logs/",
"pipeline/",
"scripts/",
"testings/",
".git-blame-ignore-revs",
".gitattributes",
".gitignore",
".pre-commit-config.yaml",
],
// Enables signature help in Java.
"java.signatureHelp.enabled": true,
// Enables detailed signature help descriptions.
"java.signatureHelp.description.enabled": true,
// Downloads sources for Maven dependencies.
"java.maven.downloadSources": true,
// Enables Gradle project import.
"java.import.gradle.enabled": true,
// Downloads sources for Eclipse projects.
"java.eclipse.downloadSources": true,
// Enables import of the Gradle wrapper.
"java.import.gradle.wrapper.enabled": true,
"spring.initializr.defaultLanguage": "Java",
"spring.initializr.defaultGroupId": "stirling.software.SPDF",
"spring.initializr.defaultArtifactId": "SPDF",
"cSpell.enabled": false,
} }

View File

@@ -11,14 +11,12 @@ Fork Stirling-PDF and create a new branch out of `main`.
Then add a reference to the language in the navbar by adding a new language entry to the dropdown: Then add a reference to the language in the navbar by adding a new language entry to the dropdown:
- Edit the file: [languages.html](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/templates/fragments/languages.html) - Edit the file: [languages.html](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/templates/fragments/languages.html)
- Add a flag SVG file to: [flags directory](https://github.com/Stirling-Tools/Stirling-PDF/tree/main/src/main/resources/static/images/flags)
Any SVG flags are fine; most of the current ones were sourced from [here](https://flagicons.lipis.dev/). If your language isn't represented by a flag, choose a similar one, such as Saudi Arabia's flag for Arabic.
For example, to add Polish, you would add: For example, to add Polish, you would add:
```html ```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> <div th:replace="~{fragments/languageEntry :: languageEntry ('pl_PL', 'Polski')}" ></div>
``` ```
The `data-bs-language-code` is the code used to reference the file in the next step. The `data-bs-language-code` is the code used to reference the file in the next step.

View File

@@ -119,10 +119,10 @@ Stirling-PDF currently supports 39 languages!
| Arabic (العربية) (ar_AR) | ![89%](https://geps.dev/progress/89) | | Arabic (العربية) (ar_AR) | ![89%](https://geps.dev/progress/89) |
| Azerbaijani (Azərbaycan Dili) (az_AZ) | ![88%](https://geps.dev/progress/88) | | Azerbaijani (Azərbaycan Dili) (az_AZ) | ![88%](https://geps.dev/progress/88) |
| Basque (Euskara) (eu_ES) | ![51%](https://geps.dev/progress/51) | | Basque (Euskara) (eu_ES) | ![51%](https://geps.dev/progress/51) |
| Bulgarian (Български) (bg_BG) | ![85%](https://geps.dev/progress/85) | | Bulgarian (Български) (bg_BG) | ![99%](https://geps.dev/progress/99) |
| Catalan (Català) (ca_CA) | ![80%](https://geps.dev/progress/80) | | Catalan (Català) (ca_CA) | ![80%](https://geps.dev/progress/80) |
| Croatian (Hrvatski) (hr_HR) | ![87%](https://geps.dev/progress/87) | | Croatian (Hrvatski) (hr_HR) | ![86%](https://geps.dev/progress/86) |
| Czech (Česky) (cs_CZ) | ![98%](https://geps.dev/progress/98) | | Czech (Česky) (cs_CZ) | ![97%](https://geps.dev/progress/97) |
| Danish (Dansk) (da_DK) | ![85%](https://geps.dev/progress/85) | | Danish (Dansk) (da_DK) | ![85%](https://geps.dev/progress/85) |
| Dutch (Nederlands) (nl_NL) | ![85%](https://geps.dev/progress/85) | | Dutch (Nederlands) (nl_NL) | ![85%](https://geps.dev/progress/85) |
| English (English) (en_GB) | ![100%](https://geps.dev/progress/100) | | English (English) (en_GB) | ![100%](https://geps.dev/progress/100) |
@@ -142,15 +142,15 @@ Stirling-PDF currently supports 39 languages!
| Polish (Polski) (pl_PL) | ![85%](https://geps.dev/progress/85) | | Polish (Polski) (pl_PL) | ![85%](https://geps.dev/progress/85) |
| Portuguese (Português) (pt_PT) | ![97%](https://geps.dev/progress/97) | | Portuguese (Português) (pt_PT) | ![97%](https://geps.dev/progress/97) |
| Portuguese Brazilian (Português) (pt_BR) | ![98%](https://geps.dev/progress/98) | | Portuguese Brazilian (Português) (pt_BR) | ![98%](https://geps.dev/progress/98) |
| Romanian (Română) (ro_RO) | ![81%](https://geps.dev/progress/81) | | Romanian (Română) (ro_RO) | ![80%](https://geps.dev/progress/80) |
| Russian (Русский) (ru_RU) | ![98%](https://geps.dev/progress/98) | | Russian (Русский) (ru_RU) | ![97%](https://geps.dev/progress/97) |
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![63%](https://geps.dev/progress/63) | | Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![63%](https://geps.dev/progress/63) |
| Simplified Chinese (简体中文) (zh_CN) | ![99%](https://geps.dev/progress/99) | | Simplified Chinese (简体中文) (zh_CN) | ![99%](https://geps.dev/progress/99) |
| Slovakian (Slovensky) (sk_SK) | ![74%](https://geps.dev/progress/74) | | Slovakian (Slovensky) (sk_SK) | ![74%](https://geps.dev/progress/74) |
| Slovenian (Slovenščina) (sl_SI) | ![97%](https://geps.dev/progress/97) | | Slovenian (Slovenščina) (sl_SI) | ![96%](https://geps.dev/progress/96) |
| Spanish (Español) (es_ES) | ![87%](https://geps.dev/progress/87) | | Spanish (Español) (es_ES) | ![86%](https://geps.dev/progress/86) |
| Swedish (Svenska) (sv_SE) | ![92%](https://geps.dev/progress/92) | | Swedish (Svenska) (sv_SE) | ![92%](https://geps.dev/progress/92) |
| Thai (ไทย) (th_TH) | ![86%](https://geps.dev/progress/86) | | Thai (ไทย) (th_TH) | ![85%](https://geps.dev/progress/85) |
| Tibetan (བོད་ཡིག་) (zh_BO) | ![94%](https://geps.dev/progress/94) | | Tibetan (བོད་ཡིག་) (zh_BO) | ![94%](https://geps.dev/progress/94) |
| Traditional Chinese (繁體中文) (zh_TW) | ![98%](https://geps.dev/progress/98) | | Traditional Chinese (繁體中文) (zh_TW) | ![98%](https://geps.dev/progress/98) |
| Turkish (Türkçe) (tr_TR) | ![82%](https://geps.dev/progress/82) | | Turkish (Türkçe) (tr_TR) | ![82%](https://geps.dev/progress/82) |

View File

@@ -260,7 +260,7 @@ spotless {
googleJavaFormat("1.25.2").aosp().reorderImports(false) googleJavaFormat("1.25.2").aosp().reorderImports(false)
importOrder("java", "javax", "org", "com", "net", "io") importOrder("java", "javax", "org", "com", "net", "io", "jakarta", "lombok", "me", "stirling")
toggleOffOn() toggleOffOn()
trimTrailingWhitespace() trimTrailingWhitespace()
leadingTabsToSpaces() leadingTabsToSpaces()
@@ -272,7 +272,7 @@ sonar {
properties { properties {
property "sonar.projectKey", "Stirling-Tools_Stirling-PDF" property "sonar.projectKey", "Stirling-Tools_Stirling-PDF"
property "sonar.organization", "stirling-tools" 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.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.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/**" 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/**"
@@ -297,14 +297,14 @@ dependencies {
implementation 'ch.qos.logback:logback-core:1.5.15' implementation 'ch.qos.logback:logback-core:1.5.15'
implementation 'ch.qos.logback:logback-classic:1.5.15' implementation 'ch.qos.logback:logback-classic:1.5.15'
// Exclude vulnerable BouncyCastle version used in tableau // Exclude vulnerable BouncyCastle version used in tableau
configurations.all { configurations.all {
exclude group: 'org.bouncycastle', module: 'bcpkix-jdk15on' exclude group: 'org.bouncycastle', module: 'bcpkix-jdk15on'
exclude group: 'org.bouncycastle', module: 'bcutil-jdk15on' exclude group: 'org.bouncycastle', module: 'bcutil-jdk15on'
exclude group: 'org.bouncycastle', module: 'bcmail-jdk15on' exclude group: 'org.bouncycastle', module: 'bcmail-jdk15on'
} }
if (System.getenv("STIRLING_PDF_DESKTOP_UI") != "false") { if (System.getenv("STIRLING_PDF_DESKTOP_UI") != "false") {
implementation 'org.apache.commons:commons-compress:1.26.0' implementation 'org.apache.commons:commons-compress:1.26.0'
implementation "me.friwi:jcefmaven:127.3.1" implementation "me.friwi:jcefmaven:127.3.1"
@@ -408,7 +408,7 @@ dependencies {
implementation "org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion" implementation "org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion"
implementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion" implementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion"
implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion"
implementation "io.micrometer:micrometer-core:1.14.3" implementation "io.micrometer:micrometer-core:1.14.4"
implementation group: "com.google.zxing", name: "core", version: "3.5.3" implementation group: "com.google.zxing", name: "core", version: "3.5.3"
// https://mvnrepository.com/artifact/org.commonmark/commonmark // https://mvnrepository.com/artifact/org.commonmark/commonmark
implementation "org.commonmark:commonmark:0.24.0" implementation "org.commonmark:commonmark:0.24.0"

View File

@@ -6,6 +6,7 @@ import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
@Configuration @Configuration

View File

@@ -13,6 +13,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.posthog.java.shaded.org.json.JSONObject; import com.posthog.java.shaded.org.json.JSONObject;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.utils.GeneralUtils;

View File

@@ -7,6 +7,7 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.utils.GeneralUtils;

View File

@@ -22,7 +22,9 @@ import io.github.pixee.security.SystemCommand;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy; import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.UI.WebBrowser; import stirling.software.SPDF.UI.WebBrowser;
import stirling.software.SPDF.config.ConfigInitializer; import stirling.software.SPDF.config.ConfigInitializer;
import stirling.software.SPDF.config.InstallationPathConfig; import stirling.software.SPDF.config.InstallationPathConfig;

View File

@@ -34,11 +34,14 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import jakarta.annotation.PreDestroy; import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.friwi.jcefmaven.CefAppBuilder; import me.friwi.jcefmaven.CefAppBuilder;
import me.friwi.jcefmaven.EnumProgress; import me.friwi.jcefmaven.EnumProgress;
import me.friwi.jcefmaven.MavenCefAppHandlerAdapter; import me.friwi.jcefmaven.MavenCefAppHandlerAdapter;
import me.friwi.jcefmaven.impl.progress.ConsoleProgressHandler; import me.friwi.jcefmaven.impl.progress.ConsoleProgressHandler;
import stirling.software.SPDF.UI.WebBrowser; import stirling.software.SPDF.UI.WebBrowser;
import stirling.software.SPDF.config.InstallationPathConfig; import stirling.software.SPDF.config.InstallationPathConfig;
import stirling.software.SPDF.utils.UIScaling; import stirling.software.SPDF.utils.UIScaling;

View File

@@ -14,6 +14,7 @@ import javax.swing.*;
import io.github.pixee.security.BoundedLineReader; import io.github.pixee.security.BoundedLineReader;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.utils.UIScaling; import stirling.software.SPDF.utils.UIScaling;
@Slf4j @Slf4j

View File

@@ -20,6 +20,7 @@ import org.springframework.core.io.ResourceLoader;
import org.thymeleaf.spring6.SpringTemplateEngine; import org.thymeleaf.spring6.SpringTemplateEngine;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
@Configuration @Configuration
@@ -127,15 +128,6 @@ public class AppConfig {
} }
} }
@Bean(name = "bookAndHtmlFormatsInstalled")
public boolean bookAndHtmlFormatsInstalled() {
String installOps = System.getProperty("INSTALL_BOOK_AND_ADVANCED_HTML_OPS");
if (installOps == null) {
installOps = System.getenv("INSTALL_BOOK_AND_ADVANCED_HTML_OPS");
}
return "true".equalsIgnoreCase(installOps);
}
@ConditionalOnMissingClass("stirling.software.SPDF.config.security.SecurityConfiguration") @ConditionalOnMissingClass("stirling.software.SPDF.config.security.SecurityConfiguration")
@Bean(name = "activSecurity") @Bean(name = "activSecurity")
public boolean missingActivSecurity() { public boolean missingActivSecurity() {

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.config; package stirling.software.SPDF.config;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -9,30 +8,24 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
@Service @Service
@Slf4j @Slf4j
@DependsOn({"bookAndHtmlFormatsInstalled"})
public class EndpointConfiguration { public class EndpointConfiguration {
private static final String REMOVE_BLANKS = "remove-blanks"; private static final String REMOVE_BLANKS = "remove-blanks";
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>(); private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>();
private Map<String, Set<String>> endpointGroups = new ConcurrentHashMap<>(); private Map<String, Set<String>> endpointGroups = new ConcurrentHashMap<>();
private boolean bookAndHtmlFormatsInstalled;
@Autowired @Autowired
public EndpointConfiguration( public EndpointConfiguration(ApplicationProperties applicationProperties) {
ApplicationProperties applicationProperties,
@Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled) {
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
this.bookAndHtmlFormatsInstalled = bookAndHtmlFormatsInstalled;
init(); init();
processEnvironmentConfigs(); processEnvironmentConfigs();
} }
@@ -197,8 +190,8 @@ public class EndpointConfiguration {
addEndpointToGroup("LibreOffice", "pdf-to-html"); addEndpointToGroup("LibreOffice", "pdf-to-html");
addEndpointToGroup("LibreOffice", "pdf-to-xml"); addEndpointToGroup("LibreOffice", "pdf-to-xml");
// Unoconv // Unoconvert
addEndpointToGroup("Unoconv", "file-to-pdf"); addEndpointToGroup("Unoconvert", "file-to-pdf");
// qpdf // qpdf
addEndpointToGroup("qpdf", "compress-pdf"); addEndpointToGroup("qpdf", "compress-pdf");
@@ -272,12 +265,6 @@ public class EndpointConfiguration {
List<String> endpointsToRemove = applicationProperties.getEndpoints().getToRemove(); List<String> endpointsToRemove = applicationProperties.getEndpoints().getToRemove();
List<String> groupsToRemove = applicationProperties.getEndpoints().getGroupsToRemove(); List<String> groupsToRemove = applicationProperties.getEndpoints().getGroupsToRemove();
if (!bookAndHtmlFormatsInstalled) {
if (groupsToRemove == null) {
groupsToRemove = new ArrayList<>();
}
groupsToRemove.add("Calibre");
}
if (endpointsToRemove != null) { if (endpointsToRemove != null) {
for (String endpoint : endpointsToRemove) { for (String endpoint : endpointsToRemove) {
disableEndpoint(endpoint.trim()); disableEndpoint(endpoint.trim());

View File

@@ -9,6 +9,7 @@ import java.util.stream.Collectors;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Configuration @Configuration
@@ -16,21 +17,29 @@ import lombok.extern.slf4j.Slf4j;
public class ExternalAppDepConfig { public class ExternalAppDepConfig {
private final EndpointConfiguration endpointConfiguration; private final EndpointConfiguration endpointConfiguration;
private final Map<String, List<String>> commandToGroupMapping =
new HashMap<>() {
{ private final String weasyprintPath;
put("soffice", List.of("LibreOffice")); private final String unoconvPath;
put("/opt/venv/bin/weasyprint", List.of("Weasyprint")); private final Map<String, List<String>> commandToGroupMapping;
put("pdftohtml", List.of("Pdftohtml"));
put("/opt/venv/bin/unoconvert", List.of("Unoconv"));
put("qpdf", List.of("qpdf"));
put("tesseract", List.of("tesseract"));
}
};
public ExternalAppDepConfig(EndpointConfiguration endpointConfiguration) { public ExternalAppDepConfig(
EndpointConfiguration endpointConfiguration, RuntimePathConfig runtimePathConfig) {
this.endpointConfiguration = endpointConfiguration; this.endpointConfiguration = endpointConfiguration;
weasyprintPath = runtimePathConfig.getWeasyPrintPath();
unoconvPath = runtimePathConfig.getUnoConvertPath();
commandToGroupMapping =
new HashMap<>() {
{
put("soffice", List.of("LibreOffice"));
put(weasyprintPath, List.of("Weasyprint"));
put("pdftohtml", List.of("Pdftohtml"));
put(unoconvPath, List.of("Unoconvert"));
put("qpdf", List.of("qpdf"));
put("tesseract", List.of("tesseract"));
}
};
} }
private boolean isCommandAvailable(String command) { private boolean isCommandAvailable(String command) {
@@ -101,9 +110,9 @@ public class ExternalAppDepConfig {
checkDependencyAndDisableGroup("tesseract"); checkDependencyAndDisableGroup("tesseract");
checkDependencyAndDisableGroup("soffice"); checkDependencyAndDisableGroup("soffice");
checkDependencyAndDisableGroup("qpdf"); checkDependencyAndDisableGroup("qpdf");
checkDependencyAndDisableGroup("/opt/venv/bin/weasyprint"); checkDependencyAndDisableGroup(weasyprintPath);
checkDependencyAndDisableGroup("pdftohtml"); checkDependencyAndDisableGroup("pdftohtml");
checkDependencyAndDisableGroup("/opt/venv/bin/unoconvert"); checkDependencyAndDisableGroup(unoconvPath);
// Special handling for Python/OpenCV dependencies // Special handling for Python/OpenCV dependencies
boolean pythonAvailable = isCommandAvailable("python3") || isCommandAvailable("python"); boolean pythonAvailable = isCommandAvailable("python3") || isCommandAvailable("python");
if (!pythonAvailable) { if (!pythonAvailable) {

View File

@@ -13,7 +13,9 @@ import org.springframework.stereotype.Component;
import io.micrometer.common.util.StringUtils; import io.micrometer.common.util.StringUtils;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.utils.GeneralUtils;

View File

@@ -11,7 +11,6 @@ public class InstallationPathConfig {
// Root paths // Root paths
private static final String LOG_PATH; private static final String LOG_PATH;
private static final String CONFIG_PATH; private static final String CONFIG_PATH;
private static final String PIPELINE_PATH;
private static final String CUSTOM_FILES_PATH; private static final String CUSTOM_FILES_PATH;
private static final String CLIENT_WEBUI_PATH; private static final String CLIENT_WEBUI_PATH;
@@ -19,11 +18,6 @@ public class InstallationPathConfig {
private static final String SETTINGS_PATH; private static final String SETTINGS_PATH;
private static final String CUSTOM_SETTINGS_PATH; private static final String CUSTOM_SETTINGS_PATH;
// Pipeline paths
private static final String PIPELINE_WATCHED_FOLDERS_PATH;
private static final String PIPELINE_FINISHED_FOLDERS_PATH;
private static final String PIPELINE_DEFAULT_WEB_UI_CONFIGS;
// Custom file paths // Custom file paths
private static final String STATIC_PATH; private static final String STATIC_PATH;
private static final String TEMPLATES_PATH; private static final String TEMPLATES_PATH;
@@ -35,7 +29,6 @@ public class InstallationPathConfig {
// Initialize root paths // Initialize root paths
LOG_PATH = BASE_PATH + "logs" + File.separator; LOG_PATH = BASE_PATH + "logs" + File.separator;
CONFIG_PATH = BASE_PATH + "configs" + File.separator; CONFIG_PATH = BASE_PATH + "configs" + File.separator;
PIPELINE_PATH = BASE_PATH + "pipeline" + File.separator;
CUSTOM_FILES_PATH = BASE_PATH + "customFiles" + File.separator; CUSTOM_FILES_PATH = BASE_PATH + "customFiles" + File.separator;
CLIENT_WEBUI_PATH = BASE_PATH + "clientWebUI" + File.separator; CLIENT_WEBUI_PATH = BASE_PATH + "clientWebUI" + File.separator;
@@ -43,11 +36,6 @@ public class InstallationPathConfig {
SETTINGS_PATH = CONFIG_PATH + "settings.yml"; SETTINGS_PATH = CONFIG_PATH + "settings.yml";
CUSTOM_SETTINGS_PATH = CONFIG_PATH + "custom_settings.yml"; CUSTOM_SETTINGS_PATH = CONFIG_PATH + "custom_settings.yml";
// Initialize pipeline paths
PIPELINE_WATCHED_FOLDERS_PATH = PIPELINE_PATH + "watchedFolders" + File.separator;
PIPELINE_FINISHED_FOLDERS_PATH = PIPELINE_PATH + "finishedFolders" + File.separator;
PIPELINE_DEFAULT_WEB_UI_CONFIGS = PIPELINE_PATH + "defaultWebUIConfigs" + File.separator;
// Initialize custom file paths // Initialize custom file paths
STATIC_PATH = CUSTOM_FILES_PATH + "static" + File.separator; STATIC_PATH = CUSTOM_FILES_PATH + "static" + File.separator;
TEMPLATES_PATH = CUSTOM_FILES_PATH + "templates" + File.separator; TEMPLATES_PATH = CUSTOM_FILES_PATH + "templates" + File.separator;
@@ -92,10 +80,6 @@ public class InstallationPathConfig {
return CONFIG_PATH; return CONFIG_PATH;
} }
public static String getPipelinePath() {
return PIPELINE_PATH;
}
public static String getCustomFilesPath() { public static String getCustomFilesPath() {
return CUSTOM_FILES_PATH; return CUSTOM_FILES_PATH;
} }
@@ -112,18 +96,6 @@ public class InstallationPathConfig {
return CUSTOM_SETTINGS_PATH; return CUSTOM_SETTINGS_PATH;
} }
public static String getPipelineWatchedFoldersDir() {
return PIPELINE_WATCHED_FOLDERS_PATH;
}
public static String getPipelineFinishedFoldersDir() {
return PIPELINE_FINISHED_FOLDERS_PATH;
}
public static String getPipelineDefaultWebUIConfigsDir() {
return PIPELINE_DEFAULT_WEB_UI_CONFIGS;
}
public static String getStaticPath() { public static String getStaticPath() {
return STATIC_PATH; return STATIC_PATH;
} }

View File

@@ -14,6 +14,7 @@ import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
import stirling.software.SPDF.utils.RequestUriUtils; import stirling.software.SPDF.utils.RequestUriUtils;
@Component @Component

View File

@@ -7,6 +7,7 @@ import org.springframework.context.annotation.Configuration;
import com.posthog.java.PostHog; import com.posthog.java.PostHog;
import jakarta.annotation.PreDestroy; import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Configuration @Configuration

View File

@@ -0,0 +1,86 @@
package stirling.software.SPDF.config;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Configuration;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.CustomPaths.Operations;
import stirling.software.SPDF.model.ApplicationProperties.CustomPaths.Pipeline;
@Slf4j
@Configuration
@Getter
public class RuntimePathConfig {
private final ApplicationProperties properties;
private final String basePath;
private final String weasyPrintPath;
private final String unoConvertPath;
// Pipeline paths
private final String pipelineWatchedFoldersPath;
private final String pipelineFinishedFoldersPath;
private final String pipelineDefaultWebUiConfigs;
private final String pipelinePath;
public RuntimePathConfig(ApplicationProperties properties) {
this.properties = properties;
this.basePath = InstallationPathConfig.getPath();
String pipelinePath = basePath + "pipeline" + File.separator;
String watchedFoldersPath = pipelinePath + "watchedFolders" + File.separator;
String finishedFoldersPath = pipelinePath + "finishedFolders" + File.separator;
String webUiConfigsPath = pipelinePath + "defaultWebUIConfigs" + File.separator;
Pipeline pipeline = properties.getSystem().getCustomPaths().getPipeline();
if (pipeline != null) {
if (!StringUtils.isEmpty(pipeline.getWatchedFoldersDir())) {
watchedFoldersPath = pipeline.getWatchedFoldersDir();
}
if (!StringUtils.isEmpty(pipeline.getFinishedFoldersDir())) {
finishedFoldersPath = pipeline.getFinishedFoldersDir();
}
if (!StringUtils.isEmpty(pipeline.getWebUIConfigsDir())) {
webUiConfigsPath = pipeline.getWebUIConfigsDir();
}
}
this.pipelinePath = pipelinePath;
this.pipelineWatchedFoldersPath = watchedFoldersPath;
this.pipelineFinishedFoldersPath = finishedFoldersPath;
this.pipelineDefaultWebUiConfigs = webUiConfigsPath;
boolean isDocker = isRunningInDocker();
// Initialize Operation paths
String weasyPrintPath = isDocker ? "/opt/venv/bin/weasyprint" : "weasyprint";
String unoConvertPath = isDocker ? "/opt/venv/bin/unoconvert" : "unoconvert";
// Check for custom operation paths
Operations operations = properties.getSystem().getCustomPaths().getOperations();
if (operations != null) {
if (!StringUtils.isEmpty(operations.getWeasyprint())) {
weasyPrintPath = operations.getWeasyprint();
}
if (!StringUtils.isEmpty(operations.getUnoconvert())) {
unoConvertPath = operations.getUnoconvert();
}
}
// Assign operations final fields
this.weasyPrintPath = weasyPrintPath;
this.unoConvertPath = unoConvertPath;
}
private boolean isRunningInDocker() {
return Files.exists(Paths.get("/.dockerenv"));
}
}

View File

@@ -14,7 +14,9 @@ import org.springframework.security.web.authentication.SimpleUrlAuthenticationFa
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.User; import stirling.software.SPDF.model.User;
@Slf4j @Slf4j

View File

@@ -10,7 +10,9 @@ import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.utils.RequestUriUtils; import stirling.software.SPDF.utils.RequestUriUtils;
@Slf4j @Slf4j

View File

@@ -18,8 +18,10 @@ import com.coveo.saml.SamlClient;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.SPDFApplication; import stirling.software.SPDF.SPDFApplication;
import stirling.software.SPDF.config.security.saml2.CertificateUtils; import stirling.software.SPDF.config.security.saml2.CertificateUtils;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal; import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;

View File

@@ -16,7 +16,9 @@ import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.User; import stirling.software.SPDF.model.User;
import stirling.software.SPDF.utils.RequestUriUtils; import stirling.software.SPDF.utils.RequestUriUtils;

View File

@@ -6,6 +6,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import jakarta.servlet.*; import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import stirling.software.SPDF.utils.RequestUriUtils; import stirling.software.SPDF.utils.RequestUriUtils;
public class IPRateLimitingFilter implements Filter { public class IPRateLimitingFilter implements Filter {

View File

@@ -6,7 +6,9 @@ import java.util.UUID;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.interfaces.DatabaseInterface; import stirling.software.SPDF.config.interfaces.DatabaseInterface;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.Role; import stirling.software.SPDF.model.Role;

View File

@@ -6,7 +6,9 @@ import java.util.concurrent.TimeUnit;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.AttemptCounter; import stirling.software.SPDF.model.AttemptCounter;

View File

@@ -29,6 +29,7 @@ import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationFailureHandler; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationFailureHandler;
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationSuccessHandler; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationSuccessHandler;
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2UserService; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2UserService;

View File

@@ -22,7 +22,9 @@ import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal; import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
import stirling.software.SPDF.model.ApiKeyAuthenticationToken; import stirling.software.SPDF.model.ApiKeyAuthenticationToken;

View File

@@ -23,6 +23,7 @@ import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import stirling.software.SPDF.model.Role; import stirling.software.SPDF.model.Role;
@Component @Component

View File

@@ -21,6 +21,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.interfaces.DatabaseInterface; import stirling.software.SPDF.config.interfaces.DatabaseInterface;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal; import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
@@ -139,6 +140,9 @@ public class UserService implements UserServiceInterface {
User user = User user =
findByUsernameIgnoreCase(username) findByUsernameIgnoreCase(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found")); .orElseThrow(() -> new UsernameNotFoundException("User not found"));
if (user.getApiKey() == null || user.getApiKey().length() == 0) {
user = addApiKeyToUser(username);
}
return user.getApiKey(); return user.getApiKey();
} }

View File

@@ -11,6 +11,7 @@ import org.springframework.context.annotation.Configuration;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.InstallationPathConfig; import stirling.software.SPDF.config.InstallationPathConfig;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.provider.UnsupportedProviderException; import stirling.software.SPDF.model.provider.UnsupportedProviderException;

View File

@@ -26,6 +26,7 @@ import org.springframework.jdbc.datasource.init.ScriptException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.InstallationPathConfig; import stirling.software.SPDF.config.InstallationPathConfig;
import stirling.software.SPDF.config.interfaces.DatabaseInterface; import stirling.software.SPDF.config.interfaces.DatabaseInterface;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;

View File

@@ -13,6 +13,7 @@ import org.springframework.security.web.authentication.SimpleUrlAuthenticationFa
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j

View File

@@ -14,6 +14,7 @@ import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
import stirling.software.SPDF.config.security.LoginAttemptService; import stirling.software.SPDF.config.security.LoginAttemptService;
import stirling.software.SPDF.config.security.UserService; import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;

View File

@@ -12,6 +12,7 @@ import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.oidc.user.OidcUser; import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.LoginAttemptService; import stirling.software.SPDF.config.security.LoginAttemptService;
import stirling.software.SPDF.config.security.UserService; import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;

View File

@@ -20,6 +20,7 @@ import org.springframework.security.oauth2.client.registration.InMemoryClientReg
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.UserService; import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2; import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;

View File

@@ -11,6 +11,7 @@ import org.springframework.security.web.authentication.SimpleUrlAuthenticationFa
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j

View File

@@ -12,8 +12,10 @@ import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.LoginAttemptService; import stirling.software.SPDF.config.security.LoginAttemptService;
import stirling.software.SPDF.config.security.UserService; import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;

View File

@@ -13,6 +13,7 @@ import org.springframework.security.saml2.provider.service.authentication.OpenSa
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.UserService; import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.User; import stirling.software.SPDF.model.User;

View File

@@ -18,7 +18,9 @@ import org.springframework.security.saml2.provider.service.registration.Saml2Mes
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver; import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2; import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2;

View File

@@ -5,6 +5,7 @@ import org.springframework.stereotype.Component;
import jakarta.servlet.http.HttpSessionEvent; import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener; import jakarta.servlet.http.HttpSessionListener;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Component @Component

View File

@@ -11,6 +11,7 @@ import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import jakarta.transaction.Transactional; import jakarta.transaction.Transactional;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal; import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.SPDF.model.SessionEntity; import stirling.software.SPDF.model.SessionEntity;

View File

@@ -10,6 +10,7 @@ import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import jakarta.transaction.Transactional; import jakarta.transaction.Transactional;
import stirling.software.SPDF.model.SessionEntity; import stirling.software.SPDF.model.SessionEntity;
@Repository @Repository

View File

@@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.Hidden;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import stirling.software.SPDF.service.LanguageService; import stirling.software.SPDF.service.LanguageService;
@RestController @RestController

View File

@@ -25,6 +25,7 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.database.DatabaseService; import stirling.software.SPDF.config.security.database.DatabaseService;
@Slf4j @Slf4j

View File

@@ -32,6 +32,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.general.MergePdfsRequest; import stirling.software.SPDF.model.api.general.MergePdfsRequest;
import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.utils.GeneralUtils;

View File

@@ -21,6 +21,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.SortTypes; import stirling.software.SPDF.model.SortTypes;
import stirling.software.SPDF.model.api.PDFWithPageNums; import stirling.software.SPDF.model.api.PDFWithPageNums;
import stirling.software.SPDF.model.api.general.RearrangePagesRequest; import stirling.software.SPDF.model.api.general.RearrangePagesRequest;

View File

@@ -27,6 +27,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.PDFWithPageNums; import stirling.software.SPDF.model.api.PDFWithPageNums;
import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils; import stirling.software.SPDF.utils.WebResponseUtils;

View File

@@ -31,6 +31,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.PdfMetadata; import stirling.software.SPDF.model.PdfMetadata;
import stirling.software.SPDF.model.api.SplitPdfByChaptersRequest; import stirling.software.SPDF.model.api.SplitPdfByChaptersRequest;
import stirling.software.SPDF.service.PdfMetadataService; import stirling.software.SPDF.service.PdfMetadataService;

View File

@@ -24,6 +24,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.general.SplitPdfBySizeOrCountRequest; import stirling.software.SPDF.model.api.general.SplitPdfBySizeOrCountRequest;
import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.utils.GeneralUtils;

View File

@@ -26,7 +26,9 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.UserService; import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal; import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;

View File

@@ -1,77 +0,0 @@
package stirling.software.SPDF.controller.api.converters;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation;
import stirling.software.SPDF.model.api.GeneralFile;
import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.FileToPdf;
import stirling.software.SPDF.utils.WebResponseUtils;
// @RestController
// @Tag(name = "Convert", description = "Convert APIs")
// @RequestMapping("/api/v1/convert")
public class ConvertBookToPDFController {
private final boolean bookAndHtmlFormatsInstalled;
private final CustomPDDocumentFactory pdfDocumentFactory;
@Autowired
public ConvertBookToPDFController(
CustomPDDocumentFactory pdfDocumentFactory,
@Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled) {
this.pdfDocumentFactory = pdfDocumentFactory;
this.bookAndHtmlFormatsInstalled = bookAndHtmlFormatsInstalled;
}
@PostMapping(consumes = "multipart/form-data", value = "/book/pdf")
@Operation(
summary =
"Convert a BOOK/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx) to PDF",
description =
"(Requires bookAndHtmlFormatsInstalled flag and Calibre installed) This endpoint takes an BOOK/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx) input and converts it to PDF format.")
public ResponseEntity<byte[]> HtmlToPdf(@ModelAttribute GeneralFile request) throws Exception {
MultipartFile fileInput = request.getFileInput();
if (!bookAndHtmlFormatsInstalled) {
throw new IllegalArgumentException(
"bookAndHtmlFormatsInstalled flag is False, this functionality is not available");
}
if (fileInput == null) {
throw new IllegalArgumentException("Please provide a file for conversion.");
}
String originalFilename = Filenames.toSimpleFileName(fileInput.getOriginalFilename());
if (originalFilename != null) {
String originalFilenameLower = originalFilename.toLowerCase();
if (!originalFilenameLower.endsWith(".epub")
&& !originalFilenameLower.endsWith(".mobi")
&& !originalFilenameLower.endsWith(".azw3")
&& !originalFilenameLower.endsWith(".fb2")
&& !originalFilenameLower.endsWith(".txt")
&& !originalFilenameLower.endsWith(".docx")) {
throw new IllegalArgumentException(
"File must be in .epub, .mobi, .azw3, .fb2, .txt, or .docx format.");
}
}
byte[] pdfBytes = FileToPdf.convertBookTypeToPdf(fileInput.getBytes(), originalFilename);
pdfBytes = pdfDocumentFactory.createNewBytesBasedOnOldDocument(pdfBytes);
String outputFilename =
originalFilename.replaceFirst("[.][^.]+$", "")
+ ".pdf"; // Remove file extension and append .pdf
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
}
}

View File

@@ -1,7 +1,6 @@
package stirling.software.SPDF.controller.api.converters; package stirling.software.SPDF.controller.api.converters;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@@ -13,6 +12,7 @@ import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.config.RuntimePathConfig;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest; import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest;
import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.service.CustomPDDocumentFactory;
@@ -24,20 +24,21 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@RequestMapping("/api/v1/convert") @RequestMapping("/api/v1/convert")
public class ConvertHtmlToPDF { public class ConvertHtmlToPDF {
private final boolean bookAndHtmlFormatsInstalled;
private final CustomPDDocumentFactory pdfDocumentFactory; private final CustomPDDocumentFactory pdfDocumentFactory;
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private final RuntimePathConfig runtimePathConfig;
@Autowired @Autowired
public ConvertHtmlToPDF( public ConvertHtmlToPDF(
CustomPDDocumentFactory pdfDocumentFactory, CustomPDDocumentFactory pdfDocumentFactory,
@Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled, ApplicationProperties applicationProperties,
ApplicationProperties applicationProperties) { RuntimePathConfig runtimePathConfig) {
this.pdfDocumentFactory = pdfDocumentFactory; this.pdfDocumentFactory = pdfDocumentFactory;
this.bookAndHtmlFormatsInstalled = bookAndHtmlFormatsInstalled;
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
this.runtimePathConfig = runtimePathConfig;
} }
@PostMapping(consumes = "multipart/form-data", value = "/html/pdf") @PostMapping(consumes = "multipart/form-data", value = "/html/pdf")
@@ -65,10 +66,10 @@ public class ConvertHtmlToPDF {
byte[] pdfBytes = byte[] pdfBytes =
FileToPdf.convertHtmlToPdf( FileToPdf.convertHtmlToPdf(
runtimePathConfig.getWeasyPrintPath(),
request, request,
fileInput.getBytes(), fileInput.getBytes(),
originalFilename, originalFilename,
bookAndHtmlFormatsInstalled,
disableSanitize); disableSanitize);
pdfBytes = pdfDocumentFactory.createNewBytesBasedOnOldDocument(pdfBytes); pdfBytes = pdfDocumentFactory.createNewBytesBasedOnOldDocument(pdfBytes);

View File

@@ -31,6 +31,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.converters.ConvertToImageRequest; import stirling.software.SPDF.model.api.converters.ConvertToImageRequest;
import stirling.software.SPDF.model.api.converters.ConvertToPdfRequest; import stirling.software.SPDF.model.api.converters.ConvertToPdfRequest;
import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.service.CustomPDDocumentFactory;

View File

@@ -11,7 +11,6 @@ import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.AttributeProvider; import org.commonmark.renderer.html.AttributeProvider;
import org.commonmark.renderer.html.HtmlRenderer; import org.commonmark.renderer.html.HtmlRenderer;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@@ -23,6 +22,7 @@ import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.config.RuntimePathConfig;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.api.GeneralFile; import stirling.software.SPDF.model.api.GeneralFile;
import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.service.CustomPDDocumentFactory;
@@ -34,20 +34,20 @@ import stirling.software.SPDF.utils.WebResponseUtils;
@RequestMapping("/api/v1/convert") @RequestMapping("/api/v1/convert")
public class ConvertMarkdownToPdf { public class ConvertMarkdownToPdf {
private final boolean bookAndHtmlFormatsInstalled;
private final CustomPDDocumentFactory pdfDocumentFactory; private final CustomPDDocumentFactory pdfDocumentFactory;
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private final RuntimePathConfig runtimePathConfig;
@Autowired @Autowired
public ConvertMarkdownToPdf( public ConvertMarkdownToPdf(
CustomPDDocumentFactory pdfDocumentFactory, CustomPDDocumentFactory pdfDocumentFactory,
@Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled, ApplicationProperties applicationProperties,
ApplicationProperties applicationProperties) { RuntimePathConfig runtimePathConfig) {
this.pdfDocumentFactory = pdfDocumentFactory; this.pdfDocumentFactory = pdfDocumentFactory;
this.bookAndHtmlFormatsInstalled = bookAndHtmlFormatsInstalled;
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
this.runtimePathConfig = runtimePathConfig;
} }
@PostMapping(consumes = "multipart/form-data", value = "/markdown/pdf") @PostMapping(consumes = "multipart/form-data", value = "/markdown/pdf")
@@ -86,10 +86,10 @@ public class ConvertMarkdownToPdf {
byte[] pdfBytes = byte[] pdfBytes =
FileToPdf.convertHtmlToPdf( FileToPdf.convertHtmlToPdf(
runtimePathConfig.getWeasyPrintPath(),
null, null,
htmlContent.getBytes(), htmlContent.getBytes(),
"converted.html", "converted.html",
bookAndHtmlFormatsInstalled,
disableSanitize); disableSanitize);
pdfBytes = pdfDocumentFactory.createNewBytesBasedOnOldDocument(pdfBytes); pdfBytes = pdfDocumentFactory.createNewBytesBasedOnOldDocument(pdfBytes);
String outputFilename = String outputFilename =

View File

@@ -22,6 +22,7 @@ import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.config.RuntimePathConfig;
import stirling.software.SPDF.model.api.GeneralFile; import stirling.software.SPDF.model.api.GeneralFile;
import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.ProcessExecutor; import stirling.software.SPDF.utils.ProcessExecutor;
@@ -34,10 +35,13 @@ import stirling.software.SPDF.utils.WebResponseUtils;
public class ConvertOfficeController { public class ConvertOfficeController {
private final CustomPDDocumentFactory pdfDocumentFactory; private final CustomPDDocumentFactory pdfDocumentFactory;
private final RuntimePathConfig runtimePathConfig;
@Autowired @Autowired
public ConvertOfficeController(CustomPDDocumentFactory pdfDocumentFactory) { public ConvertOfficeController(
CustomPDDocumentFactory pdfDocumentFactory, RuntimePathConfig runtimePathConfig) {
this.pdfDocumentFactory = pdfDocumentFactory; this.pdfDocumentFactory = pdfDocumentFactory;
this.runtimePathConfig = runtimePathConfig;
} }
public File convertToPdf(MultipartFile inputFile) throws IOException, InterruptedException { public File convertToPdf(MultipartFile inputFile) throws IOException, InterruptedException {
@@ -61,7 +65,7 @@ public class ConvertOfficeController {
List<String> command = List<String> command =
new ArrayList<>( new ArrayList<>(
Arrays.asList( Arrays.asList(
"/opt/venv/bin/unoconvert", runtimePathConfig.getUnoConvertPath(),
"--port", "--port",
"2003", "2003",
"--convert-to", "--convert-to",

View File

@@ -1,95 +0,0 @@
package stirling.software.SPDF.controller.api.converters;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation;
import stirling.software.SPDF.model.api.converters.PdfToBookRequest;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
import stirling.software.SPDF.utils.WebResponseUtils;
// @RestController
// @Tag(name = "Convert", description = "Convert APIs")
// @RequestMapping("/api/v1/convert")
public class ConvertPDFToBookController {
@Qualifier("bookAndHtmlFormatsInstalled")
private final boolean bookAndHtmlFormatsInstalled;
public ConvertPDFToBookController(
@Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled) {
this.bookAndHtmlFormatsInstalled = bookAndHtmlFormatsInstalled;
}
@PostMapping(consumes = "multipart/form-data", value = "/pdf/book")
@Operation(
summary =
"Convert a PDF to a Book/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx .. (others to include by chatgpt) to PDF",
description =
"(Requires bookAndHtmlFormatsInstalled flag and Calibre installed) This endpoint Convert a PDF to a Book/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx .. (others to include by chatgpt) to PDF")
public ResponseEntity<byte[]> HtmlToPdf(@ModelAttribute PdfToBookRequest request)
throws Exception {
MultipartFile fileInput = request.getFileInput();
if (!bookAndHtmlFormatsInstalled) {
throw new IllegalArgumentException(
"bookAndHtmlFormatsInstalled flag is False, this functionality is not available");
}
if (fileInput == null) {
throw new IllegalArgumentException("Please provide a file for conversion.");
}
// Validate the output format
String outputFormat = request.getOutputFormat().toLowerCase();
List<String> allowedFormats =
Arrays.asList(
"epub", "mobi", "azw3", "docx", "rtf", "txt", "html", "lit", "fb2", "pdb",
"lrf");
if (!allowedFormats.contains(outputFormat)) {
throw new IllegalArgumentException("Invalid output format: " + outputFormat);
}
byte[] outputFileBytes;
List<String> command = new ArrayList<>();
Path tempOutputFile =
Files.createTempFile(
"output_", // Use the output format for the file extension
"." + outputFormat);
Path tempInputFile = null;
try {
// Create temp input file from the provided PDF
// Assuming input is always PDF
tempInputFile = Files.createTempFile("input_", ".pdf");
Files.write(tempInputFile, fileInput.getBytes());
command.add("ebook-convert");
command.add(tempInputFile.toString());
command.add(tempOutputFile.toString());
ProcessExecutorResult returnCode =
ProcessExecutor.getInstance(ProcessExecutor.Processes.CALIBRE)
.runCommandWithOutputHandling(command);
outputFileBytes = Files.readAllBytes(tempOutputFile);
} finally {
// Clean up temporary files
if (tempInputFile != null) {
Files.deleteIfExists(tempInputFile);
}
Files.deleteIfExists(tempOutputFile);
}
String outputFilename =
Filenames.toSimpleFileName(fileInput.getOriginalFilename())
.replaceFirst("[.][^.]+$", "")
+ "."
+ // Remove file extension and append .pdf
outputFormat;
return WebResponseUtils.bytesToWebResponse(outputFileBytes, outputFilename);
}
}

View File

@@ -21,6 +21,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.converters.PdfToPdfARequest; import stirling.software.SPDF.model.api.converters.PdfToPdfARequest;
import stirling.software.SPDF.utils.ProcessExecutor; import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;

View File

@@ -18,6 +18,8 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.RuntimePathConfig;
import stirling.software.SPDF.model.api.converters.UrlToPdfRequest; import stirling.software.SPDF.model.api.converters.UrlToPdfRequest;
import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.utils.GeneralUtils;
@@ -32,10 +34,13 @@ import stirling.software.SPDF.utils.WebResponseUtils;
public class ConvertWebsiteToPDF { public class ConvertWebsiteToPDF {
private final CustomPDDocumentFactory pdfDocumentFactory; private final CustomPDDocumentFactory pdfDocumentFactory;
private final RuntimePathConfig runtimePathConfig;
@Autowired @Autowired
public ConvertWebsiteToPDF(CustomPDDocumentFactory pdfDocumentFactory) { public ConvertWebsiteToPDF(
CustomPDDocumentFactory pdfDocumentFactory, RuntimePathConfig runtimePathConfig) {
this.pdfDocumentFactory = pdfDocumentFactory; this.pdfDocumentFactory = pdfDocumentFactory;
this.runtimePathConfig = runtimePathConfig;
} }
@PostMapping(consumes = "multipart/form-data", value = "/url/pdf") @PostMapping(consumes = "multipart/form-data", value = "/url/pdf")
@@ -65,7 +70,7 @@ public class ConvertWebsiteToPDF {
// Prepare the WeasyPrint command // Prepare the WeasyPrint command
List<String> command = new ArrayList<>(); List<String> command = new ArrayList<>();
command.add("/opt/venv/bin/weasyprint"); command.add(runtimePathConfig.getWeasyPrintPath());
command.add(URL); command.add(URL);
command.add(tempOutputFile.toString()); command.add(tempOutputFile.toString());

View File

@@ -25,9 +25,12 @@ import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.PDFWithPageNums; import stirling.software.SPDF.model.api.PDFWithPageNums;
import stirling.software.SPDF.pdf.FlexibleCSVWriter; import stirling.software.SPDF.pdf.FlexibleCSVWriter;
import technology.tabula.ObjectExtractor; import technology.tabula.ObjectExtractor;
import technology.tabula.Page; import technology.tabula.Page;
import technology.tabula.Table; import technology.tabula.Table;
@@ -51,22 +54,20 @@ public class ExtractCSVController {
try (PDDocument document = Loader.loadPDF(form.getFileInput().getBytes())) { try (PDDocument document = Loader.loadPDF(form.getFileInput().getBytes())) {
List<Integer> pages = form.getPageNumbersList(document, true); List<Integer> pages = form.getPageNumbersList(document, true);
SpreadsheetExtractionAlgorithm sea = new SpreadsheetExtractionAlgorithm(); SpreadsheetExtractionAlgorithm sea = new SpreadsheetExtractionAlgorithm();
CSVFormat format = CSVFormat.EXCEL.builder() CSVFormat format =
.setEscape('"') CSVFormat.EXCEL.builder().setEscape('"').setQuoteMode(QuoteMode.ALL).build();
.setQuoteMode(QuoteMode.ALL)
.build();
for (int pageNum : pages) { for (int pageNum : pages) {
try (ObjectExtractor extractor = new ObjectExtractor(document)) { try (ObjectExtractor extractor = new ObjectExtractor(document)) {
log.info("{}",pageNum); log.info("{}", pageNum);
Page page = extractor.extract(pageNum); Page page = extractor.extract(pageNum);
List<Table> tables = sea.extract(page); List<Table> tables = sea.extract(page);
for (int i = 0; i < tables.size(); i++) { for (int i = 0; i < tables.size(); i++) {
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
FlexibleCSVWriter csvWriter = new FlexibleCSVWriter(format); FlexibleCSVWriter csvWriter = new FlexibleCSVWriter(format);
csvWriter.write(sw, Collections.singletonList(tables.get(i))); csvWriter.write(sw, Collections.singletonList(tables.get(i)));
String entryName = generateEntryName(baseName, pageNum, i + 1); String entryName = generateEntryName(baseName, pageNum, i + 1);
csvEntries.add(new CsvEntry(entryName, sw.toString())); csvEntries.add(new CsvEntry(entryName, sw.toString()));
} }
@@ -83,7 +84,8 @@ public class ExtractCSVController {
} }
} }
private ResponseEntity<byte[]> createZipResponse(List<CsvEntry> entries, String baseName) throws IOException { private ResponseEntity<byte[]> createZipResponse(List<CsvEntry> entries, String baseName)
throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zipOut = new ZipOutputStream(baos)) { try (ZipOutputStream zipOut = new ZipOutputStream(baos)) {
for (CsvEntry entry : entries) { for (CsvEntry entry : entries) {
@@ -93,21 +95,25 @@ public class ExtractCSVController {
zipOut.closeEntry(); zipOut.closeEntry();
} }
} }
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentDisposition(ContentDisposition.builder("attachment") headers.setContentDisposition(
.filename(baseName + "_extracted.zip").build()); ContentDisposition.builder("attachment")
.filename(baseName + "_extracted.zip")
.build());
headers.setContentType(MediaType.parseMediaType("application/zip")); headers.setContentType(MediaType.parseMediaType("application/zip"));
return ResponseEntity.ok().headers(headers).body(baos.toByteArray()); return ResponseEntity.ok().headers(headers).body(baos.toByteArray());
} }
private ResponseEntity<String> createCsvResponse(CsvEntry entry, String baseName) { private ResponseEntity<String> createCsvResponse(CsvEntry entry, String baseName) {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentDisposition(ContentDisposition.builder("attachment") headers.setContentDisposition(
.filename(baseName + "_extracted.csv").build()); ContentDisposition.builder("attachment")
.filename(baseName + "_extracted.csv")
.build());
headers.setContentType(MediaType.parseMediaType("text/csv")); headers.setContentType(MediaType.parseMediaType("text/csv"));
return ResponseEntity.ok().headers(headers).body(entry.content()); return ResponseEntity.ok().headers(headers).body(entry.content());
} }

View File

@@ -21,6 +21,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.misc.ExtractHeaderRequest; import stirling.software.SPDF.model.api.misc.ExtractHeaderRequest;
import stirling.software.SPDF.utils.WebResponseUtils; import stirling.software.SPDF.utils.WebResponseUtils;

View File

@@ -33,6 +33,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.misc.AutoSplitPdfRequest; import stirling.software.SPDF.model.api.misc.AutoSplitPdfRequest;
import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils; import stirling.software.SPDF.utils.WebResponseUtils;

View File

@@ -29,6 +29,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.misc.RemoveBlankPagesRequest; import stirling.software.SPDF.model.api.misc.RemoveBlankPagesRequest;
import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;

View File

@@ -31,6 +31,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.misc.OptimizePdfRequest; import stirling.software.SPDF.model.api.misc.OptimizePdfRequest;
import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.utils.GeneralUtils;

View File

@@ -30,6 +30,7 @@ import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.misc.ExtractImageScansRequest; import stirling.software.SPDF.model.api.misc.ExtractImageScansRequest;
import stirling.software.SPDF.utils.CheckProgramInstall; import stirling.software.SPDF.utils.CheckProgramInstall;
import stirling.software.SPDF.utils.ProcessExecutor; import stirling.software.SPDF.utils.ProcessExecutor;

View File

@@ -38,6 +38,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.PDFExtractImagesRequest; import stirling.software.SPDF.model.api.PDFExtractImagesRequest;
import stirling.software.SPDF.utils.ImageProcessingUtils; import stirling.software.SPDF.utils.ImageProcessingUtils;
import stirling.software.SPDF.utils.WebResponseUtils; import stirling.software.SPDF.utils.WebResponseUtils;

View File

@@ -25,6 +25,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.misc.FlattenRequest; import stirling.software.SPDF.model.api.misc.FlattenRequest;
import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils; import stirling.software.SPDF.utils.WebResponseUtils;

View File

@@ -21,6 +21,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.misc.MetadataRequest; import stirling.software.SPDF.model.api.misc.MetadataRequest;
import stirling.software.SPDF.utils.WebResponseUtils; import stirling.software.SPDF.utils.WebResponseUtils;
import stirling.software.SPDF.utils.propertyeditor.StringToMapPropertyEditor; import stirling.software.SPDF.utils.propertyeditor.StringToMapPropertyEditor;

View File

@@ -30,6 +30,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.api.misc.ProcessPdfWithOcrRequest; import stirling.software.SPDF.model.api.misc.ProcessPdfWithOcrRequest;
import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.service.CustomPDDocumentFactory;

View File

@@ -16,6 +16,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.misc.OverlayImageRequest; import stirling.software.SPDF.model.api.misc.OverlayImageRequest;
import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;

View File

@@ -26,6 +26,7 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.misc.PrintFileRequest; import stirling.software.SPDF.model.api.misc.PrintFileRequest;
@RestController @RestController

View File

@@ -19,7 +19,9 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletContext; import jakarta.servlet.ServletContext;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.SPDFApplication; import stirling.software.SPDF.SPDFApplication;
import stirling.software.SPDF.model.ApiEndpoint; import stirling.software.SPDF.model.ApiEndpoint;
import stirling.software.SPDF.model.Role; import stirling.software.SPDF.model.Role;

View File

@@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.PipelineConfig; import stirling.software.SPDF.model.PipelineConfig;
import stirling.software.SPDF.model.PipelineResult; import stirling.software.SPDF.model.PipelineResult;
import stirling.software.SPDF.model.api.HandleDataRequest; import stirling.software.SPDF.model.api.HandleDataRequest;

View File

@@ -5,9 +5,14 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystemException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@@ -24,7 +29,8 @@ import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.InstallationPathConfig;
import stirling.software.SPDF.config.RuntimePathConfig;
import stirling.software.SPDF.model.PipelineConfig; import stirling.software.SPDF.model.PipelineConfig;
import stirling.software.SPDF.model.PipelineOperation; import stirling.software.SPDF.model.PipelineOperation;
import stirling.software.SPDF.model.PipelineResult; import stirling.software.SPDF.model.PipelineResult;
@@ -50,18 +56,19 @@ public class PipelineDirectoryProcessor {
ObjectMapper objectMapper, ObjectMapper objectMapper,
ApiDocService apiDocService, ApiDocService apiDocService,
PipelineProcessor processor, PipelineProcessor processor,
FileMonitor fileMonitor) { FileMonitor fileMonitor,
RuntimePathConfig runtimePathConfig) {
this.objectMapper = objectMapper; this.objectMapper = objectMapper;
this.apiDocService = apiDocService; this.apiDocService = apiDocService;
this.watchedFoldersDir = InstallationPathConfig.getPipelineWatchedFoldersDir(); this.watchedFoldersDir = runtimePathConfig.getPipelineWatchedFoldersPath();
this.finishedFoldersDir = InstallationPathConfig.getPipelineFinishedFoldersDir(); this.finishedFoldersDir = runtimePathConfig.getPipelineFinishedFoldersPath();
this.processor = processor; this.processor = processor;
this.fileMonitor = fileMonitor; this.fileMonitor = fileMonitor;
} }
@Scheduled(fixedRate = 60000) @Scheduled(fixedRate = 60000)
public void scanFolders() { public void scanFolders() {
Path watchedFolderPath = Paths.get(watchedFoldersDir); Path watchedFolderPath = Paths.get(watchedFoldersDir).toAbsolutePath();
if (!Files.exists(watchedFolderPath)) { if (!Files.exists(watchedFolderPath)) {
try { try {
Files.createDirectories(watchedFolderPath); Files.createDirectories(watchedFolderPath);
@@ -71,19 +78,33 @@ public class PipelineDirectoryProcessor {
return; return;
} }
} }
try (Stream<Path> paths = Files.walk(watchedFolderPath)) {
paths.filter(Files::isDirectory) try {
.forEach( Files.walkFileTree(
t -> { watchedFolderPath,
try { new SimpleFileVisitor<>() {
if (!t.equals(watchedFolderPath) && !t.endsWith("processing")) { @Override
handleDirectory(t); public FileVisitResult preVisitDirectory(
} Path dir, BasicFileAttributes attrs) {
} catch (Exception e) { try {
log.error("Error handling directory: {}", t, e); // Skip root directory and "processing" subdirectories
if (!dir.equals(watchedFolderPath) && !dir.endsWith("processing")) {
handleDirectory(dir);
} }
}); } catch (Exception e) {
} catch (Exception e) { log.error("Error handling directory: {}", dir, e);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path path, IOException exc) {
// Handle broken symlinks or inaccessible directories
log.error("Error accessing path: {}", path, exc);
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
log.error("Error walking through directory: {}", watchedFolderPath, e); log.error("Error walking through directory: {}", watchedFolderPath, e);
} }
} }
@@ -187,6 +208,7 @@ public class PipelineDirectoryProcessor {
} }
return isAllowed; return isAllowed;
}) })
.map(Path::toAbsolutePath)
.filter( .filter(
path -> { path -> {
boolean isReady = boolean isReady =
@@ -200,7 +222,10 @@ public class PipelineDirectoryProcessor {
}) })
.map(Path::toFile) .map(Path::toFile)
.toArray(File[]::new); .toArray(File[]::new);
log.info("Collected {} files for processing", files.length); log.info(
"Collected {} files for processing for {}",
files.length,
dir.toAbsolutePath().toString());
return files; return files;
} }
} }
@@ -210,8 +235,35 @@ public class PipelineDirectoryProcessor {
List<File> filesToProcess = new ArrayList<>(); List<File> filesToProcess = new ArrayList<>();
for (File file : files) { for (File file : files) {
Path targetPath = resolveUniqueFilePath(processingDir, file.getName()); Path targetPath = resolveUniqueFilePath(processingDir, file.getName());
Files.move(file.toPath(), targetPath);
filesToProcess.add(targetPath.toFile()); // Retry with exponential backoff
int maxRetries = 3;
int retryDelayMs = 500;
boolean moved = false;
for (int attempt = 1; attempt <= maxRetries; attempt++) {
try {
Files.move(file.toPath(), targetPath, StandardCopyOption.REPLACE_EXISTING);
moved = true;
break;
} catch (FileSystemException e) {
if (attempt < maxRetries) {
log.info("File move failed (attempt {}), retrying...", attempt);
try {
Thread.sleep(retryDelayMs * (int) Math.pow(2, attempt - 1));
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
if (moved) {
filesToProcess.add(targetPath.toFile());
} else {
log.error("Failed to move file after {} attempts: {}", maxRetries, file.getName());
}
} }
return filesToProcess; return filesToProcess;
} }

View File

@@ -29,7 +29,9 @@ import io.github.pixee.security.Filenames;
import io.github.pixee.security.ZipSecurity; import io.github.pixee.security.ZipSecurity;
import jakarta.servlet.ServletContext; import jakarta.servlet.ServletContext;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.SPDFApplication; import stirling.software.SPDF.SPDFApplication;
import stirling.software.SPDF.model.PipelineConfig; import stirling.software.SPDF.model.PipelineConfig;
import stirling.software.SPDF.model.PipelineOperation; import stirling.software.SPDF.model.PipelineOperation;

View File

@@ -66,6 +66,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.security.SignPDFWithCertRequest; import stirling.software.SPDF.model.api.security.SignPDFWithCertRequest;
import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.service.CustomPDDocumentFactory;
import stirling.software.SPDF.utils.WebResponseUtils; import stirling.software.SPDF.utils.WebResponseUtils;

View File

@@ -60,6 +60,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.PDFFile; import stirling.software.SPDF.model.api.PDFFile;
import stirling.software.SPDF.utils.WebResponseUtils; import stirling.software.SPDF.utils.WebResponseUtils;

View File

@@ -26,6 +26,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.PDFText; import stirling.software.SPDF.model.PDFText;
import stirling.software.SPDF.model.api.security.ManualRedactPdfRequest; import stirling.software.SPDF.model.api.security.ManualRedactPdfRequest;
import stirling.software.SPDF.model.api.security.RedactPdfRequest; import stirling.software.SPDF.model.api.security.RedactPdfRequest;

View File

@@ -19,7 +19,9 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal; import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
import stirling.software.SPDF.model.*; import stirling.software.SPDF.model.*;

View File

@@ -1,6 +1,5 @@
package stirling.software.SPDF.controller.web; package stirling.software.SPDF.controller.web;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@@ -15,14 +14,6 @@ import stirling.software.SPDF.utils.CheckProgramInstall;
@Tag(name = "Convert", description = "Convert APIs") @Tag(name = "Convert", description = "Convert APIs")
public class ConverterWebController { public class ConverterWebController {
@ConditionalOnExpression("${bookAndHtmlFormatsInstalled}")
@GetMapping("/book-to-pdf")
@Hidden
public String convertBookToPdfForm(Model model) {
model.addAttribute("currentPage", "book-to-pdf");
return "convert/book-to-pdf";
}
@GetMapping("/img-to-pdf") @GetMapping("/img-to-pdf")
@Hidden @Hidden
public String convertImgToPdfForm(Model model) { public String convertImgToPdfForm(Model model) {
@@ -67,14 +58,6 @@ public class ConverterWebController {
// PDF TO...... // PDF TO......
@ConditionalOnExpression("${bookAndHtmlFormatsInstalled}")
@GetMapping("/pdf-to-book")
@Hidden
public String convertPdfToBookForm(Model model) {
model.addAttribute("currentPage", "pdf-to-book");
return "convert/pdf-to-book";
}
@GetMapping("/pdf-to-img") @GetMapping("/pdf-to-img")
@Hidden @Hidden
public String pdfToimgForm(Model model) { public String pdfToimgForm(Model model) {

View File

@@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import stirling.software.SPDF.config.security.database.DatabaseService; import stirling.software.SPDF.config.security.database.DatabaseService;
import stirling.software.SPDF.utils.FileInfo; import stirling.software.SPDF.utils.FileInfo;

View File

@@ -25,7 +25,9 @@ import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.InstallationPathConfig; import stirling.software.SPDF.config.InstallationPathConfig;
import stirling.software.SPDF.config.RuntimePathConfig;
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface; import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
import stirling.software.SPDF.model.SignatureFile; import stirling.software.SPDF.model.SignatureFile;
import stirling.software.SPDF.service.SignatureService; import stirling.software.SPDF.service.SignatureService;
@@ -38,14 +40,17 @@ public class GeneralWebController {
private final SignatureService signatureService; private final SignatureService signatureService;
private final UserServiceInterface userService; private final UserServiceInterface userService;
private final ResourceLoader resourceLoader; private final ResourceLoader resourceLoader;
private final RuntimePathConfig runtimePathConfig;
public GeneralWebController( public GeneralWebController(
SignatureService signatureService, SignatureService signatureService,
@Autowired(required = false) UserServiceInterface userService, @Autowired(required = false) UserServiceInterface userService,
ResourceLoader resourceLoader) { ResourceLoader resourceLoader,
RuntimePathConfig runtimePathConfig) {
this.signatureService = signatureService; this.signatureService = signatureService;
this.userService = userService; this.userService = userService;
this.resourceLoader = resourceLoader; this.resourceLoader = resourceLoader;
this.runtimePathConfig = runtimePathConfig;
} }
@GetMapping("/pipeline") @GetMapping("/pipeline")
@@ -54,11 +59,9 @@ public class GeneralWebController {
model.addAttribute("currentPage", "pipeline"); model.addAttribute("currentPage", "pipeline");
List<String> pipelineConfigs = new ArrayList<>(); List<String> pipelineConfigs = new ArrayList<>();
List<Map<String, String>> pipelineConfigsWithNames = new ArrayList<>(); List<Map<String, String>> pipelineConfigsWithNames = new ArrayList<>();
if (new File(InstallationPathConfig.getPipelineDefaultWebUIConfigsDir()).exists()) { if (new File(runtimePathConfig.getPipelineDefaultWebUiConfigs()).exists()) {
try (Stream<Path> paths = try (Stream<Path> paths =
Files.walk( Files.walk(Paths.get(runtimePathConfig.getPipelineDefaultWebUiConfigs()))) {
Paths.get(
InstallationPathConfig.getPipelineDefaultWebUIConfigsDir()))) {
List<Path> jsonFiles = List<Path> jsonFiles =
paths.filter(Files::isRegularFile) paths.filter(Files::isRegularFile)
.filter(p -> p.toString().endsWith(".json")) .filter(p -> p.toString().endsWith(".json"))

View File

@@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.Hidden;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.Dependency; import stirling.software.SPDF.model.Dependency;

View File

@@ -19,7 +19,9 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.StartupApplicationListener; import stirling.software.SPDF.config.StartupApplicationListener;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;

View File

@@ -31,6 +31,7 @@ import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.InstallationPathConfig; import stirling.software.SPDF.config.InstallationPathConfig;
import stirling.software.SPDF.config.YamlPropertySourceFactory; import stirling.software.SPDF.config.YamlPropertySourceFactory;
import stirling.software.SPDF.model.provider.GithubProvider; import stirling.software.SPDF.model.provider.GithubProvider;
@@ -285,6 +286,26 @@ public class ApplicationProperties {
private String enableAnalytics; private String enableAnalytics;
private Datasource datasource; private Datasource datasource;
private Boolean disableSanitize; private Boolean disableSanitize;
private CustomPaths customPaths = new CustomPaths();
}
@Data
public static class CustomPaths {
private Pipeline pipeline = new Pipeline();
private Operations operations = new Operations();
@Data
public static class Pipeline {
private String watchedFoldersDir;
private String finishedFoldersDir;
private String webUIConfigsDir;
}
@Data
public static class Operations {
private String weasyprint;
private String unoconvert;
}
} }
@Data @Data

View File

@@ -6,6 +6,7 @@ import java.util.Date;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import lombok.Data; import lombok.Data;
@Entity @Entity

View File

@@ -14,6 +14,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.utils.GeneralUtils;
@Data @Data

View File

@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import stirling.software.SPDF.model.api.PDFFile; import stirling.software.SPDF.model.api.PDFFile;
@Data @Data

View File

@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import stirling.software.SPDF.model.api.PDFFile; import stirling.software.SPDF.model.api.PDFFile;
@Data @Data

View File

@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import stirling.software.SPDF.model.api.PDFFile; import stirling.software.SPDF.model.api.PDFFile;
@Data @Data

View File

@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import stirling.software.SPDF.model.api.PDFFile; import stirling.software.SPDF.model.api.PDFFile;
@Data @Data

View File

@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import stirling.software.SPDF.model.api.PDFFile; import stirling.software.SPDF.model.api.PDFFile;
@Data @Data

View File

@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import stirling.software.SPDF.model.api.PDFFile; import stirling.software.SPDF.model.api.PDFFile;
@Data @Data

View File

@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import stirling.software.SPDF.model.api.PDFFile; import stirling.software.SPDF.model.api.PDFFile;
@Data @Data

View File

@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import stirling.software.SPDF.model.api.PDFWithPageNums; import stirling.software.SPDF.model.api.PDFWithPageNums;
@Data @Data

View File

@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import stirling.software.SPDF.model.api.PDFComparison; import stirling.software.SPDF.model.api.PDFComparison;
@Data @Data

View File

@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import stirling.software.SPDF.model.api.PDFComparison; import stirling.software.SPDF.model.api.PDFComparison;
@Data @Data

Some files were not shown because too many files have changed in this diff Show More