Merge branch 'main' into session_2025_03_22

This commit is contained in:
Ludy 2025-03-30 18:19:18 +02:00 committed by GitHub
commit f33d8b0f23
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 50 additions and 32 deletions

View File

@ -139,7 +139,7 @@ Stirling-PDF currently supports 39 languages!
| Korean (한국어) (ko_KR) | ![95%](https://geps.dev/progress/95) | | Korean (한국어) (ko_KR) | ![95%](https://geps.dev/progress/95) |
| Norwegian (Norsk) (no_NB) | ![89%](https://geps.dev/progress/89) | | Norwegian (Norsk) (no_NB) | ![89%](https://geps.dev/progress/89) |
| Persian (فارسی) (fa_IR) | ![90%](https://geps.dev/progress/90) | | Persian (فارسی) (fa_IR) | ![90%](https://geps.dev/progress/90) |
| Polish (Polski) (pl_PL) | ![82%](https://geps.dev/progress/82) | | Polish (Polski) (pl_PL) | ![98%](https://geps.dev/progress/98) |
| Portuguese (Português) (pt_PT) | ![93%](https://geps.dev/progress/93) | | Portuguese (Português) (pt_PT) | ![93%](https://geps.dev/progress/93) |
| Portuguese Brazilian (Português) (pt_BR) | ![96%](https://geps.dev/progress/96) | | Portuguese Brazilian (Português) (pt_BR) | ![96%](https://geps.dev/progress/96) |
| Romanian (Română) (ro_RO) | ![77%](https://geps.dev/progress/77) | | Romanian (Română) (ro_RO) | ![77%](https://geps.dev/progress/77) |

View File

@ -204,6 +204,7 @@ public class UserService implements UserServiceInterface {
user.setPassword(passwordEncoder.encode(password)); user.setPassword(passwordEncoder.encode(password));
user.setEnabled(true); user.setEnabled(true);
user.setAuthenticationType(AuthenticationType.WEB); user.setAuthenticationType(AuthenticationType.WEB);
user.addAuthority(new Authority(Role.USER.getRoleId(), user));
userRepository.save(user); userRepository.save(user);
databaseService.exportDatabase(); databaseService.exportDatabase();
} }
@ -229,6 +230,22 @@ public class UserService implements UserServiceInterface {
saveUser(username, password, role, false); saveUser(username, password, role, false);
} }
public void saveUser(String username, String password, boolean firstLogin, boolean enabled)
throws IllegalArgumentException, SQLException, UnsupportedProviderException {
if (!isUsernameValid(username)) {
throw new IllegalArgumentException(getInvalidUsernameMessage());
}
User user = new User();
user.setUsername(username);
user.setPassword(passwordEncoder.encode(password));
user.addAuthority(new Authority(Role.USER.getRoleId(), user));
user.setEnabled(enabled);
user.setAuthenticationType(AuthenticationType.WEB);
user.setFirstLogin(firstLogin);
userRepository.save(user);
databaseService.exportDatabase();
}
public void deleteUser(String username) { public void deleteUser(String username) {
Optional<User> userOpt = findByUsernameIgnoreCase(username); Optional<User> userOpt = findByUsernameIgnoreCase(username);
if (userOpt.isPresent()) { if (userOpt.isPresent()) {
@ -351,6 +368,7 @@ public class UserService implements UserServiceInterface {
List<String> notAllowedUserList = new ArrayList<>(); List<String> notAllowedUserList = new ArrayList<>();
notAllowedUserList.add("ALL_USERS".toLowerCase()); notAllowedUserList.add("ALL_USERS".toLowerCase());
notAllowedUserList.add("anonymoususer");
boolean notAllowedUser = notAllowedUserList.contains(username.toLowerCase()); boolean notAllowedUser = notAllowedUserList.contains(username.toLowerCase());
return (isValidSimpleUsername || isValidEmail) && !notAllowedUser; return (isValidSimpleUsername || isValidEmail) && !notAllowedUser;
} }

View File

@ -1036,10 +1036,10 @@ decrypt.unexpectedError=Wystąpił błąd podczas przetwarzania pliku. Spróbuj
decrypt.serverError=Błąd serwera podczas odszyfrowywania: {0} decrypt.serverError=Błąd serwera podczas odszyfrowywania: {0}
decrypt.success=Plik został pomyślnie odszyfrowany. decrypt.success=Plik został pomyślnie odszyfrowany.
#multiTool-advert #multiTool-advert
multiTool-advert.message=Ta funkcja jest również dostępna na naszej <a href="{0}">stronie narzędzia wielofunkcyjnego</a>. Sprawdź ją, aby uzyskać lepszy interfejs zarządzania stronami i dodatkowe funkcje! multiTool-advert.message=Ta funkcja jest również dostępna na naszej <a href="{0}">stronie narzędzia wielofunkcyjnego</a>. Sprawdź ją, aby uzyskać lepszy interfejs zarządzania stronami i dodatkowe funkcje!
#view pdf #view pdf
viewPdf.title=Przeglądaj/Edytuj PDF viewPdf.title=Przeglądaj/Edytuj PDF
viewPdf.header=Podejrzyj PDF viewPdf.header=Podejrzyj PDF

View File

@ -27,7 +27,7 @@ function getChartColors() {
} }
// Watch for theme changes and update chart if needed // Watch for theme changes and update chart if needed
function setupThemeChangeListener() { function setupThemeChangeListener() {
// Start observing theme changes // Start observing theme changes
document.addEventListener("modeChanged", (event) => { document.addEventListener("modeChanged", (event) => {
@ -41,7 +41,7 @@ function setupThemeChangeListener() {
} }
}, 100); }, 100);
}); });
// Also watch for system preference changes // Also watch for system preference changes
window window
.matchMedia('(prefers-color-scheme: dark)') .matchMedia('(prefers-color-scheme: dark)')
@ -60,22 +60,22 @@ function setupThemeChangeListener() {
function filterData() { function filterData() {
const includeHome = document.getElementById('hideHomeCheckbox').checked; const includeHome = document.getElementById('hideHomeCheckbox').checked;
const includeLogin = document.getElementById('hideLoginCheckbox').checked; const includeLogin = document.getElementById('hideLoginCheckbox').checked;
filteredData = allEndpointData.filter(item => { filteredData = allEndpointData.filter(item => {
if (!includeHome && item.endpoint === '/') return false; if (!includeHome && item.endpoint === '/') return false;
if (!includeLogin && item.endpoint === '/login') return false; if (!includeLogin && item.endpoint === '/login') return false;
return true; return true;
}); });
// Sort and calculate // Sort and calculate
sortedData = [...filteredData].sort((a, b) => b.count - a.count); sortedData = [...filteredData].sort((a, b) => b.count - a.count);
totalEndpoints = filteredData.length; totalEndpoints = filteredData.length;
totalVisits = filteredData.reduce((sum, item) => sum + item.count, 0); totalVisits = filteredData.reduce((sum, item) => sum + item.count, 0);
// Update stats // Update stats
document.getElementById('totalEndpoints').textContent = totalEndpoints.toLocaleString(); document.getElementById('totalEndpoints').textContent = totalEndpoints.toLocaleString();
document.getElementById('totalVisits').textContent = totalVisits.toLocaleString(); document.getElementById('totalVisits').textContent = totalVisits.toLocaleString();
// Update the chart with current limit // Update the chart with current limit
const currentLimit = document.getElementById('currentlyShowing').textContent; const currentLimit = document.getElementById('currentlyShowing').textContent;
const limit = (currentLimit === endpointStatsTranslations.all) const limit = (currentLimit === endpointStatsTranslations.all)
@ -96,33 +96,33 @@ async function fetchEndpointData() {
<span class="visually-hidden">${endpointStatsTranslations.loading}</span> <span class="visually-hidden">${endpointStatsTranslations.loading}</span>
</div>`; </div>`;
chartContainer.appendChild(loadingDiv); chartContainer.appendChild(loadingDiv);
// Also add animation to refresh button // Also add animation to refresh button
const refreshBtn = document.getElementById('refreshBtn'); const refreshBtn = document.getElementById('refreshBtn');
refreshBtn.classList.add('refreshing'); refreshBtn.classList.add('refreshing');
refreshBtn.disabled = true; refreshBtn.disabled = true;
const response = await fetch('/api/v1/info/load/all'); const response = await fetch('/api/v1/info/load/all');
if (!response.ok) { if (!response.ok) {
throw new Error('Network response was not ok'); throw new Error('Network response was not ok');
} }
const data = await response.json(); const data = await response.json();
allEndpointData = data; allEndpointData = data;
// Apply filters // Apply filters
filterData(); filterData();
// Remove loading state // Remove loading state
chartContainer.removeChild(loadingDiv); chartContainer.removeChild(loadingDiv);
refreshBtn.classList.remove('refreshing'); refreshBtn.classList.remove('refreshing');
refreshBtn.disabled = false; refreshBtn.disabled = false;
} catch (error) { } catch (error) {
console.error('Error fetching endpoint data:', error); console.error('Error fetching endpoint data:', error);
// Show error message to user // Show error message to user
showError(endpointStatsTranslations.failedToLoad); showError(endpointStatsTranslations.failedToLoad);
// Reset refresh button // Reset refresh button
const refreshBtn = document.getElementById('refreshBtn'); const refreshBtn = document.getElementById('refreshBtn');
refreshBtn.classList.remove('refreshing'); refreshBtn.classList.remove('refreshing');
@ -141,24 +141,24 @@ function formatEndpointName(endpoint) {
function updateTable(data) { function updateTable(data) {
const tableBody = document.getElementById('endpointTableBody'); const tableBody = document.getElementById('endpointTableBody');
tableBody.innerHTML = ''; tableBody.innerHTML = '';
data.forEach((item, index) => { data.forEach((item, index) => {
const percentage = ((item.count / totalVisits) * 100).toFixed(2); const percentage = ((item.count / totalVisits) * 100).toFixed(2);
const row = document.createElement('tr'); const row = document.createElement('tr');
// Format endpoint for better readability // Format endpoint for better readability
let displayEndpoint = item.endpoint; let displayEndpoint = item.endpoint;
if (displayEndpoint.length > 40) { if (displayEndpoint.length > 40) {
displayEndpoint = displayEndpoint.substring(0, 37) + '...'; displayEndpoint = displayEndpoint.substring(0, 37) + '...';
} }
row.innerHTML = ` row.innerHTML = `
<td>${index + 1}</td> <td>${index + 1}</td>
<td title="${item.endpoint}">${displayEndpoint}</td> <td title="${item.endpoint}">${displayEndpoint}</td>
<td>${item.count.toLocaleString()}</td> <td>${item.count.toLocaleString()}</td>
<td>${percentage}%</td> <td>${percentage}%</td>
`; `;
tableBody.appendChild(row); tableBody.appendChild(row);
}); });
} }
@ -172,10 +172,10 @@ function updateChart(dataLimit) {
const displayedPercentage = totalVisits > 0 const displayedPercentage = totalVisits > 0
? ((displayedVisits / totalVisits) * 100).toFixed(2) ? ((displayedVisits / totalVisits) * 100).toFixed(2)
: '0'; : '0';
document.getElementById('displayedVisits').textContent = displayedVisits.toLocaleString(); document.getElementById('displayedVisits').textContent = displayedVisits.toLocaleString();
document.getElementById('displayedPercentage').textContent = displayedPercentage; document.getElementById('displayedPercentage').textContent = displayedPercentage;
// If the limit equals the total filtered items, show "All"; otherwise "Top X" // If the limit equals the total filtered items, show "All"; otherwise "Top X"
document.getElementById('currentlyShowing').textContent = document.getElementById('currentlyShowing').textContent =
(dataLimit === filteredData.length) (dataLimit === filteredData.length)
@ -303,30 +303,30 @@ function updateChart(dataLimit) {
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
// Set up theme change listener // Set up theme change listener
setupThemeChangeListener(); setupThemeChangeListener();
// Initial data fetch // Initial data fetch
fetchEndpointData(); fetchEndpointData();
// Set up button event listeners // Set up button event listeners
document.getElementById('top10Btn').addEventListener('click', function() { document.getElementById('top10Btn').addEventListener('click', function() {
updateChart(10); updateChart(10);
setActiveButton(this); setActiveButton(this);
}); });
document.getElementById('top20Btn').addEventListener('click', function() { document.getElementById('top20Btn').addEventListener('click', function() {
updateChart(20); updateChart(20);
setActiveButton(this); setActiveButton(this);
}); });
document.getElementById('allBtn').addEventListener('click', function() { document.getElementById('allBtn').addEventListener('click', function() {
updateChart(filteredData.length); updateChart(filteredData.length);
setActiveButton(this); setActiveButton(this);
}); });
document.getElementById('refreshBtn').addEventListener('click', function() { document.getElementById('refreshBtn').addEventListener('click', function() {
fetchEndpointData(); fetchEndpointData();
}); });
// Set up filter checkbox listeners // Set up filter checkbox listeners
document.getElementById('hideHomeCheckbox').addEventListener('change', filterData); document.getElementById('hideHomeCheckbox').addEventListener('change', filterData);
document.getElementById('hideLoginCheckbox').addEventListener('change', filterData); document.getElementById('hideLoginCheckbox').addEventListener('change', filterData);
@ -350,14 +350,14 @@ function showError(message) {
<span class="material-symbols-rounded" style="vertical-align: bottom; margin-right: 5px;">error</span> <span class="material-symbols-rounded" style="vertical-align: bottom; margin-right: 5px;">error</span>
${message} ${message}
<button id="errorRetryBtn" class="btn btn-outline-danger btn-sm" style="margin-left: 10px;"> <button id="errorRetryBtn" class="btn btn-outline-danger btn-sm" style="margin-left: 10px;">
<span class="material-symbols-rounded" style="font-size: 1rem; vertical-align: bottom;">refresh</span> <span class="material-symbols-rounded" style="font-size: 1rem; vertical-align: bottom;">refresh</span>
${endpointStatsTranslations.retry} ${endpointStatsTranslations.retry}
</button> </button>
`; `;
chartContainer.innerHTML = ''; chartContainer.innerHTML = '';
chartContainer.appendChild(errorDiv); chartContainer.appendChild(errorDiv);
// Add retry button functionality // Add retry button functionality
document.getElementById('errorRetryBtn').addEventListener('click', fetchEndpointData); document.getElementById('errorRetryBtn').addEventListener('click', fetchEndpointData);
} }