Skip to content

Commit

Permalink
Merge branch 'feature/40-mvp-funksjonality-across-sites' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrianBalunan committed Mar 12, 2026
2 parents 579f917 + 7a1f261 commit a7be88e
Show file tree
Hide file tree
Showing 29 changed files with 1,358 additions and 46 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: ci

on:
push:
branches: [main]
branches: [main, develop]
pull_request:
branches: [main]
branches: [main, develop]

jobs:
test:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Adrian
.vscode/
.idea/
helpmehelpapplication/target
.target/
.helpmehelpapplication\target/
.helpmehelpapplication\.idea/
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"java.configuration.updateBuildConfiguration": "interactive"
"java.configuration.updateBuildConfiguration": "interactive",
"java.compile.nullAnalysis.mode": "disabled"
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Consists of: Cathrine Kristiansen, Adrian Balunan, Roar Fagerkind, Robin Prestmo

- Team number: `6`
- Team members:
- Robin Prestmo - Product Owner
- Robin Strand Prestmo - Product Owner
- Adrian Balunan - Scrum Master
- Cathrine Kristiansen - Archive and Document Responsible
- Roar Fagerkind - Software Quality Responsible
Expand Down
Binary file removed docs/Møtedokumenter/Internmeeting, 05.02.2026.pdf
Binary file not shown.
File renamed without changes.
Binary file not shown.
Binary file not shown.
33 changes: 30 additions & 3 deletions helpmehelpapplication/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,36 @@
<version>25.0.1</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>25.0.1</version>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.41.0</version>
</dependency>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.12.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.13.2</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.21.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>9.6.0</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.4.240</version>
<scope>test</scope>
</dependency>
</dependencies>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
package ntnu.sytemutvikling.team6.DAO;

import ntnu.sytemutvikling.team6.scraper.APICharityData;

import java.sql.*;
import java.util.List;

/**
* Manages the charity
* <p>
* This class is responsible for establishing connections using environment variables
* and maintaining the {@code charities} table based on data retrieved from the IK API.
* </p>
*/

