Skip to content

Commit

Permalink
Merge pull request #61 from cathrkri/60-download-charity-logo
Browse files Browse the repository at this point in the history
Merge 60 with develop
  • Loading branch information
roaraf authored Apr 12, 2026
2 parents e99953a + 628d94a commit cc2afdd
Show file tree
Hide file tree
Showing 15 changed files with 433 additions and 265 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion helpmehelpapplication/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.41.0</version>
<version>4.43.0</version>
</dependency>
<dependency>
<groupId>com.opencsv</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package ntnu.systemutvikling.team6.database;

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

import ntnu.systemutvikling.team6.models.Charity;
import ntnu.systemutvikling.team6.models.CharityRegistry;
import ntnu.systemutvikling.team6.models.Donation;
import ntnu.systemutvikling.team6.models.DonationRegistry;
import ntnu.systemutvikling.team6.scraper.APICharityData;
import ntnu.systemutvikling.team6.scraper.LogoDownloader;
import ntnu.systemutvikling.team6.scraper.URLCharityScraper;

/**
Expand Down Expand Up @@ -79,6 +80,7 @@ status VARCHAR(255) NOT NULL,
logoURL TEXT,
categories TEXT,
key_values TEXT,
logoBlob MEDIUMBLOB,
UNIQUE KEY unique_org_number (org_number)
) ENGINE=InnoDB;
Expand Down Expand Up @@ -117,23 +119,43 @@ REFERENCES Charities (`UUID_charities`)

/**
* This method is used to verify the integrity of the data in the {@code charities} table and to
* update it based on the data retrieved from the IK API. The param charities are retrieved from
* update it based on the data retrieved from the IK API and the charity's URL.
* The param charities are retrieved from
* the IK API through the APICharityData class. Called in initialize method in
* HmHApplication.java, which is the main class of the application, to ensure that the data is up
* to date when the application starts. Uses a a temp table to ensure that the data in the
* database is consistent with the data from the API.
* to date when the application starts. Uses a temp table to ensure that the data in the database
* is consistent with the data from the API.
* <p>Uses a URLScraper object to get data not contained in the API, and static methods from
* LogoDownloader to get the charity's logo as a blob.</p>
*
* @param charities
* @param charities a list of {@code Charity} objects to add to the database
*/
public void addAPIDataToTable(List<Charity> charities) {
Connection conn = null;
int charityCounter = 0;

// Scrapes description, logo, categories, and key values from IK
for (Charity charity : charities) {
charityCounter++;

System.out.println("Scraping charity " + charityCounter + " of " + charities.size());
URLCharityScraper urlScraper = new URLCharityScraper(charity.getURL());
urlScraper.scrapeCharityPage();

charity.setDescription(urlScraper.getDescription());
charity.setCategory(urlScraper.getCategories());
charity.setLogoURL(urlScraper.getLogoURL());
charity.setKeyValues(urlScraper.getKeyValues());
byte[] logoBlob = LogoDownloader.downloadImageAsBlob(charity.getLogoURL());
charity.setLogoBlob(logoBlob);
}
try {
conn = connection.getMySqlConnection();
conn.setAutoCommit(false);
String sql_query =
"""
INSERT INTO Charities (UUID_charities, org_number, charity_name, charity_link, pre_approved, status, description, logoURL, categories, key_values)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
INSERT INTO Charities (UUID_charities, org_number, charity_name, charity_link, pre_approved, status, description, logoURL, categories, key_values, logoBlob)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
charity_name = VALUES(charity_name),
charity_link = VALUES(charity_link),
Expand All @@ -142,7 +164,8 @@ INSERT INTO Charities (UUID_charities, org_number, charity_name, charity_link, p
description = VALUES(description),
logoURL = VALUES(logoURL),
categories = VALUES(categories),
key_values = VALUES(key_values)
key_values = VALUES(key_values),
logoBlob = VALUES(logoBlob)
""";

try (PreparedStatement ps = conn.prepareStatement(sql_query)) {
Expand All @@ -152,14 +175,6 @@ INSERT INTO Charities (UUID_charities, org_number, charity_name, charity_link, p
} else {
ps.setString(1, charity.getUUID().toString());
}
// Scrapes description, logo, categories, and key values from IK
URLCharityScraper urlScraper = new URLCharityScraper(charity.getURL());
urlScraper.scrapeCharityPage();

charity.setDescription(urlScraper.getDescription());
charity.setCategory(urlScraper.getCategories());
charity.setLogoURL(urlScraper.getLogoURL());
charity.setKeyValues(urlScraper.getKeyValues());

ps.setString(2, charity.getOrg_number().replaceAll("\\s", ""));
ps.setString(3, charity.getName());
Expand All @@ -170,6 +185,7 @@ INSERT INTO Charities (UUID_charities, org_number, charity_name, charity_link, p
ps.setString(8, charity.getLogoURL());
ps.setString(9, charity.getCategory());
ps.setString(10, charity.getKeyValues());
ps.setBytes(11, charity.getLogoBlob());

ps.addBatch();
}
Expand Down Expand Up @@ -239,13 +255,20 @@ WHERE NOT EXISTS (
}
}

/**
* Fetches the data stored in the database and converts it to a list of Charity objects
* in the form of a registry (CharityRegistry).
*
* @return a CharityRegistry of all the charities registered in the database
*/
public CharityRegistry getCharitiesFromDB() {
CharityRegistry registry = null;
Connection conn = null;
try {
conn = connection.getMySqlConnection();
String sql_query =
"SELECT UUID_charities, org_number, charity_name, charity_link, pre_approved, status FROM Charities";
"SELECT UUID_charities, org_number, charity_name, charity_link, pre_approved, status, description, logoURL, " +
"categories, key_values, logoBlob FROM Charities";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql_query);

Expand All @@ -259,6 +282,12 @@ public CharityRegistry getCharitiesFromDB() {
rs.getString("charity_name"),
rs.getBoolean("pre_approved"),
rs.getString("status"));
charity.setDescription(rs.getString("description"));
charity.setLogoURL(rs.getString("logoURL"));
charity.setCategory(rs.getString("categories"));
charity.setKeyValues(rs.getString("key_values"));
charity.setLogoBlob(rs.getBytes("logoBlob"));

registry.addCharity(charity);
}
} catch (SQLException e) {
Expand All @@ -268,6 +297,41 @@ public CharityRegistry getCharitiesFromDB() {
return registry;
}

public List<String> getCategoriesFromDB() {
Map<String, String> categoryMap = new HashMap<>();

String sql_query = "SELECT categories FROM Charities";

try (Connection conn = connection.getMySqlConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql_query)) {

while (rs.next()) {
String categoriesStr = rs.getString("categories");

if (categoriesStr != null && !categoriesStr.isEmpty()) {
String[] splitCategories = categoriesStr.split(",");

for (String category : splitCategories) {
String trimmed = category.trim();

if (!trimmed.isEmpty()) {
categoryMap.putIfAbsent(trimmed.toLowerCase(), trimmed);
}
}
}
}
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("ERROR: Something went wrong while fetching categories from the database.");
}

var categories = new ArrayList<>(categoryMap.values());
Collections.sort(categories);

return categories;
}

public DonationRegistry getDonationFromDB() {
DonationRegistry registry = null;
Connection conn = null;
Expand Down Expand Up @@ -317,4 +381,4 @@ public DonationRegistry getDonationFromDB() {
}
return registry;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public class Charity {
/* List that contains the charity's Feedbacks */
private List<Feedback> feedbacks;

/* Bytecode for the charity logo */
private byte[] logoBlob;

/**
* Contructor for creating a new charity. Taylored to match data given from Api. Other attributes
* will just be initialized as empty
Expand Down Expand Up @@ -91,6 +94,7 @@ public Charity(
this.logoURL = "";
this.keyValues = "";
this.feedbacks = new ArrayList<>();
this.logoBlob = null;
}

/** Getters for the charity's attributes. */
Expand Down Expand Up @@ -138,6 +142,10 @@ public String getKeyValues() {
return this.keyValues;
}

public byte[] getLogoBlob() {
return this.logoBlob;
}

/** Setter for verification status. This one sets the charity as verified. */
public void setVerified() {
this.status = "approved";
Expand Down Expand Up @@ -167,4 +175,9 @@ public void setLogoURL(String url) {
public void setKeyValues(String values) {
this.keyValues = values;
}

/** Setter for the charity's logo Blob. */
public void setLogoBlob(byte[] logoBlob) {
this.logoBlob = logoBlob;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ public CharityRegistry parseJSON(String JSONData) {

CharityRegistry charityRegistry = new CharityRegistry();
for (APICharityData apiCharityData : charityData) {
if (apiCharityData.getStatus().equalsIgnoreCase("obs")) {
continue;
}
Charity charity =
new Charity(
apiCharityData.getOrg_number(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package ntnu.systemutvikling.team6.scraper;

import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
* Facilitates downloading of .png images from the individual charity's page on IK, converting them
* to bytecode (blob), and then back to a .png.
*/
public class LogoDownloader {

/**
* Downloads a image from the given URL and converts it to a blob.
*
* @param imageUrl the URL of the image
* @return a blob containing the image data
*/
public static byte[] downloadImageAsBlob(String imageUrl) {
if (imageUrl == null || imageUrl.isBlank()) return null;

try (InputStream in = new URL(imageUrl).openStream()) {
return in.readAllBytes();
} catch (Exception e) {
System.out.println("Error: Something went wrong when downloading the image.");
return null;
}
}

/**
* Converts a blob of image data back to a .png image file.
*
* @param imageBytes the blob containing the image data
* @param fileName the filename of the .png image file
*/
public static void convertBlobToPNG(byte[] imageBytes, String fileName) {
if (imageBytes == null) {
return;
}
try {
Path folder = Paths.get("target", "logo");
Files.createDirectories(folder);

Path filePath = folder.resolve(fileName + ".png");

Files.write(filePath, imageBytes);

} catch (Exception e) {
System.out.println("Error: Something went wrong when converting blob to png.");
}
}
}
Loading

0 comments on commit cc2afdd

Please sign in to comment.