19 Commits

Author SHA1 Message Date
bc00515c1b Edit case issues fixed - Now add case and edit case are working fine 2026-08-02 22:32:54 +05:30
60f9aa05a0 Query 19,20,21,22 migrated - Find same case details in punching screen in case of co-applicant 2026-08-02 14:34:21 +05:30
4705649ae8 Auto Cut Feature Done 2026-08-02 12:52:05 +05:30
5acaffc224 Migrated Query - 24 find punchedrecords 2026-08-02 11:49:39 +05:30
0a1b901b12 More refactoring in js code 2026-08-02 11:09:55 +05:30
440c13cc49 Code Refactored 2026-08-02 10:37:20 +05:30
9b9557105c Removed stale files 2026-08-02 01:09:53 +05:30
af360d7793 Case Punching Feature Done 2026-08-02 00:47:00 +05:30
452e6189e4 Migrated Queries - 4,5 and 70 2026-08-01 23:10:28 +05:30
7e4fb66fc6 Restore installer tests excluded by gitignore 2026-08-01 21:56:23 +05:30
213f560c4a Apply .gitignore 2026-08-01 21:44:11 +05:30
8449578424 Migrated Query 3 - Using Parameterized query 2026-08-01 20:56:12 +05:30
1adcc04efc Punching screen controller created - migrated initview and addcase endpoints 2026-08-01 19:16:24 +05:30
0e5de99f55 Update RedisCachingQueryProvider.java 2026-08-01 16:15:46 +05:30
0dae53017d Query migration to db done - Query persistence in cache is also done 2026-08-01 16:08:52 +05:30
934937feb0 commit 2026-08-01 15:41:35 +05:30
dcb6850306 Fixed PEM Keys issue 2026-08-01 09:51:36 +05:30
f264f90f3b commit 2026-07-27 21:42:45 +05:30
cd11b389e5 Update .gitignore 2026-07-26 23:48:03 +05:30
227 changed files with 7582 additions and 6982 deletions

BIN
.DS_Store vendored

Binary file not shown.

6
.gitignore vendored
View File

@@ -30,6 +30,8 @@
/.nb-gradle/ /.nb-gradle/
/cygnus-onprem-app/target /cygnus-onprem-app/target
/cygnus-cloud-client/target /cygnus-cloud-client/target
/cygnus-installer/src/test
/cygnus-cloud-client/target
/cygnus-cloud-service/target /cygnus-cloud-service/target
/cygnus-installer/src/target
/cygnus-installer/target
/cygnus-onprem-db/target
/cygnus-lib/target

8
.vscode/launch.json vendored
View File

@@ -59,14 +59,18 @@
"REDIS_HOST": "103.125.129.116", "REDIS_HOST": "103.125.129.116",
"REDIS_PORT": "7901", "REDIS_PORT": "7901",
"REDIS_PASSWORD": "M@triXR3d1s@6202", "REDIS_PASSWORD": "M@triXR3d1s@6202",
"REDIS_DATABASE": "1",
"REDIS_SSL": "false", "REDIS_SSL": "false",
"CYGNUS_QUERY_CACHE_ENABLED": "false",
"CYGNUS_CLOUD_BASE_URL": "http://localhost:8090", "CYGNUS_CLOUD_BASE_URL": "http://localhost:8090",
"CYGNUS_TOKEN_URL": "http://localhost:8090/oauth2/token", "CYGNUS_TOKEN_URL": "http://localhost:8090/oauth2/token",
"CYGNUS_CLIENT_ID": "matrix", "CYGNUS_CLIENT_ID": "matrix",
"CYGNUS_INSTALLATION_ID": "matrix-delhi-cygnus-01", "CYGNUS_INSTALLATION_ID": "matrix-delhi-cygnus-01",
"CYGNUS_CLIENT_ASSERTION": "file:${workspaceFolder}/matrix-installation/config/machine-assertion.jwt", "CYGNUS_CLIENT_ASSERTION": "file:${workspaceFolder}/config/clients/matrix/matrix-matrix-delhi-cygnus-01-assertion.jwt",
"CYGNUS_LOGIN_KEY_ID": "cygnus-login-2026-01", "CYGNUS_LOGIN_KEY_ID": "cygnus-login-2026-01",
"CYGNUS_LOGIN_PUBLIC_KEY": "file:${workspaceFolder}/matrix-installation/config/keys/login-public.pem", "CYGNUS_LOGIN_PUBLIC_KEY": "file:${workspaceFolder}/config/keys/login-public.pem",
"CYGNUS_PAYLOAD_PRIVATE_KEY": "file:${workspaceFolder}/config/keys/case-save-private.pem",
"CYGNUS_PAYLOAD_PUBLIC_KEY": "file:${workspaceFolder}/config/keys/case-save-public.pem",
"CYGNUS_CLOUD_REQUEST_TIMEOUT": "PT10S", "CYGNUS_CLOUD_REQUEST_TIMEOUT": "PT10S",
"CYGNUS_TOKEN_REFRESH_SKEW": "PT30S" "CYGNUS_TOKEN_REFRESH_SKEW": "PT30S"
}, },

View File

