diff --git a/.gitignore b/.gitignore index 24fca5a..6c18783 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Adrian .vscode/ .idea/ +helpmehelpapplication/target .target/ .helpmehelpapplication\target/ .helpmehelpapplication\.idea/ diff --git a/.vscode/settings.json b/.vscode/settings.json index c5f3f6b..0153b31 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "java.configuration.updateBuildConfiguration": "interactive" + "java.configuration.updateBuildConfiguration": "interactive", + "java.compile.nullAnalysis.mode": "disabled" } \ No newline at end of file diff --git a/docs/ER-Diagram v1.png b/docs/ER-Diagram v1.png new file mode 100644 index 0000000..65f1094 Binary files /dev/null and b/docs/ER-Diagram v1.png differ diff --git a/docs/ER-Diagram v2.png b/docs/ER-Diagram v2.png new file mode 100644 index 0000000..08d4a88 Binary files /dev/null and b/docs/ER-Diagram v2.png differ diff --git a/docs/ER-DiagramFile.mwb b/docs/ER-DiagramFile.mwb new file mode 100644 index 0000000..c05526f Binary files /dev/null and b/docs/ER-DiagramFile.mwb differ diff --git a/docs/ER-DiagramFile.mwb.bak b/docs/ER-DiagramFile.mwb.bak new file mode 100644 index 0000000..24c783b Binary files /dev/null and b/docs/ER-DiagramFile.mwb.bak differ diff --git a/helpmehelpapplication/Organization_message.puml b/helpmehelpapplication/Organization_message.puml new file mode 100644 index 0000000..81ef5b9 --- /dev/null +++ b/helpmehelpapplication/Organization_message.puml @@ -0,0 +1,31 @@ + +'https://plantuml.com/sequence-diagram + +@startuml +title Messaging between Organisation and User + +actor Organisation as Org +actor User +participant "Organization Portal (UI)" as OrgUI +participant "User App (UI)" as UserUI +participant "Messaging Service" as MsgSvc +database "Messages DB" as MsgDB +participant "Notification Service" as Notify + +Org -> OrgUI: Write message to user +OrgUI -> MsgSvc: sendMessage(orgId, userId, content) +MsgSvc -> MsgDB: store message +MsgDB --> MsgSvc: stored +MsgSvc -> Notify: notifyUser(userId, "New message") +Notify --> MsgSvc: queued +MsgSvc --> OrgUI: sent OK +OrgUI --> Org: Message sent + +User -> UserUI: Open Inbox +UserUI -> MsgSvc: getInbox(userId) +MsgSvc -> MsgDB: fetch messages for userId +MsgDB --> MsgSvc: messages +MsgSvc --> UserUI: messages +UserUI --> User: Display inbox + +@enduml \ No newline at end of file diff --git a/helpmehelpapplication/Organization_onboard.puml b/helpmehelpapplication/Organization_onboard.puml new file mode 100644 index 0000000..fe48d6f --- /dev/null +++ b/helpmehelpapplication/Organization_onboard.puml @@ -0,0 +1,46 @@ + +'https://plantuml.com/sequence-diagram + +@startuml +title Organisation onboarding + +actor Organisation as Org +participant "Organization Portal (UI)" as UI +participant "Authentication Service" as Auth +participant "Email Service" as Mail +participant "Organisation Service" as OrgSvc +database "Organisation DB" as OrgDB +participant "Payment Provider" as Pay + +Org -> UI: Open Organisation Portal Dashboard +UI --> Org: Show portal dashboard + +Org -> UI: Register organisation account +UI -> Auth: register(orgEmail, password) +Auth --> UI: accountCreated + verificationToken + +Auth -> Mail: sendVerificationEmail(orgEmail, token) +Mail --> Auth: sent + +Org -> UI: Click verification link (token) +UI -> Auth: verifyEmail(token) +Auth --> UI: verified OK + +Org -> UI: Create organisation profile (name, desc, category, media) +UI -> OrgSvc: createProfile(profileData) +OrgSvc -> OrgDB: insert profile +OrgDB --> OrgSvc: created +OrgSvc --> UI: profileCreated +UI --> Org: Profile created + +Org -> UI: Set up payout account +UI -> Pay: createConnectedAccount(orgData) +Pay --> UI: connectedAccountId + status + +UI -> OrgSvc: savePayoutAccount(orgId, connectedAccountId) +OrgSvc -> OrgDB: update payout info +OrgDB --> OrgSvc: saved +OrgSvc --> UI: payoutSetupSaved +UI --> Org: Payout setup complete + +@enduml diff --git a/helpmehelpapplication/Organization_update_profile.puml b/helpmehelpapplication/Organization_update_profile.puml new file mode 100644 index 0000000..e6ef6f0 --- /dev/null +++ b/helpmehelpapplication/Organization_update_profile.puml @@ -0,0 +1,26 @@ + +'https://plantuml.com/sequence-diagram + +@startuml +title Organisation updates profile + +actor Organisation as Org +participant "Organization Portal (UI)" as UI +participant "Organisation Service" as OrgSvc +database "Organisation DB" as OrgDB + +Org -> UI: Open My Organisation Profile +UI -> OrgSvc: getProfile +OrgSvc -> OrgDB: load profile +OrgDB --> OrgSvc: profile data +OrgSvc --> UI: profile data +UI --> Org: Show profile + +Org -> UI: Edit profile fields + upload media +UI -> OrgSvc: updateProfile +OrgSvc -> OrgDB: update profile +OrgDB --> OrgSvc: updated +OrgSvc --> UI: update OK +UI --> Org: Show updated profile + +@enduml diff --git a/helpmehelpapplication/User_authenticator.puml b/helpmehelpapplication/User_authenticator.puml new file mode 100644 index 0000000..403814f --- /dev/null +++ b/helpmehelpapplication/User_authenticator.puml @@ -0,0 +1,36 @@ + +'https://plantuml.com/sequence-diagram + +@startuml +title User authentication for for signin and Login + +actor User +participant "Desktop App (UI)" as UI +participant "Authenticator Service" as Auth +database "User DB" as UDB + +User -> UI: Open Dashboard +UI --> User: Show dashboard + +User -> UI: Click Login +UI --> User: Show Welcome/Login page + +User -> UI: Go to Sign In +UI --> User: Show Sign In form + +User -> UI: Submit credentials +UI -> Auth: signIn(email, password) +Auth -> UDB: validate credentials +UDB --> Auth: valid +Auth --> UI: session/token +UI --> User: Logged in (Dashboard updated) + +User -> UI: Click "My Profile" (from Dashboard) +UI --> User: Show Profile + +User -> UI: Click Logout +UI -> Auth: logout(session) +Auth --> UI: session terminated +UI --> User: Redirect to Dashboard + +@enduml diff --git a/helpmehelpapplication/User_browser.puml b/helpmehelpapplication/User_browser.puml new file mode 100644 index 0000000..d279b7e --- /dev/null +++ b/helpmehelpapplication/User_browser.puml @@ -0,0 +1,56 @@ + +'https://plantuml.com/sequence-diagram + +@startuml +title User explores organisations + +actor User +participant "Desktop App (UI)" as UI +participant "Organisation Service" as OrgSvc +database "Organisation DB" as OrgDB + +User -> UI: Open Dashboard +UI --> User: Show dashboard + +User -> UI: Click "Browse Organisations" +UI -> OrgSvc: getFeaturedOrgs() +OrgSvc -> OrgDB: query featured orgs +OrgDB --> OrgSvc: org list +OrgSvc --> UI: org list +UI --> User: Show organisations list + +alt User chooses Category + User -> UI: Select category + UI -> OrgSvc: getOrgsByCategory(category) + OrgSvc -> OrgDB: query orgs by category + OrgDB --> OrgSvc: results + OrgSvc --> UI: results + UI --> User: Show filtered list +end + +alt User uses Filter/Sort + User -> UI: Set filters/sort + UI -> OrgSvc: getOrgsFiltered(filters, sort) + OrgSvc -> OrgDB: query with filters/sort + OrgDB --> OrgSvc: results + OrgSvc --> UI: results + UI --> User: Show filtered list +end + +alt User searches from Dashboard or list + User -> UI: Search organisations (query) + UI -> OrgSvc: searchOrgs(query) + OrgSvc -> OrgDB: fulltext/search query + OrgDB --> OrgSvc: results + OrgSvc --> UI: results + UI --> User: Show search results +end + +User -> UI: Open organisation page +UI -> OrgSvc: getOrganisationDetails(orgId) +OrgSvc -> OrgDB: load org details +OrgDB --> OrgSvc: org details +OrgSvc --> UI: org details +UI --> User: Show organisation page + +@enduml \ No newline at end of file diff --git a/helpmehelpapplication/User_donate.puml b/helpmehelpapplication/User_donate.puml new file mode 100644 index 0000000..f856d18 --- /dev/null +++ b/helpmehelpapplication/User_donate.puml @@ -0,0 +1,41 @@ + +'https://plantuml.com/sequence-diagram + +@startuml +title User donation + +actor User +participant "Desktop App (UI)" as UI +participant "Donation Service" as DonSvc +participant "Payment Provider" as Pay +database "Donation DB" as DonDB +participant "Organisation Service" as OrgSvc + +User -> UI: Click "Donate" +UI --> User: Show donation form + +User -> UI: Enter amount + confirm +UI -> DonSvc: createDonationIntent(userId, orgId, amount) + +DonSvc -> OrgSvc: validateOrganisation(orgId) +OrgSvc --> DonSvc: OK + +DonSvc -> Pay: createPaymentIntent(amount) +Pay --> DonSvc: paymentIntentId + clientSecret + +DonSvc --> UI: clientSecret +UI -> Pay: Complete payment (clientSecret) +Pay --> UI: Payment success + +UI -> DonSvc: confirmDonation(paymentIntentId) +DonSvc -> Pay: verifyPayment(paymentIntentId) +Pay --> DonSvc: verified OK + +DonSvc -> DonDB: store donation record +DonDB --> DonSvc: stored + +DonSvc --> UI: Donation confirmation +UI --> User: Show "Thank you" + receipt + +@enduml + diff --git a/helpmehelpapplication/pom.xml b/helpmehelpapplication/pom.xml index da3d4e2..1794a9e 100644 --- a/helpmehelpapplication/pom.xml +++ b/helpmehelpapplication/pom.xml @@ -25,6 +25,43 @@ javafx-controls 25.0.1 + + org.openjfx + javafx-fxml + 21 + + + org.seleniumhq.selenium + selenium-java + 4.41.0 + + + com.opencsv + opencsv + 5.12.0 + + + com.google.code.gson + gson + 2.13.2 + + + org.mockito + mockito-core + 5.21.0 + test + + + com.mysql + mysql-connector-j + 9.6.0 + + + com.h2database + h2 + 2.4.240 + test + @@ -49,7 +86,7 @@ javafx-maven-plugin 0.0.8 - ntnu.gruppe21.Main + ntnu.systemutvikling.team6.Main diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/DAO/DonationDAO.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/DAO/DonationDAO.java new file mode 100644 index 0000000..c99056f --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/DAO/DonationDAO.java @@ -0,0 +1,43 @@ +package ntnu.systemutvikling.team6.DAO; + +import java.sql.*; +import java.util.UUID; +import ntnu.systemutvikling.team6.database.DatabaseConnection; +import ntnu.systemutvikling.team6.models.Charity; + +/** + * This class is responsible for sending concurrent information about the donation to the Donation + * Database. Usally called from the DonationPageController, where the user confirms their donation. + */ +public class DonationDAO { + private static final DatabaseConnection connection = new DatabaseConnection(); + + /** + * Gets the total ammount of donations for a given charity, and sends it to the database throught + * MySQL. + * + * @param charity + * @param amount + */ + public static void addDonation(Charity charity, double amount) { + String sql_query = + """ + INSERT INTO Donations (UUID_Donations, amount, date, Charities_UUID_charities) + VALUES (?, ?, ?, ?) + """; + try (Connection conn = connection.getMySqlConnection(); + PreparedStatement ps = conn.prepareStatement(sql_query)) { + conn.setAutoCommit(false); + + ps.setString(1, UUID.randomUUID().toString()); + ps.setDouble(2, amount); + ps.setDate(3, new Date(System.currentTimeMillis())); + ps.setString(4, charity.getUUID().toString()); + + ps.executeUpdate(); + conn.commit(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/HmHApplication.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/HmHApplication.java new file mode 100644 index 0000000..293aa2d --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/HmHApplication.java @@ -0,0 +1,68 @@ +package ntnu.systemutvikling.team6; + +import static javafx.application.Application.launch; + +import java.net.http.HttpClient; +import java.util.Objects; +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.image.Image; +import javafx.stage.Stage; +import ntnu.systemutvikling.team6.database.DatabaseManager; +import ntnu.systemutvikling.team6.models.Charity; +import ntnu.systemutvikling.team6.models.CharityRegistry; +import ntnu.systemutvikling.team6.scraper.APICharityScraper; + +public class HmHApplication extends Application { + @Override + public void start(Stage stage) throws Exception { + FXMLLoader fxmlLoader = + new FXMLLoader(HmHApplication.class.getResource("/fxml/frontPage.fxml")); + Scene scene = new Scene(fxmlLoader.load()); + Image icon = + new Image( + Objects.requireNonNull(HmHApplication.class.getResource("/images/Logo.png")) + .openStream()); + stage.getIcons().add(icon); + stage.setTitle("Help Me Help"); + stage.setScene(scene); + + stage.setFullScreen(true); + + stage.show(); + } + + @Override + public 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.getName()); + } + db.addAPIDataToTable(charityRegistry.getAllCharities()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void main(String[] args) { + System.out.println("Hello world!"); + launch(args); + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/Main.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/Main.java new file mode 100644 index 0000000..d039f90 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/Main.java @@ -0,0 +1,8 @@ +package ntnu.systemutvikling.team6; + +public class Main { + // Make sure you're connected to the NTNU network for this to work + public static void main(String[] args) { + HmHApplication.main(args); + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/CharityPageController.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/CharityPageController.java new file mode 100644 index 0000000..8eb853f --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/CharityPageController.java @@ -0,0 +1,61 @@ +package ntnu.systemutvikling.team6.controller; + +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import ntnu.systemutvikling.team6.models.Charity; + +/** + * This controller represents the charity page, where the user can read about the charity and choose + * to donate to it. It also has a button to return to the front page. + */ +public class CharityPageController { + @FXML private Label CharityDescription; + + @FXML private Label CharityName; + + @FXML + public void initialize() {} + + private Charity charity; + + /** + * This method is used to set the charity that is being displayed on the page. It also updates the + * labels with the charity's name and description. It acts like an initializer for the charity + * page, since the charity is not known until the user clicks on a charity from the front page. + * Param charity is the charity that is being displayed on the page, AND is called on from the + * front page when the user clicks on a charity, to set the charity that is being displayed on the + * page. + * + * @param charity + */ + @FXML + public void setCharity(Charity charity) { + this.charity = charity; + + CharityDescription.setText(charity.getDescription()); + CharityName.setText(charity.getName()); + } + + /** + * This method is used to switch to the front page. + * + * @param event + */ + @FXML + public void switchToFrontPage(ActionEvent event) { + System.out.println("Click"); + LoaderScene.LoadScene("FrontPage", event, charity); + } + + /** + * This method is used to switch to the donation page. + * + * @param event + */ + @FXML + public void switchToDonationPage(ActionEvent event) { + System.out.println("Click"); + LoaderScene.LoadScene("donationPage", event, charity); + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/DonationPageController.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/DonationPageController.java new file mode 100644 index 0000000..839a3e8 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/DonationPageController.java @@ -0,0 +1,133 @@ +package ntnu.systemutvikling.team6.controller; + +import java.util.Optional; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import ntnu.systemutvikling.team6.DAO.DonationDAO; +import ntnu.systemutvikling.team6.models.Charity; + +/** + * This controller represents the donation page, where the user can enter a donation amount and + * confirm their donation to the charity. It also has a button to return to the front page. + */ +public class DonationPageController { + @FXML private Charity charity; + + @FXML private TextField donatioAmount; + + @FXML private Label CharityName; + + /** + * Initialize method for the donation page. Sets the charity name label to the name of the charity + * that is being donated to. The charity is set from the original page it was called from when the + * user clicks on the donate button, and is passed as a parameter to this method. + * + * @param charity + */ + @FXML + public void setCharity(Charity charity) { + this.charity = charity; + + CharityName.setText(charity.getName()); + } + + /** + * This method is used to switch back to the front page when the user clicks the back button. + * + * @param event + */ + public void switchToFrontPage(ActionEvent event) { + LoaderScene.LoadScene("FrontPage", event, null); + } + + /** + * This method is used to switch back to the Donation page when the user clicks the back button. + * + * @param event + */ + public void switchToCharityPage(ActionEvent event) { + LoaderScene.LoadScene("charityPage", event, charity); + } + + /** + * This method is used to process the donation when the user clicks the donate button. Checks if + * the input is valid and displays appropriate error messages if it is not. If the input is valid, + * it shows a confirmation dialog to the user. Shows a confirmation dialog. If the user confirms, + * the donation is processed and the user is taken back to the front page. + * + * @param event + */ + public void Donate(ActionEvent event) { + String input = donatioAmount.getText().trim(); + + if (input.isEmpty()) { + showAlert(Alert.AlertType.ERROR, "Invalid input", "Please enter a donation amount."); + return; + } + double amount; + + try { + amount = Double.parseDouble(input); + } catch (NumberFormatException e) { + showAlert(Alert.AlertType.ERROR, "Invalid input", "Please enter a valid number."); + return; + } + + if (amount <= 0) { + showAlert(Alert.AlertType.ERROR, "Invalid amount", "Donation must be greater than 0."); + return; + } + + if (amount > 100_000) { + showAlert(Alert.AlertType.WARNING, "Amount too high", "Maximum donation is 100,000."); + return; + } + + Alert confirm = new Alert(Alert.AlertType.CONFIRMATION); + confirm.setTitle("Confirm Donation"); + confirm.setHeaderText("You're about to donate " + amount + " to " + charity.getName()); + confirm.setContentText("Are you sure?"); + Optional result = confirm.showAndWait(); + + if (result.isPresent() && result.get() == ButtonType.OK) { + // Process donation + processDonation(charity, amount); + showAlert( + Alert.AlertType.INFORMATION, + "Thank you!", + "You have donated " + amount + " to " + charity.getName()); + donatioAmount.clear(); + LoaderScene.LoadScene("FrontPage", event, null); + } + } + + /** + * Invoke DAO object to add the donation to the database. This method is called from the Donate + * method after the user confirms their donation. + * + * @param charity + * @param amount + */ + public void processDonation(Charity charity, double amount) { + DonationDAO.addDonation(charity, amount); + } + + /** + * Show an JavaFx alert dialog with the specified type, title, and message. + * + * @param type + * @param title + * @param message + */ + private void showAlert(Alert.AlertType type, String title, String message) { + Alert alert = new Alert(type); + alert.setTitle(title); + alert.setHeaderText(null); + alert.setContentText(message); + alert.showAndWait(); + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/FrontpageController.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/FrontpageController.java new file mode 100644 index 0000000..f8ffc2a --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/FrontpageController.java @@ -0,0 +1,109 @@ +package ntnu.systemutvikling.team6.controller; + +import java.util.Random; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.control.Label; +import javafx.scene.layout.FlowPane; +import ntnu.systemutvikling.team6.database.DatabaseManager; +import ntnu.systemutvikling.team6.models.Charity; +import ntnu.systemutvikling.team6.models.CharityRegistry; +import ntnu.systemutvikling.team6.models.Donation; +import ntnu.systemutvikling.team6.models.DonationRegistry; + +/** + * Landing page's controller. This is the first page the user sees when they open the application. + * It displays a random featured charity, some statistics about the charities and donations, and a + * list of all charities in the database. The user can click on a charity to see more details about + * it, or click on the featured charity to see more details about it. It also has buttons to switch + * to the charity page and the donation page for the featured charity + */ +public class FrontpageController { + @FXML private Charity featuredCharity; + + @FXML private FlowPane cardsContainer; + + @FXML private Label Carosel_Organisasjon; + + @FXML private Label Carosel_Beskrivelse; + + @FXML private Label Total_Orgnisasjon; + + @FXML private Label Total_Donations; + + @FXML private Label PreApproved_Percentage; + + /** + * Initialize method for the front page. This method is called when the front page is loaded. It + * retrieves the list of charities and donations from the database. The list of charities is + * displayed as a list of cards, where each card represents a charity from the + * Innsamlingskontrollen A random charity is selected to be featured on the page, and its name and + * description are displayed in the carousel section. The total number of charities, total amount + * of donations, and percentage of pre-approved charities are also displayed on the page. + */ + @FXML + public void initialize() { + try { + DatabaseManager db = new DatabaseManager(); + CharityRegistry Charities = db.getCharitiesFromDB(); + DonationRegistry Donations = db.getDonationFromDB(); + for (Charity ch : Charities.getAllCharities()) { + + FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/organizationCard.fxml")); + + Parent card = loader.load(); + + OrganizationCardController cardController = loader.getController(); + + // System.out.println("Added Name: " + ch.getName() + " Added Description: " + + // ch.getDescription()); + cardController.setOrganization(ch); + + cardsContainer.getChildren().add(card); + } + int Charities_size = Charities.getAllCharities().size(); + Random random = new Random(); + int randomIndex = random.nextInt(Charities_size); + Charity randomCharity = Charities.getAllCharities().get(randomIndex); + + this.featuredCharity = randomCharity; + Carosel_Organisasjon.setText(randomCharity.getName()); + Carosel_Beskrivelse.setText(randomCharity.getDescription()); + + Total_Orgnisasjon.setText(Integer.toString(Charities_size)); + Total_Donations.setText( + Double.toString( + Donations.getAllDonations().stream().mapToDouble(Donation::getAmount).sum())); + PreApproved_Percentage.setText( + String.format( + "%.2f", + Charities.getAllCharities().stream().filter(Charity::getPreApproved).count() + * 100.0 + / Charities_size) + + "%"); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * This method is used to switch to the charity page for the selected charity + * + * @param event + */ + public void switchToCharityPage(ActionEvent event) { + LoaderScene.LoadScene("CharityPage", event, featuredCharity); + } + + /** + * This method is used to switch to the donation page for the selected charity. + * + * @param event + */ + public void switchToDonationPage(ActionEvent event) { + LoaderScene.LoadScene("DonationPage", event, featuredCharity); + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/LoaderScene.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/LoaderScene.java new file mode 100644 index 0000000..83ace1e --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/LoaderScene.java @@ -0,0 +1,63 @@ +package ntnu.systemutvikling.team6.controller; + +import java.io.IOException; +import java.util.Objects; +import javafx.event.ActionEvent; +import javafx.fxml.FXMLLoader; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.image.Image; +import javafx.stage.Stage; +import ntnu.systemutvikling.team6.HmHApplication; +import ntnu.systemutvikling.team6.models.Charity; + +/** + * This class is a utility class that is used to load different scenes in the application. For now, + * It is used to switch between the front page, charity page, and donation page. It takes care of + * loading the FXML file, setting the controller, and switching the scene. + */ +public class LoaderScene { + /** + * When going to a new scene, this method is called to load the new scene. It takes the name of + * the scene to load, the event that triggered the scene change, and the charity that is being + * passed to the new scene (if applicable). It loads the FXML file for the new scene, sets the + * controller, and switches the scene. + * + * @param sceneName + * @param event + * @param charity + */ + public static void LoadScene(String sceneName, ActionEvent event, Charity charity) { + try { + System.out.println(HmHApplication.class.getResource("/fxml/" + sceneName + ".fxml")); + FXMLLoader fxmlLoader = + new FXMLLoader(HmHApplication.class.getResource("/fxml/" + sceneName + ".fxml")); + Parent root = fxmlLoader.load(); + + System.out.println("Controller: " + fxmlLoader.getController()); + Object controller = fxmlLoader.getController(); + + // Needs to be expanded when more pages get implemented. + if (controller instanceof CharityPageController charityController) { + charityController.setCharity(charity); + } + if (controller instanceof DonationPageController donationController) { + donationController.setCharity(charity); + } + + Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow(); + Image icon = + new Image( + Objects.requireNonNull(HmHApplication.class.getResource("/images/Logo.png")) + .openStream()); + stage.getIcons().add(icon); + Scene scene = new Scene(root); + stage.setScene(scene); + stage.setFullScreen(true); + stage.show(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/OrganizationCardController.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/OrganizationCardController.java new file mode 100644 index 0000000..b51e530 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/controller/OrganizationCardController.java @@ -0,0 +1,36 @@ +package ntnu.systemutvikling.team6.controller; + +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import ntnu.systemutvikling.team6.models.Charity; + +/** + * This controller represents the organization card that is displayed on the front page and is + * looped upon in FronpageController. It is used to display the name and description of a charity, + * and to switch to the charity page or donation page when the user clicks on the card. + */ +public class OrganizationCardController { + + @FXML private Label organizationName; + + @FXML private Label organizationDescription; + + private Charity charity; + + public void setOrganization(Charity charity) { + this.charity = charity; + + organizationName.setText(charity.getName()); + organizationDescription.setText(charity.getDescription()); + } + + /* EVENTS */ + public void switchToCharityPage(ActionEvent event) { + LoaderScene.LoadScene("CharityPage", event, charity); + } + + public void switchToDonationPage(ActionEvent event) { + LoaderScene.LoadScene("DonationPage", event, charity); + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/database/DatabaseConnection.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/database/DatabaseConnection.java new file mode 100644 index 0000000..28c325d --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/database/DatabaseConnection.java @@ -0,0 +1,65 @@ +package ntnu.systemutvikling.team6.database; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +/** Represents a reusable database connection through enviroment variables. */ +public class DatabaseConnection { + private final String databaseURL; + private final String username; + private final String password; + + /** + * Constructs a new {@code DatabaseConnection} using database credentials retrieved from system + * environment variables. + * + * @throws IllegalStateException if either databaseURL, username, or password is {@code null} or + * blank + */ + public DatabaseConnection() { + this.databaseURL = + "jdbc:mysql://namox.idi.ntnu.no:3306/apbaluna?useSSL=false&serverTimezone=UTC"; + this.username = "apbaluna"; + this.password = "GYntUFPG"; + } + + /** + * Constructs a new {@code DatabaseConnection} using database credentials + * + *

