mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-05 03:55: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.*;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.ResourceLoader;
|
import org.springframework.core.io.ResourceLoader;
|
||||||
@ -35,7 +34,6 @@ import stirling.software.common.configuration.InstallationPathConfig;
|
|||||||
import stirling.software.common.configuration.RuntimePathConfig;
|
import stirling.software.common.configuration.RuntimePathConfig;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.common.model.ApplicationProperties;
|
||||||
import stirling.software.common.service.UserServiceInterface;
|
import stirling.software.common.service.UserServiceInterface;
|
||||||
import stirling.software.common.util.CheckProgramInstall;
|
|
||||||
import stirling.software.common.util.ExceptionUtils;
|
import stirling.software.common.util.ExceptionUtils;
|
||||||
import stirling.software.common.util.GeneralUtils;
|
import stirling.software.common.util.GeneralUtils;
|
||||||
|
|
||||||
@ -74,7 +72,8 @@ public class UIDataController {
|
|||||||
InputStream is = resource.getInputStream();
|
InputStream is = resource.getInputStream();
|
||||||
String json = new String(is.readAllBytes(), StandardCharsets.UTF_8);
|
String json = new String(is.readAllBytes(), StandardCharsets.UTF_8);
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
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"));
|
data.setDependencies(licenseData.get("dependencies"));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Failed to load licenses data", e);
|
log.error("Failed to load licenses data", e);
|
||||||
@ -92,10 +91,12 @@ public class UIDataController {
|
|||||||
List<Map<String, String>> pipelineConfigsWithNames = new ArrayList<>();
|
List<Map<String, String>> pipelineConfigsWithNames = new ArrayList<>();
|
||||||
|
|
||||||
if (new java.io.File(runtimePathConfig.getPipelineDefaultWebUiConfigs()).exists()) {
|
if (new java.io.File(runtimePathConfig.getPipelineDefaultWebUiConfigs()).exists()) {
|
||||||
try (Stream<Path> paths = Files.walk(Paths.get(runtimePathConfig.getPipelineDefaultWebUiConfigs()))) {
|
try (Stream<Path> paths =
|
||||||
List<Path> jsonFiles = paths.filter(Files::isRegularFile)
|
Files.walk(Paths.get(runtimePathConfig.getPipelineDefaultWebUiConfigs()))) {
|
||||||
.filter(p -> p.toString().endsWith(".json"))
|
List<Path> jsonFiles =
|
||||||
.toList();
|
paths.filter(Files::isRegularFile)
|
||||||
|
.filter(p -> p.toString().endsWith(".json"))
|
||||||
|
.toList();
|
||||||
|
|
||||||
for (Path jsonFile : jsonFiles) {
|
for (Path jsonFile : jsonFiles) {
|
||||||
String content = Files.readString(jsonFile, StandardCharsets.UTF_8);
|
String content = Files.readString(jsonFile, StandardCharsets.UTF_8);
|
||||||
@ -103,12 +104,16 @@ public class UIDataController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (String config : pipelineConfigs) {
|
for (String config : pipelineConfigs) {
|
||||||
Map<String, Object> jsonContent = new ObjectMapper()
|
Map<String, Object> jsonContent =
|
||||||
.readValue(config, new TypeReference<Map<String, Object>>() {});
|
new ObjectMapper()
|
||||||
|
.readValue(config, new TypeReference<Map<String, Object>>() {});
|
||||||
String name = (String) jsonContent.get("name");
|
String name = (String) jsonContent.get("name");
|
||||||
if (name == null || name.length() < 1) {
|
if (name == null || name.length() < 1) {
|
||||||
String filename = jsonFiles.get(pipelineConfigs.indexOf(config))
|
String filename =
|
||||||
.getFileName().toString();
|
jsonFiles
|
||||||
|
.get(pipelineConfigs.indexOf(config))
|
||||||
|
.getFileName()
|
||||||
|
.toString();
|
||||||
name = filename.substring(0, filename.lastIndexOf('.'));
|
name = filename.substring(0, filename.lastIndexOf('.'));
|
||||||
}
|
}
|
||||||
Map<String, String> configWithName = new HashMap<>();
|
Map<String, String> configWithName = new HashMap<>();
|
||||||
@ -152,7 +157,6 @@ public class UIDataController {
|
|||||||
return ResponseEntity.ok(data);
|
return ResponseEntity.ok(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/ocr-pdf")
|
@GetMapping("/ocr-pdf")
|
||||||
@Operation(summary = "Get OCR PDF data")
|
@Operation(summary = "Get OCR PDF data")
|
||||||
public ResponseEntity<OcrData> getOcrPdfData() {
|
public ResponseEntity<OcrData> getOcrPdfData() {
|
||||||
@ -181,39 +185,49 @@ public class UIDataController {
|
|||||||
private List<FontResource> getFontNames() {
|
private List<FontResource> getFontNames() {
|
||||||
List<FontResource> fontNames = new ArrayList<>();
|
List<FontResource> fontNames = new ArrayList<>();
|
||||||
fontNames.addAll(getFontNamesFromLocation("classpath:static/fonts/*.woff2"));
|
fontNames.addAll(getFontNamesFromLocation("classpath:static/fonts/*.woff2"));
|
||||||
fontNames.addAll(getFontNamesFromLocation(
|
fontNames.addAll(
|
||||||
"file:" + InstallationPathConfig.getStaticPath() + "fonts" + java.io.File.separator + "*"));
|
getFontNamesFromLocation(
|
||||||
|
"file:"
|
||||||
|
+ InstallationPathConfig.getStaticPath()
|
||||||
|
+ "fonts"
|
||||||
|
+ java.io.File.separator
|
||||||
|
+ "*"));
|
||||||
return fontNames;
|
return fontNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<FontResource> getFontNamesFromLocation(String locationPattern) {
|
private List<FontResource> getFontNamesFromLocation(String locationPattern) {
|
||||||
try {
|
try {
|
||||||
Resource[] resources = GeneralUtils.getResourcesFromLocationPattern(locationPattern, resourceLoader);
|
Resource[] resources =
|
||||||
|
GeneralUtils.getResourcesFromLocationPattern(locationPattern, resourceLoader);
|
||||||
return Arrays.stream(resources)
|
return Arrays.stream(resources)
|
||||||
.map(resource -> {
|
.map(
|
||||||
try {
|
resource -> {
|
||||||
String filename = resource.getFilename();
|
try {
|
||||||
if (filename != null) {
|
String filename = resource.getFilename();
|
||||||
int lastDotIndex = filename.lastIndexOf('.');
|
if (filename != null) {
|
||||||
if (lastDotIndex != -1) {
|
int lastDotIndex = filename.lastIndexOf('.');
|
||||||
String name = filename.substring(0, lastDotIndex);
|
if (lastDotIndex != -1) {
|
||||||
String extension = filename.substring(lastDotIndex + 1);
|
String name = filename.substring(0, lastDotIndex);
|
||||||
return new FontResource(name, extension);
|
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)
|
.filter(Objects::nonNull)
|
||||||
.toList();
|
.toList();
|
||||||
} catch (Exception e) {
|
} 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 classes
|
||||||
@Data
|
@Data
|
||||||
public static class HomeData {
|
public static class HomeData {
|
||||||
@ -256,12 +270,18 @@ public class UIDataController {
|
|||||||
|
|
||||||
private static String getFormatFromExtension(String extension) {
|
private static String getFormatFromExtension(String extension) {
|
||||||
switch (extension) {
|
switch (extension) {
|
||||||
case "ttf": return "truetype";
|
case "ttf":
|
||||||
case "woff": return "woff";
|
return "truetype";
|
||||||
case "woff2": return "woff2";
|
case "woff":
|
||||||
case "eot": return "embedded-opentype";
|
return "woff";
|
||||||
case "svg": return "svg";
|
case "woff2":
|
||||||
default: return "";
|
return "woff2";
|
||||||
|
case "eot":
|
||||||
|
return "embedded-opentype";
|
||||||
|
case "svg":
|
||||||
|
return "svg";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package stirling.software.proprietary.controller.api;
|
package stirling.software.proprietary.controller.api;
|
||||||
|
|
||||||
|
import static stirling.software.common.util.ProviderUtils.validateProvider;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.http.ResponseEntity;
|
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.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
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 io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
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.service.TeamService;
|
||||||
import stirling.software.proprietary.security.session.SessionPersistentRegistry;
|
import stirling.software.proprietary.security.session.SessionPersistentRegistry;
|
||||||
|
|
||||||
import static stirling.software.common.util.ProviderUtils.validateProvider;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/proprietary/ui-data")
|
@RequestMapping("/api/v1/proprietary/ui-data")
|
||||||
@ -120,7 +117,8 @@ public class ProprietaryUIDataController {
|
|||||||
if (oauth != null && oauth.getEnabled()) {
|
if (oauth != null && oauth.getEnabled()) {
|
||||||
if (oauth.isSettingsValid()) {
|
if (oauth.isSettingsValid()) {
|
||||||
String firstChar = String.valueOf(oauth.getProvider().charAt(0));
|
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);
|
providerList.put("/oauth2/authorization/" + oauth.getProvider(), clientName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,25 +126,29 @@ public class ProprietaryUIDataController {
|
|||||||
if (client != null) {
|
if (client != null) {
|
||||||
GoogleProvider google = client.getGoogle();
|
GoogleProvider google = client.getGoogle();
|
||||||
if (validateProvider(google)) {
|
if (validateProvider(google)) {
|
||||||
providerList.put("/oauth2/authorization/" + google.getName(), google.getClientName());
|
providerList.put(
|
||||||
|
"/oauth2/authorization/" + google.getName(), google.getClientName());
|
||||||
}
|
}
|
||||||
|
|
||||||
GitHubProvider github = client.getGithub();
|
GitHubProvider github = client.getGithub();
|
||||||
if (validateProvider(github)) {
|
if (validateProvider(github)) {
|
||||||
providerList.put("/oauth2/authorization/" + github.getName(), github.getClientName());
|
providerList.put(
|
||||||
|
"/oauth2/authorization/" + github.getName(), github.getClientName());
|
||||||
}
|
}
|
||||||
|
|
||||||
KeycloakProvider keycloak = client.getKeycloak();
|
KeycloakProvider keycloak = client.getKeycloak();
|
||||||
if (validateProvider(keycloak)) {
|
if (validateProvider(keycloak)) {
|
||||||
providerList.put("/oauth2/authorization/" + keycloak.getName(), keycloak.getClientName());
|
providerList.put(
|
||||||
|
"/oauth2/authorization/" + keycloak.getName(),
|
||||||
|
keycloak.getClientName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SAML2 saml2 = securityProps.getSaml2();
|
SAML2 saml2 = securityProps.getSaml2();
|
||||||
if (securityProps.isSaml2Active() &&
|
if (securityProps.isSaml2Active()
|
||||||
applicationProperties.getSystem().getEnableAlphaFunctionality() &&
|
&& applicationProperties.getSystem().getEnableAlphaFunctionality()
|
||||||
applicationProperties.getPremium().isEnabled()) {
|
&& applicationProperties.getPremium().isEnabled()) {
|
||||||
String samlIdp = saml2.getProvider();
|
String samlIdp = saml2.getProvider();
|
||||||
String saml2AuthenticationPath = "/saml2/authenticate/" + saml2.getRegistrationId();
|
String saml2AuthenticationPath = "/saml2/authenticate/" + saml2.getRegistrationId();
|
||||||
|
|
||||||
@ -156,7 +158,9 @@ public class ProprietaryUIDataController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove null entries
|
// 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.setProviderList(providerList);
|
||||||
data.setLoginMethod(securityProps.getLoginMethod());
|
data.setLoginMethod(securityProps.getLoginMethod());
|
||||||
@ -193,7 +197,8 @@ public class ProprietaryUIDataController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if user is part of the Internal team
|
// 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;
|
shouldRemove = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,13 +211,17 @@ public class ProprietaryUIDataController {
|
|||||||
int maxInactiveInterval = sessionPersistentRegistry.getMaxInactiveInterval();
|
int maxInactiveInterval = sessionPersistentRegistry.getMaxInactiveInterval();
|
||||||
boolean hasActiveSession = false;
|
boolean hasActiveSession = false;
|
||||||
Date lastRequest = null;
|
Date lastRequest = null;
|
||||||
Optional<SessionEntity> latestSession = sessionPersistentRegistry.findLatestSession(user.getUsername());
|
Optional<SessionEntity> latestSession =
|
||||||
|
sessionPersistentRegistry.findLatestSession(user.getUsername());
|
||||||
|
|
||||||
if (latestSession.isPresent()) {
|
if (latestSession.isPresent()) {
|
||||||
SessionEntity sessionEntity = latestSession.get();
|
SessionEntity sessionEntity = latestSession.get();
|
||||||
Date lastAccessedTime = sessionEntity.getLastRequest();
|
Date lastAccessedTime = sessionEntity.getLastRequest();
|
||||||
Instant now = Instant.now();
|
Instant now = Instant.now();
|
||||||
Instant expirationTime = lastAccessedTime.toInstant().plus(maxInactiveInterval, ChronoUnit.SECONDS);
|
Instant expirationTime =
|
||||||
|
lastAccessedTime
|
||||||
|
.toInstant()
|
||||||
|
.plus(maxInactiveInterval, ChronoUnit.SECONDS);
|
||||||
|
|
||||||
if (now.isAfter(expirationTime)) {
|
if (now.isAfter(expirationTime)) {
|
||||||
sessionPersistentRegistry.expireSession(sessionEntity.getSessionId());
|
sessionPersistentRegistry.expireSession(sessionEntity.getSessionId());
|
||||||
@ -233,22 +242,29 @@ public class ProprietaryUIDataController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sort users by active status and last request date
|
// Sort users by active status and last request date
|
||||||
List<User> sortedUsers = allUsers.stream()
|
List<User> sortedUsers =
|
||||||
.sorted((u1, u2) -> {
|
allUsers.stream()
|
||||||
boolean u1Active = userSessions.get(u1.getUsername());
|
.sorted(
|
||||||
boolean u2Active = userSessions.get(u2.getUsername());
|
(u1, u2) -> {
|
||||||
if (u1Active && !u2Active) return -1;
|
boolean u1Active = userSessions.get(u1.getUsername());
|
||||||
if (!u1Active && u2Active) return 1;
|
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 u1LastRequest =
|
||||||
Date u2LastRequest = userLastRequest.getOrDefault(u2.getUsername(), new Date(0));
|
userLastRequest.getOrDefault(
|
||||||
return u2LastRequest.compareTo(u1LastRequest);
|
u1.getUsername(), new Date(0));
|
||||||
})
|
Date u2LastRequest =
|
||||||
.toList();
|
userLastRequest.getOrDefault(
|
||||||
|
u2.getUsername(), new Date(0));
|
||||||
|
return u2LastRequest.compareTo(u1LastRequest);
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
|
||||||
List<Team> allTeams = teamRepository.findAll().stream()
|
List<Team> allTeams =
|
||||||
.filter(team -> !team.getName().equals(TeamService.INTERNAL_TEAM_NAME))
|
teamRepository.findAll().stream()
|
||||||
.toList();
|
.filter(team -> !team.getName().equals(TeamService.INTERNAL_TEAM_NAME))
|
||||||
|
.toList();
|
||||||
|
|
||||||
AdminSettingsData data = new AdminSettingsData();
|
AdminSettingsData data = new AdminSettingsData();
|
||||||
data.setUsers(sortedUsers);
|
data.setUsers(sortedUsers);
|
||||||
@ -321,9 +337,10 @@ public class ProprietaryUIDataController {
|
|||||||
@Operation(summary = "Get teams list data")
|
@Operation(summary = "Get teams list data")
|
||||||
public ResponseEntity<TeamsData> getTeamsData() {
|
public ResponseEntity<TeamsData> getTeamsData() {
|
||||||
List<TeamWithUserCountDTO> allTeamsWithCounts = teamRepository.findAllTeamsWithUserCount();
|
List<TeamWithUserCountDTO> allTeamsWithCounts = teamRepository.findAllTeamsWithUserCount();
|
||||||
List<TeamWithUserCountDTO> teamsWithCounts = allTeamsWithCounts.stream()
|
List<TeamWithUserCountDTO> teamsWithCounts =
|
||||||
.filter(team -> !team.getName().equals(TeamService.INTERNAL_TEAM_NAME))
|
allTeamsWithCounts.stream()
|
||||||
.toList();
|
.filter(team -> !team.getName().equals(TeamService.INTERNAL_TEAM_NAME))
|
||||||
|
.toList();
|
||||||
|
|
||||||
List<Object[]> teamActivities = sessionRepository.findLatestActivityByTeam();
|
List<Object[]> teamActivities = sessionRepository.findLatestActivityByTeam();
|
||||||
Map<Long, Date> teamLastRequest = new HashMap<>();
|
Map<Long, Date> teamLastRequest = new HashMap<>();
|
||||||
@ -344,8 +361,10 @@ public class ProprietaryUIDataController {
|
|||||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||||
@Operation(summary = "Get team details data")
|
@Operation(summary = "Get team details data")
|
||||||
public ResponseEntity<TeamDetailsData> getTeamDetailsData(@PathVariable("id") Long id) {
|
public ResponseEntity<TeamDetailsData> getTeamDetailsData(@PathVariable("id") Long id) {
|
||||||
Team team = teamRepository.findById(id)
|
Team team =
|
||||||
.orElseThrow(() -> new RuntimeException("Team not found"));
|
teamRepository
|
||||||
|
.findById(id)
|
||||||
|
.orElseThrow(() -> new RuntimeException("Team not found"));
|
||||||
|
|
||||||
if (team.getName().equals(TeamService.INTERNAL_TEAM_NAME)) {
|
if (team.getName().equals(TeamService.INTERNAL_TEAM_NAME)) {
|
||||||
return ResponseEntity.status(403).build();
|
return ResponseEntity.status(403).build();
|
||||||
@ -353,10 +372,19 @@ public class ProprietaryUIDataController {
|
|||||||
|
|
||||||
List<User> teamUsers = userRepository.findAllByTeamId(id);
|
List<User> teamUsers = userRepository.findAllByTeamId(id);
|
||||||
List<User> allUsers = userRepository.findAllWithTeam();
|
List<User> allUsers = userRepository.findAllWithTeam();
|
||||||
List<User> availableUsers = allUsers.stream()
|
List<User> availableUsers =
|
||||||
.filter(user -> (user.getTeam() == null || !user.getTeam().getId().equals(id)) &&
|
allUsers.stream()
|
||||||
(user.getTeam() == null || !user.getTeam().getName().equals(TeamService.INTERNAL_TEAM_NAME)))
|
.filter(
|
||||||
.toList();
|
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);
|
List<Object[]> userSessions = sessionRepository.findLatestSessionByTeamId(id);
|
||||||
Map<String, Date> userLastRequest = new HashMap<>();
|
Map<String, Date> userLastRequest = new HashMap<>();
|
||||||
|
@ -26,9 +26,9 @@ http {
|
|||||||
try_files $uri $uri/ /index.html;
|
try_files $uri $uri/ /index.html;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Proxy API calls to backend
|
# Proxy API calls to backend (with query parameters and sub-paths)
|
||||||
location /api/ {
|
location ~ ^/api(.*)$ {
|
||||||
proxy_pass ${VITE_API_BASE_URL}/api/;
|
proxy_pass ${VITE_API_BASE_URL}/api$1;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
@ -575,6 +575,10 @@
|
|||||||
"title": "Validate PDF Signature",
|
"title": "Validate PDF Signature",
|
||||||
"desc": "Verify digital signatures and certificates in PDF documents"
|
"desc": "Verify digital signatures and certificates in PDF documents"
|
||||||
},
|
},
|
||||||
|
"swagger": {
|
||||||
|
"title": "API Documentation",
|
||||||
|
"desc": "View API documentation and test endpoints"
|
||||||
|
},
|
||||||
"replaceColorPdf": {
|
"replaceColorPdf": {
|
||||||
"title": "Advanced Colour options",
|
"title": "Advanced Colour options",
|
||||||
"desc": "Replace colour for text and background in PDF and invert full colour of pdf to reduce file size"
|
"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"
|
"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": {
|
"cookieBanner": {
|
||||||
"popUp": {
|
"popUp": {
|
||||||
"title": "How we use Cookies",
|
"title": "How we use Cookies",
|
||||||
|
@ -575,6 +575,10 @@
|
|||||||
"title": "Validate PDF Signature",
|
"title": "Validate PDF Signature",
|
||||||
"desc": "Verify digital signatures and certificates in PDF documents"
|
"desc": "Verify digital signatures and certificates in PDF documents"
|
||||||
},
|
},
|
||||||
|
"swagger": {
|
||||||
|
"title": "API Documentation",
|
||||||
|
"desc": "View API documentation and test endpoints"
|
||||||
|
},
|
||||||
"replaceColorPdf": {
|
"replaceColorPdf": {
|
||||||
"title": "Replace and Invert Color",
|
"title": "Replace and Invert Color",
|
||||||
"desc": "Replace color for text and background in PDF and invert full color of pdf to reduce file size"
|
"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"
|
"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": {
|
"cookieBanner": {
|
||||||
"popUp": {
|
"popUp": {
|
||||||
"title": "How we use Cookies",
|
"title": "How we use Cookies",
|
||||||
|
@ -2,6 +2,7 @@ import React, { useState, useCallback, useMemo, useEffect } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import ContentCutIcon from "@mui/icons-material/ContentCut";
|
import ContentCutIcon from "@mui/icons-material/ContentCut";
|
||||||
import ZoomInMapIcon from "@mui/icons-material/ZoomInMap";
|
import ZoomInMapIcon from "@mui/icons-material/ZoomInMap";
|
||||||
|
import ApiIcon from "@mui/icons-material/Api";
|
||||||
import { useMultipleEndpointsEnabled } from "./useEndpointConfig";
|
import { useMultipleEndpointsEnabled } from "./useEndpointConfig";
|
||||||
import { Tool, ToolDefinition, BaseToolProps, ToolRegistry } from "../types/tool";
|
import { Tool, ToolDefinition, BaseToolProps, ToolRegistry } from "../types/tool";
|
||||||
|
|
||||||
@ -26,6 +27,15 @@ const toolDefinitions: Record<string, ToolDefinition> = {
|
|||||||
description: "Reduce PDF file size",
|
description: "Reduce PDF file size",
|
||||||
endpoints: ["compress-pdf"]
|
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