@@ -1,6 +1,7 @@
package com.cygnus.client; package com.cygnus.client;
import com.cygnus.client.model.CloudIdentitySession; import com.cygnus.client.model.CloudIdentitySession;
import com.cygnus.client.model.CloudQueryResponse;
import com.cygnus.client.model.LoginPayload; import com.cygnus.client.model.LoginPayload;
import com.cygnus.client.security.LoginEnvelopeEncryptor; import com.cygnus.client.security.LoginEnvelopeEncryptor;
import com.cygnus.client.security.MachineTokenProvider; import com.cygnus.client.security.MachineTokenProvider;
@@ -50,4 +51,26 @@ public class CloudIdentityClient {
.bodyToMono(CloudIdentitySession.class)) .bodyToMono(CloudIdentitySession.class))
.timeout(properties.requestTimeout()); .timeout(properties.requestTimeout());
} }
public Mono<CloudQueryResponse> fetchQuery(int queryId) {
return tokenProvider.accessToken()
.flatMap(token -> webClient.get()
.uri(properties.baseUri().resolve("/api/v1/queries/" + queryId))
.header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(CloudQueryResponse.class))
.timeout(properties.requestTimeout());
}
public Mono<CloudQueryResponse> fetchQuery(String queryKey) {
return tokenProvider.accessToken()
.flatMap(token -> webClient.get()
.uri(properties.baseUri().resolve("/api/v1/queries/key/" + queryKey))
.header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(CloudQueryResponse.class))
.timeout(properties.requestTimeout());
}
} }

View File

@@ -0,0 +1,4 @@
package com.cygnus.client.model;
public record CloudQueryResponse(int queryId, String query) {
}

View File

@@ -0,0 +1,4 @@
package com.cygnus.cloud.query;
public record CloudQuery(int queryId, String query) {
}

View File

@@ -0,0 +1,34 @@
package com.cygnus.cloud.query;
import jakarta.validation.constraints.Min;
import org.springframework.validation.annotation.Validated;
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.RestController;
import reactor.core.publisher.Mono;
@Validated
@RestController
@RequestMapping("/api/v1/queries")
public class CloudQueryController {
private final QueryCatalogRepository repository;
public CloudQueryController(QueryCatalogRepository repository) {
this.repository = repository;
}
@GetMapping("/{queryId}")
public Mono<CloudQuery> query(
@PathVariable @Min(1) int queryId) {
return repository.findEnabled(queryId)
.switchIfEmpty(Mono.error(new QueryNotFoundException(queryId)));
}
@GetMapping("/key/{queryKey}")
public Mono<CloudQuery> queryByKey(@PathVariable String queryKey) {
return repository.findEnabled(queryKey)
.switchIfEmpty(Mono.error(new QueryNotFoundException(queryKey)));
}
}

View File

@@ -0,0 +1,71 @@
package com.cygnus.cloud.query;
import com.cygnus.cloud.database.ReactiveDatabaseClient;
import io.vertx.sqlclient.Tuple;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Mono;
@Repository
public class QueryCatalogRepository {
private static final String INITIALIZE = """
CREATE SCHEMA IF NOT EXISTS platform;
CREATE SEQUENCE IF NOT EXISTS platform.application_query_id_seq;
CREATE TABLE IF NOT EXISTS platform.application_query (
query_id integer PRIMARY KEY DEFAULT nextval('platform.application_query_id_seq'),
query_key varchar(100),
query_text text NOT NULL,
enabled boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT current_timestamp,
updated_at timestamptz NOT NULL DEFAULT current_timestamp,
CONSTRAINT ck_platform_application_query_id
CHECK (query_id > 0),
CONSTRAINT ck_platform_application_query_text
CHECK (length(btrim(query_text)) > 0)
);
ALTER TABLE platform.application_query
ADD COLUMN IF NOT EXISTS query_key varchar(100);
ALTER TABLE platform.application_query ALTER COLUMN query_id
SET DEFAULT nextval('platform.application_query_id_seq');
CREATE UNIQUE INDEX IF NOT EXISTS ux_platform_application_query_key
ON platform.application_query (query_key) WHERE query_key IS NOT NULL;
SELECT setval('platform.application_query_id_seq',
greatest(coalesce((SELECT max(query_id) FROM platform.application_query), 0) + 1, 1), false)
""";
private static final String FIND = """
SELECT query_id, query_text
FROM platform.application_query
WHERE query_id = $1
AND enabled = true
""";
private static final String FIND_BY_KEY = """
SELECT query_id, query_text
FROM platform.application_query
WHERE query_key = $1
AND enabled = true
""";
private final ReactiveDatabaseClient database;
public QueryCatalogRepository(ReactiveDatabaseClient database) {
this.database = database;
}
public Mono<Void> initialize() {
return database.query(INITIALIZE).then();
}
public Mono<CloudQuery> findEnabled(int queryId) {
return database.preparedQuery(FIND, Tuple.of(queryId))
.flatMapMany(rows -> reactor.core.publisher.Flux.fromIterable(rows))
.next()
.map(row -> new CloudQuery(
row.getInteger("query_id"), row.getString("query_text")));
}
public Mono<CloudQuery> findEnabled(String queryKey) {
return database.preparedQuery(FIND_BY_KEY, Tuple.of(queryKey))
.flatMapMany(rows -> reactor.core.publisher.Flux.fromIterable(rows))
.next()
.map(row -> new CloudQuery(row.getInteger("query_id"), row.getString("query_text")));
}
}

View File

@@ -0,0 +1,22 @@
package com.cygnus.cloud.query;
import java.time.Duration;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class QueryCatalogSchemaInitializer implements ApplicationRunner {
private final QueryCatalogRepository repository;
public QueryCatalogSchemaInitializer(QueryCatalogRepository repository) {
this.repository = repository;
}
@Override
public void run(ApplicationArguments arguments) {
repository.initialize()
.block(Duration.ofMinutes(2));
}
}

View File

@@ -0,0 +1,16 @@
package com.cygnus.cloud.query;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.NOT_FOUND)
public class QueryNotFoundException extends RuntimeException {
public QueryNotFoundException(int queryId) {
super("Query was not found: " + queryId);
}
public QueryNotFoundException(String queryKey) {
super("Query was not found: " + queryKey);
}
}

View File

@@ -36,6 +36,8 @@ public class CloudSecurityConfiguration {
.permitAll() .permitAll()
.pathMatchers("/api/v1/identity/login") .pathMatchers("/api/v1/identity/login")
.hasAuthority("SCOPE_identity.login") .hasAuthority("SCOPE_identity.login")
.pathMatchers("/api/v1/queries/**")
.hasAuthority("SCOPE_identity.login")
.pathMatchers("/api/v1/admin/**") .pathMatchers("/api/v1/admin/**")
.hasAuthority("SCOPE_cygnus.admin") .hasAuthority("SCOPE_cygnus.admin")
.anyExchange().authenticated()) .anyExchange().authenticated())

View File

@@ -0,0 +1,23 @@
CREATE SCHEMA IF NOT EXISTS platform;
CREATE SEQUENCE IF NOT EXISTS platform.application_query_id_seq;
CREATE TABLE IF NOT EXISTS platform.application_query (
query_id integer PRIMARY KEY DEFAULT nextval('platform.application_query_id_seq'),
query_key varchar(100),
query_text text NOT NULL,
enabled boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT current_timestamp,
updated_at timestamptz NOT NULL DEFAULT current_timestamp,
CONSTRAINT ck_platform_application_query_id
CHECK (query_id > 0),
CONSTRAINT ck_platform_application_query_text
CHECK (length(btrim(query_text)) > 0)
);
ALTER TABLE platform.application_query
ADD COLUMN IF NOT EXISTS query_key varchar(100);
CREATE UNIQUE INDEX IF NOT EXISTS ux_platform_application_query_key
ON platform.application_query (query_key) WHERE query_key IS NOT NULL;
ALTER TABLE platform.application_query ALTER COLUMN query_id
SET DEFAULT nextval('platform.application_query_id_seq');
SELECT setval('platform.application_query_id_seq',
greatest(coalesce((SELECT max(query_id) FROM platform.application_query), 0) + 1, 1), false);

View File

@@ -0,0 +1,25 @@
DO $$
DECLARE
current_type text;
BEGIN
SELECT data_type
INTO current_type
FROM information_schema.columns
WHERE table_schema = 'platform'
AND table_name = 'application_query'
AND column_name = 'query_id';
IF current_type IN ('character varying', 'text') THEN
ALTER TABLE platform.application_query
DROP CONSTRAINT IF EXISTS ck_platform_application_query_id;
ALTER TABLE platform.application_query
ALTER COLUMN query_id TYPE integer
USING regexp_replace(query_id, '^Query', '')::integer;
ALTER TABLE platform.application_query
ADD CONSTRAINT ck_platform_application_query_id
CHECK (query_id > 0);
END IF;
END
$$;

View File

@@ -0,0 +1,11 @@
-- Stable query key; query_id is generated by PostgreSQL.
BEGIN;
INSERT INTO platform.application_query(query_key, query_text, enabled, created_at, updated_at, ismigrated)
VALUES ('APPLICATION_SAVE',
'procedure!C0L!select * from public.save_application_details(?::jsonb,?::smallint,?::smallint,?::smallint)',
true, clock_timestamp(), clock_timestamp(), true)
ON CONFLICT (query_key) WHERE query_key IS NOT NULL DO UPDATE SET
query_text=excluded.query_text, enabled=true, updated_at=clock_timestamp(), ismigrated=true;
COMMIT;

View File

