diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..dd77cae --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,22 @@ +name: ci + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: "25" + cache: maven + + - run: mvn -B test \ No newline at end of file diff --git a/.gitignore b/.gitignore index f28f5be..24fca5a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ # Adrian .vscode/ .idea/ +.target/ +.helpmehelpapplication\target/ +.helpmehelpapplication\.idea/ diff --git a/.idea/Prosjekt-Repo.iml b/.idea/Prosjekt-Repo.iml deleted file mode 100644 index d6ebd48..0000000 --- a/.idea/Prosjekt-Repo.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 5b796c4..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index 9c58d6b..c2b4d1f 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Planned core functionalities (3–4 will be fully implemented): ## Technology Stack -- **Programming Language:** Java +- **Programming Language:** Java 25 - **Application Type:** Desktop application - **UI:** JavaFX - **Database:** Relational database diff --git "a/docs/M\303\270tedokumenter/Team Meeting 1.pdf" "b/docs/M\303\270tedokumenter/Team Meeting 1.pdf" new file mode 100644 index 0000000..e383f4b Binary files /dev/null and "b/docs/M\303\270tedokumenter/Team Meeting 1.pdf" differ diff --git a/docs/Use_Case/1 b/docs/Use_Case/1 deleted file mode 100644 index 8b13789..0000000 --- a/docs/Use_Case/1 +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/Use_Case/Organization.png b/docs/Use_Case/Organization.png new file mode 100644 index 0000000..d7a561f Binary files /dev/null and b/docs/Use_Case/Organization.png differ diff --git a/docs/Use_Case/Use_Case_uml.docx b/docs/Use_Case/Use_Case_uml.docx new file mode 100644 index 0000000..bc3df02 Binary files /dev/null and b/docs/Use_Case/Use_Case_uml.docx differ diff --git a/docs/Use_Case/Temp_user_case.png b/docs/Use_Case/user_case_user.png similarity index 100% rename from docs/Use_Case/Temp_user_case.png rename to docs/Use_Case/user_case_user.png diff --git a/docs/sequence_diagram/Org_Onboard.png b/docs/sequence_diagram/Org_Onboard.png new file mode 100644 index 0000000..fa3974a Binary files /dev/null and b/docs/sequence_diagram/Org_Onboard.png differ diff --git a/docs/sequence_diagram/Organization_message.png b/docs/sequence_diagram/Organization_message.png new file mode 100644 index 0000000..416cdd3 Binary files /dev/null and b/docs/sequence_diagram/Organization_message.png differ diff --git a/docs/sequence_diagram/Organization_update_profile.png b/docs/sequence_diagram/Organization_update_profile.png new file mode 100644 index 0000000..a5d8036 Binary files /dev/null and b/docs/sequence_diagram/Organization_update_profile.png differ diff --git a/docs/sequence_diagram/Sequence_diagram_user_donate.png b/docs/sequence_diagram/Sequence_diagram_user_donate.png new file mode 100644 index 0000000..b45d8be Binary files /dev/null and b/docs/sequence_diagram/Sequence_diagram_user_donate.png differ diff --git a/docs/sequence_diagram/User_Browser_sequence_diagram.png b/docs/sequence_diagram/User_Browser_sequence_diagram.png new file mode 100644 index 0000000..f3498f3 Binary files /dev/null and b/docs/sequence_diagram/User_Browser_sequence_diagram.png differ diff --git a/docs/sequence_diagram/user_authentication_sequence_diagram.png b/docs/sequence_diagram/user_authentication_sequence_diagram.png new file mode 100644 index 0000000..3403802 Binary files /dev/null and b/docs/sequence_diagram/user_authentication_sequence_diagram.png differ diff --git a/helpmehelpapplication/.github/workflows/ci.yml b/helpmehelpapplication/.github/workflows/ci.yml new file mode 100644 index 0000000..ae74021 --- /dev/null +++ b/helpmehelpapplication/.github/workflows/ci.yml @@ -0,0 +1,20 @@ +name: ci + +on: + push: + branches: main + pull_request: + branches: main + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribition: temurin + java-version: "25" + cache: maven + - run: + mvn -B test diff --git a/helpmehelpapplication/.gitignore b/helpmehelpapplication/.gitignore new file mode 100644 index 0000000..e673575 --- /dev/null +++ b/helpmehelpapplication/.gitignore @@ -0,0 +1,2 @@ +.idea/ +target/ \ No newline at end of file diff --git a/.idea/.gitignore b/helpmehelpapplication/.idea/.gitignore similarity index 100% rename from .idea/.gitignore rename to helpmehelpapplication/.idea/.gitignore diff --git a/helpmehelpapplication/.idea/checkstyle-idea.xml b/helpmehelpapplication/.idea/checkstyle-idea.xml new file mode 100644 index 0000000..db90706 --- /dev/null +++ b/helpmehelpapplication/.idea/checkstyle-idea.xml @@ -0,0 +1,15 @@ + + + + 13.2.0 + JavaOnly + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/helpmehelpapplication/.idea/compiler.xml similarity index 100% rename from .idea/compiler.xml rename to helpmehelpapplication/.idea/compiler.xml diff --git a/helpmehelpapplication/.idea/dictionaries/project.xml b/helpmehelpapplication/.idea/dictionaries/project.xml new file mode 100644 index 0000000..e01d6da --- /dev/null +++ b/helpmehelpapplication/.idea/dictionaries/project.xml @@ -0,0 +1,7 @@ + + + + Prestmo + + + \ No newline at end of file diff --git a/helpmehelpapplication/.idea/inspectionProfiles/Project_Default.xml b/helpmehelpapplication/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..769a78f --- /dev/null +++ b/helpmehelpapplication/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/helpmehelpapplication/.idea/jarRepositories.xml similarity index 100% rename from .idea/jarRepositories.xml rename to helpmehelpapplication/.idea/jarRepositories.xml diff --git a/.idea/misc.xml b/helpmehelpapplication/.idea/misc.xml similarity index 65% rename from .idea/misc.xml rename to helpmehelpapplication/.idea/misc.xml index 3a943e7..5e4e294 100644 --- a/.idea/misc.xml +++ b/helpmehelpapplication/.idea/misc.xml @@ -4,11 +4,9 @@ - - - + \ No newline at end of file diff --git a/.idea/vcs.xml b/helpmehelpapplication/.idea/vcs.xml similarity index 69% rename from .idea/vcs.xml rename to helpmehelpapplication/.idea/vcs.xml index 35eb1dd..6c0b863 100644 --- a/.idea/vcs.xml +++ b/helpmehelpapplication/.idea/vcs.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/helpmehelpapplication/helpmehelpapplication.iml b/helpmehelpapplication/helpmehelpapplication.iml new file mode 100644 index 0000000..9e3449c --- /dev/null +++ b/helpmehelpapplication/helpmehelpapplication.iml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/Main.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/Main.java index d265ebe..b30c2e3 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/Main.java +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/Main.java @@ -1,7 +1,7 @@ package ntnu.sytemutvikling.team6; public class Main { - public static void main(String[] args) { - System.out.println("Hello world!"); - } -} \ No newline at end of file + 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 index 4a389f4..2c2cb3f 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Charity.java +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Charity.java @@ -1,98 +1,95 @@ /** - * This class represents a charity organization. It contains information about the charity such as its name, description, total donations, verification status, and category. - * + * 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; -import java.util.ArrayList; -abstract 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; - } +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 index e69de29..2935c74 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/CharityRegistry.java +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/CharityRegistry.java @@ -0,0 +1,36 @@ +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/Donation.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Donation.java index 78569b2..70f6268 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Donation.java +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Donation.java @@ -2,78 +2,67 @@ import java.time.LocalDateTime; import java.util.UUID; +import ntnu.sytemutvikling.team6.models.user.User; public class Donation { - /* UUID for uniquely identifying each donation */ - private UUID charityId; - - /* Ammount of money donated */ - private double amount; - - /* Date and time of the donation */ - private LocalDateTime date; - - /* The charity that received the donation */ - private Charity charity; - - /* The user/donor that made the donation */ - private User donor; - - /** - * Is the donation made anonymously? - * This can be null if the donation was made anonymously. - * - */ - private boolean isAnonymous; - - /** - * Constructor for creating a new donation. - * The charityId is generated automatically using UUID. - * If the donation is made anonymously, the isAnonymous parameter is set to true. - * @param amount - * @param date - * @param charity - * @param donor - */ - public Donation(double amount, LocalDateTime date, Charity charity, User donor) { - this.charityId = UUID.randomUUID(); - this.amount = amount; - this.date = date; - this.charity = charity; - this.donor = donor; - - - // ASSUMES that this is the way to get the anonymous setting from the user's settings. - if (donor.getSettings().getAnonymous() == false) { - this.isAnonymous = true; - } else { - this.isAnonymous = false; - - } - } - - /* Getters for the donation's attributes */ - public boolean isAnonymous() { - return isAnonymous; - } - - public UUID getCharityId() { - return charityId; - } - - public double getAmount() { - return amount; - } - - public LocalDateTime getDate() { - return date; - } - - public Charity getCharity() { - return charity; - } - - public User getDonor() { - return donor; - } + /* UUID for uniquely identifying each donation */ + private UUID charityId; + + /* Ammount of money donated */ + private double amount; + + /* Date and time of the donation */ + private LocalDateTime date; + + /* The charity that received the donation */ + private Charity charity; + + /* The user/donor that made the donation */ + private User donor; + + /** Is the donation made anonymously? This can be null if the donation was made anonymously. */ + private boolean isAnonymous; + + /** + * Constructor for creating a new donation. The charityId is generated automatically using UUID. + * If the donation is made anonymously, the isAnonymous parameter is set to true. + * + * @param amount + * @param date + * @param charity + * @param donor + */ + public Donation(double amount, LocalDateTime date, Charity charity, User donor) { + this.charityId = UUID.randomUUID(); + this.amount = amount; + this.date = date; + this.charity = charity; + this.donor = donor; + this.isAnonymous = donor.getSettings().isAnonymous(); + } + + /* Getters for the donation's attributes */ + public boolean isAnonymous() { + return isAnonymous; + } + + public UUID getCharityId() { + return charityId; + } + + public double getAmount() { + return amount; + } + + public LocalDateTime getDate() { + return date; + } + + public Charity getCharity() { + return charity; + } + + public User getDonor() { + return donor; + } } diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/DonationRegistry.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/DonationRegistry.java index f565298..ff6d4e2 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/DonationRegistry.java +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/DonationRegistry.java @@ -1,5 +1,38 @@ package ntnu.sytemutvikling.team6.models; +import java.util.*; + public class DonationRegistry { - + private final List donations; + + public DonationRegistry() { + this.donations = new ArrayList<>(); + } + + public List getAllDonations() { + return Collections.unmodifiableList(donations); + } + + public Optional findDonationById(UUID donationId) { + if (donationId == null) { + throw new IllegalArgumentException("DonationId can not be null."); + } + return donations.stream() + .filter(donations -> donationId.equals(donations.getCharityId())) + .findFirst(); + } + + public void addDonation(Donation donation) { + if (donation == null) { + throw new IllegalArgumentException("Donation can not be null."); + } + donations.add(donation); + } + + public boolean removeDonation(UUID donationId) { + if (donationId == null) { + throw new IllegalArgumentException("DonationId can not be null."); + } + return donations.removeIf(donation -> donationId.equals(donation.getCharityId())); + } } diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Feedback.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Feedback.java index 891dce1..f753e8a 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Feedback.java +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Feedback.java @@ -2,64 +2,61 @@ import java.time.LocalDateTime; import java.util.UUID; +import ntnu.sytemutvikling.team6.models.user.User; public class Feedback { - /* Feedback id */ - private UUID feedbackId; - - /** - * The author of the feedback - * If annonymous the presentation of the user will be "Anonymous". - */ - private User user; - - /* The details of the feedback*/ - private String comment; - - /* The date and time when the feedback was given */ - private LocalDateTime date; - - /* Is the feedback given anonymously? */ - private boolean isAnonymous; - - /** - * Constructor for creating a new feedback. - * - * @param user The user who gives the feedback. - * @param comment The content of the feedback. - */ - public Feedback(User user, String comment) { - this.feedbackId = UUID.randomUUID(); - this.user = user; - this.comment = comment; - this.date = LocalDateTime.now(); - - // ASSUMES that this is the way to get the anonymous setting from the user's settings. - if (user.getSettings().getAnonymous() == false) { - this.isAnonymous = true; - } else { - this.isAnonymous = false; - } - } - - /** - * Getters for the feedback's attributes. - * - * @return The feedback's attributes. - */ - public UUID getFeedbackId() { - return feedbackId; - } - public String getComment() { - return comment; - } - public LocalDateTime getDate() { - return date; - } - public User getUser() { - return user; - } - public boolean isAnonymous() { - return isAnonymous; - } + /* Feedback id */ + private UUID feedbackId; + + /** The author of the feedback If annonymous the presentation of the user will be "Anonymous". */ + private User user; + + /* The details of the feedback*/ + private String comment; + + /* The date and time when the feedback was given */ + private LocalDateTime date; + + /* Is the feedback given anonymously? */ + private boolean isAnonymous; + + /** + * Constructor for creating a new feedback. + * + * @param user The user who gives the feedback. + * @param comment The content of the feedback. + */ + public Feedback(User user, String comment) { + this.feedbackId = UUID.randomUUID(); + this.user = user; + this.comment = comment; + this.date = LocalDateTime.now(); + + this.isAnonymous = user.getSettings().isAnonymous(); + } + + /** + * Getters for the feedback's attributes. + * + * @return The feedback's attributes. + */ + public UUID getFeedbackId() { + return feedbackId; + } + + public String getComment() { + return comment; + } + + public LocalDateTime getDate() { + return date; + } + + public User getUser() { + return user; + } + + public boolean isAnonymous() { + return isAnonymous; + } } diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Inbox.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Inbox.java deleted file mode 100644 index 75fed79..0000000 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Inbox.java +++ /dev/null @@ -1,5 +0,0 @@ -package ntnu.sytemutvikling.team6.models; - -public class Inbox { - -} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Message.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Message.java deleted file mode 100644 index e69de29..0000000 diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Settings.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Settings.java deleted file mode 100644 index 71e218a..0000000 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Settings.java +++ /dev/null @@ -1,5 +0,0 @@ -package ntnu.sytemutvikling.team6.models; - -public class Settings { - -} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/User.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/User.java deleted file mode 100644 index c51d84b..0000000 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/User.java +++ /dev/null @@ -1,4 +0,0 @@ -package ntnu.sytemutvikling.team6.models; - -public class User { -} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/UserRegistry.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/UserRegistry.java index 7b97e02..c858e31 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/UserRegistry.java +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/UserRegistry.java @@ -1,6 +1,3 @@ package ntnu.sytemutvikling.team6.models; -public class UserRegistry { - - -} +public class UserRegistry {} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Inbox.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Inbox.java new file mode 100644 index 0000000..b560092 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Inbox.java @@ -0,0 +1,70 @@ +package ntnu.sytemutvikling.team6.models.user; + +import java.util.*; + +// Enhetstester mangler + +/** + * Represents a user's inbox that contains messages. Provides methods to add, remove and get + * messages. + * + * @author Robin Strand Prestmo + */ +public class Inbox { + private final List messages; + + /** Creates an empty inbox with no messages. */ + public Inbox() { + this.messages = new ArrayList<>(); + } + + /** + * Returns an unmodifiable view of the messages in this inbox. + * + * @return an unmodifiable list of messages + */ + public List getMessages() { + return Collections.unmodifiableList(messages); + } + + /** + * Finds a specific message by id. + * + * @param messageId the id of the message to search for + * @return messageId the id of the message to remove + * @throws IllegalArgumentException if messageId is null + */ + public Optional findMessageById(UUID messageId) { + if (messageId == null) { + throw new IllegalArgumentException("MessageId cannot be null."); + } + return messages.stream().filter(message -> messageId.equals(message.getId())).findFirst(); + } + + /** + * Add´s message to the messages list. + * + * @param message to be added + * @throws IllegalArgumentException if message is null + */ + public void addMessage(Message message) { + if (message == null) { + throw new IllegalArgumentException("Message cannot be null"); + } + messages.add(message); + } + + /** + * Removes a message from the inbox list. + * + * @param messageId the id to the message to be removed + * @return true if the message was removed, false if not found + * @throws IllegalArgumentException if messageId is null + */ + public boolean removeMessage(UUID messageId) { + if (messageId == null) { + throw new IllegalArgumentException("MessageId cannot be null"); + } + return messages.removeIf(message -> messageId.equals(message.getId())); + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Language.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Language.java new file mode 100644 index 0000000..ddc5d82 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Language.java @@ -0,0 +1,10 @@ +package ntnu.sytemutvikling.team6.models.user; + +/** + * Supported application languages. + * + * @author Robin Strand Prestmo + */ +public enum Language { + ENGLISH +} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Message.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Message.java new file mode 100644 index 0000000..ef9707b --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Message.java @@ -0,0 +1,69 @@ +package ntnu.sytemutvikling.team6.models.user; + +import java.time.LocalDateTime; +import java.util.UUID; + +// Enhetstester mangler + +/** + * Represents a message. + * + * @author Robin Strand Prestmo + */ +public class Message { + private final UUID id; + private final String title; + private final String from; + private final String content; + private final LocalDateTime timeAndDate; + + /** + * Creates a message with a unique identifier. The message includes a title, a string who it's + * from, content and the time and date. + * + * @param title the title of the message + * @param from who the message is from + * @param content the content of the message + * @throws IllegalArgumentException if title, from or content is null or blank. + */ + public Message(String title, String from, String content) { + + if (title == null || title.isBlank()) { + throw new IllegalArgumentException("Title cannot be null or blank."); + } + + if (from == null || from.isBlank()) { + throw new IllegalArgumentException("From cannot be null or blank."); + } + + if (content == null || content.isBlank()) { + throw new IllegalArgumentException("Content cannot be null or blank."); + } + + this.id = UUID.randomUUID(); + this.title = title; + this.from = from; + this.content = content; + this.timeAndDate = LocalDateTime.now(); + } + + public UUID getId() { + return id; + } + + public String getTitle() { + return title; + } + + public String getFrom() { + return from; + } + + public String getContent() { + return content; + } + + public LocalDateTime getTimeAndDate() { + return timeAndDate; + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Role.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Role.java new file mode 100644 index 0000000..74e134f --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Role.java @@ -0,0 +1,11 @@ +package ntnu.sytemutvikling.team6.models.user; + +/** + * Available users + * + * @author Robin Strand Prestmo + */ +public enum Role { + NORMAL_USER, + CHARITY_USER, +} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Settings.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Settings.java new file mode 100644 index 0000000..dd76557 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/Settings.java @@ -0,0 +1,69 @@ +package ntnu.sytemutvikling.team6.models.user; + +// Mangler Enhetstesting + +/** + * Represents the settings for a user. + * + * @author Robin Strand Prestmo + */ +public class Settings { + private boolean lightMode; + private Language language; + private boolean anonymous; + + /** Sets standard settings. LightMode enabled, language set to English, Anonymous disabled */ + public Settings() { + this(true, Language.ENGLISH, false); + } + + /** + * Creates settings for a user. + * + * @param lightMode choose between light or dark mode + * @param language choose language + * @param anonymous choose if user is anonymous + */ + public Settings(boolean lightMode, Language language, boolean anonymous) { + if (language == null) { + throw new IllegalArgumentException("Language cannot be null"); + } + this.lightMode = lightMode; + this.language = language; + this.anonymous = anonymous; + } + + /** Toggles between light and dark mode */ + public void toggleLightMode() { + lightMode = !lightMode; + } + + /** Toggles anonymous mode on and off */ + public void toggleAnonymousMode() { + anonymous = !anonymous; + } + + /** + * Change language to the chosen language. + * + * @param newLanguage the language to change to. + */ + public void changeLanguage(Language newLanguage) { + if (newLanguage == null) { + throw new IllegalArgumentException("Language cannot be null"); + } + language = newLanguage; + } + + public boolean isLightMode() { + return lightMode; + } + + public Language getLanguage() { + return language; + } + + public boolean isAnonymous() { + return anonymous; + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/User.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/User.java new file mode 100644 index 0000000..64594a0 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/user/User.java @@ -0,0 +1,149 @@ +package ntnu.sytemutvikling.team6.models.user; + +import java.util.UUID; +import ntnu.sytemutvikling.team6.security.PasswordHasher; + +/** + * Represents a user in the system. + * + *

