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 660d9b6..6c18783 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ .vscode/ .idea/ helpmehelpapplication/target +.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/.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/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/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 new file mode 100644 index 0000000..b30c2e3 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/Main.java @@ -0,0 +1,7 @@ +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 new file mode 100644 index 0000000..2c2cb3f --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Charity.java @@ -0,0 +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. + * + * @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 new file mode 100644 index 0000000..2935c74 --- /dev/null +++ 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 new file mode 100644 index 0000000..70f6268 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Donation.java @@ -0,0 +1,68 @@ +package ntnu.sytemutvikling.team6.models; + +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; + 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 new file mode 100644 index 0000000..ff6d4e2 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/DonationRegistry.java @@ -0,0 +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 new file mode 100644 index 0000000..f753e8a --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Feedback.java @@ -0,0 +1,62 @@ +package ntnu.sytemutvikling.team6.models; + +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(); + + 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/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/Inbox.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/UserRegistry.java similarity index 59% rename from helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Inbox.java rename to helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/UserRegistry.java index 75fed79..c858e31 100644 --- a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/Inbox.java +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/models/UserRegistry.java @@ -1,5 +1,3 @@ package ntnu.sytemutvikling.team6.models; -public class Inbox { - -} +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/docs/Use_Case/1 b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/AuthenticationService.java similarity index 100% rename from docs/Use_Case/1 rename to helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/AuthenticationService.java diff --git a/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/CharityService.java b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/CharityService.java new file mode 100644 index 0000000..3b66851 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/CharityService.java @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000..17692d5 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/DonationService.java @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000..27eee23 --- /dev/null +++ b/helpmehelpapplication/src/main/java/ntnu/sytemutvikling/team6/service/FeedbackService.java @@ -0,0 +1,3 @@ +package ntnu.sytemutvikling.team6.service; + +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", " ")); + } + } +}