@@ -30,6 +30,7 @@ public class DeploymentWriter {
try { try {
Path normalizedOutput = output.toAbsolutePath().normalize(); Path normalizedOutput = output.toAbsolutePath().normalize();
Path config = normalizedOutput.resolve("config"); Path config = normalizedOutput.resolve("config");
protectCloudConfiguration(config, profile);
Path keyDirectory = config.resolve("keys"); Path keyDirectory = config.resolve("keys");
Files.createDirectories(keyDirectory); Files.createDirectories(keyDirectory);
@@ -82,6 +83,23 @@ public class DeploymentWriter {
} }
} }
private void protectCloudConfiguration(Path deploymentConfig, ProductProfile profile) {
if (isInside(deploymentConfig, profile.assertionEncryptionPublicKey())
|| isInside(deploymentConfig, profile.loginEncryptionPublicKey())) {
throw new IllegalArgumentException(
"Refusing to write deployment files over the cloud-service "
+ "configuration directory");
}
}
private boolean isInside(Path directory, Path file) {
if (file == null) {
return false;
}
return file.toAbsolutePath().normalize().startsWith(
directory.toAbsolutePath().normalize());
}
private String installationConfiguration( private String installationConfiguration(
UUID installationUuid, UUID installationUuid,
String installationCode, String installationCode,
@@ -174,6 +192,7 @@ public class DeploymentWriter {
appendEnvironment(env, "REDIS_HOST", runtime.redisHost()); appendEnvironment(env, "REDIS_HOST", runtime.redisHost());
appendEnvironment(env, "REDIS_PORT", runtime.redisPort()); appendEnvironment(env, "REDIS_PORT", runtime.redisPort());
appendEnvironment(env, "REDIS_PASSWORD", runtime.redisPassword()); appendEnvironment(env, "REDIS_PASSWORD", runtime.redisPassword());
appendEnvironment(env, "REDIS_DATABASE", "1");
appendEnvironment(env, "REDIS_SSL", Boolean.toString(runtime.redisSsl())); appendEnvironment(env, "REDIS_SSL", Boolean.toString(runtime.redisSsl()));
appendEnvironment( appendEnvironment(
env, "CYGNUS_CLOUD_BASE_URL", normalizedCloudServiceUrl(runtime)); env, "CYGNUS_CLOUD_BASE_URL", normalizedCloudServiceUrl(runtime));

View File

@@ -156,6 +156,7 @@ public class InstallationService {
if (request.outputDirectory() == null) { if (request.outputDirectory() == null) {
throw new IllegalArgumentException("Output directory is required"); throw new IllegalArgumentException("Output directory is required");
} }
validateOutputIsolation(request.outputDirectory());
RuntimeConfiguration runtime = request.runtimeConfiguration(); RuntimeConfiguration runtime = request.runtimeConfiguration();
if (runtime == null) { if (runtime == null) {
throw new IllegalArgumentException("Runtime configuration is required"); throw new IllegalArgumentException("Runtime configuration is required");
@@ -204,6 +205,27 @@ public class InstallationService {
} }
} }
private void validateOutputIsolation(Path outputDirectory) {
Path deploymentConfig = outputDirectory
.toAbsolutePath()
.normalize()
.resolve("config");
if (isInside(deploymentConfig, profile.assertionEncryptionPublicKey())
|| isInside(deploymentConfig, profile.loginEncryptionPublicKey())) {
throw new IllegalArgumentException(
"Output directory would overwrite the cloud-service config folder. "
+ "Select a dedicated deployment directory, such as "
+ "'matrix-installation'.");
}
}
private boolean isInside(Path directory, Path file) {
if (file == null) {
return false;
}
return file.toAbsolutePath().normalize().startsWith(directory);
}
private String normalizedCloudServiceUrl(String value) { private String normalizedCloudServiceUrl(String value) {
String normalized = value.trim(); String normalized = value.trim();
return normalized.endsWith("/") return normalized.endsWith("/")

View File

@@ -1,6 +1,7 @@
package com.cygnus.installer; package com.cygnus.installer;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.net.URI; import java.net.URI;
import java.nio.file.Files; import java.nio.file.Files;
@@ -108,6 +109,7 @@ class DeploymentWriterTest {
.contains("MATRIX_IMAGE=\"registry.example.com/matrix:1.0.0\"") .contains("MATRIX_IMAGE=\"registry.example.com/matrix:1.0.0\"")
.contains("MATRIX_DB_URL=\"jdbc:postgresql://db:5432/matrix\"") .contains("MATRIX_DB_URL=\"jdbc:postgresql://db:5432/matrix\"")
.contains("REDIS_HOST=\"redis\"") .contains("REDIS_HOST=\"redis\"")
.contains("REDIS_DATABASE=\"1\"")
.contains("CYGNUS_CLOUD_BASE_URL=\"http://host.docker.internal:8090\"") .contains("CYGNUS_CLOUD_BASE_URL=\"http://host.docker.internal:8090\"")
.contains("CYGNUS_TOKEN_URL=\"http://host.docker.internal:8090/oauth2/token\"") .contains("CYGNUS_TOKEN_URL=\"http://host.docker.internal:8090/oauth2/token\"")
.contains("CYGNUS_CLIENT_ID=\"matrix-client\"") .contains("CYGNUS_CLIENT_ID=\"matrix-client\"")
@@ -121,4 +123,84 @@ class DeploymentWriterTest {
assertThat(output.resolve("config/keys/client-signing-private.pem")) assertThat(output.resolve("config/keys/client-signing-private.pem"))
.isRegularFile(); .isRegularFile();
} }
@Test
void refusesToOverwriteCloudServiceConfiguration() throws Exception {
Path cloudConfig = temporaryDirectory.resolve("config");
Path cloudKeys = cloudConfig.resolve("keys");
Files.createDirectories(cloudKeys);
Path assertionPublic = cloudKeys.resolve("assertion-decryption-public.pem");
Path loginPublic = cloudKeys.resolve("login-public.pem");
Files.writeString(assertionPublic, "assertion-public-key");
Files.writeString(loginPublic, "login-public-key");
var profile = new ProductProfile(
"matrix",
"Matrix",
"matrix-onprem",
"MATRIX_IMAGE",
"matrix",
"installation.yml",
"MATRIX_INSTALLATION_CONFIG",
"/srv/matrix/config/installation.yml",
"8080:8080",
"/matrix/",
"/oauth2/token",
assertionPublic,
loginPublic,
"cygnus-login-2026-01",
List.of());
assertThatThrownBy(() -> new DeploymentWriter().write(
temporaryDirectory,
UUID.randomUUID(),
"primary",
"matrix-client",
new ActivationDtos.ValidationResponse(
"activation-token",
OffsetDateTime.now().plusMinutes(5),
UUID.randomUUID(),
"matrix-client",
"FULL",
2),
new ActivationDtos.RegistrationResponse(
UUID.randomUUID(),
UUID.randomUUID(),
UUID.randomUUID(),
null,
"primary",
1,
"ACTIVE"),
new InstallationKeyService().generate(),
"assertion",
new InstallerSettings(
"matrix",
URI.create("https://cloud.example.com"),
URI.create("https://cloud.example.com"),
"/api/v1/installations",
"production",
temporaryDirectory,
temporaryDirectory,
"1",
new IniDocument(Map.of())),
profile,
"registry.example.com/matrix:1.0.0",
Map.of(),
new RuntimeConfiguration(
"https://cloud.example.com",
"jdbc:postgresql://db/matrix",
"postgres",
"secret",
"redis",
"7901",
"secret",
false,
"PT10S",
"PT30S")))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("cloud-service configuration");
assertThat(assertionPublic).hasContent("assertion-public-key");
assertThat(loginPublic).hasContent("login-public-key");
}
} }

View File

@@ -1,12 +0,0 @@
spring:
main:
banner-mode: "off"
application:
name: technobee-service-installer
technobee:
installer:
config: ${TECHNOBEE_INSTALLER_CONFIG:./installer.ini}
version: ${TECHNOBEE_INSTALLER_VERSION:1.0.0}
logging:
level:
root: WARN

View File

@@ -1,3 +0,0 @@
artifactId=technobee-service-installer
groupId=com.cygnus
version=1.0.0-SNAPSHOT

View File

@@ -1,36 +0,0 @@
com/cygnus/installer/MachineAssertionService.class
com/cygnus/installer/ActivationDtos$ValidationResponse.class
com/cygnus/installer/SwingInstallationWizard$2.class
com/cygnus/installer/CommandResult.class
com/cygnus/installer/InstallationProgressListener.class
com/cygnus/installer/ProductProfileRegistry.class
com/cygnus/installer/InstallationRequest.class
com/cygnus/installer/InstallerConfiguration.class
com/cygnus/installer/ProductProfile.class
com/cygnus/installer/InstallationWizard.class
com/cygnus/installer/TechnobeeServiceInstallerApplication.class
com/cygnus/installer/DeploymentWriter.class
com/cygnus/installer/InstallationKeyService.class
com/cygnus/installer/DockerComposeDeploymentService.class
com/cygnus/installer/ActivationClient.class
com/cygnus/installer/ActivationDtos$RegistrationResponse.class
com/cygnus/installer/IniDocument.class
com/cygnus/installer/SwingInstallationWizard$3.class
com/cygnus/installer/InstallerConfigurationException.class
com/cygnus/installer/DockerRegistryLoginService.class
com/cygnus/installer/SwingInstallationWizard.class
com/cygnus/installer/ActivationDtos.class
com/cygnus/installer/DockerPrerequisiteChecker.class
com/cygnus/installer/InstallerBootstrapProperties.class
com/cygnus/installer/SwingInstallationWizard$1.class
com/cygnus/installer/CommandExecutor.class
com/cygnus/installer/IniConfigurationLoader.class
com/cygnus/installer/InstallationService.class
com/cygnus/installer/InstallationResult.class
com/cygnus/installer/RuntimeConfiguration.class
com/cygnus/installer/ActivationDtos$RegistrationRequest.class
com/cygnus/installer/ActivationDtos$ValidationRequest.class
com/cygnus/installer/PrerequisiteException.class
com/cygnus/installer/InstallerSettings.class
com/cygnus/installer/InstallationKeyPair.class
com/cygnus/installer/SwingInstallationWizard$ProgressUpdate.class

View File

@@ -1,28 +0,0 @@
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/ActivationClient.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/ActivationDtos.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/CommandExecutor.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/CommandResult.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/DeploymentWriter.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/DockerComposeDeploymentService.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/DockerPrerequisiteChecker.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/DockerRegistryLoginService.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/IniConfigurationLoader.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/IniDocument.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationKeyPair.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationKeyService.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationProgressListener.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationRequest.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationResult.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationService.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationWizard.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallerBootstrapProperties.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallerConfiguration.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallerConfigurationException.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallerSettings.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/MachineAssertionService.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/PrerequisiteException.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/ProductProfile.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/ProductProfileRegistry.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/RuntimeConfiguration.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/SwingInstallationWizard.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/TechnobeeServiceInstallerApplication.java

View File

@@ -1,11 +0,0 @@
com/cygnus/installer/MachineAssertionServiceTest.class
com/cygnus/installer/DockerRegistryLoginServiceTest$CapturingExecutor.class
com/cygnus/installer/DockerRegistryLoginServiceTest.class
com/cygnus/installer/DockerComposeDeploymentServiceTest$CapturingExecutor.class
com/cygnus/installer/InstallationServiceTest.class
com/cygnus/installer/DockerPrerequisiteCheckerTest$1.class
com/cygnus/installer/ProductProfileRegistryTest.class
com/cygnus/installer/IniConfigurationLoaderTest.class
com/cygnus/installer/DockerComposeDeploymentServiceTest.class
com/cygnus/installer/DeploymentWriterTest.class
com/cygnus/installer/DockerPrerequisiteCheckerTest.class

View File

@@ -1,8 +0,0 @@
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/test/java/com/cygnus/installer/DeploymentWriterTest.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/test/java/com/cygnus/installer/DockerComposeDeploymentServiceTest.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/test/java/com/cygnus/installer/DockerPrerequisiteCheckerTest.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/test/java/com/cygnus/installer/DockerRegistryLoginServiceTest.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/test/java/com/cygnus/installer/IniConfigurationLoaderTest.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/test/java/com/cygnus/installer/InstallationServiceTest.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/test/java/com/cygnus/installer/MachineAssertionServiceTest.java
/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/test/java/com/cygnus/installer/ProductProfileRegistryTest.java

View File

@@ -1,4 +0,0 @@
-------------------------------------------------------------------------------
Test set: com.cygnus.installer.DeploymentWriterTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.174 s -- in com.cygnus.installer.DeploymentWriterTest

View File

@@ -1,4 +0,0 @@
-------------------------------------------------------------------------------
Test set: com.cygnus.installer.DockerComposeDeploymentServiceTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.002 s -- in com.cygnus.installer.DockerComposeDeploymentServiceTest

View File

@@ -1,4 +0,0 @@
-------------------------------------------------------------------------------
Test set: com.cygnus.installer.DockerPrerequisiteCheckerTest
-------------------------------------------------------------------------------
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.004 s -- in com.cygnus.installer.DockerPrerequisiteCheckerTest

View File

@@ -1,4 +0,0 @@
-------------------------------------------------------------------------------
Test set: com.cygnus.installer.DockerRegistryLoginServiceTest
-------------------------------------------------------------------------------
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.010 s -- in com.cygnus.installer.DockerRegistryLoginServiceTest

View File

@@ -1,4 +0,0 @@
-------------------------------------------------------------------------------
Test set: com.cygnus.installer.IniConfigurationLoaderTest
-------------------------------------------------------------------------------
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.008 s -- in com.cygnus.installer.IniConfigurationLoaderTest

View File

@@ -1,4 +0,0 @@
-------------------------------------------------------------------------------
Test set: com.cygnus.installer.InstallationServiceTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.002 s -- in com.cygnus.installer.InstallationServiceTest

View File

@@ -1,4 +0,0 @@
-------------------------------------------------------------------------------
Test set: com.cygnus.installer.MachineAssertionServiceTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.570 s -- in com.cygnus.installer.MachineAssertionServiceTest

View File

@@ -1,4 +0,0 @@
-------------------------------------------------------------------------------
Test set: com.cygnus.installer.ProductProfileRegistryTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.005 s -- in com.cygnus.installer.ProductProfileRegistryTest

47
cygnus-lib/pom.xml Normal file
View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.cygnus</groupId>
<artifactId>cygnus-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>cygnus-lib</artifactId>
<packaging>jar</packaging>
<name>Cygnus Shared Library</name>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,101 @@
package lib.constants;
/** Canonical user-facing messages shared by Cygnus applications. */
public enum ApplicationMessage {
BAD_REQUEST(400, "HTTP-400", "Invalid request",
"Cygnus could not process the submitted request.",
"Review the supplied information and try again."),
SESSION_REQUIRED(401, "AUTH-401", "Sign in required",
"Your session is missing or has expired.",
"Sign in again to continue securely."),
ACCESS_DENIED(403, "AUTH-403", "Access denied",
"You do not have permission to open this page.",
"Contact your administrator if this feature should be available to you."),
PAGE_NOT_FOUND(404, "HTTP-404", "Page not found",
"The requested page could not be found.",
"Check the address or return to the application dashboard."),
METHOD_NOT_ALLOWED(405, "HTTP-405", "Action not allowed",
"This page does not support the requested action.",
"Return to the previous page and try an available action."),
CONFLICT(409, "HTTP-409", "Request conflict",
"The request conflicts with the current state of the data.",
"Refresh the page and try again."),
PAYLOAD_TOO_LARGE(413, "HTTP-413", "File is too large",
"The submitted content exceeds the permitted size.",
"Reduce the file size and try again."),
TOO_MANY_REQUESTS(429, "HTTP-429", "Too many requests",
"Cygnus has received too many requests in a short period.",
"Wait briefly before trying again."),
PAYLOAD_INVALID(400, "REQ-4001", "Invalid request details",
"The encrypted request could not be verified.",
"Refresh the page and submit the form again."),
APPLICATION_VALIDATION_FAILED(422, "APP-4221", "Application validation failed",
"One or more application fields contain invalid information.",
"Correct the highlighted fields and submit the application again."),
APPLICATION_ACCESS_DENIED(403, "APP-4031", "Application access denied",
"The selected portfolio or application is not available to your account.",
"Select an authorized portfolio or contact your administrator."),
APPLICATION_SAVE_CONFLICT(409, "APP-4091", "Application save conflict",
"This request was already processed or the application changed.",
"Refresh the application before submitting it again."),
APPLICATION_SAVED(200, "APP-2001", "Application saved",
"The application details were saved successfully.", ""),
APPLICATIONS_LOADED(200, "APP-2002", "Applications loaded",
"The application records were loaded successfully.", ""),
APPLICATION_LOAD_FAILED(500, "APP-5002", "Applications could not be loaded",
"Cygnus could not load the application details.",
"Try again. If the issue continues, share the reference ID with support."),
APPLICATION_SAVE_FAILED(500, "APP-5001", "Application could not be saved",
"Cygnus could not save the application details.",
"Try again. If the issue continues, share the reference ID with support."),
INTERNAL_SERVER_ERROR(500, "HTTP-500", "Something went wrong",
"Cygnus could not complete your request.",
"Try again. If the issue continues, share the reference ID with support."),
BAD_GATEWAY(502, "HTTP-502", "Service response unavailable",
"A required service returned an invalid response.",
"Try again shortly. If the issue continues, contact support."),
SERVICE_UNAVAILABLE(503, "HTTP-503", "Service temporarily unavailable",
"A required Cygnus service is currently unavailable.",
"Wait briefly and try again."),
GATEWAY_TIMEOUT(504, "HTTP-504", "Service response timed out",
"A required service took too long to respond.",
"Try the request again shortly.");
private final int httpStatus;
private final String code;
private final String title;
private final String message;
private final String description;
ApplicationMessage(
int httpStatus, String code, String title, String message, String description) {
this.httpStatus = httpStatus;
this.code = code;
this.title = title;
this.message = message;
this.description = description;
}
public static ApplicationMessage fromHttpStatus(int status) {
return switch (status) {
case 400 -> BAD_REQUEST;
case 401 -> SESSION_REQUIRED;
case 403 -> ACCESS_DENIED;
case 404 -> PAGE_NOT_FOUND;
case 405 -> METHOD_NOT_ALLOWED;
case 409 -> CONFLICT;
case 413 -> PAYLOAD_TOO_LARGE;
case 429 -> TOO_MANY_REQUESTS;
case 502 -> BAD_GATEWAY;
case 503 -> SERVICE_UNAVAILABLE;
case 504 -> GATEWAY_TIMEOUT;
default -> INTERNAL_SERVER_ERROR;
};
}
public int getHttpStatus() { return httpStatus; }
public String getCode() { return code; }
public String getTitle() { return title; }
public String getMessage() { return message; }
public String getDescription() { return description; }
}

View File

@@ -0,0 +1,20 @@
package lib.exceptions;
import lib.constants.ApplicationMessage;
/** Single typed application exception carrying a safe user-facing message. */
public class ApplicationException extends RuntimeException {
private final ApplicationMessage applicationMessage;
public ApplicationException(ApplicationMessage message, String technicalMessage) {
super(technicalMessage);
this.applicationMessage = message;
}
public ApplicationException(ApplicationMessage message, String technicalMessage, Throwable cause) {
super(technicalMessage, cause);
this.applicationMessage = message;
}
public ApplicationMessage getApplicationMessage() { return applicationMessage; }
}

View File

@@ -0,0 +1,12 @@
package lib.models;
/** Consistent API response contract for every migrated workflow. */
public record ApiResponse<T>(boolean success, T data, MessageDetails message) {
public static <T> ApiResponse<T> success(T data, MessageDetails message) {
return new ApiResponse<>(true, data, message);
}
public static <T> ApiResponse<T> failure(MessageDetails message) {
return new ApiResponse<>(false, null, message);
}
}

View File

@@ -0,0 +1,87 @@
package lib.models;
import java.io.Serial;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
/** User-editable case initiation data. Identity and audit fields come from UserSession. */
@Getter
@Setter
public class ApplicationDetails implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Integer applicationId;
private Short portfolioId;
private Short bankBranchId;
private String applicationNumber;
private String bankCode;
private String product;
private String loanAmount;
private String customerName;
private String fatherName;
private String applicationType;
private String category;
private String dateOfBirth;
private String contactPerson;
private String mobileNumber;
private String specialInstruction;
private Boolean residenceVerification;
private Boolean residenceTelephoneVerification;
private Boolean officeVerification;
private Boolean officeTelephoneVerification;
private Boolean propertyVerification;
private Boolean referenceVerification;
private Boolean documentVerification;
private Boolean residenceCoApplicant;
private Boolean residenceCoProprietor;
private Boolean officeCoProprietor;
private Boolean sameResidenceAddress;
private Boolean sameOfficeAddress;
private Boolean samePropertyAddress;
private String residenceAddress1;
private String residenceAddress2;
private String residenceAddress3;
private String residenceLandmark;
private Integer residenceColonyId;
private String residenceCity;
private String residencePincode;
private String residencePhone;
private String companyName;
private String officeAddress1;
private String officeAddress2;
private String officeAddress3;
private String officeLandmark;
private Integer officeColonyId;
private String officeCity;
private String officePincode;
private String department;
private String designation;
private String officePhone;
private String extension;
private String propertyAddress1;
private String propertyAddress2;
private String propertyAddress3;
private String propertyLandmark;
private Integer propertyColonyId;
private String propertyCity;
private String propertyPincode;
private String referenceName1;
private String referenceAddress1;
private String referenceContactNumber1;
private String referenceName2;
private String referenceAddress2;
private String referenceContactNumber2;
private Map<String, String> dynamicFields = new LinkedHashMap<>();
private Boolean autoCutOff;
private Integer formMode;
}

View File

@@ -0,0 +1,4 @@
package lib.models;
/** Data returned after saving a loan-verification application. */
public record ApplicationSaveData(String operation, Integer applicationId, String mvCode) {}

View File

@@ -0,0 +1,16 @@
package lib.models;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/** Result row returned by the application-save database operation. */
@Getter
@Setter
@NoArgsConstructor
public class ApplicationSaveResult {
private String operation;
private Integer applicationId;
private String mvCode;
private String internalUuid;
}

View File

@@ -0,0 +1,23 @@
package lib.models;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CasePunching {
private MessageDetails messageDetails;
private Map<String, String> optionsl;
private Map<String, List<Option>> options;
private List<String> visibleSections;
private Short portfolioId;
private Integer formMode;
private String userId;
private String dynamicFields;
private String dynamicHtml;
private String verificationCaseId;
private String documentCaseId;
}

View File

@@ -0,0 +1,11 @@
package lib.models;
/** Hybrid RSA-OAEP/AES-GCM envelope submitted by the initiation page. */
public record CaseSaveRequest(
String keyId,
String encryptedKey,
String initializationVector,
String encryptedPayload,
String requestId,
String timestamp) {
}

View File

@@ -0,0 +1,15 @@
package lib.models;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/** Existing application details used by the case-initiation duplicate checks. */
public record DuplicateDetailsData(List<Map<String, Object>> records) {
public DuplicateDetailsData {
records = records == null ? List.of() : records.stream()
.map(record -> Collections.unmodifiableMap(new LinkedHashMap<>(record)))
.toList();
}
}

View File

@@ -0,0 +1,19 @@
package lib.models;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
public class EditCaseSummary {
private String documentCaseId;
private String mvCode;
private String fileNumber;
private String customerName;
private String applicationType;
private String product;
private String receivedOn;
private String punchedBy;
private String branchCode;
private Short portfolioId;
}

View File

@@ -0,0 +1,10 @@
package lib.models;
import java.util.List;
/** Localities returned to the case-initiation autocomplete. */
public record LocalityData(List<LocalityOption> localities) {
public LocalityData {
localities = localities == null ? List.of() : List.copyOf(localities);
}
}

View File

@@ -0,0 +1,4 @@
package lib.models;
/** One company-authorized locality autocomplete result. */
public record LocalityOption(Integer id, String location, String pincode, String city) {}

View File

@@ -0,0 +1,58 @@
package lib.models;
import lib.constants.ApplicationMessage;
import java.io.Serial;
import java.io.Serializable;
import java.time.Instant;
import java.util.Objects;
import java.util.UUID;
import lombok.Getter;
/** Dependency-free error information shared across Cygnus modules. */
@Getter
public final class MessageDetails implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private final int httpStatus;
private final String code;
private final String title;
private final String message;
private final String description;
private final String referenceId;
private final Instant timestamp;
public MessageDetails(ApplicationMessage message) {
this(message.getHttpStatus(), message.getCode(), message.getTitle(),
message.getMessage(), message.getDescription(),
UUID.randomUUID().toString(), Instant.now());
}
private MessageDetails(
int httpStatus,
String code,
String title,
String message,
String description,
String referenceId,
Instant timestamp) {
if (httpStatus < 100 || httpStatus > 599) {
throw new IllegalArgumentException("HTTP status must be between 100 and 599");
}
this.httpStatus = httpStatus;
this.code = required(code, "code");
this.title = required(title, "title");
this.message = required(message, "message");
this.description = description == null ? "" : description.trim();
this.referenceId = required(referenceId, "referenceId");
this.timestamp = Objects.requireNonNull(timestamp, "timestamp");
}
private static String required(String value, String name) {
if (value == null || value.isBlank()) {
throw new IllegalArgumentException(name + " is required");
}
return value.trim();
}
}

View File

@@ -0,0 +1,13 @@
package lib.models;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Option {
private Object value;
private String label;
private String description;
private String group;
}

View File

@@ -0,0 +1,15 @@
package lib.models;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Collections;
/** Form-shaped punched applications returned to the case-initiation workspace. */
public record PunchedRecordsData(List<Map<String, Object>> records) {
public PunchedRecordsData {
records = records == null ? List.of() : records.stream()
.map(record -> Collections.unmodifiableMap(new LinkedHashMap<>(record)))
.toList();
}
}

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