mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-02 18:45:21 +00:00
formatting and UI
This commit is contained in:
parent
dc6735d360
commit
30461cd91e
@ -9,7 +9,6 @@ import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
@ -35,7 +34,6 @@ import stirling.software.common.configuration.InstallationPathConfig;
|
||||
import stirling.software.common.configuration.RuntimePathConfig;
|
||||
import stirling.software.common.model.ApplicationProperties;
|
||||
import stirling.software.common.service.UserServiceInterface;
|
||||
import stirling.software.common.util.CheckProgramInstall;
|
||||
import stirling.software.common.util.ExceptionUtils;
|
||||
import stirling.software.common.util.GeneralUtils;
|
||||
|
||||
@ -57,10 +55,10 @@ public class UIDataController {
|
||||
public ResponseEntity<HomeData> getHomeData() {
|
||||
String showSurvey = System.getenv("SHOW_SURVEY");
|
||||
boolean showSurveyValue = showSurvey == null || "true".equalsIgnoreCase(showSurvey);
|
||||
|
||||
|
||||
HomeData data = new HomeData();
|
||||
data.setShowSurveyFromDocker(showSurveyValue);
|
||||
|
||||
|
||||
return ResponseEntity.ok(data);
|
||||
}
|
||||
|
||||
@ -69,18 +67,19 @@ public class UIDataController {
|
||||
public ResponseEntity<LicensesData> getLicensesData() {
|
||||
LicensesData data = new LicensesData();
|
||||
Resource resource = new ClassPathResource("static/3rdPartyLicenses.json");
|
||||
|
||||
|
||||
try {
|
||||
InputStream is = resource.getInputStream();
|
||||
String json = new String(is.readAllBytes(), StandardCharsets.UTF_8);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Map<String, List<Dependency>> licenseData = mapper.readValue(json, new TypeReference<>() {});
|
||||
Map<String, List<Dependency>> licenseData =
|
||||
mapper.readValue(json, new TypeReference<>() {});
|
||||
data.setDependencies(licenseData.get("dependencies"));
|
||||
} catch (IOException e) {
|
||||
log.error("Failed to load licenses data", e);
|
||||
data.setDependencies(Collections.emptyList());
|
||||
}
|
||||
|
||||
|
||||
return ResponseEntity.ok(data);
|
||||
}
|
||||
|
||||
@ -90,25 +89,31 @@ public class UIDataController {
|
||||
PipelineData data = new PipelineData();
|
||||
List<String> pipelineConfigs = new ArrayList<>();
|
||||
List<Map<String, String>> pipelineConfigsWithNames = new ArrayList<>();
|
||||
|
||||
|
||||
if (new java.io.File(runtimePathConfig.getPipelineDefaultWebUiConfigs()).exists()) {
|
||||
try (Stream<Path> paths = Files.walk(Paths.get(runtimePathConfig.getPipelineDefaultWebUiConfigs()))) {
|
||||
List<Path> jsonFiles = paths.filter(Files::isRegularFile)
|
||||
.filter(p -> p.toString().endsWith(".json"))
|
||||
.toList();
|
||||
|
||||
try (Stream<Path> paths =
|
||||
Files.walk(Paths.get(runtimePathConfig.getPipelineDefaultWebUiConfigs()))) {
|
||||
List<Path> jsonFiles =
|
||||
paths.filter(Files::isRegularFile)
|
||||
.filter(p -> p.toString().endsWith(".json"))
|
||||
.toList();
|
||||
|
||||
for (Path jsonFile : jsonFiles) {
|
||||
String content = Files.readString(jsonFile, StandardCharsets.UTF_8);
|
||||
pipelineConfigs.add(content);
|
||||
}
|
||||
|
||||
|
||||
for (String config : pipelineConfigs) {
|
||||
Map<String, Object> jsonContent = new ObjectMapper()
|
||||
.readValue(config, new TypeReference<Map<String, Object>>() {});
|
||||
Map<String, Object> jsonContent =
|
||||
new ObjectMapper()
|
||||
.readValue(config, new TypeReference<Map<String, Object>>() {});
|
||||
String name = (String) jsonContent.get("name");
|
||||
if (name == null || name.length() < 1) {
|
||||
String filename = jsonFiles.get(pipelineConfigs.indexOf(config))
|
||||
.getFileName().toString();
|
||||
String filename =
|
||||
jsonFiles
|
||||
.get(pipelineConfigs.indexOf(config))
|
||||
.getFileName()
|
||||
.toString();
|
||||
name = filename.substring(0, filename.lastIndexOf('.'));
|
||||
}
|
||||
Map<String, String> configWithName = new HashMap<>();
|
||||
@ -120,17 +125,17 @@ public class UIDataController {
|
||||
log.error("Failed to load pipeline configs", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (pipelineConfigsWithNames.isEmpty()) {
|
||||
Map<String, String> configWithName = new HashMap<>();
|
||||
configWithName.put("json", "");
|
||||
configWithName.put("name", "No preloaded configs found");
|
||||
pipelineConfigsWithNames.add(configWithName);
|
||||
}
|
||||
|
||||
|
||||
data.setPipelineConfigsWithNames(pipelineConfigsWithNames);
|
||||
data.setPipelineConfigs(pipelineConfigs);
|
||||
|
||||
|
||||
return ResponseEntity.ok(data);
|
||||
}
|
||||
|
||||
@ -141,26 +146,25 @@ public class UIDataController {
|
||||
if (userService != null) {
|
||||
username = userService.getCurrentUsername();
|
||||
}
|
||||
|
||||
|
||||
List<SignatureFile> signatures = signatureService.getAvailableSignatures(username);
|
||||
List<FontResource> fonts = getFontNames();
|
||||
|
||||
|
||||
SignData data = new SignData();
|
||||
data.setSignatures(signatures);
|
||||
data.setFonts(fonts);
|
||||
|
||||
|
||||
return ResponseEntity.ok(data);
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/ocr-pdf")
|
||||
@Operation(summary = "Get OCR PDF data")
|
||||
public ResponseEntity<OcrData> getOcrPdfData() {
|
||||
List<String> languages = getAvailableTesseractLanguages();
|
||||
|
||||
|
||||
OcrData data = new OcrData();
|
||||
data.setLanguages(languages);
|
||||
|
||||
|
||||
return ResponseEntity.ok(data);
|
||||
}
|
||||
|
||||
@ -181,39 +185,49 @@ public class UIDataController {
|
||||
private List<FontResource> getFontNames() {
|
||||
List<FontResource> fontNames = new ArrayList<>();
|
||||
fontNames.addAll(getFontNamesFromLocation("classpath:static/fonts/*.woff2"));
|
||||
fontNames.addAll(getFontNamesFromLocation(
|
||||
"file:" + InstallationPathConfig.getStaticPath() + "fonts" + java.io.File.separator + "*"));
|
||||
fontNames.addAll(
|
||||
getFontNamesFromLocation(
|
||||
"file:"
|
||||
+ InstallationPathConfig.getStaticPath()
|
||||
+ "fonts"
|
||||
+ java.io.File.separator
|
||||
+ "*"));
|
||||
return fontNames;
|
||||
}
|
||||
|
||||
private List<FontResource> getFontNamesFromLocation(String locationPattern) {
|
||||
try {
|
||||
Resource[] resources = GeneralUtils.getResourcesFromLocationPattern(locationPattern, resourceLoader);
|
||||
Resource[] resources =
|
||||
GeneralUtils.getResourcesFromLocationPattern(locationPattern, resourceLoader);
|
||||
return Arrays.stream(resources)
|
||||
.map(resource -> {
|
||||
try {
|
||||
String filename = resource.getFilename();
|
||||
if (filename != null) {
|
||||
int lastDotIndex = filename.lastIndexOf('.');
|
||||
if (lastDotIndex != -1) {
|
||||
String name = filename.substring(0, lastDotIndex);
|
||||
String extension = filename.substring(lastDotIndex + 1);
|
||||
return new FontResource(name, extension);
|
||||
.map(
|
||||
resource -> {
|
||||
try {
|
||||
String filename = resource.getFilename();
|
||||
if (filename != null) {
|
||||
int lastDotIndex = filename.lastIndexOf('.');
|
||||
if (lastDotIndex != -1) {
|
||||
String name = filename.substring(0, lastDotIndex);
|
||||
String extension = filename.substring(lastDotIndex + 1);
|
||||
return new FontResource(name, extension);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
throw ExceptionUtils.createRuntimeException(
|
||||
"error.fontLoadingFailed",
|
||||
"Error processing font file",
|
||||
e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
throw ExceptionUtils.createRuntimeException("error.fontLoadingFailed", "Error processing font file", e);
|
||||
}
|
||||
})
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
} catch (Exception e) {
|
||||
throw ExceptionUtils.createRuntimeException("error.fontDirectoryReadFailed", "Failed to read font directory", e);
|
||||
throw ExceptionUtils.createRuntimeException(
|
||||
"error.fontDirectoryReadFailed", "Failed to read font directory", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Data classes
|
||||
@Data
|
||||
public static class HomeData {
|
||||
@ -256,13 +270,19 @@ public class UIDataController {
|
||||
|
||||
private static String getFormatFromExtension(String extension) {
|
||||
switch (extension) {
|
||||
case "ttf": return "truetype";
|
||||
case "woff": return "woff";
|
||||
case "woff2": return "woff2";
|
||||
case "eot": return "embedded-opentype";
|
||||
case "svg": return "svg";
|
||||
default: return "";
|
||||
case "ttf":
|
||||
return "truetype";
|
||||
case "woff":
|
||||
return "woff";
|
||||
case "woff2":
|
||||
return "woff2";
|
||||
case "eot":
|
||||
return "embedded-opentype";
|
||||
case "svg":
|
||||
return "svg";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
package stirling.software.proprietary.controller.api;
|
||||
|
||||
import static stirling.software.common.util.ProviderUtils.validateProvider;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@ -14,7 +15,6 @@ import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
@ -24,7 +24,6 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import stirling.software.common.model.ApplicationProperties;
|
||||
@ -54,8 +53,6 @@ import stirling.software.proprietary.security.service.DatabaseService;
|
||||
import stirling.software.proprietary.security.service.TeamService;
|
||||
import stirling.software.proprietary.security.session.SessionPersistentRegistry;
|
||||
|
||||
import static stirling.software.common.util.ProviderUtils.validateProvider;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/proprietary/ui-data")
|
||||
@ -105,7 +102,7 @@ public class ProprietaryUIDataController {
|
||||
data.setRetentionDays(auditConfig.getRetentionDays());
|
||||
data.setAuditLevels(AuditLevel.values());
|
||||
data.setAuditEventTypes(AuditEventType.values());
|
||||
|
||||
|
||||
return ResponseEntity.ok(data);
|
||||
}
|
||||
|
||||
@ -120,7 +117,8 @@ public class ProprietaryUIDataController {
|
||||
if (oauth != null && oauth.getEnabled()) {
|
||||
if (oauth.isSettingsValid()) {
|
||||
String firstChar = String.valueOf(oauth.getProvider().charAt(0));
|
||||
String clientName = oauth.getProvider().replaceFirst(firstChar, firstChar.toUpperCase());
|
||||
String clientName =
|
||||
oauth.getProvider().replaceFirst(firstChar, firstChar.toUpperCase());
|
||||
providerList.put("/oauth2/authorization/" + oauth.getProvider(), clientName);
|
||||
}
|
||||
|
||||
@ -128,40 +126,46 @@ public class ProprietaryUIDataController {
|
||||
if (client != null) {
|
||||
GoogleProvider google = client.getGoogle();
|
||||
if (validateProvider(google)) {
|
||||
providerList.put("/oauth2/authorization/" + google.getName(), google.getClientName());
|
||||
providerList.put(
|
||||
"/oauth2/authorization/" + google.getName(), google.getClientName());
|
||||
}
|
||||
|
||||
GitHubProvider github = client.getGithub();
|
||||
if (validateProvider(github)) {
|
||||
providerList.put("/oauth2/authorization/" + github.getName(), github.getClientName());
|
||||
providerList.put(
|
||||
"/oauth2/authorization/" + github.getName(), github.getClientName());
|
||||
}
|
||||
|
||||
KeycloakProvider keycloak = client.getKeycloak();
|
||||
if (validateProvider(keycloak)) {
|
||||
providerList.put("/oauth2/authorization/" + keycloak.getName(), keycloak.getClientName());
|
||||
providerList.put(
|
||||
"/oauth2/authorization/" + keycloak.getName(),
|
||||
keycloak.getClientName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SAML2 saml2 = securityProps.getSaml2();
|
||||
if (securityProps.isSaml2Active() &&
|
||||
applicationProperties.getSystem().getEnableAlphaFunctionality() &&
|
||||
applicationProperties.getPremium().isEnabled()) {
|
||||
if (securityProps.isSaml2Active()
|
||||
&& applicationProperties.getSystem().getEnableAlphaFunctionality()
|
||||
&& applicationProperties.getPremium().isEnabled()) {
|
||||
String samlIdp = saml2.getProvider();
|
||||
String saml2AuthenticationPath = "/saml2/authenticate/" + saml2.getRegistrationId();
|
||||
|
||||
|
||||
if (!applicationProperties.getPremium().getProFeatures().isSsoAutoLogin()) {
|
||||
providerList.put(saml2AuthenticationPath, samlIdp + " (SAML 2)");
|
||||
}
|
||||
}
|
||||
|
||||
// Remove null entries
|
||||
providerList.entrySet().removeIf(entry -> entry.getKey() == null || entry.getValue() == null);
|
||||
|
||||
providerList
|
||||
.entrySet()
|
||||
.removeIf(entry -> entry.getKey() == null || entry.getValue() == null);
|
||||
|
||||
data.setProviderList(providerList);
|
||||
data.setLoginMethod(securityProps.getLoginMethod());
|
||||
data.setAltLogin(!providerList.isEmpty() && securityProps.isAltLogin());
|
||||
|
||||
|
||||
return ResponseEntity.ok(data);
|
||||
}
|
||||
|
||||
@ -172,12 +176,12 @@ public class ProprietaryUIDataController {
|
||||
List<User> allUsers = userRepository.findAllWithTeam();
|
||||
Iterator<User> iterator = allUsers.iterator();
|
||||
Map<String, String> roleDetails = Role.getAllRoleDetails();
|
||||
|
||||
|
||||
Map<String, Boolean> userSessions = new HashMap<>();
|
||||
Map<String, Date> userLastRequest = new HashMap<>();
|
||||
int activeUsers = 0;
|
||||
int disabledUsers = 0;
|
||||
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
User user = iterator.next();
|
||||
if (user != null) {
|
||||
@ -193,7 +197,8 @@ public class ProprietaryUIDataController {
|
||||
}
|
||||
|
||||
// Check if user is part of the Internal team
|
||||
if (user.getTeam() != null && user.getTeam().getName().equals(TeamService.INTERNAL_TEAM_NAME)) {
|
||||
if (user.getTeam() != null
|
||||
&& user.getTeam().getName().equals(TeamService.INTERNAL_TEAM_NAME)) {
|
||||
shouldRemove = true;
|
||||
}
|
||||
|
||||
@ -201,19 +206,23 @@ public class ProprietaryUIDataController {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Session status and last request time
|
||||
int maxInactiveInterval = sessionPersistentRegistry.getMaxInactiveInterval();
|
||||
boolean hasActiveSession = false;
|
||||
Date lastRequest = null;
|
||||
Optional<SessionEntity> latestSession = sessionPersistentRegistry.findLatestSession(user.getUsername());
|
||||
|
||||
Optional<SessionEntity> latestSession =
|
||||
sessionPersistentRegistry.findLatestSession(user.getUsername());
|
||||
|
||||
if (latestSession.isPresent()) {
|
||||
SessionEntity sessionEntity = latestSession.get();
|
||||
Date lastAccessedTime = sessionEntity.getLastRequest();
|
||||
Instant now = Instant.now();
|
||||
Instant expirationTime = lastAccessedTime.toInstant().plus(maxInactiveInterval, ChronoUnit.SECONDS);
|
||||
|
||||
Instant expirationTime =
|
||||
lastAccessedTime
|
||||
.toInstant()
|
||||
.plus(maxInactiveInterval, ChronoUnit.SECONDS);
|
||||
|
||||
if (now.isAfter(expirationTime)) {
|
||||
sessionPersistentRegistry.expireSession(sessionEntity.getSessionId());
|
||||
} else {
|
||||
@ -223,33 +232,40 @@ public class ProprietaryUIDataController {
|
||||
} else {
|
||||
lastRequest = new Date(0);
|
||||
}
|
||||
|
||||
|
||||
userSessions.put(user.getUsername(), hasActiveSession);
|
||||
userLastRequest.put(user.getUsername(), lastRequest);
|
||||
|
||||
|
||||
if (hasActiveSession) activeUsers++;
|
||||
if (!user.isEnabled()) disabledUsers++;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort users by active status and last request date
|
||||
List<User> sortedUsers = allUsers.stream()
|
||||
.sorted((u1, u2) -> {
|
||||
boolean u1Active = userSessions.get(u1.getUsername());
|
||||
boolean u2Active = userSessions.get(u2.getUsername());
|
||||
if (u1Active && !u2Active) return -1;
|
||||
if (!u1Active && u2Active) return 1;
|
||||
|
||||
Date u1LastRequest = userLastRequest.getOrDefault(u1.getUsername(), new Date(0));
|
||||
Date u2LastRequest = userLastRequest.getOrDefault(u2.getUsername(), new Date(0));
|
||||
return u2LastRequest.compareTo(u1LastRequest);
|
||||
})
|
||||
.toList();
|
||||
|
||||
List<Team> allTeams = teamRepository.findAll().stream()
|
||||
.filter(team -> !team.getName().equals(TeamService.INTERNAL_TEAM_NAME))
|
||||
.toList();
|
||||
|
||||
// Sort users by active status and last request date
|
||||
List<User> sortedUsers =
|
||||
allUsers.stream()
|
||||
.sorted(
|
||||
(u1, u2) -> {
|
||||
boolean u1Active = userSessions.get(u1.getUsername());
|
||||
boolean u2Active = userSessions.get(u2.getUsername());
|
||||
if (u1Active && !u2Active) return -1;
|
||||
if (!u1Active && u2Active) return 1;
|
||||
|
||||
Date u1LastRequest =
|
||||
userLastRequest.getOrDefault(
|
||||
u1.getUsername(), new Date(0));
|
||||
Date u2LastRequest =
|
||||
userLastRequest.getOrDefault(
|
||||
u2.getUsername(), new Date(0));
|
||||
return u2LastRequest.compareTo(u1LastRequest);
|
||||
})
|
||||
.toList();
|
||||
|
||||
List<Team> allTeams =
|
||||
teamRepository.findAll().stream()
|
||||
.filter(team -> !team.getName().equals(TeamService.INTERNAL_TEAM_NAME))
|
||||
.toList();
|
||||
|
||||
AdminSettingsData data = new AdminSettingsData();
|
||||
data.setUsers(sortedUsers);
|
||||
data.setCurrentUsername(authentication.getName());
|
||||
@ -261,7 +277,7 @@ public class ProprietaryUIDataController {
|
||||
data.setDisabledUsers(disabledUsers);
|
||||
data.setTeams(allTeams);
|
||||
data.setMaxPaidUsers(applicationProperties.getPremium().getMaxUsers());
|
||||
|
||||
|
||||
return ResponseEntity.ok(data);
|
||||
}
|
||||
|
||||
@ -272,7 +288,7 @@ public class ProprietaryUIDataController {
|
||||
if (authentication == null || !authentication.isAuthenticated()) {
|
||||
return ResponseEntity.status(401).build();
|
||||
}
|
||||
|
||||
|
||||
Object principal = authentication.getPrincipal();
|
||||
String username = null;
|
||||
boolean isOAuth2Login = false;
|
||||
@ -287,16 +303,16 @@ public class ProprietaryUIDataController {
|
||||
username = saml2User.name();
|
||||
isSaml2Login = true;
|
||||
}
|
||||
|
||||
|
||||
if (username == null) {
|
||||
return ResponseEntity.status(401).build();
|
||||
}
|
||||
|
||||
|
||||
Optional<User> user = userRepository.findByUsernameIgnoreCaseWithSettings(username);
|
||||
if (user.isEmpty()) {
|
||||
return ResponseEntity.status(404).build();
|
||||
}
|
||||
|
||||
|
||||
String settingsJson;
|
||||
try {
|
||||
settingsJson = objectMapper.writeValueAsString(user.get().getSettings());
|
||||
@ -304,7 +320,7 @@ public class ProprietaryUIDataController {
|
||||
log.error("Error converting settings map", e);
|
||||
return ResponseEntity.status(500).build();
|
||||
}
|
||||
|
||||
|
||||
AccountData data = new AccountData();
|
||||
data.setUsername(username);
|
||||
data.setRole(user.get().getRolesAsString());
|
||||
@ -312,7 +328,7 @@ public class ProprietaryUIDataController {
|
||||
data.setChangeCredsFlag(user.get().isFirstLogin());
|
||||
data.setOAuth2Login(isOAuth2Login);
|
||||
data.setSaml2Login(isSaml2Login);
|
||||
|
||||
|
||||
return ResponseEntity.ok(data);
|
||||
}
|
||||
|
||||
@ -321,9 +337,10 @@ public class ProprietaryUIDataController {
|
||||
@Operation(summary = "Get teams list data")
|
||||
public ResponseEntity<TeamsData> getTeamsData() {
|
||||
List<TeamWithUserCountDTO> allTeamsWithCounts = teamRepository.findAllTeamsWithUserCount();
|
||||
List<TeamWithUserCountDTO> teamsWithCounts = allTeamsWithCounts.stream()
|
||||
.filter(team -> !team.getName().equals(TeamService.INTERNAL_TEAM_NAME))
|
||||
.toList();
|
||||
List<TeamWithUserCountDTO> teamsWithCounts =
|
||||
allTeamsWithCounts.stream()
|
||||
.filter(team -> !team.getName().equals(TeamService.INTERNAL_TEAM_NAME))
|
||||
.toList();
|
||||
|
||||
List<Object[]> teamActivities = sessionRepository.findLatestActivityByTeam();
|
||||
Map<Long, Date> teamLastRequest = new HashMap<>();
|
||||
@ -332,11 +349,11 @@ public class ProprietaryUIDataController {
|
||||
Date lastActivity = (Date) result[1];
|
||||
teamLastRequest.put(teamId, lastActivity);
|
||||
}
|
||||
|
||||
|
||||
TeamsData data = new TeamsData();
|
||||
data.setTeamsWithCounts(teamsWithCounts);
|
||||
data.setTeamLastRequest(teamLastRequest);
|
||||
|
||||
|
||||
return ResponseEntity.ok(data);
|
||||
}
|
||||
|
||||
@ -344,8 +361,10 @@ public class ProprietaryUIDataController {
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@Operation(summary = "Get team details data")
|
||||
public ResponseEntity<TeamDetailsData> getTeamDetailsData(@PathVariable("id") Long id) {
|
||||
Team team = teamRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("Team not found"));
|
||||
Team team =
|
||||
teamRepository
|
||||
.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("Team not found"));
|
||||
|
||||
if (team.getName().equals(TeamService.INTERNAL_TEAM_NAME)) {
|
||||
return ResponseEntity.status(403).build();
|
||||
@ -353,10 +372,19 @@ public class ProprietaryUIDataController {
|
||||
|
||||
List<User> teamUsers = userRepository.findAllByTeamId(id);
|
||||
List<User> allUsers = userRepository.findAllWithTeam();
|
||||
List<User> availableUsers = allUsers.stream()
|
||||
.filter(user -> (user.getTeam() == null || !user.getTeam().getId().equals(id)) &&
|
||||
(user.getTeam() == null || !user.getTeam().getName().equals(TeamService.INTERNAL_TEAM_NAME)))
|
||||
.toList();
|
||||
List<User> availableUsers =
|
||||
allUsers.stream()
|
||||
.filter(
|
||||
user ->
|
||||
(user.getTeam() == null
|
||||
|| !user.getTeam().getId().equals(id))
|
||||
&& (user.getTeam() == null
|
||||
|| !user.getTeam()
|
||||
.getName()
|
||||
.equals(
|
||||
TeamService
|
||||
.INTERNAL_TEAM_NAME)))
|
||||
.toList();
|
||||
|
||||
List<Object[]> userSessions = sessionRepository.findLatestSessionByTeamId(id);
|
||||
Map<String, Date> userLastRequest = new HashMap<>();
|
||||
@ -365,13 +393,13 @@ public class ProprietaryUIDataController {
|
||||
Date lastRequest = (Date) result[1];
|
||||
userLastRequest.put(username, lastRequest);
|
||||
}
|
||||
|
||||
|
||||
TeamDetailsData data = new TeamDetailsData();
|
||||
data.setTeam(team);
|
||||
data.setTeamUsers(teamUsers);
|
||||
data.setAvailableUsers(availableUsers);
|
||||
data.setUserLastRequest(userLastRequest);
|
||||
|
||||
|
||||
return ResponseEntity.ok(data);
|
||||
}
|
||||
|
||||
@ -382,12 +410,12 @@ public class ProprietaryUIDataController {
|
||||
List<FileInfo> backupList = databaseService.getBackupList();
|
||||
String dbVersion = databaseService.getH2Version();
|
||||
boolean isVersionUnknown = "Unknown".equalsIgnoreCase(dbVersion);
|
||||
|
||||
|
||||
DatabaseData data = new DatabaseData();
|
||||
data.setBackupFiles(backupList);
|
||||
data.setDatabaseVersion(dbVersion);
|
||||
data.setVersionUnknown(isVersionUnknown);
|
||||
|
||||
|
||||
return ResponseEntity.ok(data);
|
||||
}
|
||||
|
||||
@ -453,4 +481,4 @@ public class ProprietaryUIDataController {
|
||||
private String databaseVersion;
|
||||
private boolean versionUnknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,9 +26,9 @@ http {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Proxy API calls to backend
|
||||
location /api/ {
|
||||
proxy_pass ${VITE_API_BASE_URL}/api/;
|
||||
# Proxy API calls to backend (with query parameters and sub-paths)
|
||||
location ~ ^/api(.*)$ {
|
||||
proxy_pass ${VITE_API_BASE_URL}/api$1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
@ -575,6 +575,10 @@
|
||||
"title": "Validate PDF Signature",
|
||||
"desc": "Verify digital signatures and certificates in PDF documents"
|
||||
},
|
||||
"swagger": {
|
||||
"title": "API Documentation",
|
||||
"desc": "View API documentation and test endpoints"
|
||||
},
|
||||
"replaceColorPdf": {
|
||||
"title": "Advanced Colour options",
|
||||
"desc": "Replace colour for text and background in PDF and invert full colour of pdf to reduce file size"
|
||||
@ -1521,6 +1525,12 @@
|
||||
},
|
||||
"note": "Release notes are only available in English"
|
||||
},
|
||||
"swagger": {
|
||||
"title": "API Documentation",
|
||||
"header": "API Documentation",
|
||||
"desc": "View and test the Stirling PDF API endpoints",
|
||||
"tags": "api,documentation,swagger,endpoints,development"
|
||||
},
|
||||
"cookieBanner": {
|
||||
"popUp": {
|
||||
"title": "How we use Cookies",
|
||||
|
@ -575,6 +575,10 @@
|
||||
"title": "Validate PDF Signature",
|
||||
"desc": "Verify digital signatures and certificates in PDF documents"
|
||||
},
|
||||
"swagger": {
|
||||
"title": "API Documentation",
|
||||
"desc": "View API documentation and test endpoints"
|
||||
},
|
||||
"replaceColorPdf": {
|
||||
"title": "Replace and Invert Color",
|
||||
"desc": "Replace color for text and background in PDF and invert full color of pdf to reduce file size"
|
||||
@ -1521,6 +1525,12 @@
|
||||
},
|
||||
"note": "Release notes are only available in English"
|
||||
},
|
||||
"swagger": {
|
||||
"title": "API Documentation",
|
||||
"header": "API Documentation",
|
||||
"desc": "View and test the Stirling PDF API endpoints",
|
||||
"tags": "api,documentation,swagger,endpoints,development"
|
||||
},
|
||||
"cookieBanner": {
|
||||
"popUp": {
|
||||
"title": "How we use Cookies",
|
||||
|
@ -2,6 +2,7 @@ import React, { useState, useCallback, useMemo, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import ContentCutIcon from "@mui/icons-material/ContentCut";
|
||||
import ZoomInMapIcon from "@mui/icons-material/ZoomInMap";
|
||||
import ApiIcon from "@mui/icons-material/Api";
|
||||
import { useMultipleEndpointsEnabled } from "./useEndpointConfig";
|
||||
import { Tool, ToolDefinition, BaseToolProps, ToolRegistry } from "../types/tool";
|
||||
|
||||
@ -26,6 +27,15 @@ const toolDefinitions: Record<string, ToolDefinition> = {
|
||||
description: "Reduce PDF file size",
|
||||
endpoints: ["compress-pdf"]
|
||||
},
|
||||
swagger: {
|
||||
id: "swagger",
|
||||
icon: <ApiIcon />,
|
||||
component: React.lazy(() => import("../tools/SwaggerUI")),
|
||||
maxFiles: 0,
|
||||
category: "utility",
|
||||
description: "Open API documentation",
|
||||
endpoints: ["swagger-ui"]
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
|
18
frontend/src/tools/SwaggerUI.tsx
Normal file
18
frontend/src/tools/SwaggerUI.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { BaseToolProps } from '../types/tool';
|
||||
|
||||
const SwaggerUI: React.FC<BaseToolProps> = () => {
|
||||
useEffect(() => {
|
||||
// Redirect to Swagger UI
|
||||
window.open('/swagger-ui/5.21.0/index.html', '_blank');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div style={{ textAlign: 'center', padding: '2rem' }}>
|
||||
<p>Opening Swagger UI in a new tab...</p>
|
||||
<p>If it didn't open automatically, <a href="/swagger-ui/5.21.0/index.html" target="_blank" rel="noopener noreferrer">click here</a></p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SwaggerUI;
|
Loading…
x
Reference in New Issue
Block a user