fix(documentmanagement): close leaked file handles causing Windows re-upload failures; add entity KYC document CodeValues
Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Canceled after 0s
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract Documentation build / build (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Liquibase Only mode - PostgreSQL / test (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Canceled after 0s
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract Documentation build / build (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Liquibase Only mode - PostgreSQL / test (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s
FileContentStoreService.upload() opened a FileOutputStream (write) and an InputStream (post-upload MIME check) without closing either. Windows keeps those handles open for the JVM's lifetime, so the next upsert-style delete-then-recreate of the same file (e.g. client signature/photo re-upload) failed with FileSystemException: "being used by another process". Wrapped both in try-with-resources. Also adds every distinct non-individual/constitution KYC document name (HUF, Private/Public Ltd, LLP, Partnership, Trust, Society, Proprietorship, Association, Govt/PSU, Cooperative) as a KYCIdProofType code value. resolveDocumentTypeId() on the frontend matches the picked document name against this list before creating a client_identifier; since these entity document names had no corresponding code value, every non-individual client's KYC document upload silently failed to persist. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+6
-5
@@ -95,23 +95,24 @@ public class FileContentStoreService implements ContentStoreService {
|
||||
|
||||
final var target = Files.exists(getPath(safePath, false)) ? getPath(safePath, false) : getPath(safePath, true);
|
||||
|
||||
try (var in = is) {
|
||||
IOUtils.copy(in, new FileOutputStream(target.toString()));
|
||||
try (var in = is; var out = new FileOutputStream(target.toString())) {
|
||||
IOUtils.copy(in, out);
|
||||
} catch (Exception e) {
|
||||
throw new ContentStoreException(e);
|
||||
}
|
||||
|
||||
final var relativePath = getRelativePath(target);
|
||||
|
||||
try {
|
||||
postUploadContentPolicy
|
||||
.check(ContentPolicyContext.builder().path(path).inputStream(getInputStream(target)).mimeType(mimeType).build());
|
||||
try (var in = getInputStream(target)) {
|
||||
postUploadContentPolicy.check(ContentPolicyContext.builder().path(path).inputStream(in).mimeType(mimeType).build());
|
||||
} catch (ContentPolicyException e) {
|
||||
log.warn("Delete file because it didn't comply with the post-upload policy check: {} - {}", target, e.getMessage());
|
||||
|
||||
delete(relativePath.toString());
|
||||
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new ContentStoreException(e);
|
||||
}
|
||||
|
||||
return relativePath.toString();
|
||||
|
||||
@@ -452,6 +452,7 @@
|
||||
<include file="parts/0429_add_client_pending_edit_table.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0430_add_client_edit_approval_permissions.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0431_add_original_json_to_client_pending_edit.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0432_add_entity_kyc_document_type_codes.xml" relativeToChangelogFile="true"/>
|
||||
<!-- NOTE: the numbers below (0341-0359) re-use prefixes already used above by the chequebook/CTS
|
||||
clearing catchup migrations — these come from a long-diverged branch (uate) that assigned its own
|
||||
sequence independently. Liquibase tracks changesets by filename + id + author, not by the numeric
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.13.xsd">
|
||||
|
||||
<!-- ClientKycStepComponent's constitutionDocTypes / nonIndividualDefaultDocTypes (frontend-only
|
||||
maps, one per legal-entity constitution: HUF/Private Ltd/Public Ltd/LLP/Partnership/Trust/
|
||||
Society/Proprietorship/Association/Govt-PSU/Cooperative) were never backed by a KYCIdProofType
|
||||
code value the way individual OVDs (0251_add_kyc_proof_type_codes.xml) and minor OVDs
|
||||
(0428_add_minor_kyc_id_proof_codes.xml) are. Since edit-client/create-client's
|
||||
saveKycDocProof() -> resolveDocumentTypeId() resolves the picked document NAME against this
|
||||
code list before creating the client_identifier, every non-individual client's KYC document
|
||||
upload silently failed to save the identifier/document (no error surfaced — the KYC record's
|
||||
own document-name/number fields persisted fine via the KYC entity, but the uploaded file
|
||||
never did, so it vanished on refresh). This adds every distinct entity/constitution document
|
||||
name used by the frontend as a KYCIdProofType code value so resolution succeeds. -->
|
||||
<changeSet author="CBS" id="0432-1">
|
||||
<sql>
|
||||
INSERT INTO m_code_value (code_id, code_value, code_description, order_position, is_active, is_mandatory)
|
||||
SELECT c.id, v.code_value, v.code_value,
|
||||
(SELECT COALESCE(MAX(cv.order_position), 0) FROM m_code_value cv WHERE cv.code_id = c.id)
|
||||
+ ROW_NUMBER() OVER (ORDER BY v.code_value),
|
||||
true, false
|
||||
FROM m_code c
|
||||
CROSS JOIN (VALUES
|
||||
('Certificate of Incorporation / Registration Certificate'),
|
||||
('PAN Card of Entity'),
|
||||
('Memorandum & Articles of Association / Partnership Deed / Trust Deed'),
|
||||
('Board Resolution / Authorization Letter'),
|
||||
('KYC of Authorized Signatory / Power of Attorney Holder'),
|
||||
('GST Registration Certificate'),
|
||||
('PAN Card of HUF'),
|
||||
('Declaration by Karta (with name, address & HUF member details)'),
|
||||
('KYC of Karta (OVDs + PAN + Photo)'),
|
||||
('Proof of Address of HUF'),
|
||||
('Certificate of Incorporation'),
|
||||
('Memorandum & Articles of Association'),
|
||||
('PAN of Company'),
|
||||
('Board Resolution (authorizing signatories)'),
|
||||
('KYC of Authorized Signatories'),
|
||||
('LLP Agreement'),
|
||||
('PAN of LLP'),
|
||||
('Designated Partners Resolution'),
|
||||
('KYC of Designated Partners / Authorized Signatories'),
|
||||
('Registration Certificate'),
|
||||
('Partnership Deed'),
|
||||
('PAN of Firm'),
|
||||
('Trust Deed'),
|
||||
('PAN of Trust'),
|
||||
('KYC of Trustees / Authorized Signatories'),
|
||||
('PAN of Society'),
|
||||
('Proof of Business Existence (GST Certificate / Shop License)'),
|
||||
('PAN of Proprietor'),
|
||||
('Proprietor''s KYC (OVDs + PAN + Photo)'),
|
||||
('PAN'),
|
||||
('Resolution authorizing signatories'),
|
||||
('Government Notification / Order'),
|
||||
('PAN (if applicable)'),
|
||||
('Authorized Signatory KYC')
|
||||
) AS v(code_value)
|
||||
WHERE c.code_name = 'KYCIdProofType'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv2 WHERE cv2.code_id = c.id AND cv2.code_value = v.code_value
|
||||
);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
Reference in New Issue
Block a user