A user has a unique identifier, personal information, a hashed password, a role, settings and + * an inbox. + * + *

The password is never stored ad plain text. It is hashed using {@link PasswordHasher} + * + * @author Robin Strand Prestmo + */ +public class User { + private static final PasswordHasher passwordHasher = new PasswordHasher(); + + private final UUID id; + private String name; + private String email; + private String passwordHash; + private final Role role; + private final Settings settings; + private final Inbox inbox; + + /** + * Creates a new user. + * + * @param id gives the user a unique identifier with UUID + * @param name the name of the user + * @param email the email of the user + * @param password the password for the user + * @param role users role + * @param settings the user´s settings + * @param inbox the user´s inbox + * @throws IllegalArgumentException if any required argument is invalid. + */ + public User( + String name, String email, String password, Role role, Settings settings, Inbox inbox) { + + if (name == null || name.isBlank()) { + throw new IllegalArgumentException("Name cannot be null or blank."); + } + + if (email == null || email.isBlank() || !email.contains("@") || !email.contains(".")) { + throw new IllegalArgumentException( + "Email cannot be null or blank," + " and must contain '@' and '.'"); + } + + if (role == null) { + throw new IllegalArgumentException("Role cannot be null"); + } + + if (settings == null) { + throw new IllegalArgumentException("Settings cannot be null"); + } + + if (inbox == null) { + throw new IllegalArgumentException("Inbox cannot be null"); + } + + this.id = UUID.randomUUID(); + this.name = name; + this.email = email; + this.passwordHash = passwordHasher.getHashPassword(password); + this.role = role; + this.settings = settings; + this.inbox = inbox; + } + + // Add Getters + + public UUID getId() { + return id; + } + + public String getName() { + return name; + } + + public String getEmail() { + return email; + } + + public Role getRole() { + return role; + } + + public Settings getSettings() { + return settings; + } + + public Inbox getInbox() { + return inbox; + } + + // Add Setters + + /** + * Updates the users name. + * + * @param name the new name + * @throws IllegalArgumentException if the name is null or blank + */ + public void setName(String name) { + if (name == null || name.isBlank()) { + throw new IllegalArgumentException("Name cannot be null or blank."); + } + this.name = name; + } + + /** + * Updates the users password. + * + *

The password is hashed before being stored. + * + * @param password the new password + */ + public void setPassword(String password) { + this.passwordHash = passwordHasher.getHashPassword(password); + } + + /** + * Updates the users email. + * + * @param email the new email + * @throws IllegalArgumentException if the email is null, blank, or does not contain '@' or '.' + */ + public void setEmail(String email) { + if (email == null || email.isBlank() || !email.contains("@") || !email.contains(".")) { + throw new IllegalArgumentException( + "Email cannot be null or blank," + " and must contains '@' and '.'"); + } + this.email = email; + } + + // Other methods + + /** + * Checks if the provided password matches the stored password. + * + * @param password the password to verify + * @return true if the password is correct, false otherwise + */ + public boolean checkPassword(String password) { + return passwordHasher.isValidPassword(password, passwordHash); + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/security/PasswordHasher.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/security/PasswordHasher.java new file mode 100644 index 0000000..8c2f7d9 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/security/PasswordHasher.java @@ -0,0 +1,92 @@ +package ntnu.sytemutvikling.team6.security; + +import java.security.MessageDigest; +import java.security.SecureRandom; +import java.util.Base64; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; + +/** + * A utility for hashing and verifying passwords using PBKDF2. + * + *

The generated hash contains both a random salt and the hashed password, encoded as Base64 + * string. + * + * @author Robin Strand Prestmo + */ +public final class PasswordHasher { + private static final SecureRandom RNG = new SecureRandom(); + + /** + * Hashes a password using PBKDF2 and a random salt. + * + * @param password the password to hash. + * @return a Base64 string containing the salt and the hashed password. + * @throws IllegalArgumentException if the password is null or blank. + */ + public String getHashPassword(String password) { + if (password == null || password.isBlank()) { + throw new IllegalArgumentException("Password cannot be null or blank."); + } + + String hashPass = ""; + + try { + // 1. Create salt + byte[] salt = new byte[16]; + RNG.nextBytes(salt); + + // 2. Create PBKDF2 Hash value + PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 100000, 32 * 8); + SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); + byte[] hash = factory.generateSecret(spec).getEncoded(); + + // 3. Combine salt and password bytes + byte[] hashBytes = new byte[48]; + System.arraycopy(salt, 0, hashBytes, 0, 16); + System.arraycopy(hash, 0, hashBytes, 16, 32); + + // 4. Turn the combined salt+hash into a string. + hashPass = Base64.getEncoder().encodeToString(hashBytes); + } catch (Exception e) { + throw new RuntimeException("Error while hashing password.", e); + } + return hashPass; + } + + /** + * Checks if the password matches a perviously stored hash. + * + * @param password The password the user types. + * @param hashPass Is the stored hashed password + * @return True if password is valid, otherwise false. + */ + public boolean isValidPassword(String password, String hashPass) { + if (password == null || password.isBlank()) { + return false; + } + + try { + // Extract the bytes + byte[] hashBytes = Base64.getDecoder().decode(hashPass); + + // Get salt + byte[] salt = new byte[16]; + System.arraycopy(hashBytes, 0, salt, 0, 16); + + // Compute the hash on the password the user entered + PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 100000, 32 * 8); + SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); + byte[] hash = factory.generateSecret(spec).getEncoded(); + + // Compare results + byte[] storedHash = new byte[32]; + System.arraycopy(hashBytes, 16, storedHash, 0, 32); + + return MessageDigest.isEqual(storedHash, hash); + + } catch (Exception e) { + throw new RuntimeException("Error while validating password.", e); + } + } +} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/AuthenticationService.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/AuthenticationService.java index 5f98c21..8b13789 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/AuthenticationService.java +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/AuthenticationService.java @@ -1,4 +1 @@ -package ntnu.sytemutvikling.team6.service; -public class AuthenticationService { -} diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/CharityService.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/CharityService.java index 6bd33ce..3b66851 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/CharityService.java +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/CharityService.java @@ -1,4 +1,3 @@ package ntnu.sytemutvikling.team6.service; -public class CharityService { -} +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 index bc4a7c8..17692d5 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/DonationService.java +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/DonationService.java @@ -1,4 +1,3 @@ package ntnu.sytemutvikling.team6.service; -public class DonationService { -} +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 index 93b2555..27eee23 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/FeedbackService.java +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/FeedbackService.java @@ -1,4 +1,3 @@ package ntnu.sytemutvikling.team6.service; -public class FeedbackService { -} +public class FeedbackService {} diff --git a/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/CharityRegistryTest.java b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/CharityRegistryTest.java new file mode 100644 index 0000000..232431f --- /dev/null +++ b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/CharityRegistryTest.java @@ -0,0 +1,91 @@ +package ntnu.systemutvikling.team6.models; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import ntnu.sytemutvikling.team6.models.Charity; +import ntnu.sytemutvikling.team6.models.CharityRegistry; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * UnitTest for CharityRegistry class + * + * @author Adrian Balunan + */ +public class CharityRegistryTest { + private CharityRegistry registry; + private Charity charity; + + /* Setting up variables */ + @BeforeEach + public void setup() { + registry = new CharityRegistry(); + charity = new Charity("Charity1", "Something Somewhere Somehow", "Cancer"); + } + + @Test + void testAddCharitySuccessfully() { + registry.addCharity(charity); + + assertEquals(1, registry.getAllCharities().size()); + assertTrue(registry.getAllCharities().contains(charity)); + } + + @Test + void testAddCharityNullThrowsException() { + assertThrows(IllegalArgumentException.class, () -> registry.addCharity(null)); + } + + @Test + void testGetAllCharitiesReturnsUnmodifiableList() { + registry.addCharity(charity); + + List charities = registry.getAllCharities(); + assertThrows(UnsupportedOperationException.class, () -> charities.add(charity)); + } + + @Test + void testFindCharityByIdFound() { + registry.addCharity(charity); + + Optional result = registry.findCharityById(charity.getId()); + + assertTrue(result.isPresent()); + assertEquals(charity, result.get()); + } + + @Test + void testFindCharityByIdNotFound() { + Optional result = registry.findCharityById(UUID.randomUUID()); + assertTrue(result.isEmpty()); + } + + @Test + void testFindCharityByIdNullThrowsException() { + assertThrows(IllegalArgumentException.class, () -> registry.findCharityById(null)); + } + + @Test + void testRemoveCharitySuccessfully() { + registry.addCharity(charity); + + boolean removed = registry.removeCharity(charity.getId()); + + assertTrue(removed); + assertTrue(registry.getAllCharities().isEmpty()); + } + + @Test + void testRemoveCharityNotFound() { + boolean removed = registry.removeCharity(UUID.randomUUID()); + assertFalse(removed); + } + + @Test + void testRemoveCharityNullThrowsException() { + assertThrows(IllegalArgumentException.class, () -> registry.removeCharity(null)); + } +} diff --git a/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/CharityTest.java b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/CharityTest.java new file mode 100644 index 0000000..5c2f9c2 --- /dev/null +++ b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/CharityTest.java @@ -0,0 +1,62 @@ +package ntnu.systemutvikling.team6.models; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.UUID; +import ntnu.sytemutvikling.team6.models.Charity; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * UnitTesting for Charity. + * + * @author Adrian Balunan + */ +public class CharityTest { + private Charity charity; + + @BeforeEach + public void setup() { + charity = new Charity("Charity1", "Something Somewhere Somehow", "Cancer"); + } + + /** Getters should work: */ + @Test + public void testGettingIdShouldWork() { + assertInstanceOf(UUID.class, charity.getId()); + } + + @Test + public void testGettingCategoryShouldWork() { + assertEquals("Cancer", charity.getCategory()); + } + + @Test + public void testGettingNameShouldWork() { + assertEquals("Charity1", charity.getName()); + } + + @Test + public void testGettingDescriptionShouldWork() { + assertEquals("Something Somewhere Somehow", charity.getDescription()); + } + + /** Getter and setter for IsVerified should be able to switch between true and false */ + @Test + public void testIsVerifiedReturnsCorrectly() { + assertFalse(charity.isVerified()); + charity.setVerified(); + assertTrue(charity.isVerified()); + charity.setUnverified(); + assertFalse(charity.isVerified()); + } + + /** totalDonations should display accuratly and adding works */ + @Test + public void testTotalDonationsReturnsCorrectlyAfterChanges() { + assertEquals(0, charity.getTotalDonations()); + charity.setTotalDonations(10); + charity.setTotalDonations(5); + assertEquals(15, charity.getTotalDonations()); + } +} diff --git a/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/DonationTest.java b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/DonationTest.java new file mode 100644 index 0000000..17bfaef --- /dev/null +++ b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/DonationTest.java @@ -0,0 +1,93 @@ +package ntnu.systemutvikling.team6.models; + +import static org.junit.jupiter.api.Assertions.*; + +import java.time.LocalDateTime; +import ntnu.sytemutvikling.team6.models.Charity; +import ntnu.sytemutvikling.team6.models.Donation; +import ntnu.sytemutvikling.team6.models.user.Inbox; +import ntnu.sytemutvikling.team6.models.user.Role; +import ntnu.sytemutvikling.team6.models.user.Settings; +import ntnu.sytemutvikling.team6.models.user.User; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class DonationTest { + private Settings settings; + private User user; + private Charity charity; + + // -- Setup -- + @BeforeEach + public void setup() { + charity = new Charity("name", "something somewhere somehow", "Meow"); + user = + new User("Name", "Valid@gmail.com", "123", Role.NORMAL_USER, new Settings(), new Inbox()); + } + + // --- Tests --- + @Test + void testDonationInitialization() { + LocalDateTime now = LocalDateTime.now(); + + Donation donation = new Donation(500.0, now, charity, user); + + assertNotNull(donation.getCharityId()); + assertEquals(500.0, donation.getAmount()); + assertEquals(now, donation.getDate()); + assertEquals(charity, donation.getCharity()); + assertEquals(user, donation.getDonor()); + } + + @Test + void testAnonymousFlagWhenUserIsAnonymous() { + Donation donation = new Donation(100, LocalDateTime.now(), charity, user); + + assertFalse(donation.isAnonymous()); + } + + @Test + void testAnonymousFlagWhenUserIsNotAnonymous() { + Donation donation = new Donation(100, LocalDateTime.now(), charity, user); + + assertFalse(donation.isAnonymous()); + } + + @Test + void testCharityIdIsUnique() { + Donation d1 = new Donation(50, LocalDateTime.now(), charity, user); + Donation d2 = new Donation(75, LocalDateTime.now(), charity, user); + + assertNotEquals(d1.getCharityId(), d2.getCharityId()); + } + + @Test + void testAmountStoredCorrectly() { + Donation donation = new Donation(123.45, LocalDateTime.now(), charity, user); + + assertEquals(123.45, donation.getAmount()); + } + + @Test + void testDateStoredCorrectly() { + LocalDateTime date = LocalDateTime.of(2024, 5, 10, 12, 30); + + Donation donation = new Donation(200, date, charity, user); + + assertEquals(date, donation.getDate()); + } + + @Test + void testCharityStoredCorrectly() { + Donation donation = new Donation(200, LocalDateTime.now(), charity, user); + + assertEquals(charity, donation.getCharity()); + } + + @Test + void testDonorStoredCorrectly() { + Donation donation = new Donation(200, LocalDateTime.now(), charity, user); + + assertEquals(user, donation.getDonor()); + } +} diff --git a/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/FeedbackTest.java b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/FeedbackTest.java new file mode 100644 index 0000000..a9fc57d --- /dev/null +++ b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/FeedbackTest.java @@ -0,0 +1,87 @@ +package ntnu.systemutvikling.team6.models; + +import static org.junit.jupiter.api.Assertions.*; + +import java.time.LocalDateTime; +import ntnu.sytemutvikling.team6.models.Feedback; +import ntnu.sytemutvikling.team6.models.user.Inbox; +import ntnu.sytemutvikling.team6.models.user.Role; +import ntnu.sytemutvikling.team6.models.user.Settings; +import ntnu.sytemutvikling.team6.models.user.User; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class FeedbackTest { + + private User user; + private Settings settings; + + // -- Setup -- + @BeforeEach + public void setup() { + settings = new Settings(); // default anonymous = true + user = + new User("Name", "Valid@gmail.com", "123", Role.NORMAL_USER, new Settings(), new Inbox()); + } + + // --- Tests --- + + @Test + void testFeedbackInitialization() { + LocalDateTime before = LocalDateTime.now(); + Feedback feedback = new Feedback(user, "Nice work!"); + LocalDateTime after = LocalDateTime.now(); + + assertNotNull(feedback.getFeedbackId()); + assertEquals("Nice work!", feedback.getComment()); + assertEquals(user, feedback.getUser()); + + // Date should be between before and after + assertTrue(!feedback.getDate().isBefore(before) && !feedback.getDate().isAfter(after)); + } + + @Test + void testAnonymousFlagWhenUserIsAnonymous() { + // user.settings.isAnonymous() == true → feedback.isAnonymous = false + Feedback feedback = new Feedback(user, "Anonymous feedback"); + + assertFalse(feedback.isAnonymous()); + } + + @Test + void testAnonymousFlagWhenUserIsNotAnonymous() { + user.getSettings().toggleAnonymousMode(); + Feedback feedback = new Feedback(user, "Not anonymous"); + + assertTrue(feedback.isAnonymous()); + } + + @Test + void testFeedbackIdIsUnique() { + Feedback f1 = new Feedback(user, "First"); + Feedback f2 = new Feedback(user, "Second"); + + assertNotEquals(f1.getFeedbackId(), f2.getFeedbackId()); + } + + @Test + void testCommentStoredCorrectly() { + Feedback feedback = new Feedback(user, "This is a test comment"); + + assertEquals("This is a test comment", feedback.getComment()); + } + + @Test + void testUserStoredCorrectly() { + Feedback feedback = new Feedback(user, "Hello"); + + assertEquals(user, feedback.getUser()); + } + + @Test + void testDateIsSet() { + Feedback feedback = new Feedback(user, "Testing date"); + + assertNotNull(feedback.getDate()); + } +} diff --git a/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/user/SettingsTest.java b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/user/SettingsTest.java new file mode 100644 index 0000000..18b2814 --- /dev/null +++ b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/user/SettingsTest.java @@ -0,0 +1,70 @@ +package ntnu.systemutvikling.team6.models.user; + +import static org.junit.jupiter.api.Assertions.*; + +import ntnu.sytemutvikling.team6.models.user.Language; +import ntnu.sytemutvikling.team6.models.user.Settings; +import org.junit.jupiter.api.Test; + +class SettingsTest { + + @Test + void testDefaultConstructorSetsStandardValues() { + Settings settings = new Settings(); + + assertTrue(settings.isLightMode()); + assertEquals(Language.ENGLISH, settings.getLanguage()); + assertFalse(settings.isAnonymous()); + } + + @Test + void testCustomConstructorSetsValuesCorrectly() { + Settings settings = new Settings(false, Language.ENGLISH, true); + + assertFalse(settings.isLightMode()); + assertEquals(Language.ENGLISH, settings.getLanguage()); + assertTrue(settings.isAnonymous()); + } + + @Test + void testConstructorThrowsExceptionWhenLanguageIsNull() { + assertThrows(IllegalArgumentException.class, () -> new Settings(true, null, false)); + } + + @Test + void testToggleLightMode() { + Settings settings = new Settings(true, Language.ENGLISH, false); + + settings.toggleLightMode(); + assertFalse(settings.isLightMode()); + + settings.toggleLightMode(); + assertTrue(settings.isLightMode()); + } + + @Test + void testToggleAnonymousMode() { + Settings settings = new Settings(true, Language.ENGLISH, false); + + settings.toggleAnonymousMode(); + assertTrue(settings.isAnonymous()); + + settings.toggleAnonymousMode(); + assertFalse(settings.isAnonymous()); + } + + @Test + void testChangeLanguageSuccessfully() { + Settings settings = new Settings(); + + settings.changeLanguage(Language.ENGLISH); + assertEquals(Language.ENGLISH, settings.getLanguage()); + } + + @Test + void testChangeLanguageThrowsExceptionWhenNull() { + Settings settings = new Settings(); + + assertThrows(IllegalArgumentException.class, () -> settings.changeLanguage(null)); + } +} diff --git a/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/user/UserTest.java b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/user/UserTest.java new file mode 100644 index 0000000..fd20091 --- /dev/null +++ b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/models/user/UserTest.java @@ -0,0 +1,153 @@ +package ntnu.systemutvikling.team6.models.user; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.UUID; + +import ntnu.sytemutvikling.team6.models.user.Inbox; +import ntnu.sytemutvikling.team6.models.user.Role; +import ntnu.sytemutvikling.team6.models.user.Settings; +import ntnu.sytemutvikling.team6.models.user.User; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class UserTest { + + @Nested + class constructorTests { + private final UUID validID = UUID.randomUUID(); + private final String validName = "Name"; + private final String validEmail = "Email@gmail.com"; + private final String validPassword = "Password"; + private final Role validRole = Role.NORMAL_USER; + private final Settings validSettings = new Settings(); + private final Inbox validInbox = new Inbox(); + + @Test + void shouldThrowIfNameIsNull() { + assertThrows( + IllegalArgumentException.class, + () -> + new User( + null, validEmail, validPassword, validRole, validSettings, validInbox)); + } + + @Test + void shouldThrowIfNameIsBlank() { + assertThrows( + IllegalArgumentException.class, + () -> + new User( + " ", validEmail, validPassword, validRole, validSettings, validInbox)); + } + + @Nested + class emailTests { + + @Test + void shouldThrowIfEmailIsNull() { + assertThrows( + IllegalArgumentException.class, + () -> + new User( + validName, null, validPassword, validRole, validSettings, validInbox)); + } + + @Test + void shouldThrowIfEmailIsBlank() { + assertThrows( + IllegalArgumentException.class, + () -> + new User( + validName, " ", validPassword, validRole, validSettings, validInbox)); + } + + @Test + void shouldThrowIfEmailDoesNotContainAt() { + assertThrows( + IllegalArgumentException.class, + () -> + new User( + + validName, + "test.gmail.com", + validPassword, + validRole, + validSettings, + validInbox)); + } + + @Test + void shouldThrowIfEmailDoesNotContainPeriod() { + assertThrows( + IllegalArgumentException.class, + () -> + new User( + + validName, + "test@gmailcom", + validPassword, + validRole, + validSettings, + validInbox)); + } + } + + @Test + void shouldThrowIfPasswordIsNull() { + assertThrows( + IllegalArgumentException.class, + () -> + new User( validName, validEmail, null, validRole, validSettings, validInbox)); + } + + @Test + void shouldThrowIfRoleIsNull() { + assertThrows( + IllegalArgumentException.class, + () -> + new User( + validName, validEmail, validPassword, null, validSettings, validInbox)); + } + + @Test + void shouldThrowIfPasswordIsBlank() { + assertThrows( + IllegalArgumentException.class, + () -> + new User( validName, validEmail, " ", validRole, validSettings, validInbox)); + } + + @Test + void shouldThrowIfSettingsIsNull() { + assertThrows( + IllegalArgumentException.class, + () -> + new User( validName, validEmail, validPassword, validRole, null, validInbox)); + } + + @Test + void shouldThrowIfInboxIsNull() { + assertThrows( + IllegalArgumentException.class, + () -> + new User( + validName, validEmail, validPassword, validRole, validSettings, null)); + } + + @Test + void shouldCreateUser() { + User user = + new User( + validName, validEmail, validPassword, validRole, validSettings, validInbox); + + assertAll( + () -> assertEquals(validName, user.getName()), + () -> assertEquals(validEmail, user.getEmail()), + () -> assertEquals(validRole, user.getRole()), + () -> assertEquals(validSettings, user.getSettings()), + () -> assertEquals(validInbox, user.getInbox())); + } + } +} diff --git a/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/security/PasswordHasherTest.java b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/security/PasswordHasherTest.java new file mode 100644 index 0000000..d195989 --- /dev/null +++ b/helpmehelpapplication/src/test/java/ntnu/systemutvikling/team6/security/PasswordHasherTest.java @@ -0,0 +1,71 @@ +package ntnu.systemutvikling.team6.security; + +import static org.junit.jupiter.api.Assertions.*; + +import ntnu.sytemutvikling.team6.security.PasswordHasher; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class PasswordHasherTest { + private final PasswordHasher hasher = new PasswordHasher(); + + @Nested + class getHashPasswordTest { + + @Test + void shouldThrowIfPasswordIsNull() { + assertThrows(IllegalArgumentException.class, () -> hasher.getHashPassword(null)); + } + + @Test + void shouldThrowIfPasswordIsBlank() { + assertThrows(IllegalArgumentException.class, () -> hasher.getHashPassword(" ")); + } + + @Test + void shouldReturnDifferentHashesForSamePasswordBecauseSaltIsRandom() { + String test1 = hasher.getHashPassword("Password"); + String test2 = hasher.getHashPassword("Password"); + + assertNotEquals(test1, test2); + } + } + + @Nested + class isValidPasswordTest { + + @Test + void shouldReturnTrueForCorrectPassword() { + String test = hasher.getHashPassword("Password"); + assertTrue(hasher.isValidPassword("Password", test)); + } + + @Test + void shouldReturnFalseForWrongPassword() { + String test = hasher.getHashPassword("Password"); + assertFalse(hasher.isValidPassword("password", test)); + } + + @Test + void shouldReturnFalseIfPasswordIsBlank() { + String test = hasher.getHashPassword("Test"); + assertFalse(hasher.isValidPassword(" ", test)); + } + + @Test + void shouldReturnFalseIfPasswordIsNull() { + String test = hasher.getHashPassword("Test"); + assertFalse(hasher.isValidPassword(null, test)); + } + + @Test + void shouldThrowIfStoredHashIsNull() { + assertThrows(RuntimeException.class, () -> hasher.isValidPassword("Password", null)); + } + + @Test + void shouldThrowIfStoredHashIsBlank() { + assertThrows(RuntimeException.class, () -> hasher.isValidPassword("Password", " ")); + } + } +}