public class CharityDAO {

public class DatabaseManager {
private final String databaseURL;
private final String username;
private final String password;

/**
Constructs a new {@code DatabaseManager} using database credentials
* retrieved from system environment variables.
* <p>
* Required environment variables:
* <ul>
* <li>{@code HMH_DB_URL}</li>
* <li>{@code HMH_DB_USERNAME}</li>
* <li>{@code HMH_DB_PASSWORD}</li>
* </ul>
* </p>
*
* @throws IllegalStateException if either databaseURL, username, or password is {@code null} or blank
*/

// Values stored in system environment variables for security (using ntnu's phpmyadmin for this project)
public DatabaseManager() {
this.databaseURL = System.getenv("HMH_DB_URL");
this.username = System.getenv("HMH_DB_USERNAME");
this.password = System.getenv("HMH_DB_PASSWORD");

if (this.databaseURL == null || this.databaseURL.isBlank()) {
throw new IllegalStateException("Database environment variable URL has not been set");
}

if (this.username == null || this.username.isBlank()) {
throw new IllegalStateException("Username environment variable has not been set");
}

if (this.password == null || this.password.isBlank()) {
throw new IllegalStateException("Password environment variable has not been set");
}
}

/**
* Constructs a new {@code DatabaseManager} using database credentials
* <p>
* Used primarily for JUnit tests. Production should use the constructor
* using environment variables.
* </p>
*
* @param databaseURL the url to the database
* @param username the username used to log in to the database
* @param password the password used to log in to the database
* @throws IllegalArgumentException if databaseURL, username, or password is
* {@code null} or blank
*/

public DatabaseManager(String databaseURL, String username, String password) {
this.databaseURL = databaseURL;
this.username = username;
this.password = password;

if (this.databaseURL == null || this.databaseURL.isBlank()) {
throw new IllegalArgumentException("Database environment variable URL has not been set");
}

if (this.username == null || this.username.isBlank()) {
throw new IllegalArgumentException("Username environment variable has not been set");
}

if (this.password == null || this.password.isBlank()) {
throw new IllegalArgumentException("Password environment variable has not been set");
}
}

/**
* Creates the {@code charities} table if it does not already exist.
* <p>
* The table structure is based on fields from {@link APICharityData}.
* </p>
* @throws RuntimeException if a {@link SQLException} occurs while creating the table
*/

public void createTables() {
String sql_query = """
-- MySQL Workbench Forward Engineering
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
-- -----------------------------------------------------
-- Schema HelpMeHelp
-- -----------------------------------------------------
-- -----------------------------------------------------
-- Schema HelpMeHelp
-- -----------------------------------------------------
--CREATE SCHEMA IF NOT EXISTS `HelpMeHelp` DEFAULT CHARACTER SET utf8 ;
--USE `HelpMeHelp` ;
USE apbaluna;
-- -----------------------------------------------------
-- Table `HelpMeHelp`.`Charities`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `HelpMeHelp`.`Charities` (
`UUID` CHAR(36) NOT NULL,
`charity_name` VARCHAR(255) NOT NULL,
`charity_description` VARCHAR(255) NOT NULL,
`isVerified` TINYINT NOT NULL,
`category` VARCHAR(45) NOT NULL,
PRIMARY KEY (`UUID`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `HelpMeHelp`.`Donations`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `HelpMeHelp`.`Donations` (
`UUID` CHAR(36) NOT NULL,
`amount` DECIMAL NOT NULL,
`date` DATE NOT NULL,
`Charities_UUID` CHAR(36) NOT NULL,
PRIMARY KEY (`UUID`),
INDEX `fk_Donations_Charities_idx` (`Charities_UUID` ASC) VISIBLE,
CONSTRAINT `fk_Donations_Charities`
FOREIGN KEY (`Charities_UUID`)
REFERENCES `HelpMeHelp`.`Charities` (`UUID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
""";

try (Connection conn = DriverManager.getConnection(databaseURL, username, password);
Statement s = conn.createStatement()) {

s.execute(sql_query);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("Error creating table.");
}
}

/**
* Synchronizes the {@code charities} table with the provided list of APICharityData.
* <p>
* Summary of function:
* <ul>
* <li>Inserts new records</li>
* <li>Updates existing records using {@code ON DUPLICATE KEY UPDATE}</li>
* <li>Removes database records that are not present in the provided list</li>
* </ul>
* A temporary table is used to determine which records should be deleted.
* </p>
*
* @param charities a list of ApiCharityDaya objects
* @throws RuntimeException if a {@link SQLException} occurs during database synchronization
*/

public void updateCharities(List<APICharityData> charities) {
Connection conn = null;
try {
conn = DriverManager.getConnection(databaseURL, username, password);
conn.setAutoCommit(false);
// Inserts objects values into charities
String sql_query = """
INSERT INTO charities (org_number, name, status, url, is_pre_approved)
VALUES (?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
name = VALUES(name),
status = VALUES(status),
url = VALUES(url),
is_pre_approved = VALUES(is_pre_approved)
""";

try (PreparedStatement s = conn.prepareStatement(sql_query)) {
for (APICharityData charity : charities) {
s.setString(1, charity.getOrg_number().replaceAll("\\s", ""));
s.setString(2, charity.getName());
s.setString(3, charity.getStatus());
s.setString(4, charity.getUrl());
s.setBoolean(5, charity.getIs_pre_approved());

s.addBatch();
}
s.executeBatch();
}


// Temporary table for parity check
sql_query = "CREATE TEMPORARY TABLE temp (org_number VARCHAR(100) PRIMARY KEY)";
try (PreparedStatement temp_create = conn.prepareStatement(sql_query)) {
temp_create.execute();
}

String sql_update_temp_table = "INSERT INTO temp (org_number) VALUES (?)";
try (PreparedStatement temp_update = conn.prepareStatement(sql_update_temp_table)) {
for (APICharityData charity : charities) {
temp_update.setString(1, charity.getOrg_number().replaceAll("\\s", ""));
temp_update.addBatch();
}
temp_update.executeBatch();
}



// Removes records not found in the list from charities table
sql_query = """
DELETE FROM charities c
WHERE NOT EXISTS (
SELECT 1
FROM temp t
WHERE c.org_number = t.org_number
)
""";

try (PreparedStatement delete_old_records = conn.prepareStatement(sql_query)){
delete_old_records.execute();
}

conn.commit();
} catch (SQLException e) {

if (conn != null) {
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}

e.printStackTrace();
throw new RuntimeException("ERROR: Something went wrong during updating charities table.");
} finally {
if (conn != null) {
try {
conn.setAutoCommit(true);
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package ntnu.sytemutvikling.team6.DAO;

public class DonationDAO {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package ntnu.sytemutvikling.team6;

import ntnu.sytemutvikling.team6.database.DatabaseConnection;
import ntnu.sytemutvikling.team6.database.DatabaseManager;
import ntnu.sytemutvikling.team6.models.Charity;
import ntnu.sytemutvikling.team6.models.CharityRegistry;
import ntnu.sytemutvikling.team6.scraper.APICharityScraper;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.http.HttpClient;

public class HmHApplication {
public static void main(String[] args) {
System.out.println("Hello world!");
init();

}
public static void init(){
/* Test and create tables to MySQL if ain't any */
try {
DatabaseManager db = new DatabaseManager();
db.testConnection();
db.createTables();
} catch (Exception e){
e.printStackTrace();
}
/* Test and get data from Innsamlingkontrollen API */
try {
HttpClient https = HttpClient.newHttpClient();
APICharityScraper scraper = new APICharityScraper(https);
DatabaseManager db = new DatabaseManager();

if (scraper.checkConnection()){
CharityRegistry charityRegistry = scraper.parseJSON(scraper.getJSONData());
for (Charity charity : charityRegistry.getAllCharities()){
System.out.println(charity.toString());
}
db.addAPIDataToTable(charityRegistry.getAllCharities());
}
} catch (Exception e){
e.printStackTrace();
}
}
}
Loading

0 comments on commit a7be88e

Please sign in to comment.