diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 210b5af..47cd00f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,32 +1,32 @@ -name: JavaFX Build (Gradle) - -on: - push: - pull_request: - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up JDK - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: 17 - cache: gradle - - - name: Make Gradle executable - run: chmod +x gradlew - - - name: Build using Gradle - run: ./gradlew clean build - - - name: Upload JAR artifact - uses: actions/upload-artifact@v4 - with: - name: satyam-consignment +name: JavaFX Build (Gradle) + +on: + push: + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up JDK + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 17 + cache: gradle + + - name: Make Gradle executable + run: chmod +x gradlew + + - name: Build using Gradle + run: ./gradlew clean build + + - name: Upload JAR artifact + uses: actions/upload-artifact@v4 + with: + name: OpenConsignment path: build/libs/* \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 3e918a1..9d055b4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -32,6 +32,8 @@ dependencies { implementation(libs.javafx.graphics) implementation(libs.javafx.fxml) + implementation(libs.jgit) + compileOnly(libs.lombok) annotationProcessor(libs.lombok) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 92efa9f..77afec8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,65 +1,68 @@ -[versions] -javafx = "17.0.18" -controlsfx = "11.2.2" -jasperreports = "6.21.5" -sqlite = "3.34.0" -olap4j = "1.2.0" -#itext = "2.1.7" -lombok = "1.18.20" -dagger = "2.52" -testfx = "4.0.18" -testfxCore = "4.0.17" -monocle = "17.0.10" -hamcrest = "2.2" -#junit = "5.10.1" -junitbom = "5.10.2" +[versions] +javafx = "17.0.18" +controlsfx = "11.2.2" +jasperreports = "6.21.5" +sqlite = "3.34.0" +olap4j = "1.2.0" +#itext = "2.1.7" +lombok = "1.18.20" +dagger = "2.52" +testfx = "4.0.18" +testfxCore = "4.0.17" +monocle = "17.0.10" +hamcrest = "2.2" +#junit = "5.10.1" +junitbom = "5.10.2" mockito = "5.14.2" slf4j = "2.0.17" log4j = "2.24.3" snakeyaml = "2.3" - -spotless = "7.0.2" -shadow = "7.1.2" -javafxPlugin = "0.1.0" - -[libraries] -controlsfx = { module = "org.controlsfx:controlsfx", version.ref = "controlsfx" } -jasperreports = { module = "net.sf.jasperreports:jasperreports", version.ref = "jasperreports" } -sqlite = { module = "org.xerial:sqlite-jdbc", version.ref = "sqlite" } +jgit = "7.8.1.202611041320-r" + +spotless = "7.0.2" +shadow = "7.1.2" +javafxPlugin = "0.1.0" + +[libraries] +controlsfx = { module = "org.controlsfx:controlsfx", version.ref = "controlsfx" } +jasperreports = { module = "net.sf.jasperreports:jasperreports", version.ref = "jasperreports" } +sqlite = { module = "org.xerial:sqlite-jdbc", version.ref = "sqlite" } olap4j = { module = "org.olap4j:olap4j", version.ref = "olap4j" } slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } snakeyaml = { module = "org.yaml:snakeyaml", version.ref = "snakeyaml" } log4j-slf4j2-impl = { module = "org.apache.logging.log4j:log4j-slf4j2-impl", version.ref = "log4j" } log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" } -#itext = { module = "com.lowagie:itext", version.ref = "itext" } - -javafx-controls = { module = "org.openjfx:javafx-controls", version.ref = "javafx" } -javafx-base = { module = "org.openjfx:javafx-base", version.ref = "javafx" } -javafx-graphics = { module = "org.openjfx:javafx-graphics", version.ref = "javafx" } -javafx-fxml = { module = "org.openjfx:javafx-fxml", version.ref = "javafx" } - -lombok = { module = "org.projectlombok:lombok", version.ref = "lombok" } - -dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" } -dagger-compiler = { module = "com.google.dagger:dagger-compiler", version.ref = "dagger" } - -testfx-junit5 = { module = "org.testfx:testfx-junit5", version.ref = "testfx" } -testfx-core = { module = "org.testfx:testfx-core", version.ref = "testfxCore" } -testfx-monocle = { module = "org.testfx:openjfx-monocle", version.ref = "monocle" } - -hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" } - -#junit-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } -#junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } -junit-bom = { module = "org.junit:junit-bom", version.ref = "junitbom" } -junit-jupiter = { module = "org.junit.jupiter:junit-jupiter" } -junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher" } - -mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockito" } -mockito-junit-jupiter = { module = "org.mockito:mockito-junit-jupiter", version.ref = "mockito" } - -[plugins] -javafx = { id = "org.openjfx.javafxplugin", version.ref = "javafxPlugin" } -spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } -#shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } +#itext = { module = "com.lowagie:itext", version.ref = "itext" } + +javafx-controls = { module = "org.openjfx:javafx-controls", version.ref = "javafx" } +javafx-base = { module = "org.openjfx:javafx-base", version.ref = "javafx" } +javafx-graphics = { module = "org.openjfx:javafx-graphics", version.ref = "javafx" } +javafx-fxml = { module = "org.openjfx:javafx-fxml", version.ref = "javafx" } + +jgit = { module = "org.eclipse.jgit:org.eclipse.jgit", version.ref = "jgit"} + +lombok = { module = "org.projectlombok:lombok", version.ref = "lombok" } + +dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" } +dagger-compiler = { module = "com.google.dagger:dagger-compiler", version.ref = "dagger" } + +testfx-junit5 = { module = "org.testfx:testfx-junit5", version.ref = "testfx" } +testfx-core = { module = "org.testfx:testfx-core", version.ref = "testfxCore" } +testfx-monocle = { module = "org.testfx:openjfx-monocle", version.ref = "monocle" } + +hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" } + +#junit-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } +#junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } +junit-bom = { module = "org.junit:junit-bom", version.ref = "junitbom" } +junit-jupiter = { module = "org.junit.jupiter:junit-jupiter" } +junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher" } + +mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockito" } +mockito-junit-jupiter = { module = "org.mockito:mockito-junit-jupiter", version.ref = "mockito" } + +[plugins] +javafx = { id = "org.openjfx.javafxplugin", version.ref = "javafxPlugin" } +spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } +#shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" } diff --git a/scripts/configure-backup.py b/scripts/configure-backup.py index 28a5ce9..df7b9ae 100755 --- a/scripts/configure-backup.py +++ b/scripts/configure-backup.py @@ -69,6 +69,7 @@ def init_github_repository(): return github_username = "drcbabu81" repo_url = f"git@github.com:{github_username}/{repo_name}.git" + repo_url_https = f"https://github.com/{github_username}/{repo_name}.git" try: logger.info(f"cloning {repo_name}") @@ -76,6 +77,14 @@ def init_github_repository(): ["git", "clone", repo_url], check=True, capture_output=True, text=True ) + repo_path = os.path.abspath(repo_name) + + subprocess.run( + ["git", "remote", "add", "origin-https", repo_url_https], + cwd=repo_path, + check=True, capture_output=True, text=True + ) + if (Path(repo_name) / ".git").is_dir(): logger.info("clone successful") else: diff --git a/src/main/java/openconsignment/common/AppConfig.java b/src/main/java/openconsignment/common/AppConfig.java index 91fce8b..ec59801 100644 --- a/src/main/java/openconsignment/common/AppConfig.java +++ b/src/main/java/openconsignment/common/AppConfig.java @@ -9,23 +9,32 @@ @Setter @NoArgsConstructor public class AppConfig { - private String organizationName; + private String organization; + private String year; + private Github github; public static AppConfig forOrganization(String organizationName) { AppConfig configuration = new AppConfig(); - configuration.setOrganizationName(organizationName); + configuration.setOrganization(organizationName); configuration.validate(); return configuration; } - public String organizationName() { - return organizationName; + @Getter + @Setter + @NoArgsConstructor + public static class Github { + private String repository; + private String token; + private String username; + private String branch; + private String remote; } public void validate() { - if (organizationName == null || organizationName.isBlank()) { - throw new IllegalArgumentException("organizationName must not be blank"); + if (organization == null || organization.isBlank()) { + throw new IllegalArgumentException("organization must not be blank"); } - organizationName = organizationName.strip(); + organization = organization.strip(); } } diff --git a/src/main/java/openconsignment/common/Utils.java b/src/main/java/openconsignment/common/Utils.java index a1f3a42..81d56b0 100644 --- a/src/main/java/openconsignment/common/Utils.java +++ b/src/main/java/openconsignment/common/Utils.java @@ -3,11 +3,16 @@ import java.awt.*; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.MessageDigest; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; +import java.util.HexFormat; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -118,4 +123,19 @@ public static String nextVoucherNumber(String lastVoucher) { return "0"; } } + + public static String md5sum(Path path) throws Exception { + MessageDigest digest = MessageDigest.getInstance("MD5"); + + try (InputStream input = Files.newInputStream(path)) { + byte[] buffer = new byte[8192]; + int bytesRead; + + while ((bytesRead = input.read(buffer)) != -1) { + digest.update(buffer, 0, bytesRead); + } + } + + return HexFormat.of().formatHex(digest.digest()); + } } diff --git a/src/main/java/openconsignment/controller/MainController.java b/src/main/java/openconsignment/controller/MainController.java index 73a0e4e..b3420d8 100644 --- a/src/main/java/openconsignment/controller/MainController.java +++ b/src/main/java/openconsignment/controller/MainController.java @@ -5,12 +5,19 @@ import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; +import javafx.scene.control.Alert; import javafx.scene.control.Button; -import javafx.scene.control.MenuItem; +import javafx.scene.control.ButtonType; import javafx.scene.layout.BorderPane; import javax.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import openconsignment.common.Utils; import openconsignment.common.ViewLoader; +import openconsignment.service.BackupService; +import org.eclipse.jgit.api.errors.EmptyCommitException; +@Slf4j +@SuppressWarnings("unused") public class MainController implements Initializable { @FXML @@ -25,14 +32,13 @@ public class MainController implements Initializable { @FXML private Button master_btn; - @FXML - private MenuItem welcome_screen; - private final ViewLoader viewLoader; + private final BackupService backupService; @Inject - public MainController(ViewLoader viewLoader) { + public MainController(ViewLoader viewLoader, BackupService backupService) { this.viewLoader = viewLoader; + this.backupService = backupService; } @Override @@ -74,4 +80,99 @@ private void showCollectionHistory(ActionEvent event) { private void showPaymentHistory(ActionEvent event) { viewLoader.loadCenter("/fxml/history/PaymentHistory.fxml", root); } + + @FXML + private void showBillEntryScreen(ActionEvent event) { + viewLoader.loadCenter("/fxml/entry/BillEntry.fxml", root); + } + + @FXML + private void showCollectionEntryScreen(ActionEvent event) { + viewLoader.loadCenter("/fxml/entry/CollectionEntry.fxml", root); + } + + @FXML + private void showPaymentEntryScreen(ActionEvent event) { + viewLoader.loadCenter("/fxml/entry/PaymentEntry.fxml", root); + } + + @FXML + private void showSupplierLedger(ActionEvent event) { + viewLoader.loadCenter("/fxml/report/SupplierLedger.fxml", root); + } + + @FXML + private void showBuyerLedger(ActionEvent event) { + viewLoader.loadCenter("/fxml/report/BuyerLedger.fxml", root); + } + + @FXML + private void showTransportLedger(ActionEvent event) { + viewLoader.loadCenter("/fxml/report/TransportLedger.fxml", root); + } + + @FXML + private void showSupplierMaster(ActionEvent event) { + viewLoader.loadCenter("/fxml/master/MasterSupplier.fxml", root); + } + + @FXML + private void showBuyerMaster(ActionEvent event) { + viewLoader.loadCenter("/fxml/master/MasterBuyer.fxml", root); + } + + @FXML + private void showTransportMaster(ActionEvent event) { + viewLoader.loadCenter("/fxml/master/MasterTransport.fxml", root); + } + + @FXML + private void checkSync(ActionEvent event) { + boolean synced = false; + try { + synced = backupService.checkSync(); + } catch (Exception e) { + Utils.showAlert("Error", Alert.AlertType.ERROR); + } + + if (synced) { + Utils.showAlert("Data is Synced", Alert.AlertType.INFORMATION); + } else { + Utils.showAlert("Not Synced", Alert.AlertType.WARNING); + } + } + + @FXML + private void upload(ActionEvent event) { + try { + Alert alert = + new Alert(Alert.AlertType.CONFIRMATION, "Do you want to upload?", ButtonType.YES, ButtonType.NO); + if (alert.showAndWait().orElse(ButtonType.NO) != ButtonType.YES) { + return; + } + backupService.upload(); + Utils.showAlert("Successfully uploaded", Alert.AlertType.INFORMATION); + } catch (EmptyCommitException e) { + log.info(e.toString()); + Utils.showAlert("Data is already synced. " + e, Alert.AlertType.INFORMATION); + } catch (Exception e) { + log.error(e.toString()); + Utils.showAlert(e.toString(), Alert.AlertType.ERROR); + } + } + + public void download(ActionEvent actionEvent) { + try { + Alert alert = + new Alert(Alert.AlertType.CONFIRMATION, "Do you want to download?", ButtonType.YES, ButtonType.NO); + if (alert.showAndWait().orElse(ButtonType.NO) != ButtonType.YES) { + return; + } + backupService.download(); + Utils.showAlert("Successfully downloaded", Alert.AlertType.INFORMATION); + } catch (Exception e) { + log.error(e.toString()); + Utils.showAlert(e.toString(), Alert.AlertType.ERROR); + } + } } diff --git a/src/main/java/openconsignment/controller/WelcomeScreenController.java b/src/main/java/openconsignment/controller/WelcomeScreenController.java index 73e0d70..68f870d 100644 --- a/src/main/java/openconsignment/controller/WelcomeScreenController.java +++ b/src/main/java/openconsignment/controller/WelcomeScreenController.java @@ -9,18 +9,20 @@ import javafx.scene.control.Hyperlink; import javafx.scene.text.Text; import javax.inject.Inject; +import lombok.extern.slf4j.Slf4j; import openconsignment.common.AppConfig; import openconsignment.common.Utils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +@Slf4j public class WelcomeScreenController implements Initializable { - private static final Logger logger = LoggerFactory.getLogger(WelcomeScreenController.class); private final AppConfig configuration; @FXML private Text organization_name; + @FXML + private Text year; + @Inject public WelcomeScreenController(AppConfig configuration) { this.configuration = configuration; @@ -35,12 +37,13 @@ private void handleOpenGithub(ActionEvent event) { Utils.launchBrowser(url); } catch (IOException ex) { Utils.showAlert(ex.toString()); - logger.error(ex.toString(), ex); + log.error(ex.toString(), ex); } } @Override public void initialize(URL url, ResourceBundle rb) { - organization_name.setText(configuration.organizationName()); + organization_name.setText(configuration.getOrganization()); + year.setText(configuration.getYear()); } } diff --git a/src/main/java/openconsignment/controller/report/SupplierLedgerController.java b/src/main/java/openconsignment/controller/report/SupplierLedgerController.java index 340d15c..7f552c8 100644 --- a/src/main/java/openconsignment/controller/report/SupplierLedgerController.java +++ b/src/main/java/openconsignment/controller/report/SupplierLedgerController.java @@ -15,15 +15,14 @@ import javafx.scene.control.RadioButton; import javafx.scene.control.ToggleGroup; import javax.inject.Inject; +import lombok.extern.slf4j.Slf4j; import net.sf.jasperreports.engine.*; import openconsignment.common.Constants; import openconsignment.common.Utils; import openconsignment.service.SupplierService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +@Slf4j public class SupplierLedgerController implements Initializable { - private static final Logger logger = LoggerFactory.getLogger(SupplierLedgerController.class); @FXML private ComboBox supplier_name_combo; @@ -57,7 +56,7 @@ public void initialize(URL url, ResourceBundle rb) { supplier_name_combo.setItems(FXCollections.observableArrayList(supplierList)); } catch (SQLException ex) { Utils.showAlert(ex.toString()); - logger.error(ex.toString(), ex); + log.error(ex.toString(), ex); } } @@ -70,7 +69,7 @@ private void generatePDF(ActionEvent event) { Utils.showAlert("Report Successfully Generated", AlertType.INFORMATION); } catch (IOException | SQLException | JRException ex) { Utils.showAlert(ex.toString()); - logger.error(ex.toString(), ex); + log.error(ex.toString(), ex); } } @@ -81,7 +80,7 @@ private void launchPdf(ActionEvent event) { Utils.showAlert("PDF opened successfully.", AlertType.INFORMATION); } catch (IOException ex) { Utils.showAlert(ex.toString()); - logger.error(ex.toString(), ex); + log.error(ex.toString(), ex); } } } diff --git a/src/main/java/openconsignment/service/BackupService.java b/src/main/java/openconsignment/service/BackupService.java new file mode 100644 index 0000000..4c7a4b9 --- /dev/null +++ b/src/main/java/openconsignment/service/BackupService.java @@ -0,0 +1,226 @@ +package openconsignment.service; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import javax.inject.Inject; +import javax.inject.Singleton; +import lombok.extern.slf4j.Slf4j; +import openconsignment.common.AppConfig; +import openconsignment.common.Constants; +import openconsignment.common.Utils; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.PullResult; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.transport.PushResult; +import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; + +@Slf4j +@Singleton +public class BackupService { + + private final AppConfig appConfig; + + @Inject + public BackupService(AppConfig appConfig) { + this.appConfig = appConfig; + } + + private void cloneRepo() throws GitAPIException, IOException, URISyntaxException { + + log.info("executing git clone"); + + AppConfig.Github github = appConfig.getGithub(); + String repoPath = github.getRepository(); + String username = github.getUsername(); + String token = github.getToken(); + String branchName = github.getBranch(); + String remoteName = github.getRemote(); + + if (Files.exists(Path.of(repoPath))) { + log.info("skipping git clone as repo already exist"); + return; + } + + String repoUrl = "https://github.com/" + username + "/" + repoPath + ".git"; + + try (Git ignored = Git.cloneRepository() + .setURI(repoUrl) + .setDirectory(new File(repoPath)) + .setBranch(branchName) + .setCredentialsProvider(new UsernamePasswordCredentialsProvider(username, token)) + .call()) { + + log.info("Authenticated clone successful"); + } + + try (Git git = Git.open(new File(repoPath))) { + + // HTTPS remote + git.remoteAdd() + .setName(remoteName) + .setUri(new URIish("https://github.com/" + username + "/" + repoPath + ".git")) + .call(); + + git.remoteSetUrl() + .setRemoteName("origin") + .setRemoteUri(new URIish("git@github.com:" + username + "/" + repoPath + ".git")) + .call(); + } + } + + public boolean checkSync() throws Exception { + log.info("executing called"); + try { + pull(); + return compareDatabaseHashes(); + } catch (Exception e) { + log.error("Error during git pull", e); + throw e; + } + } + + private String getRepoFileHash() throws Exception { + return Utils.md5sum(Path.of(appConfig.getGithub().getRepository() + "/" + Constants.DATABASE_FILE_NAME)); + } + + public boolean compareDatabaseHashes() throws Exception { + String localFileHash = Utils.md5sum(Path.of(Constants.DATABASE_FILE_NAME)); + String repoFileHash = getRepoFileHash(); + + boolean result = 0 == localFileHash.compareTo(repoFileHash); + log.info("CheckSync result = {}, localFileHash = {}, repoFileHash = {}", result, localFileHash, repoFileHash); + return result; + } + + private void copyRepoToLocal() throws IOException { + AppConfig.Github github = appConfig.getGithub(); + String repoPath = github.getRepository(); + + log.info("Copying {} to {}", repoPath, Constants.DATABASE_FILE_NAME); + Files.copy( + Path.of(new File(repoPath + "/" + Constants.DATABASE_FILE_NAME).toURI()), + Path.of(new File(Constants.DATABASE_FILE_NAME).toURI()), + StandardCopyOption.REPLACE_EXISTING); + log.info("Copied {} to {}", repoPath, Constants.DATABASE_FILE_NAME); + } + + private void pull() throws IOException, GitAPIException, URISyntaxException { + log.info("executing git pull"); + + AppConfig.Github github = appConfig.getGithub(); + String repoPath = github.getRepository(); + String username = github.getUsername(); + String token = github.getToken(); + String branchName = github.getBranch(); + String remoteName = github.getRemote(); + + if (!Files.exists(Path.of(repoPath))) { + log.info("cloning {}", repoPath); + cloneRepo(); + } + + log.info("token is {}", token); + + try (Git git = Git.open(new File(repoPath))) { + + PullResult result = git.pull() + .setRemote(remoteName) + .setRemoteBranchName(branchName) + .setCredentialsProvider(new UsernamePasswordCredentialsProvider(username, token)) + .call(); + + if (result.isSuccessful()) { + log.info("Successfully pulled: {}", branchName); + } else { + throw new IllegalStateException("Pull failed for branch: " + branchName); + } + } + } + + public void download() throws GitAPIException, IOException, URISyntaxException { + pull(); + copyRepoToLocal(); + } + + private void copyLocalToRepo() throws IOException { + AppConfig.Github github = appConfig.getGithub(); + String repoPath = github.getRepository(); + + log.info("Copying {} to {}", Constants.DATABASE_FILE_NAME, repoPath); + Files.copy( + Path.of(new File(Constants.DATABASE_FILE_NAME).toURI()), + Path.of(new File(repoPath + "/" + Constants.DATABASE_FILE_NAME).toURI()), + StandardCopyOption.REPLACE_EXISTING); + log.info("Copied {} to {}", Constants.DATABASE_FILE_NAME, repoPath); + } + + private void addAndCommit() throws IOException, GitAPIException { + + log.info("executing add and commit"); + + AppConfig.Github github = appConfig.getGithub(); + String repoPath = github.getRepository(); + + try (Git git = Git.open(new File(repoPath))) { + + // Stage changes + git.add().addFilepattern(".").call(); + + // Current time in string + String currentTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + + String repoFileHash = "null"; + try { + repoFileHash = getRepoFileHash(); + } catch (Exception e) { + log.error(e.toString()); + } + + String message = "Backed up at " + currentTime + "; database hash = " + repoFileHash; + + // Commit changes + RevCommit commit = + git.commit().setMessage(message).setAllowEmpty(false).call(); + + log.info("Commit: " + commit.getId().getName()); + } + } + + private void push() throws IOException, GitAPIException { + log.info("executing git push"); + + AppConfig.Github github = appConfig.getGithub(); + String repoPath = github.getRepository(); + String username = github.getUsername(); + String token = github.getToken(); + String branchName = github.getBranch(); + String remoteName = github.getRemote(); + + log.info("token is {}", token); + + try (Git git = Git.open(new File(repoPath))) { + Iterable results = git.push() + .setRemote(remoteName) + .setCredentialsProvider(new UsernamePasswordCredentialsProvider(username, token)) + .call(); + + for (PushResult result : results) { + log.info(result.getMessages()); + } + } + } + + public void upload() throws GitAPIException, IOException { + copyLocalToRepo(); + addAndCommit(); + push(); + } +} diff --git a/src/main/java/openconsignment/service/BuyerService.java b/src/main/java/openconsignment/service/BuyerService.java index 823f1e6..7eb6aa4 100644 --- a/src/main/java/openconsignment/service/BuyerService.java +++ b/src/main/java/openconsignment/service/BuyerService.java @@ -49,7 +49,7 @@ public void renameBuyer(String oldName, String newName) throws SQLException { public void generatePdf(String buyerName, boolean isAgewise) throws SQLException, JRException { Map payload = new HashMap<>(); - payload.put(Constants.ORGANIZATION_NAME_KEY, configuration.organizationName()); + payload.put(Constants.ORGANIZATION_NAME_KEY, configuration.getOrganization()); payload.put("buyerName", buyerName); if (isAgewise) { diff --git a/src/main/java/openconsignment/service/SupplierService.java b/src/main/java/openconsignment/service/SupplierService.java index 7f8eb0e..a476ff3 100644 --- a/src/main/java/openconsignment/service/SupplierService.java +++ b/src/main/java/openconsignment/service/SupplierService.java @@ -50,7 +50,7 @@ public void renameSupplier(String oldName, String newName) throws SQLException { public void generatePdf(String supplierName, boolean isAgewise) throws SQLException, JRException { Map payload = new HashMap<>(); - payload.put(Constants.ORGANIZATION_NAME_KEY, configuration.organizationName()); + payload.put(Constants.ORGANIZATION_NAME_KEY, configuration.getOrganization()); payload.put("supplierName", supplierName); if (isAgewise) { diff --git a/src/main/java/openconsignment/service/TransportService.java b/src/main/java/openconsignment/service/TransportService.java index 8007adc..4785790 100644 --- a/src/main/java/openconsignment/service/TransportService.java +++ b/src/main/java/openconsignment/service/TransportService.java @@ -46,7 +46,7 @@ public void generatePdf(String transportName, String fromDate, String toDate) th transportRepository.getTransportReportFor(transportName, fromDate, toDate); Map payload = new HashMap<>(); - payload.put(Constants.ORGANIZATION_NAME_KEY, configuration.organizationName()); + payload.put(Constants.ORGANIZATION_NAME_KEY, configuration.getOrganization()); payload.put("transportName", transportName); payload.put("fromDate", fromDate); payload.put("toDate", toDate); diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index aada7ee..8167cdc 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -1 +1,8 @@ -organizationName: "SATYAM AGENCIES" +organization: "SATYAM AGENCIES" +year: 2001-02 +github: + token: "" + username: "razdeep" + branch: "main" + remote: "origin-https" + repository: "Satyam-Database-2001-02" \ No newline at end of file diff --git a/src/main/resources/fxml/Main.fxml b/src/main/resources/fxml/Main.fxml index 6357a76..2f6c3a9 100644 --- a/src/main/resources/fxml/Main.fxml +++ b/src/main/resources/fxml/Main.fxml @@ -1,97 +1,144 @@ - - - - - - - - - - - -
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/resources/fxml/WelcomeScreen.fxml b/src/main/resources/fxml/WelcomeScreen.fxml index 645c681..ad21a09 100644 --- a/src/main/resources/fxml/WelcomeScreen.fxml +++ b/src/main/resources/fxml/WelcomeScreen.fxml @@ -1,54 +1,68 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/fxml/report/BuyerLedger.fxml b/src/main/resources/fxml/report/BuyerLedger.fxml index d01305e..47ea9e7 100644 --- a/src/main/resources/fxml/report/BuyerLedger.fxml +++ b/src/main/resources/fxml/report/BuyerLedger.fxml @@ -3,12 +3,11 @@ - - + + @@ -50,4 +49,4 @@ - + diff --git a/src/main/resources/fxml/report/SupplierLedger.fxml b/src/main/resources/fxml/report/SupplierLedger.fxml index 4745eb1..3e8c83c 100644 --- a/src/main/resources/fxml/report/SupplierLedger.fxml +++ b/src/main/resources/fxml/report/SupplierLedger.fxml @@ -3,12 +3,11 @@ - - + + @@ -51,4 +50,4 @@ - + diff --git a/src/main/resources/fxml/report/TransportLedger.fxml b/src/main/resources/fxml/report/TransportLedger.fxml index 01aa234..02caf53 100644 --- a/src/main/resources/fxml/report/TransportLedger.fxml +++ b/src/main/resources/fxml/report/TransportLedger.fxml @@ -3,12 +3,11 @@ - - + + @@ -48,4 +47,4 @@ - + diff --git a/src/test/java/openconsignment/di/ConfigurationModuleTest.java b/src/test/java/openconsignment/di/ConfigurationModuleTest.java index 0a09125..ee15ee2 100644 --- a/src/test/java/openconsignment/di/ConfigurationModuleTest.java +++ b/src/test/java/openconsignment/di/ConfigurationModuleTest.java @@ -30,7 +30,7 @@ void missingFileIsCopiedFromBundledResourceAndLoaded() throws IOException { AppConfig configuration = load(file); assertEquals(bundled, Files.readString(file)); - assertEquals(configuration.organizationName(), load(file).organizationName()); + assertEquals(configuration.getOrganization(), load(file).getOrganization()); } @Test @@ -42,33 +42,33 @@ void emptyExistingFileIsRejectedAndPreserved() throws IOException { } @Test - void loadsUtf8OrganizationNameAndTrimsWhitespace() throws IOException { - Path file = Files.writeString(tempDir.resolve("application.yaml"), "organizationName: \" Café Agencies \"\n"); + void loadsUtf8OrganizationAndTrimsWhitespace() throws IOException { + Path file = Files.writeString(tempDir.resolve("application.yaml"), "organization: \" Café Agencies \"\n"); - assertEquals("Café Agencies", load(file).organizationName()); + assertEquals("Café Agencies", load(file).getOrganization()); } @Test void loadedConfigurationDoesNotChangeWhenFileIsEdited() throws IOException { - Path file = Files.writeString(tempDir.resolve("application.yaml"), "organizationName: First\n"); + Path file = Files.writeString(tempDir.resolve("application.yaml"), "organization: First\n"); AppConfig configuration = load(file); - Files.writeString(file, "organizationName: Second\n"); + Files.writeString(file, "organization: Second\n"); - assertEquals("First", configuration.organizationName()); - assertEquals("Second", load(file).organizationName()); + assertEquals("First", configuration.getOrganization()); + assertEquals("Second", load(file).getOrganization()); } @Test - void rejectsBlankOrganizationName() throws IOException { - Path file = Files.writeString(tempDir.resolve("application.yaml"), "organizationName: \" \"\n"); + void rejectsBlankOrganization() throws IOException { + Path file = Files.writeString(tempDir.resolve("application.yaml"), "organization: \" \"\n"); assertThrows(IllegalArgumentException.class, () -> load(file)); } @Test void rejectsMalformedYaml() throws IOException { - Path file = Files.writeString(tempDir.resolve("application.yaml"), "organizationName: [\n"); + Path file = Files.writeString(tempDir.resolve("application.yaml"), "organization: [\n"); assertThrows(YAMLException.class, () -> load(file)); } @@ -83,16 +83,16 @@ void missingOrganizationNameIsRejectedWithoutBundledFallback() throws IOExceptio @Test void existingConfigurationIsLoadedWithoutBeingOverwritten() throws IOException { - String content = "# Custom settings\norganizationName: External Organization\n"; + String content = "# Custom settings\norganization: External Organization\n"; Path file = Files.writeString(tempDir.resolve("application.yaml"), content); - assertEquals("External Organization", load(file).organizationName()); + assertEquals("External Organization", load(file).getOrganization()); assertEquals(content, Files.readString(file)); } @Test void malformedConfigurationErrorIdentifiesSourceFile() throws IOException { - Path file = Files.writeString(tempDir.resolve("application.yaml"), "organizationName: [\n"); + Path file = Files.writeString(tempDir.resolve("application.yaml"), "organization: [\n"); YAMLException error = assertThrows(YAMLException.class, () -> load(file)); @@ -134,14 +134,14 @@ void developmentRunUsesConfigurationInWorkingDirectory() throws IOException { @Test void bindsNumericScalarToStringProperty() throws IOException { - Path file = Files.writeString(tempDir.resolve("application.yaml"), "organizationName: 123\n"); + Path file = Files.writeString(tempDir.resolve("application.yaml"), "organization: 123\n"); - assertEquals("123", load(file).organizationName()); + assertEquals("123", load(file).getOrganization()); } @Test void rejectsMappingOrganizationName() throws IOException { - Path file = Files.writeString(tempDir.resolve("application.yaml"), "organizationName: {name: Example}\n"); + Path file = Files.writeString(tempDir.resolve("application.yaml"), "organization: {name: Example}\n"); assertThrows(YAMLException.class, () -> load(file)); } @@ -155,22 +155,22 @@ void rejectsNonMappingDocument() throws IOException { @Test void rejectsNullOrganizationName() throws IOException { - Path file = Files.writeString(tempDir.resolve("application.yaml"), "organizationName: null\n"); + Path file = Files.writeString(tempDir.resolve("application.yaml"), "organization: null\n"); assertThrows(IllegalArgumentException.class, () -> load(file)); } @Test void rejectsEmptyOrganizationName() throws IOException { - Path file = Files.writeString(tempDir.resolve("application.yaml"), "organizationName: \"\"\n"); + Path file = Files.writeString(tempDir.resolve("application.yaml"), "organization: \"\"\n"); assertThrows(IllegalArgumentException.class, () -> load(file)); } @Test void rejectsDuplicateKeys() throws IOException { - Path file = Files.writeString( - tempDir.resolve("application.yaml"), "organizationName: First\norganizationName: Second\n"); + Path file = + Files.writeString(tempDir.resolve("application.yaml"), "organization: First\norganization: Second\n"); assertThrows(YAMLException.class, () -> load(file)); }