Used primarily for JUnit tests. Production should use the constructor using environment + * variables. + * + * @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 DatabaseConnection(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 and returns a new MySQL database connection. + * + * @return a {@link Connection} to the database + * @throws SQLException if the connection cannot be established + */ + public Connection getMySqlConnection() throws SQLException { + return DriverManager.getConnection(databaseURL, username, password); + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/database/DatabaseManager.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/database/DatabaseManager.java new file mode 100644 index 0000000..a4007a0 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/database/DatabaseManager.java @@ -0,0 +1,299 @@ +package ntnu.systemutvikling.team6.database; + +import java.sql.*; +import java.util.List; +import java.util.UUID; +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; + +/** + * Manages the Database with MySQL tables and JDBC. + * + *

This class is responsible for creating the tables needed for the application, if not done + * already and maintaining the {@code charities} table based on data retrieved from the IK API. It + * is also responsible for retrieving the data from the database and sending it to the application + * through the CharityRegistry and DonationRegistry. It is used by the FrontpageController to + * retrieve the data needed to display the charities + */ +public class DatabaseManager { + private final DatabaseConnection connection; + + /** + * Contractor for DatabaseManager. It uses a DatabaseConnection object that contains a connection + * credentials. + */ + public DatabaseManager() { + this.connection = new DatabaseConnection(); + } + + /** + * Connection test for the Database. Does a simple SELECT SQL query and returns either true og and + * Exception if failed + * + * @return true if Sucsedd or SQLExepction if failed + */ + public boolean testConnection() { + try (Connection conn = connection.getMySqlConnection(); + Statement stmt = conn.createStatement()) { + + ResultSet rs = stmt.executeQuery("SELECT 1"); + + if (rs.next()) { + System.out.println("Database connection verified."); + return true; + } + + } catch (SQLException e) { + System.out.println("Database connection failed."); + e.printStackTrace(); + } + + return false; + } + + /** + * Creates the {@code Charities} and {@code Donations} tables if they do not already exist. + * + *

The table structure for Charities is based on fields from {@link APICharityData}. + * + * @throws RuntimeException if a {@link SQLException} occurs while creating the table + */ + public void createTables() { + String sql_query1 = + """ + -- ----------------------------------------------------- + -- Table `HelpMeHelp`.`Charities` + -- ----------------------------------------------------- + CREATE TABLE IF NOT EXISTS Charities ( + UUID_charities CHAR(36) PRIMARY KEY, + org_number VARCHAR(255) NOT NULL, + charity_name VARCHAR(255) NOT NULL, + charity_link VARCHAR(255) NOT NULL, + pre_approved TINYINT NOT NULL, + status VARCHAR(255) NOT NULL, + UNIQUE KEY unique_org_number (org_number) + ) ENGINE=InnoDB; + + + """; + String sql_query2 = + """ + -- ----------------------------------------------------- + -- Table `HelpMeHelp`.`Donations` + -- ----------------------------------------------------- + CREATE TABLE IF NOT EXISTS Donations ( + `UUID_Donations` CHAR(36) NOT NULL, + `amount` DECIMAL NOT NULL, + `date` DATE NOT NULL, + `Charities_UUID_charities` CHAR(36) NOT NULL, + PRIMARY KEY (`UUID_Donations`), + INDEX `fk_Donations_Charities_idx` (`Charities_UUID_charities` ASC) VISIBLE, + CONSTRAINT `fk_Donations_Charities` + FOREIGN KEY (`Charities_UUID_charities`) + REFERENCES Charities (`UUID_charities`) + ON DELETE CASCADE + ON UPDATE CASCADE) + ENGINE = InnoDB; + """; + + try (Connection conn = connection.getMySqlConnection(); + Statement s = conn.createStatement()) { + + s.execute(sql_query1); + s.execute(sql_query2); + } catch (SQLException e) { + e.printStackTrace(); + throw new RuntimeException("Error creating table."); + } + } + + /** + * 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 + * 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. + * + * @param charities + */ + public void addAPIDataToTable(List charities) { + Connection conn = null; + try { + conn = connection.getMySqlConnection(); + conn.setAutoCommit(false); + String sql_query = + """ + INSERT INTO Charities (UUID_charities, org_number, charity_name, charity_link, pre_approved, status) + VALUES (?, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE + charity_name = VALUES(charity_name), + charity_link = VALUES(charity_link), + pre_approved = VALUES(pre_approved), + status = VALUES(status) + """; + + try (PreparedStatement ps = conn.prepareStatement(sql_query)) { + for (Charity charity : charities) { + if (charity.getUUID() == null) { + ps.setString(1, UUID.randomUUID().toString()); + } else { + ps.setString(1, charity.getUUID().toString()); + } + + ps.setString(2, charity.getOrg_number().replaceAll("\\s", "")); + ps.setString(3, charity.getName()); + ps.setString(4, charity.getDescription()); + ps.setBoolean(5, charity.getPreApproved()); // Description is the link + ps.setString(6, charity.getStatus()); + + ps.addBatch(); + } + ps.executeBatch(); + } + + // -- Intergerty Check: + String createTemp = + """ + CREATE TEMPORARY TABLE temp_api_charities ( + org_number VARCHAR(20) PRIMARY KEY + ) + """; + + try (PreparedStatement ps = conn.prepareStatement(createTemp)) { + ps.execute(); + } + + String insertTemp = "INSERT IGNORE INTO temp_api_charities (org_number) VALUES (?)"; + + try (PreparedStatement ps = conn.prepareStatement(insertTemp)) { + + for (Charity charity : charities) { + ps.setString(1, charity.getOrg_number().replaceAll("\\s", "")); + ps.addBatch(); + } + + ps.executeBatch(); + } + + String deleteSql = + """ + DELETE FROM Charities c + WHERE NOT EXISTS ( + SELECT 1 + FROM temp_api_charities t + WHERE t.org_number = c.org_number + ) + """; + + try (PreparedStatement ps = conn.prepareStatement(deleteSql)) { + ps.executeUpdate(); + } + + 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(); + } + } + } + } + + 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"; + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql_query); + + registry = new CharityRegistry(); + while (rs.next()) { + Charity charity = + new Charity( + rs.getString("UUID_charities"), + rs.getString("org_number"), + rs.getString("charity_link"), + rs.getString("charity_name"), + rs.getBoolean("pre_approved"), + rs.getString("status")); + registry.addCharity(charity); + } + } catch (SQLException e) { + e.printStackTrace(); + throw new RuntimeException("ERROR: Something went wrong during updating charities table."); + } + return registry; + } + + public DonationRegistry getDonationFromDB() { + DonationRegistry registry = null; + Connection conn = null; + try { + conn = connection.getMySqlConnection(); + String sql_query = + """ + SELECT + d.UUID_Donations, + d.amount, + d.date, + c.UUID_charities, + c.org_number, + c.charity_name, + c.charity_link, + c.pre_approved, + c.status + FROM Donations d + JOIN Charities c + ON d.Charities_UUID_charities = c.UUID_charities + """; + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql_query); + + registry = new DonationRegistry(); + while (rs.next()) { + Charity charity = + new Charity( + rs.getString("UUID_charities"), + rs.getString("org_number"), + rs.getString("charity_name"), + rs.getString("charity_link"), + rs.getBoolean("pre_approved"), + rs.getString("status")); + + Donation donation = + new Donation( + rs.getString("UUID_Donations"), + rs.getDouble("amount"), + rs.getDate("date").toLocalDate(), + charity); + registry.addDonation(donation); + } + } catch (SQLException e) { + e.printStackTrace(); + throw new RuntimeException("ERROR: Something went wrong during updating charities table."); + } + return registry; + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/Charity.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/Charity.java new file mode 100644 index 0000000..d97d996 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/Charity.java @@ -0,0 +1,126 @@ +/** + * This class represents a charity organization. It contains information about the charity such as + * its name, description, total donations, verification status, and category. + * + * @author Adrian Balunan + */ +package ntnu.systemutvikling.team6.models; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class Charity { + /* UUID for uniquely identifying each charity */ + private UUID UUID; + + /* Org_number from API, apparently not unique */ + private String org_number; + + /* Name of the charity */ + private String name; + + /* Description of the charity's mission and activities */ + private String description; + + /* Is the charity verified? */ + private String status; + + private boolean is_pre_approved; + + /* Category for the charity */ + private String category; + + /* List that contains the charity's Feedbacks */ + private List feedbacks; + + /** + * Contructor for creating a new charity. Taylored to match data given from Api. Other attributes + * will just be initialized as empty + * + * @param org_number matches from innsamlingkontrollen + * @param name matches from innsamlingkontrollen + * @param is_pre_approved name matches from innsamlingkontrollen + * @param status name matches from innsamlingkontrollen + */ + public Charity( + String org_number, String link, String name, boolean is_pre_approved, String status) { + this.UUID = java.util.UUID.randomUUID(); + this.org_number = org_number.replaceAll("\\s", ""); + this.name = name; + this.description = "Les mer her: " + link; + this.is_pre_approved = is_pre_approved; + this.status = status; + this.feedbacks = new ArrayList<>(); + this.category = ""; + } + + /** + * Contructor for creating a new charity. Taylored to match data given from DATABASE. Other + * attributes will just be initialized as empty + * + * @param org_number matches from innsamlingkontrollen + * @param name matches from innsamlingkontrollen + * @param is_pre_approved name matches from innsamlingkontrollen + * @param status name matches from innsamlingkontrollen + */ + public Charity( + String uuid, + String org_number, + String link, + String name, + boolean is_pre_approved, + String status) { + this.UUID = UUID.fromString(uuid); + this.org_number = org_number.replaceAll("\\s", ""); + this.name = name; + this.description = link; + this.is_pre_approved = is_pre_approved; + this.status = status; + this.feedbacks = new ArrayList<>(); + this.category = ""; + } + + /** Getters for the charity's attributes. */ + public UUID getUUID() { + return UUID; + } + + public String getOrg_number() { + return org_number; + } + + public String getStatus() { + return status; + } + + public boolean getPreApproved() { + return is_pre_approved; + } + + public List getFeedbacks() { + return feedbacks; + } + + public String getCategory() { + return category; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + /** Setter for verification status. This one sets the charity as verified. */ + public void setVerified() { + this.status = "approved"; + } + + /** Setter for verification status. This one sets the charity as unverified. */ + public void setUnverified() { + this.status = "Veto"; + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/CharityRegistry.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/CharityRegistry.java new file mode 100644 index 0000000..962b833 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/CharityRegistry.java @@ -0,0 +1,52 @@ +package ntnu.systemutvikling.team6.models; + +import java.util.*; + +public class CharityRegistry { + private final List charities; + + public CharityRegistry() { + this.charities = new ArrayList<>(); + } + + public List getAllCharities() { + return Collections.unmodifiableList(charities); + } + + public Optional findCharityByOrgnumber(String org_number) { + if (org_number == null) { + throw new IllegalArgumentException("CharityId can not be null."); + } + return charities.stream() + .filter(charity -> org_number.equals(charity.getOrg_number())) + .findFirst(); + } + + public Optional findCharityByUUID(UUID uuid) { + if (uuid == null) { + throw new IllegalArgumentException("Uuid can not be null."); + } + return charities.stream().filter(charity -> uuid.equals(charity.getUUID())).findFirst(); + } + + public void addCharity(Charity charity) { + if (charity == null) { + throw new IllegalArgumentException("Charity can not be null."); + } + charities.add(charity); + } + + public boolean removeCharity(String org_number) { + if (org_number == null) { + throw new IllegalArgumentException("CharityId can not be null."); + } + return charities.removeIf(charity -> org_number.equals(charity.getOrg_number())); + } + + public boolean removeCharityUUID(UUID uuid) { + if (uuid == null) { + throw new IllegalArgumentException("CharityId can not be null."); + } + return charities.removeIf(charity -> uuid.equals(charity.getUUID())); + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Donation.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/Donation.java similarity index 64% rename from helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Donation.java rename to helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/Donation.java index 70f6268..64d8733 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Donation.java +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/Donation.java @@ -1,8 +1,8 @@ -package ntnu.sytemutvikling.team6.models; +package ntnu.systemutvikling.team6.models; -import java.time.LocalDateTime; +import java.time.LocalDate; import java.util.UUID; -import ntnu.sytemutvikling.team6.models.user.User; +import ntnu.systemutvikling.team6.models.user.User; public class Donation { /* UUID for uniquely identifying each donation */ @@ -12,7 +12,7 @@ public class Donation { private double amount; /* Date and time of the donation */ - private LocalDateTime date; + private LocalDate date; /* The charity that received the donation */ private Charity charity; @@ -32,7 +32,7 @@ public class Donation { * @param charity * @param donor */ - public Donation(double amount, LocalDateTime date, Charity charity, User donor) { + public Donation(double amount, LocalDate date, Charity charity, User donor) { this.charityId = UUID.randomUUID(); this.amount = amount; this.date = date; @@ -41,6 +41,24 @@ public Donation(double amount, LocalDateTime date, Charity charity, User donor) this.isAnonymous = donor.getSettings().isAnonymous(); } + /** + * Constructor for creating a new donation. Taylored for getting info FROM DATABASE. NEEDS TO BE + * CHANGED in phase 3. + * + * @param amount + * @param date + * @param charity + * @param uuid + */ + public Donation(String uuid, double amount, LocalDate date, Charity charity) { + this.charityId = UUID.fromString(uuid); + this.amount = amount; + this.date = date; + this.charity = charity; + this.donor = null; + this.isAnonymous = true; + } + /* Getters for the donation's attributes */ public boolean isAnonymous() { return isAnonymous; @@ -54,7 +72,7 @@ public double getAmount() { return amount; } - public LocalDateTime getDate() { + public LocalDate getDate() { return date; } diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/DonationRegistry.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/DonationRegistry.java similarity index 95% rename from helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/DonationRegistry.java rename to helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/DonationRegistry.java index ff6d4e2..b06009d 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/DonationRegistry.java +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/DonationRegistry.java @@ -1,4 +1,4 @@ -package ntnu.sytemutvikling.team6.models; +package ntnu.systemutvikling.team6.models; import java.util.*; diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Feedback.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/Feedback.java similarity index 92% rename from helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Feedback.java rename to helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/Feedback.java index f753e8a..490c47e 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Feedback.java +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/Feedback.java @@ -1,8 +1,8 @@ -package ntnu.sytemutvikling.team6.models; +package ntnu.systemutvikling.team6.models; import java.time.LocalDateTime; import java.util.UUID; -import ntnu.sytemutvikling.team6.models.user.User; +import ntnu.systemutvikling.team6.models.user.User; public class Feedback { /* Feedback id */ diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/UserRegistry.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/UserRegistry.java new file mode 100644 index 0000000..514cbec --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/UserRegistry.java @@ -0,0 +1,3 @@ +package ntnu.systemutvikling.team6.models; + +public class UserRegistry {} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Inbox.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/Inbox.java similarity index 97% rename from helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Inbox.java rename to helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/Inbox.java index b560092..e0d95a9 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Inbox.java +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/Inbox.java @@ -1,4 +1,4 @@ -package ntnu.sytemutvikling.team6.models.user; +package ntnu.systemutvikling.team6.models.user; import java.util.*; diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Language.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/Language.java similarity index 70% rename from helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Language.java rename to helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/Language.java index ddc5d82..c568ede 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Language.java +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/Language.java @@ -1,4 +1,4 @@ -package ntnu.sytemutvikling.team6.models.user; +package ntnu.systemutvikling.team6.models.user; /** * Supported application languages. diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Message.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/Message.java similarity index 97% rename from helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Message.java rename to helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/Message.java index ef9707b..b70ece1 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Message.java +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/Message.java @@ -1,4 +1,4 @@ -package ntnu.sytemutvikling.team6.models.user; +package ntnu.systemutvikling.team6.models.user; import java.time.LocalDateTime; import java.util.UUID; diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Role.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/Role.java similarity index 70% rename from helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Role.java rename to helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/Role.java index 74e134f..94e0b22 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Role.java +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/Role.java @@ -1,4 +1,4 @@ -package ntnu.sytemutvikling.team6.models.user; +package ntnu.systemutvikling.team6.models.user; /** * Available users diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Settings.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/Settings.java similarity index 97% rename from helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Settings.java rename to helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/Settings.java index dd76557..d814283 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Settings.java +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/Settings.java @@ -1,4 +1,4 @@ -package ntnu.sytemutvikling.team6.models.user; +package ntnu.systemutvikling.team6.models.user; // Mangler Enhetstesting diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/User.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/User.java similarity index 97% rename from helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/User.java rename to helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/User.java index 64594a0..ef59000 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/User.java +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/models/user/User.java @@ -1,7 +1,7 @@ -package ntnu.sytemutvikling.team6.models.user; +package ntnu.systemutvikling.team6.models.user; import java.util.UUID; -import ntnu.sytemutvikling.team6.security.PasswordHasher; +import ntnu.systemutvikling.team6.security.PasswordHasher; /** * Represents a user in the system. diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/scraper/APICharityData.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/scraper/APICharityData.java new file mode 100644 index 0000000..10a489d --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/scraper/APICharityData.java @@ -0,0 +1,89 @@ +package ntnu.systemutvikling.team6.scraper; + +import ntnu.systemutvikling.team6.database.DatabaseManager; + +/** + * Represents data parsed from the IK API JSON response. Instances are immutable; to update any + * value, a new object must be created. + * + *

Receives data directly from {@link APICharityScraper}. + * + *

{@code org_number} should be a unique number, as it is used as a primary key in {@link + * DatabaseManager}. + */ +public class APICharityData { + private final String org_number; + private final String name; + private final String status; + private final String url; + private final boolean is_pre_approved; + + /** + * Constructs a new APICharityData object. This class represents the data provided from the IK + * Api, and is used expand and provide data to our design of a charity. + * + * @param org_number a unique number that identifies the organization + * @param name the name of the organization + * @param status {@code approved} for approved organizations, {@code obs} for non-approved + * organizations + * @param url the URL for more info about the organization on the IK domain + * @param is_pre_approved whether the organization was pre-approved + */ + public APICharityData( + String org_number, String name, String status, String url, boolean is_pre_approved) { + if (org_number == null || org_number.isBlank()) { + throw new IllegalArgumentException("ERROR: Org number cannot be null or blank"); + } + this.org_number = org_number.replaceAll("\\s", ""); + this.name = name; + this.status = status; + this.url = url; + this.is_pre_approved = is_pre_approved; + } + + /** + * Returns the organization number. Must not be {@code null} or blank. + * + * @return the organization number + */ + public String getOrg_number() { + return this.org_number; + } + + /** + * Returns the name of the organization. Whitespace removed. + * + * @return the name of the organization + */ + public String getName() { + return name; + } + + /** + * Returns whether the organization is approved or not + * + * @return the approved status of the organization + */ + public String getStatus() { + return status; + } + + /** + * Returns the URL of the organizations information page on IK + * + * @return the URL for more info about the organization + */ + public String getUrl() { + return url; + } + + /** + * Returns whether the organization was pre-approved. + * + * @return {@code true} if organization was pre-approved
+ * {@code false} otherwise + */ + public boolean getIs_pre_approved() { + return this.is_pre_approved; + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/scraper/APICharityScraper.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/scraper/APICharityScraper.java new file mode 100644 index 0000000..89422a1 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/scraper/APICharityScraper.java @@ -0,0 +1,95 @@ +package ntnu.systemutvikling.team6.scraper; + +import com.google.gson.Gson; +import java.io.IOException; +import java.net.*; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import ntnu.systemutvikling.team6.models.Charity; +import ntnu.systemutvikling.team6.models.CharityRegistry; + +/** + * Fetches JSON information from the IK API and parses the JSON into a list of {@link + * APICharityData} objects. AND can update the database. + */ +public class APICharityScraper { + private final HttpClient client; + private final HttpRequest request; + private static final String API_url = "https://app.innsamlingskontrollen.no/api/public/v1/all"; + + /** + * Constructs a new APICharityScraper object. + * + * @param client the client responsible for making the http connection. + * @throws URISyntaxException if the API URL is malformed or violates URI syntax rules + */ + public APICharityScraper(HttpClient client) throws URISyntaxException { + this.client = client; + this.request = HttpRequest.newBuilder().uri(new URI(API_url)).GET().build(); + } + + /** + * Checks if the http request returns an 'OK' response. + * + * @return {@code true} if connection was successful + * @throws IOException if an I/O error occurs while sending or receiving the HTTP reques + * @throws InterruptedException if the operation is interrupted while waiting for the response + * @throws RuntimeException if the connection is unsuccessful + */ + public boolean checkConnection() throws IOException, InterruptedException { + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() == 200) { + return true; + } + throw new RuntimeException( + "Connection failed: HTTP error code: " + + response.statusCode() + + "\nResponse text: " + + response.body()); + } + + /** + * Fetches the JSON data from the IK API and stores it in a String. + * + * @return a String of the JSON values in IK API + * @throws IOException if an I/O error occurs while sending or receiving the HTTP request + * @throws InterruptedException if the operation is interrupted while waiting for the response + */ + public String getJSONData() throws IOException, InterruptedException { + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + + return response.body(); + } + + /** + * Parses the JSON data using gson and translates the {@code APICharityData} into our predefined + * charity classes and puts it in a CharityRegistry object. + * + * @param JSONData the {@code String} of JSON data to be parsed + * @return a CharityRegistry class object + * @throws com.google.gson.JsonSyntaxException if the provided JSON is not valid + */ + public CharityRegistry parseJSON(String JSONData) { + Gson gson = new Gson(); + APICharityData[] charityData = gson.fromJson(JSONData, APICharityData[].class); + + if (charityData == null) { + return new CharityRegistry(); + } + + CharityRegistry charityRegistry = new CharityRegistry(); + for (APICharityData apiCharityData : charityData) { + Charity charity = + new Charity( + apiCharityData.getOrg_number(), + apiCharityData.getUrl(), + apiCharityData.getName(), + apiCharityData.getIs_pre_approved(), + apiCharityData.getStatus()); + charityRegistry.addCharity(charity); + } + return charityRegistry; + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/security/PasswordHasher.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/security/PasswordHasher.java similarity index 98% rename from helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/security/PasswordHasher.java rename to helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/security/PasswordHasher.java index 8c2f7d9..baf5e4b 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/security/PasswordHasher.java +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/security/PasswordHasher.java @@ -1,4 +1,4 @@ -package ntnu.sytemutvikling.team6.security; +package ntnu.systemutvikling.team6.security; import java.security.MessageDigest; import java.security.SecureRandom; diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/AuthenticationService.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/service/AuthenticationService.java similarity index 100% rename from helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/AuthenticationService.java rename to helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/service/AuthenticationService.java diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/service/CharityService.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/service/CharityService.java new file mode 100644 index 0000000..b471c19 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/service/CharityService.java @@ -0,0 +1,3 @@ +package ntnu.systemutvikling.team6.service; + +public class CharityService {} diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/service/DonationService.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/service/DonationService.java new file mode 100644 index 0000000..fca9633 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/service/DonationService.java @@ -0,0 +1,3 @@ +package ntnu.systemutvikling.team6.service; + +public class DonationService {} diff --git a/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/service/FeedbackService.java b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/service/FeedbackService.java new file mode 100644 index 0000000..ae1f984 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/systemutvikling/team6/service/FeedbackService.java @@ -0,0 +1,3 @@ +package ntnu.systemutvikling.team6.service; + +public class FeedbackService {} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/Main.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/Main.java deleted file mode 100644 index b30c2e3..0000000 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/Main.java +++ /dev/null @@ -1,7 +0,0 @@ -package ntnu.sytemutvikling.team6; - -public class Main { - public static void main(String[] args) { - System.out.println("Hello world!"); - } -} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Charity.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Charity.java deleted file mode 100644 index 2c2cb3f..0000000 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Charity.java +++ /dev/null @@ -1,95 +0,0 @@ -/** - * This class represents a charity organization. It contains information about the charity such as - * its name, description, total donations, verification status, and category. - * - * @author Adrian Balunan - */ -package ntnu.sytemutvikling.team6.models; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -public class Charity { - /* UUID for uniquely identifying each charity */ - private UUID id; - - /* Name of the charity */ - private String name; - - /* Description of the charity's mission and activities */ - private String description; - - /* Total Donations received */ - private int totalDonations; - - /* Is the charity verified? */ - private boolean isVerified; - - /* Category for the charity */ - private String category; - - /* List that contains the charity's Feedbacks */ - private List feedbacks; - - /** - * Konstructor for creating a new charity. The ID is generated automatically using UUID. Total - * donations are initialized to 0. The charity is unverified by default. - * - * @param name - * @param description - * @param category - */ - public Charity(String name, String description, String category) { - this.id = UUID.randomUUID(); - this.name = name; - this.description = description; - this.totalDonations = 0; - this.isVerified = false; - this.feedbacks = new ArrayList<>(); - this.category = category; - } - - /** Getters for the charity's attributes. */ - public UUID getId() { - return id; - } - - public String getCategory() { - return category; - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - - public int getTotalDonations() { - return totalDonations; - } - - public boolean isVerified() { - return isVerified; - } - - /** Setter for verification status. This one sets the charity as verified. */ - public void setVerified() { - this.isVerified = true; - } - - /** Setter for verification status. This one sets the charity as unverified. */ - public void setUnverified() { - this.isVerified = false; - } - - /** - * Setter for total donations. This method is used to update the total donations when a new - * donation is made. - */ - public void setTotalDonations(int amount) { - this.totalDonations += amount; - } -} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/CharityRegistry.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/CharityRegistry.java deleted file mode 100644 index 2935c74..0000000 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/CharityRegistry.java +++ /dev/null @@ -1,36 +0,0 @@ -package ntnu.sytemutvikling.team6.models; - -import java.util.*; - -public class CharityRegistry { - private final List charities; - - public CharityRegistry() { - this.charities = new ArrayList<>(); - } - - public List getAllCharities() { - return Collections.unmodifiableList(charities); - } - - public Optional findCharityById(UUID charityId) { - if (charityId == null) { - throw new IllegalArgumentException("CharityId can not be null."); - } - return charities.stream().filter(charity -> charityId.equals(charity.getId())).findFirst(); - } - - public void addCharity(Charity charity) { - if (charity == null) { - throw new IllegalArgumentException("Charity can not be null."); - } - charities.add(charity); - } - - public boolean removeCharity(UUID charityId) { - if (charityId == null) { - throw new IllegalArgumentException("CharityId can not be null."); - } - return charities.removeIf(charity -> charityId.equals(charity.getId())); - } -} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/UserRegistry.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/UserRegistry.java deleted file mode 100644 index c858e31..0000000 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/UserRegistry.java +++ /dev/null @@ -1,3 +0,0 @@ -package ntnu.sytemutvikling.team6.models; - -public class UserRegistry {} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/CharityService.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/CharityService.java deleted file mode 100644 index 3b66851..0000000 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/CharityService.java +++ /dev/null @@ -1,3 +0,0 @@ -package ntnu.sytemutvikling.team6.service; - -public class CharityService {} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/DonationService.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/DonationService.java deleted file mode 100644 index 17692d5..0000000 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/DonationService.java +++ /dev/null @@ -1,3 +0,0 @@ -package ntnu.sytemutvikling.team6.service; - -public class DonationService {} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/FeedbackService.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/FeedbackService.java deleted file mode 100644 index 27eee23..0000000 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/FeedbackService.java +++ /dev/null @@ -1,3 +0,0 @@ -package ntnu.sytemutvikling.team6.service; - -public class FeedbackService {} diff --git a/helpmehelpapplication/src/main/resources/fxml/aboutPage.fxml b/helpmehelpapplication/src/main/resources/fxml/aboutPage.fxml new file mode 100644 index 0000000..10e12e8 --- /dev/null +++ b/helpmehelpapplication/src/main/resources/fxml/aboutPage.fxml @@ -0,0 +1,579 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/helpmehelpapplication/src/main/resources/fxml/charityPage.fxml b/helpmehelpapplication/src/main/resources/fxml/charityPage.fxml new file mode 100644 index 0000000..041b51b --- /dev/null +++ b/helpmehelpapplication/src/main/resources/fxml/charityPage.fxml @@ -0,0 +1,518 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/helpmehelpapplication/src/main/resources/fxml/donationPage.fxml b/helpmehelpapplication/src/main/resources/fxml/donationPage.fxml new file mode 100644 index 0000000..d2fcb6c --- /dev/null +++ b/helpmehelpapplication/src/main/resources/fxml/donationPage.fxml @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/helpmehelpapplication/src/main/resources/fxml/frontPage.fxml b/helpmehelpapplication/src/main/resources/fxml/frontPage.fxml new file mode 100644 index 0000000..93ed395 --- /dev/null +++ b/helpmehelpapplication/src/main/resources/fxml/frontPage.fxml @@ -0,0 +1,382 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/helpmehelpapplication/src/main/resources/fxml/organizationCard.fxml b/helpmehelpapplication/src/main/resources/fxml/organizationCard.fxml new file mode 100644 index 0000000..47ddc78 --- /dev/null +++ b/helpmehelpapplication/src/main/resources/fxml/organizationCard.fxml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + +