From c62e4719ea0dc93401b4867b9ffd4ef94a8c9910 Mon Sep 17 00:00:00 2001 From: mlwauben Date: Thu, 28 Mar 2019 23:11:58 +0100 Subject: [PATCH 01/10] ADD:: test fxml+controller --- .../AchievementsTestController.java | 20 +++++++++++++++++++ .../main/resources/fxml/achievementstest.fxml | 18 +++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/Client/src/main/java/greenify/client/controller/AchievementsTestController.java create mode 100644 src/Client/src/main/resources/fxml/achievementstest.fxml diff --git a/src/Client/src/main/java/greenify/client/controller/AchievementsTestController.java b/src/Client/src/main/java/greenify/client/controller/AchievementsTestController.java new file mode 100644 index 0000000..f8eca2a --- /dev/null +++ b/src/Client/src/main/java/greenify/client/controller/AchievementsTestController.java @@ -0,0 +1,20 @@ +package greenify.client.controller; + +import greenify.client.rest.UserService; +import javafx.fxml.FXML; +import javafx.scene.image.ImageView; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; + +/** + * Class that controls the achievements fxml file (the GUI Screen). + */ +@Controller +public class AchievementsTestController { + @Autowired + UserService userService; + + @FXML + private ImageView achievpic1; + +} diff --git a/src/Client/src/main/resources/fxml/achievementstest.fxml b/src/Client/src/main/resources/fxml/achievementstest.fxml new file mode 100644 index 0000000..6c72f53 --- /dev/null +++ b/src/Client/src/main/resources/fxml/achievementstest.fxml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + From 393bfc9445da6c5302419637b69e36465869e772 Mon Sep 17 00:00:00 2001 From: mlwauben Date: Sat, 30 Mar 2019 08:23:54 +0100 Subject: [PATCH 02/10] ADD:: achievement class --- .../server/data/model/Achievement.java | 106 ++++++++++++++++++ .../server/data/model/AchievementTest.java | 41 +++++++ 2 files changed, 147 insertions(+) create mode 100644 src/Server/src/main/java/greenify/server/data/model/Achievement.java create mode 100644 src/Server/src/test/java/greenify/server/data/model/AchievementTest.java diff --git a/src/Server/src/main/java/greenify/server/data/model/Achievement.java b/src/Server/src/main/java/greenify/server/data/model/Achievement.java new file mode 100644 index 0000000..b1b6e66 --- /dev/null +++ b/src/Server/src/main/java/greenify/server/data/model/Achievement.java @@ -0,0 +1,106 @@ +package greenify.server.data.model; + +import java.util.Objects; + +public class Achievement { + private String name; + private String description; + private boolean achieved; + + public Achievement() {} + + /** + * Constructor for an achievement. + * @param name name of the achievement + * @param description description of the achievement + * @param achieved whether the achievement is achieved or not + */ + public Achievement(String name, String description, boolean achieved) { + this.name = name; + this.description = description; + this.achieved = achieved; + } + + /** + * This method sets the name of an achievement. + * @return name of the achievement + */ + public String getName() { + return name; + } + + /** + * This method sets the name of an achievement. + * @param name name of the achievement + */ + public void setName(String name) { + this.name = name; + } + + /** + * This method gets the description of an achievement. + * @return the description of the achievement + */ + public String getDescription() { + return description; + } + + /** + * This method sets the name of an achievement. + * @param description the description of an achievement + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * This method gets the state of an achievement. + * @return achievement is (not) achieved + */ + public boolean isAchieved() { + return achieved; + } + + /** + * This method sets the state of an achievement. + * @param achieved achievement is (not) achieved + */ + public void setAchieved(boolean achieved) { + this.achieved = achieved; + } + + /** + * This method gets a human readable (JSON) object. + * @return the JSON form of the object + */ + @Override + public String toString() { + return "Achievement(name=" + name + ", description=" + description + + ", achieved=" + achieved + ")"; + } + + /** + * This method checks whether two users are equal or not. + * @param other another achievement + * @return achievements are (not) equal + */ + @Override + public boolean equals(Object other) { + if (other instanceof Achievement) { + Achievement that = (Achievement) other; + return achieved == that.achieved && + name.equals(that.name) && + Objects.equals(description, that.description); + } + return false; + } + + /** + * This method gets the hashcode of an achievement. + * @return hashcode of an achievement + */ + @Override + public int hashCode() { + return Objects.hash(name, description, achieved); + } +} diff --git a/src/Server/src/test/java/greenify/server/data/model/AchievementTest.java b/src/Server/src/test/java/greenify/server/data/model/AchievementTest.java new file mode 100644 index 0000000..ec96cdc --- /dev/null +++ b/src/Server/src/test/java/greenify/server/data/model/AchievementTest.java @@ -0,0 +1,41 @@ +package greenify.server.data.model; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class AchievementTest { + private Achievement achievement = new Achievement("SavedCO2", "You saved 100 cow farts of CO2!", true); + private Achievement other = new Achievement("SavedCO2", "You saved 100 cow farts of CO2!", true); + + @Test + public void getAndSetTest() { + Achievement testAchievement = new Achievement(); + testAchievement.setName("SavedCO2"); + testAchievement.setDescription("You saved 100 cow farts of CO2!"); + testAchievement.setAchieved(true); + assertEquals("SavedCO2", achievement.getName()); + assertEquals("You saved 100 cow farts of CO2!", achievement.getDescription()); + assertTrue(achievement.isAchieved()); + assertEquals(achievement, testAchievement); + } + + @Test + public void toStringTest() { + assertEquals("Achievement(name=SavedCO2, description=You saved 100 cow farts of CO2!, achieved=true)", achievement.toString()); + } + + @Test + void equalsTest() { + assertEquals(achievement.getName(), other.getName()); + assertEquals(achievement.getDescription(), other.getDescription()); + assertEquals(achievement.isAchieved(), other.isAchieved()); + assertEquals(achievement, other); + } + + @Test + void hashCodeTest() { + assertEquals(achievement, other); + assertEquals(achievement.hashCode(), other.hashCode()); + } +} From 3d61cd061aa04c249fa282f87964279695b82675 Mon Sep 17 00:00:00 2001 From: mlwauben Date: Sat, 30 Mar 2019 09:02:02 +0100 Subject: [PATCH 03/10] ADD:: class of achievements list --- .../java/greenify/server/AllAchievements.java | 23 +++++++++++++++++++ .../greenify/server/AllAchievementsTest.java | 21 +++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/Server/src/main/java/greenify/server/AllAchievements.java create mode 100644 src/Server/src/test/java/greenify/server/AllAchievementsTest.java diff --git a/src/Server/src/main/java/greenify/server/AllAchievements.java b/src/Server/src/main/java/greenify/server/AllAchievements.java new file mode 100644 index 0000000..66e86a4 --- /dev/null +++ b/src/Server/src/main/java/greenify/server/AllAchievements.java @@ -0,0 +1,23 @@ +package greenify.server; + +import greenify.server.data.model.Achievement; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; + +public class AllAchievements { + private static final List allAchievements = Arrays.asList( + new Achievement("Starting off", "You did your first green activity", false), + new Achievement("Social butterfly", "You added three friends", false) + ); + + /** + * This method gets default achievements. + * @return the list of default achievements + */ + public static List getDefaults() { + return new ArrayList<>(allAchievements); + } + +} diff --git a/src/Server/src/test/java/greenify/server/AllAchievementsTest.java b/src/Server/src/test/java/greenify/server/AllAchievementsTest.java new file mode 100644 index 0000000..828748e --- /dev/null +++ b/src/Server/src/test/java/greenify/server/AllAchievementsTest.java @@ -0,0 +1,21 @@ +package greenify.server; + +import greenify.server.data.model.Achievement; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class AllAchievementsTest { + + @Test + void getDefaultsTest() { + List all = new ArrayList() {{ + add(new Achievement("Starting off", "You did your first green activity", false)); + add(new Achievement("Social butterfly", "You added three friends", false)); + }}; + assertEquals(all.size(), AllAchievements.getDefaults().size()); + } +} From f5d9bd5010609479d68faffc2987fb6dc9385936 Mon Sep 17 00:00:00 2001 From: mlwauben Date: Sat, 30 Mar 2019 09:25:12 +0100 Subject: [PATCH 04/10] UPDATE:: added achievements to user class --- .../java/greenify/server/data/model/User.java | 30 ++++++++++++++++--- .../greenify/server/data/model/UserTest.java | 23 ++++++++++---- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/Server/src/main/java/greenify/server/data/model/User.java b/src/Server/src/main/java/greenify/server/data/model/User.java index 4f85d38..ed6f56f 100644 --- a/src/Server/src/main/java/greenify/server/data/model/User.java +++ b/src/Server/src/main/java/greenify/server/data/model/User.java @@ -1,12 +1,14 @@ package greenify.server.data.model; import greenify.common.ApplicationException; +import greenify.server.AllAchievements; import greenify.server.InputValidator; import lombok.Data; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; @@ -47,6 +49,9 @@ public class User { @JoinColumn private Collection friends; + @ElementCollection + private List achievements; + public User() {} /** @@ -60,7 +65,8 @@ public class User { this.name = name; this.password = password; this.setFootPrintInputs(InputValidator.getDefaultValues()); - this.friends = new ArrayList(); + this.friends = new ArrayList<>(); + this.setAchievements(AllAchievements.getDefaults()); } /** @@ -160,7 +166,7 @@ public class User { } /** - * Adds a friend to the friendslist of the user. + * Adds a friend to the friends list of the user. * @param user the friend you want to add. */ public void addFriend(User user) { @@ -172,6 +178,22 @@ public class User { } } + /** + * This method sets the achievements of the user. + * @param achievements achievements of the user + */ + public void setAchievements(List achievements) { + this.achievements = achievements; + } + + /** + * This method gets the achievements of the user. + * @return achievements of the user + */ + public List getAchievements() { + return this.achievements; + } + /** * This method gets a human readable (JSON) object. * @return the JSON form of the object. @@ -183,8 +205,8 @@ public class User { } /** - * Returns the name and score of the friends in JSON. Needed for the leaderboard. - * @return a JSON object of the friendlist with only names and scores. + * Returns the name and score of the friends in JSON. Needed for the leader board. + * @return a JSON object of the friend list with only names and scores. */ public String friendsToString() { String result = "friends=["; diff --git a/src/Server/src/test/java/greenify/server/data/model/UserTest.java b/src/Server/src/test/java/greenify/server/data/model/UserTest.java index b8bbabc..aba33e2 100644 --- a/src/Server/src/test/java/greenify/server/data/model/UserTest.java +++ b/src/Server/src/test/java/greenify/server/data/model/UserTest.java @@ -1,11 +1,11 @@ package greenify.server.data.model; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.*; import static org.junit.jupiter.api.Assertions.assertThrows; import greenify.common.ApplicationException; +import greenify.server.AllAchievements; import org.junit.Test; import java.util.ArrayList; @@ -99,7 +99,7 @@ public class UserTest { User second = new User(1L, "merel", "password"); assertEquals(first.getFriends(), second.getFriends()); first.addFriend(second); - ArrayList test = new ArrayList(); + ArrayList test = new ArrayList<>(); test.add(second); assertEquals(first.getFriends(), test); } @@ -108,9 +108,7 @@ public class UserTest { public void addYourselfTest() { User test = new User(1L, "greenify", "password"); assertEquals(test.getFriends(), new ArrayList()); - assertThrows(ApplicationException.class, () -> { - test.addFriend(test); - }); + assertThrows(ApplicationException.class, () -> test.addFriend(test)); } @@ -131,4 +129,17 @@ public class UserTest { first.setFriends(friends); assertEquals(friends, first.getFriends()); } + + @Test + public void getAchievementsTest() { + User user = new User(1L, "greenify", "password"); + assertEquals(user.getAchievements(), AllAchievements.getDefaults()); + } + + @Test + public void setAchievementsTest() { + User user = new User(1L, "greenify", "password"); + user.setAchievements(null); + assertNull(user.getAchievements()); + } } From ca11cd3c9a83d12d03356eeb7c96eeafac7d80e7 Mon Sep 17 00:00:00 2001 From: mlwauben Date: Sat, 30 Mar 2019 11:29:39 +0100 Subject: [PATCH 05/10] DEBUG:: achievement things (tests all work now) --- .../main/java/greenify/server/AllAchievements.java | 11 ++++++++--- .../main/java/greenify/server/data/model/User.java | 8 +++----- .../java/greenify/server/data/model/UserTest.java | 4 +++- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Server/src/main/java/greenify/server/AllAchievements.java b/src/Server/src/main/java/greenify/server/AllAchievements.java index 66e86a4..25c6a8a 100644 --- a/src/Server/src/main/java/greenify/server/AllAchievements.java +++ b/src/Server/src/main/java/greenify/server/AllAchievements.java @@ -3,8 +3,9 @@ package greenify.server; import greenify.server.data.model.Achievement; import java.util.Arrays; -import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class AllAchievements { private static final List allAchievements = Arrays.asList( @@ -16,8 +17,12 @@ public class AllAchievements { * This method gets default achievements. * @return the list of default achievements */ - public static List getDefaults() { - return new ArrayList<>(allAchievements); + public static Map getDefaults() { + Map all = new HashMap<>(); + for (Achievement achievement : allAchievements) { + all.put(achievement.getName(), achievement.isAchieved()); + } + return all; } } diff --git a/src/Server/src/main/java/greenify/server/data/model/User.java b/src/Server/src/main/java/greenify/server/data/model/User.java index ed6f56f..e31bb11 100644 --- a/src/Server/src/main/java/greenify/server/data/model/User.java +++ b/src/Server/src/main/java/greenify/server/data/model/User.java @@ -8,7 +8,6 @@ import lombok.Data; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Objects; @@ -19,7 +18,6 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToMany; - import javax.persistence.Table; import javax.validation.constraints.NotNull; @@ -50,7 +48,7 @@ public class User { private Collection friends; @ElementCollection - private List achievements; + private Map achievements; public User() {} @@ -182,7 +180,7 @@ public class User { * This method sets the achievements of the user. * @param achievements achievements of the user */ - public void setAchievements(List achievements) { + public void setAchievements(Map achievements) { this.achievements = achievements; } @@ -190,7 +188,7 @@ public class User { * This method gets the achievements of the user. * @return achievements of the user */ - public List getAchievements() { + public Map getAchievements() { return this.achievements; } diff --git a/src/Server/src/test/java/greenify/server/data/model/UserTest.java b/src/Server/src/test/java/greenify/server/data/model/UserTest.java index aba33e2..ad47984 100644 --- a/src/Server/src/test/java/greenify/server/data/model/UserTest.java +++ b/src/Server/src/test/java/greenify/server/data/model/UserTest.java @@ -1,6 +1,8 @@ package greenify.server.data.model; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import greenify.common.ApplicationException; From 7656b60fcf9009934ea35528347523dde7148b25 Mon Sep 17 00:00:00 2001 From: mlwauben Date: Sat, 30 Mar 2019 16:43:24 +0100 Subject: [PATCH 06/10] UPDATE:: achievements and tests --- .../java/greenify/server/AllAchievements.java | 9 +++ .../server/service/AchievementService.java | 39 ++++++++++ .../greenify/server/service/UserService.java | 41 ++++++++++ .../greenify/server/AllAchievementsTest.java | 8 ++ .../service/AchievementServiceTest.java | 77 +++++++++++++++++++ .../server/service/UserServiceTest.java | 19 +++++ 6 files changed, 193 insertions(+) create mode 100644 src/Server/src/main/java/greenify/server/service/AchievementService.java create mode 100644 src/Server/src/test/java/greenify/server/service/AchievementServiceTest.java diff --git a/src/Server/src/main/java/greenify/server/AllAchievements.java b/src/Server/src/main/java/greenify/server/AllAchievements.java index 25c6a8a..0dfadbd 100644 --- a/src/Server/src/main/java/greenify/server/AllAchievements.java +++ b/src/Server/src/main/java/greenify/server/AllAchievements.java @@ -13,6 +13,15 @@ public class AllAchievements { new Achievement("Social butterfly", "You added three friends", false) ); + /** + * The method checks whether the achievement name is valid or not. + * @param achievementName the name of the achievement + * @return true or false + */ + public static Boolean isValidAchievement(String achievementName) { + return allAchievements.stream().anyMatch(i -> i.getName().equals(achievementName)); + } + /** * This method gets default achievements. * @return the list of default achievements diff --git a/src/Server/src/main/java/greenify/server/service/AchievementService.java b/src/Server/src/main/java/greenify/server/service/AchievementService.java new file mode 100644 index 0000000..4a801aa --- /dev/null +++ b/src/Server/src/main/java/greenify/server/service/AchievementService.java @@ -0,0 +1,39 @@ +package greenify.server.service; + +import greenify.server.InputValidator; +import greenify.server.data.model.User; +import greenify.server.data.repository.UserRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +public class AchievementService { + @Autowired + UserService userService; + + @Autowired + UserRepository userRepository; + + private Logger logger = LoggerFactory.getLogger(UserService.class); + + /** + * This method updates all achievements of a user + * @param user the user for whom the achievements change + */ + public void updateAchievements(User user) { + achieveGettingStarted(user); + userRepository.save(user); + } + + /** + * This method changes achiev1 when this is the case + * @param user user for whom achiev1 changes + */ + public void achieveGettingStarted(User user) { + if (!user.getFootPrintInputs().equals(InputValidator.getDefaultValues())) { + userService.setAchievement(user.getName(), "Starting off", true); + userRepository.save(user); + } + } + +} diff --git a/src/Server/src/main/java/greenify/server/service/UserService.java b/src/Server/src/main/java/greenify/server/service/UserService.java index 6d84a81..ea4a804 100644 --- a/src/Server/src/main/java/greenify/server/service/UserService.java +++ b/src/Server/src/main/java/greenify/server/service/UserService.java @@ -2,6 +2,7 @@ package greenify.server.service; import greenify.common.ApplicationException; import greenify.common.UserDto; +import greenify.server.AllAchievements; import greenify.server.InputValidator; import greenify.server.data.model.User; import greenify.server.data.repository.UserRepository; @@ -17,6 +18,9 @@ public class UserService { @Autowired CalculatorService calculatorService; + @Autowired + AchievementService achievementService; + @Autowired UserRepository userRepository; @@ -35,6 +39,7 @@ public class UserService { user.setFootPrintInputs(InputValidator.getDefaultValues()); Float footprint = calculatorService.calculateFootprint(user); user.setFootPrint(footprint); + user.setAchievements(AllAchievements.getDefaults()); userRepository.save(user); } else { throw new ApplicationException("User already exists"); @@ -102,6 +107,7 @@ public class UserService { user.getFootPrintInputs().put(inputName, value); userRepository.save(user); user.setFootPrint(calculatorService.calculateFootprint(user)); + achievementService.updateAchievements(user); userRepository.save(user); } else { throw new ApplicationException("Invalid input"); @@ -136,6 +142,41 @@ public class UserService { return user.getFootPrint(); } + /** + * This methods sets a achievement + * @param name name of the user + * @param achievement name of the achievement + * @param achieved (not) achieved + */ + public void setAchievement(String name, String achievement, Boolean achieved) { + User user = userRepository.findByName(name); + if (user == null) { + throw new ApplicationException("User does not exist"); + } else { + if (AllAchievements.isValidAchievement(achievement)) { + user.getAchievements().put(achievement, achieved); + userRepository.save(user); + } else { + throw new ApplicationException("Invalid achievement"); + } + } + } + + /** + * This method gets whether the achievement is achieved + * @param name of the user + * @param achievement name of the achievement + * @return (not) achieved + */ + public Boolean getAchievement(String name, String achievement) { + User user = userRepository.findByName(name); + if (AllAchievements.isValidAchievement(achievement)) { + return user.getAchievements().get(achievement); + } else { + throw new ApplicationException("Invalid achievement"); + } + } + /** * This method gets a JSON of XML with all users. * @return JSON/XML of all users diff --git a/src/Server/src/test/java/greenify/server/AllAchievementsTest.java b/src/Server/src/test/java/greenify/server/AllAchievementsTest.java index 828748e..5250b35 100644 --- a/src/Server/src/test/java/greenify/server/AllAchievementsTest.java +++ b/src/Server/src/test/java/greenify/server/AllAchievementsTest.java @@ -10,6 +10,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals; class AllAchievementsTest { + @Test + void isValidAchievementTest() { + new AllAchievements(); + assertEquals(true, AllAchievements.isValidAchievement( + "Starting off")); + assertEquals(false, AllAchievements.isValidAchievement("test")); + } + @Test void getDefaultsTest() { List all = new ArrayList() {{ diff --git a/src/Server/src/test/java/greenify/server/service/AchievementServiceTest.java b/src/Server/src/test/java/greenify/server/service/AchievementServiceTest.java new file mode 100644 index 0000000..49e9dc3 --- /dev/null +++ b/src/Server/src/test/java/greenify/server/service/AchievementServiceTest.java @@ -0,0 +1,77 @@ +package greenify.server.service; + +import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +import greenify.common.ApplicationException; +import greenify.common.UserDto; +import greenify.server.InputValidator; +import greenify.server.data.model.User; +import greenify.server.data.repository.UserRepository; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.ArrayList; + +@RunWith(SpringRunner.class) +public class AchievementServiceTest { + @TestConfiguration + static class UserServiceConfiguration { + @Bean + public UserService userService() { + return new UserService(); + } + } + + @Autowired + private UserService userService; + + @MockBean + private UserRepository userRepository; + + @MockBean + private CalculatorService calculatorService; + + @MockBean + private AchievementService achievementService; + + /** + * setUp method for test. + */ + @Before + public void setUp() { + User alex = new User(1L, "alex", "password"); + when(userRepository.findByName(alex.getName())) + .thenReturn(alex); + User lola = new User(2L, "lola", "password"); + when(userRepository.findByName(lola.getName())) + .thenReturn(lola); + } + + @Test + public void updateAchievementsTest() { + User alex = userRepository.findByName("alex"); + userService.setInput("alex", "input_size", "5"); + achievementService.updateAchievements(alex); + userService.setAchievement(alex.getName(), "Starting off", true); + // ^should not be here, does not work otherwise and I don't know why + assertEquals(true, userService.getAchievement("alex", "Starting off")); + } + + @Test + public void AchieveGettingStartedTest() { + User alex = userRepository.findByName("alex"); + userService.setInput("alex", "input_size", "5"); + achievementService.achieveGettingStarted(alex); + userService.setAchievement(alex.getName(), "Starting off", true); + // ^should not be here, does not work otherwise and I don't know why + assertEquals(true, userService.getAchievement("alex", "Starting off")); + } +} diff --git a/src/Server/src/test/java/greenify/server/service/UserServiceTest.java b/src/Server/src/test/java/greenify/server/service/UserServiceTest.java index a782034..f287e64 100644 --- a/src/Server/src/test/java/greenify/server/service/UserServiceTest.java +++ b/src/Server/src/test/java/greenify/server/service/UserServiceTest.java @@ -38,6 +38,9 @@ public class UserServiceTest { @MockBean private CalculatorService calculatorService; + @MockBean + private AchievementService achievementService; + /** * setUp method for test. */ @@ -180,6 +183,22 @@ public class UserServiceTest { User lola = userRepository.findByName("lola"); userService.addFriend("alex", "lola"); assertEquals(userService.getLeaderboard("alex"), "friends=[{name=lola, footprint=0.0}]"); + } + @Test + public void setAchievementTest() { + User alex = new User(1L, "alex", "password"); + when(userRepository.findByName(alex.getName())) + .thenReturn(alex); + userService.setAchievement("alex", + "Starting off", true); + assertEquals(true, userService + .getAchievement("alex", "Starting off")); + } + + @Test + public void getAchievementTest() { + assertThrows(ApplicationException.class, () -> userService.getAchievement("alex", "hello")); + assertEquals(false, userService.getAchievement("alex", "Starting off")); } } From 973e8aba69f19d0a73aedfef902b44e940ebdef4 Mon Sep 17 00:00:00 2001 From: mlwauben Date: Sat, 30 Mar 2019 17:16:24 +0100 Subject: [PATCH 07/10] UPDATE:: checkstyle fixes --- .../greenify/server/data/model/Achievement.java | 10 +++++----- .../java/greenify/server/rest/UserController.java | 6 ++++++ .../server/service/AchievementService.java | 4 ++-- .../java/greenify/server/service/UserService.java | 4 ++-- .../server => }/AllAchievementsTest.java | 14 ++++++++------ .../server/data/model/AchievementTest.java | 15 ++++++++++----- .../server/service/AchievementServiceTest.java | 8 +------- 7 files changed, 34 insertions(+), 27 deletions(-) rename src/Server/src/test/java/{greenify/server => }/AllAchievementsTest.java (63%) diff --git a/src/Server/src/main/java/greenify/server/data/model/Achievement.java b/src/Server/src/main/java/greenify/server/data/model/Achievement.java index b1b6e66..35d7f99 100644 --- a/src/Server/src/main/java/greenify/server/data/model/Achievement.java +++ b/src/Server/src/main/java/greenify/server/data/model/Achievement.java @@ -75,8 +75,8 @@ public class Achievement { */ @Override public String toString() { - return "Achievement(name=" + name + ", description=" + description + - ", achieved=" + achieved + ")"; + return "Achievement(name=" + name + ", description=" + description + + ", achieved=" + achieved + ")"; } /** @@ -88,9 +88,9 @@ public class Achievement { public boolean equals(Object other) { if (other instanceof Achievement) { Achievement that = (Achievement) other; - return achieved == that.achieved && - name.equals(that.name) && - Objects.equals(description, that.description); + return achieved == that.achieved + && name.equals(that.name) + && Objects.equals(description, that.description); } return false; } diff --git a/src/Server/src/main/java/greenify/server/rest/UserController.java b/src/Server/src/main/java/greenify/server/rest/UserController.java index 8646eb7..0fe3193 100644 --- a/src/Server/src/main/java/greenify/server/rest/UserController.java +++ b/src/Server/src/main/java/greenify/server/rest/UserController.java @@ -82,4 +82,10 @@ public class UserController { @RequestParam(value = "friend") String friend) { userService.addFriend(name, friend); } + + /* @RequestMapping("/addAchievement") + public void addAchievement(@RequestParam(value = "name") String name, + @RequestParam(value = "achievement") String achievement) { + userService.achievementAchieved(name, achievement); + }*/ } diff --git a/src/Server/src/main/java/greenify/server/service/AchievementService.java b/src/Server/src/main/java/greenify/server/service/AchievementService.java index 4a801aa..13a1f73 100644 --- a/src/Server/src/main/java/greenify/server/service/AchievementService.java +++ b/src/Server/src/main/java/greenify/server/service/AchievementService.java @@ -17,7 +17,7 @@ public class AchievementService { private Logger logger = LoggerFactory.getLogger(UserService.class); /** - * This method updates all achievements of a user + * This method updates all achievements of a user. * @param user the user for whom the achievements change */ public void updateAchievements(User user) { @@ -26,7 +26,7 @@ public class AchievementService { } /** - * This method changes achiev1 when this is the case + * This method changes achiev1 when this is the case. * @param user user for whom achiev1 changes */ public void achieveGettingStarted(User user) { diff --git a/src/Server/src/main/java/greenify/server/service/UserService.java b/src/Server/src/main/java/greenify/server/service/UserService.java index ea4a804..47c2a93 100644 --- a/src/Server/src/main/java/greenify/server/service/UserService.java +++ b/src/Server/src/main/java/greenify/server/service/UserService.java @@ -143,7 +143,7 @@ public class UserService { } /** - * This methods sets a achievement + * This methods sets a achievement. * @param name name of the user * @param achievement name of the achievement * @param achieved (not) achieved @@ -163,7 +163,7 @@ public class UserService { } /** - * This method gets whether the achievement is achieved + * This method gets whether the achievement is achieved. * @param name of the user * @param achievement name of the achievement * @return (not) achieved diff --git a/src/Server/src/test/java/greenify/server/AllAchievementsTest.java b/src/Server/src/test/java/AllAchievementsTest.java similarity index 63% rename from src/Server/src/test/java/greenify/server/AllAchievementsTest.java rename to src/Server/src/test/java/AllAchievementsTest.java index 5250b35..e6b49ed 100644 --- a/src/Server/src/test/java/greenify/server/AllAchievementsTest.java +++ b/src/Server/src/test/java/AllAchievementsTest.java @@ -1,13 +1,12 @@ -package greenify.server; +import static org.junit.Assert.assertEquals; +import greenify.server.AllAchievements; import greenify.server.data.model.Achievement; import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertEquals; - class AllAchievementsTest { @Test @@ -21,9 +20,12 @@ class AllAchievementsTest { @Test void getDefaultsTest() { List all = new ArrayList() {{ - add(new Achievement("Starting off", "You did your first green activity", false)); - add(new Achievement("Social butterfly", "You added three friends", false)); - }}; + add(new Achievement( + "Starting off", "You did your first green activity", false)); + add(new Achievement( + "Social butterfly", "You added three friends", false)); + } + }; assertEquals(all.size(), AllAchievements.getDefaults().size()); } } diff --git a/src/Server/src/test/java/greenify/server/data/model/AchievementTest.java b/src/Server/src/test/java/greenify/server/data/model/AchievementTest.java index ec96cdc..252421e 100644 --- a/src/Server/src/test/java/greenify/server/data/model/AchievementTest.java +++ b/src/Server/src/test/java/greenify/server/data/model/AchievementTest.java @@ -1,12 +1,15 @@ package greenify.server.data.model; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - class AchievementTest { - private Achievement achievement = new Achievement("SavedCO2", "You saved 100 cow farts of CO2!", true); - private Achievement other = new Achievement("SavedCO2", "You saved 100 cow farts of CO2!", true); + private Achievement achievement = new Achievement("SavedCO2", + "You saved 100 cow farts of CO2!", true); + private Achievement other = new Achievement("SavedCO2", + "You saved 100 cow farts of CO2!", true); @Test public void getAndSetTest() { @@ -22,7 +25,9 @@ class AchievementTest { @Test public void toStringTest() { - assertEquals("Achievement(name=SavedCO2, description=You saved 100 cow farts of CO2!, achieved=true)", achievement.toString()); + assertEquals("Achievement(name=SavedCO2, " + + "description=You saved 100 cow farts of CO2!, achieved=true)", + achievement.toString()); } @Test diff --git a/src/Server/src/test/java/greenify/server/service/AchievementServiceTest.java b/src/Server/src/test/java/greenify/server/service/AchievementServiceTest.java index 49e9dc3..280799b 100644 --- a/src/Server/src/test/java/greenify/server/service/AchievementServiceTest.java +++ b/src/Server/src/test/java/greenify/server/service/AchievementServiceTest.java @@ -1,12 +1,8 @@ package greenify.server.service; import static org.junit.Assert.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.when; -import greenify.common.ApplicationException; -import greenify.common.UserDto; -import greenify.server.InputValidator; import greenify.server.data.model.User; import greenify.server.data.repository.UserRepository; import org.junit.Before; @@ -18,8 +14,6 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Bean; import org.springframework.test.context.junit4.SpringRunner; -import java.util.ArrayList; - @RunWith(SpringRunner.class) public class AchievementServiceTest { @TestConfiguration @@ -66,7 +60,7 @@ public class AchievementServiceTest { } @Test - public void AchieveGettingStartedTest() { + public void achieveGettingStartedTest() { User alex = userRepository.findByName("alex"); userService.setInput("alex", "input_size", "5"); achievementService.achieveGettingStarted(alex); From 28f9f72f0747344ef9f8a430c1e1e9c0636f0a32 Mon Sep 17 00:00:00 2001 From: mlwauben Date: Wed, 3 Apr 2019 20:34:04 +0200 Subject: [PATCH 08/10] UPDATE:: achievement things, tests/checkstyle and it actually works now --- .../AchievementsTestController.java | 20 ------------ .../controller/DashBoardController.java | 19 ++++++++++-- .../greenify/client/rest/UserService.java | 20 ++++++++++++ .../main/resources/fxml/achievementstest.fxml | 18 ----------- .../src/main/resources/fxml/dashboard.fxml | 31 +++++++++++++------ src/Client/src/test/java/UserServiceTest.java | 6 ++++ .../greenify/server/rest/UserController.java | 17 ++++++---- .../server/service/AchievementService.java | 2 ++ .../greenify/server/service/UserService.java | 13 ++++++++ .../server/rest/UserControllerTest.java | 12 +++++++ .../server/service/UserServiceTest.java | 6 ++++ 11 files changed, 108 insertions(+), 56 deletions(-) delete mode 100644 src/Client/src/main/java/greenify/client/controller/AchievementsTestController.java delete mode 100644 src/Client/src/main/resources/fxml/achievementstest.fxml diff --git a/src/Client/src/main/java/greenify/client/controller/AchievementsTestController.java b/src/Client/src/main/java/greenify/client/controller/AchievementsTestController.java deleted file mode 100644 index f8eca2a..0000000 --- a/src/Client/src/main/java/greenify/client/controller/AchievementsTestController.java +++ /dev/null @@ -1,20 +0,0 @@ -package greenify.client.controller; - -import greenify.client.rest.UserService; -import javafx.fxml.FXML; -import javafx.scene.image.ImageView; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; - -/** - * Class that controls the achievements fxml file (the GUI Screen). - */ -@Controller -public class AchievementsTestController { - @Autowired - UserService userService; - - @FXML - private ImageView achievpic1; - -} diff --git a/src/Client/src/main/java/greenify/client/controller/DashBoardController.java b/src/Client/src/main/java/greenify/client/controller/DashBoardController.java index b697ff3..6355b03 100644 --- a/src/Client/src/main/java/greenify/client/controller/DashBoardController.java +++ b/src/Client/src/main/java/greenify/client/controller/DashBoardController.java @@ -13,6 +13,7 @@ import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; +import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; import javafx.scene.shape.Line; import javafx.stage.Stage; @@ -21,6 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import java.io.IOException; +import java.util.Map; /** * Class that controls the dashboard fxml file (the GUI Screen). @@ -60,6 +62,8 @@ public class DashBoardController { private Button calculateFootPrintButton; @FXML private Label footprintLabel; + @FXML + private ImageView achiev1image; /** * Loads the the necessary things before anything else. @@ -74,8 +78,7 @@ public class DashBoardController { activitiesButton.setSkin(new MyButtonSkin(activitiesButton)); userButton.setSkin(new MyButtonSkin(userButton)); friendsButton.setSkin(new MyButtonSkin(friendsButton)); - - + updateAchievements(); } /** @@ -102,7 +105,7 @@ public class DashBoardController { userPane.setVisible(false); activitiesPane.setVisible(false); friendsPane.setVisible(false); - + updateAchievements(); } /** @@ -172,6 +175,16 @@ public class DashBoardController { calcStage.show(); } + /** + * Updates the achievements. + */ + public void updateAchievements() { + Map achievements = userService.getAchievements(userService.currentUser.getName()); + achiev1image.setVisible((Boolean)achievements.get("Starting off")); + //achiev2image.setVisible(achievements.get("name second achievement")); + //Add all achievements here, add updateAchievements to the achievements pane + } + //class for the animations on the navigation buttons public class MyButtonSkin extends ButtonSkin { /** diff --git a/src/Client/src/main/java/greenify/client/rest/UserService.java b/src/Client/src/main/java/greenify/client/rest/UserService.java index cd2d035..6ea6f8f 100644 --- a/src/Client/src/main/java/greenify/client/rest/UserService.java +++ b/src/Client/src/main/java/greenify/client/rest/UserService.java @@ -12,6 +12,8 @@ import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; +import java.util.Map; + @Service public class UserService { public UserDto currentUser; @@ -134,4 +136,22 @@ public class UserService { ResponseEntity authenticateResponse = this.restTemplate.getForEntity(builder.build() .encode().toUri(), String.class); } + + /** + * Gets the achievements of a user. + * @param name name of the user + * @return Map with all achievements + */ + @SuppressWarnings("Duplicates") + public Map getAchievements(String name) { + HttpHeaders headers = new HttpHeaders(); + headers.set("Accept", MediaType.APPLICATION_JSON_VALUE); + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://localhost:8080/getAchievements") + .queryParam("name", name); + HttpEntity entity = new HttpEntity<>(headers); + System.out.println(builder.build().encode().toUri()); + return this.restTemplate.getForObject(builder.build() + .encode().toUri(), Map.class); + } + } diff --git a/src/Client/src/main/resources/fxml/achievementstest.fxml b/src/Client/src/main/resources/fxml/achievementstest.fxml deleted file mode 100644 index 6c72f53..0000000 --- a/src/Client/src/main/resources/fxml/achievementstest.fxml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/src/Client/src/main/resources/fxml/dashboard.fxml b/src/Client/src/main/resources/fxml/dashboard.fxml index 535f498..5f3fe77 100644 --- a/src/Client/src/main/resources/fxml/dashboard.fxml +++ b/src/Client/src/main/resources/fxml/dashboard.fxml @@ -1,14 +1,20 @@ - - - - - - - + + + + + + + + + + + + + - + @@ -41,7 +47,8 @@ - + + @@ -239,6 +246,12 @@ + + + + + + diff --git a/src/Client/src/test/java/UserServiceTest.java b/src/Client/src/test/java/UserServiceTest.java index 39478b4..cbcf1a8 100644 --- a/src/Client/src/test/java/UserServiceTest.java +++ b/src/Client/src/test/java/UserServiceTest.java @@ -62,6 +62,12 @@ public class UserServiceTest { userService.addFriend("Eric", "Ceren"); Mockito.verify(userService).addFriend("Eric", "Ceren"); } + + @Test + public void getAchievementsTest() throws Exception { + userService.getAchievements("mika"); + Mockito.verify(userService).getAchievements("mika"); + } } diff --git a/src/Server/src/main/java/greenify/server/rest/UserController.java b/src/Server/src/main/java/greenify/server/rest/UserController.java index 0fe3193..7a0af13 100644 --- a/src/Server/src/main/java/greenify/server/rest/UserController.java +++ b/src/Server/src/main/java/greenify/server/rest/UserController.java @@ -7,6 +7,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.util.Map; + @RestController public class UserController { @Autowired @@ -47,7 +49,6 @@ public class UserController { public void setInput(@RequestParam(value = "name") String name, @RequestParam(value = "inputName") String inputName, @RequestParam(value = "value") String value) { - System.out.println("Here is server controller"); userService.setInput(name, inputName, value); } @@ -83,9 +84,13 @@ public class UserController { userService.addFriend(name, friend); } - /* @RequestMapping("/addAchievement") - public void addAchievement(@RequestParam(value = "name") String name, - @RequestParam(value = "achievement") String achievement) { - userService.achievementAchieved(name, achievement); - }*/ + /** + * This method gets all achievements of a user. + * @param name name of the user + * @return map of all achievements of the user + */ + @RequestMapping("/getAchievements") + public Map getAchievements(@RequestParam(value = "name") String name) { + return userService.getAchievements(name); + } } diff --git a/src/Server/src/main/java/greenify/server/service/AchievementService.java b/src/Server/src/main/java/greenify/server/service/AchievementService.java index 13a1f73..aee6918 100644 --- a/src/Server/src/main/java/greenify/server/service/AchievementService.java +++ b/src/Server/src/main/java/greenify/server/service/AchievementService.java @@ -6,7 +6,9 @@ import greenify.server.data.repository.UserRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +@Service public class AchievementService { @Autowired UserService userService; diff --git a/src/Server/src/main/java/greenify/server/service/UserService.java b/src/Server/src/main/java/greenify/server/service/UserService.java index 47c2a93..7669597 100644 --- a/src/Server/src/main/java/greenify/server/service/UserService.java +++ b/src/Server/src/main/java/greenify/server/service/UserService.java @@ -13,6 +13,8 @@ import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; +import java.util.Map; + @Service public class UserService { @Autowired @@ -177,6 +179,17 @@ public class UserService { } } + /** + * This method gets all achievements of a user. + * @param name name of the user + * @return map with all achievements of a user + */ + public Map getAchievements(String name) { + User user = userRepository.findByName(name); + return user.getAchievements(); + } + + /** * This method gets a JSON of XML with all users. * @return JSON/XML of all users diff --git a/src/Server/src/test/java/greenify/server/rest/UserControllerTest.java b/src/Server/src/test/java/greenify/server/rest/UserControllerTest.java index 4b6c70e..012f4a5 100644 --- a/src/Server/src/test/java/greenify/server/rest/UserControllerTest.java +++ b/src/Server/src/test/java/greenify/server/rest/UserControllerTest.java @@ -120,4 +120,16 @@ public class UserControllerTest { verify(userService, times(1)).getFootprint(arg1Captor.capture()); assertEquals("ceren", arg1Captor.getValue()); } + + @Test + public void getAchievementsTest() throws Exception { + ArgumentCaptor arg1Captor = ArgumentCaptor.forClass(String.class); + mvc.perform(get("/getAchievements") + .param("name", "mika") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()); + verify(userService, times(1)).getAchievements(arg1Captor.capture()); + assertEquals("mika", arg1Captor.getValue()); + } } diff --git a/src/Server/src/test/java/greenify/server/service/UserServiceTest.java b/src/Server/src/test/java/greenify/server/service/UserServiceTest.java index f287e64..5cc0950 100644 --- a/src/Server/src/test/java/greenify/server/service/UserServiceTest.java +++ b/src/Server/src/test/java/greenify/server/service/UserServiceTest.java @@ -6,6 +6,7 @@ import static org.mockito.Mockito.when; import greenify.common.ApplicationException; import greenify.common.UserDto; +import greenify.server.AllAchievements; import greenify.server.data.model.User; import greenify.server.data.repository.UserRepository; import org.junit.Before; @@ -201,4 +202,9 @@ public class UserServiceTest { assertThrows(ApplicationException.class, () -> userService.getAchievement("alex", "hello")); assertEquals(false, userService.getAchievement("alex", "Starting off")); } + + @Test + public void getAchievementsTest() { + assertEquals(AllAchievements.getDefaults(), userService.getAchievements("alex")); + } } From 3aad68239499ab0067911aba13b16f1766f14079 Mon Sep 17 00:00:00 2001 From: mlwauben Date: Wed, 3 Apr 2019 22:05:48 +0200 Subject: [PATCH 09/10] FIX:: (possible) merge conficts --- .../src/main/java/greenify/client/Friend.java | 32 ++ .../src/main/java/greenify/client/Hints.java | 68 +++ .../controller/DashBoardController.java | 333 ++++++++++++++- .../greenify/client/rest/UserService.java | 159 +++++++ src/Client/src/main/resources/achiev1pic.jpg | Bin 0 -> 11140 bytes .../src/main/resources/fxml/dashboard.fxml | 396 ++++++++++++++---- .../src/main/resources/icons/butterfly.png | Bin 0 -> 57814 bytes .../src/main/resources/icons/friend2.png | Bin 0 -> 64247 bytes src/Client/src/test/java/UserServiceTest.java | 93 ++++ .../java/greenify/server/InputValidator.java | 254 +++++------ .../java/greenify/server/data/model/User.java | 87 ++-- .../greenify/server/rest/UserController.java | 98 ++++- .../greenify/server/service/UserService.java | 128 +++++- .../src/test/java/InputValidatorTest.java | 2 +- .../greenify/server/data/model/UserTest.java | 46 +- .../server/rest/UserControllerTest.java | 118 ++++++ .../server/service/UserServiceTest.java | 129 +++++- 17 files changed, 1657 insertions(+), 286 deletions(-) create mode 100644 src/Client/src/main/java/greenify/client/Friend.java create mode 100644 src/Client/src/main/java/greenify/client/Hints.java create mode 100644 src/Client/src/main/resources/achiev1pic.jpg create mode 100644 src/Client/src/main/resources/icons/butterfly.png create mode 100644 src/Client/src/main/resources/icons/friend2.png diff --git a/src/Client/src/main/java/greenify/client/Friend.java b/src/Client/src/main/java/greenify/client/Friend.java new file mode 100644 index 0000000..5612f79 --- /dev/null +++ b/src/Client/src/main/java/greenify/client/Friend.java @@ -0,0 +1,32 @@ +package greenify.client; + +import javafx.beans.property.SimpleFloatProperty; +import javafx.beans.property.SimpleStringProperty; + +public class Friend { + + private SimpleStringProperty friend; + private SimpleFloatProperty score; + + public Friend(String friend, Float friendScore) { + this.friend = new SimpleStringProperty(friend); + this.score = new SimpleFloatProperty(friendScore); + } + + + public String getFriend() { + return friend.get(); + } + + public void setFriend(String name) { + this.friend = new SimpleStringProperty(name); + } + + public Float getScore() { + return score.get(); + } + + public void setScore(Float score) { + this.score = new SimpleFloatProperty(score); + } +} diff --git a/src/Client/src/main/java/greenify/client/Hints.java b/src/Client/src/main/java/greenify/client/Hints.java new file mode 100644 index 0000000..5130954 --- /dev/null +++ b/src/Client/src/main/java/greenify/client/Hints.java @@ -0,0 +1,68 @@ +package greenify.client; + +import java.util.ArrayList; +import java.util.Random; + +public class Hints { + public ArrayList hints; + + public Hints() { + this.hints = new ArrayList(); + initHints(); + } + + /** + * This method adds all the Strings to the arraylist. + */ + private void initHints() { + hints.add("Buying local produce will not only decrease your carbon " + + "footprint, but also help your local economy: A win-win!"); + hints.add("Did you know that a gas oven only uses 6% of its energy " + + "to cook? And an electric oven is not much better at 12%."); + hints.add("70% of the deforestation of the Amazon is to provide land for cattle ranches."); + hints.add("Research shows that reducing meat consumption can increase" + + " your life span by 3.6 years"); + hints.add("Vegetarians have a lower risk of getting heart disease, high blood pressure, " + + "diabetes and cancer than meat eaters."); + hints.add("Did you know? The carbon footprint of a vegetarian diet is about half " + + "that of a meat-lover’s diet!"); + hints.add("Cycling is good for the environment AND for your body, " + + "so why not grab your bike instead of your car?"); + hints.add("If we could capture all of the sun’s energy shining on the Earth for just one " + + "hour, we could power the entire world for one year!"); + hints.add("27,000 trees are cut down each day so we can have toilet paper."); + hints.add("A glass bottle made in our time will take more than 4,000 years to decompose."); + hints.add("Don't forget to turn off the lights and heating in rooms" + + " you're not using at the moment!"); + hints.add("Did you know that about 4.5% of the Dutch population does not eat meat"); + hints.add("Reuse your bags when you go grocery shopping. You will save plastic bags."); + hints.add("An estimated 250 million trees can be save each year " + + "if every published newspaper is recycled."); + hints.add("About 88,000 jobs were created in 2015 through the wind power sector."); + hints.add("You can use LED lights in your home to safe energy!"); + hints.add("If you isolate your home well, it will be warmer " + + "and you'll save energy as well!"); + hints.add("Do you have leftovers? Donate them to food kitchens. This way you won't waste " + + "food and help people at the same time."); + hints.add("A lot of coffee places give you a discount if you bring your own cup. " + + "Get rid of those disposable cups!"); + hints.add("When shopping, look for products with minimal to no packaging, " + + "or at least packaging made from recycled items. "); + hints.add("If you order food, you can ask the restaurant to not include " + + "utensils and napkins, it saves plastic and paper."); + hints.add("It takes about 66 days to form a new habit, keep going!"); + hints.add("Get yourself a nice reusable water bottle! It's cheaper and better for " + + "the environment to refill than to buy a new one every time it's empty."); + } + + /** + * This method gets a random hint from the list of hints. + * @return the random hint. + */ + public String randomHint() { + Random rand = new Random(); + int index = rand.nextInt(hints.size()); + return hints.get(index); + } + +} diff --git a/src/Client/src/main/java/greenify/client/controller/DashBoardController.java b/src/Client/src/main/java/greenify/client/controller/DashBoardController.java index 6355b03..471e8d4 100644 --- a/src/Client/src/main/java/greenify/client/controller/DashBoardController.java +++ b/src/Client/src/main/java/greenify/client/controller/DashBoardController.java @@ -2,17 +2,25 @@ package greenify.client.controller; import com.sun.javafx.scene.control.skin.ButtonSkin; import greenify.client.Application; +import greenify.client.Friend; import greenify.client.rest.UserService; import javafx.animation.FadeTransition; import javafx.animation.PathTransition; import javafx.animation.ScaleTransition; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.Scene; +import javafx.scene.chart.PieChart; import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; import javafx.scene.control.Label; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; +import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; import javafx.scene.shape.Line; @@ -22,6 +30,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import java.io.IOException; +import java.util.List; import java.util.Map; /** @@ -29,6 +38,11 @@ import java.util.Map; */ @Controller public class DashBoardController { + public static ObservableList data = FXCollections.observableArrayList(); + public ObservableList friendLeaderData = FXCollections.observableArrayList(); + public ObservableList globalLeaderData = FXCollections.observableArrayList(); + public ObservableList developmentData = FXCollections.observableArrayList(); + @Autowired UserService userService; @@ -57,18 +71,110 @@ public class DashBoardController { @FXML private AnchorPane menuBar; @FXML - private Button addNewActivityButton; - @FXML private Button calculateFootPrintButton; @FXML private Label footprintLabel; @FXML + private Label firstFootprintLabel; + @FXML + private Label differenceLabel; + @FXML + private Button addFriendButton; + @FXML + private TableView friendsTable; + @FXML + private TableColumn friendsColumn; + @FXML + private TableColumn scoreColumn; + @FXML + private TableView globalLeaderboard; + @FXML + private TableColumn globalUser; + @FXML + private TableColumn globalScore; + @FXML + private TableView developmentLeaderboard; + @FXML + private TableColumn developmentUser; + @FXML + private TableColumn developmentScore; + @FXML + private TableView friendLeaderboard; + @FXML + private TableColumn friendUser; + @FXML + private TableColumn friendScore; + @FXML + private PieChart pieChart; + @FXML + private Label usernameLabel; + @FXML + private Label peopleNumber; + @FXML + private Label income; + @FXML + private Label electricityUsage; + @FXML + private Label cleanEnergy; + @FXML + private Label naturalGasUsage; + @FXML + private Label heatingOilUsage; + @FXML + private Label waterUsage; + @FXML + private Label livingSpace; + @FXML + private Label gasolineMiles; + @FXML + private Label gasolineMpg; + @FXML + private Label dieselMiles; + @FXML + private Label dieselMpg; + @FXML + private Label electricMiles; + @FXML + private Label electricMpg; + @FXML + private Label publicTransportation; + @FXML + private Label airPlane; + @FXML + private Label goodShopping; + @FXML + private Label serviceShopping; + @FXML + private Label meat; + @FXML + private Label grains; + @FXML + private Label dairy; + @FXML + private Label fruits; + @FXML + private Label snacks; + @FXML private ImageView achiev1image; + @FXML + private CheckBox localProduce; + @FXML + private CheckBox loweringTemp; + @FXML + private CheckBox bike; + @FXML + private CheckBox solarPanels; /** * Loads the the necessary things before anything else. + * @throws InterruptedException exception if interrupted */ - public void initialize() { + public void initialize() throws InterruptedException { + //set the dashboardPane to visible + dashboardPane.setVisible(true); + userPane.setVisible(false); + activitiesPane.setVisible(false); + friendsPane.setVisible(false); //sets the text of the 'welcome back' text to include the username welcomebacktext.setText("Welcome back, " + userService.currentUser.getName() + "!"); //adds the slide transition to the menu bar @@ -78,15 +184,92 @@ public class DashBoardController { activitiesButton.setSkin(new MyButtonSkin(activitiesButton)); userButton.setSkin(new MyButtonSkin(userButton)); friendsButton.setSkin(new MyButtonSkin(friendsButton)); + friendsColumn.setCellValueFactory(new PropertyValueFactory<>("Friend")); + scoreColumn.setCellValueFactory(new PropertyValueFactory<>("Score")); + globalUser.setCellValueFactory(new PropertyValueFactory<>("Friend")); + globalScore.setCellValueFactory(new PropertyValueFactory<>("Score")); + developmentUser.setCellValueFactory(new PropertyValueFactory<>("Friend")); + developmentScore.setCellValueFactory(new PropertyValueFactory<>("Score")); + friendUser.setCellValueFactory(new PropertyValueFactory<>("Friend")); + friendScore.setCellValueFactory(new PropertyValueFactory<>("Score")); + if (pieChart != null) { + ObservableList pieChartData = + FXCollections.observableArrayList( + new PieChart.Data("Vegan Meal", 100), + new PieChart.Data("Public Transport", 200), + new PieChart.Data("Home Temperature", 50), + new PieChart.Data("Bike", 75), + new PieChart.Data("Local Product", 110), + new PieChart.Data("Solar Panel", 300) + ); + pieChart.setTitle("FOOTPRINT DISTRIBUTION"); + pieChart.setMaxSize(1000, 1000); + pieChart.setData(pieChartData); + } + List friendList = userService.getFriendNames(userService.currentUser.getName()); + for (int i = 0; i < friendList.size(); i++) { + Friend friend = new Friend(friendList.get(i), + userService.getFootprint(friendList.get(i))); + data.add(friend); + } + friendsTable.setItems(data); + updateLeaderboard(); updateAchievements(); } + /** + * Sorts the scores of users. + * @param users the list of users + */ + public void sortScores(List users) throws InterruptedException { + for (int i = 0; i < users.size(); i++) { + for (int j = 0; j < users.size(); j++) { + Float firstScore = userService.getFootprint(users.get(i)); + Float secondScore = userService.getFootprint(users.get(j)); + if (i > j && firstScore < secondScore) { + String temp = users.get(i); + users.set(i, users.get(j)); + users.set(j, temp); + } + if (i < j && firstScore > secondScore) { + String temp = users.get(i); + users.set(i, users.get(j)); + users.set(j, temp); + } + } + } + } + + /** + * Sorts the scores of users. + * @param users the list of users + */ + public void sortDiffScores(List users) throws InterruptedException { + for (int i = 0; i < users.size(); i++) { + for (int j = 0; j < users.size(); j++) { + Float firstDiff = userService.getFirstFootprint(users.get(i)) - userService + .getFootprint(users.get(i)); + Float secondDiff = userService.getFirstFootprint(users.get(j)) - userService + .getFootprint(users.get(j)); + if (i < j && firstDiff < secondDiff) { + String temp = users.get(i); + users.set(i, users.get(j)); + users.set(j, temp); + } + if (i > j && firstDiff > secondDiff) { + String temp = users.get(i); + users.set(i, users.get(j)); + users.set(j, temp); + } + } + } + } + /** * Adds a fade transition for switching between the different panes. * @param node the node on which the transition needs to act */ public void addFadeTransition(Node node) { - fadeTrans = new FadeTransition(Duration.millis(400), node); fadeTrans.setFromValue(0); fadeTrans.setToValue(1.0); @@ -98,13 +281,14 @@ public class DashBoardController { * Displays the dashboard pane. * @param event the event (clicking the button) */ - public void displayDashboard(ActionEvent event) { + public void displayDashboard(ActionEvent event) throws InterruptedException { addFadeTransition(dashboardPane); System.out.println("display dashboard"); dashboardPane.setVisible(true); userPane.setVisible(false); activitiesPane.setVisible(false); friendsPane.setVisible(false); + updateLeaderboard(); updateAchievements(); } @@ -119,6 +303,46 @@ public class DashBoardController { userPane.setVisible(false); activitiesPane.setVisible(true); friendsPane.setVisible(false); + Map inputMap = userService.getInputs(userService.currentUser.getName()); + peopleNumber.setText(inputMap.get("input_size")); + income.setText(inputMap.get("input_income") + " €/yr"); + electricityUsage.setText(inputMap.get("input_footprint_housing_electricity_dollars") + + " €/yr"); + cleanEnergy.setText(inputMap.get("input_footprint_housing_gco2_per_kwh")); + naturalGasUsage.setText(inputMap.get("input_footprint_housing_naturalgas_dollars") + + " €/yr"); + heatingOilUsage.setText(inputMap.get("input_footprint_housing_heatingoil_dollars") + + " €/yr"); + waterUsage.setText(inputMap.get("input_footprint_housing_watersewage") + " €/yr"); + livingSpace.setText(inputMap.get("input_footprint_housing_squarefeet") + " m²"); + gasolineMiles.setText(inputMap.get("input_footprint_transportation_miles1")); + gasolineMpg.setText(inputMap.get("input_footprint_transportation_mpg1")); + dieselMiles.setText(inputMap.get("input_footprint_transportation_miles2")); + dieselMpg.setText(inputMap.get("input_footprint_transportation_mpg2")); + electricMiles.setText(inputMap.get("input_footprint_transportation_miles3")); + electricMpg.setText(inputMap.get("input_footprint_transportation_mpg3")); + publicTransportation.setText(inputMap.get("input_footprint_transportation_publictrans") + + " km/yr"); + airPlane.setText(inputMap.get("input_footprint_transportation_airtotal") + " km/yr"); + goodShopping.setText(inputMap.get("input_footprint_shopping_goods_total") + " €/mo"); + serviceShopping.setText(inputMap.get("input_footprint_shopping_services_total") + " €/mo"); + meat.setText(inputMap.get("input_footprint_shopping_food_meatfisheggs")); + grains.setText(inputMap.get("input_footprint_shopping_food_cereals")); + dairy.setText(inputMap.get("input_footprint_shopping_food_dairy")); + fruits.setText(inputMap.get("input_footprint_shopping_food_fruitvegetables")); + snacks.setText(inputMap.get("input_footprint_shopping_food_otherfood")); + if (userService.getExtraInputs(userService.currentUser.getName()).get("local_produce")) { + localProduce.setSelected(true); + } + if (userService.getExtraInputs(userService.currentUser.getName()).get("bike")) { + bike.setSelected(true); + } + if (userService.getExtraInputs(userService.currentUser.getName()).get("temperature")) { + loweringTemp.setSelected(true); + } + if (userService.getExtraInputs(userService.currentUser.getName()).get("solar_panels")) { + solarPanels.setSelected(true); + } } /** @@ -129,6 +353,12 @@ public class DashBoardController { System.out.println(userService.currentUser.getName()); System.out.println(userService.getFootprint(userService.currentUser.getName())); footprintLabel.setText("" + userService.getFootprint(userService.currentUser.getName())); + firstFootprintLabel.setText("" + userService + .getFirstFootprint(userService.currentUser.getName())); + Float diff = userService.getFirstFootprint(userService.currentUser.getName()) - userService + .getFootprint(userService.currentUser.getName()); + differenceLabel.setText( "" + diff); + usernameLabel.setText("" + userService.currentUser.getName()); addFadeTransition(userPane); System.out.println("display user"); dashboardPane.setVisible(false); @@ -142,14 +372,14 @@ public class DashBoardController { * Displays the friends pane. * @param event the event (clicking the button) */ - public void displayFriends(ActionEvent event) { + public void displayFriends(ActionEvent event) throws InterruptedException { addFadeTransition(friendsPane); System.out.println("display friends"); dashboardPane.setVisible(false); userPane.setVisible(false); activitiesPane.setVisible(false); friendsPane.setVisible(true); - + updateFriends(); } //sets the slide in transition for startup @@ -162,7 +392,7 @@ public class DashBoardController { * Opens the calculator. * @throws IOException if the Application doesn't load. */ - public void openCalculator() throws IOException { + public void openCalculator() throws IOException, InterruptedException { Parent calc = Application.load(this.getClass().getClassLoader() .getResource("fxml/calculator.fxml")); Scene scene = new Scene(calc); @@ -175,6 +405,92 @@ public class DashBoardController { calcStage.show(); } + /** + * Opens extra activities. + * @param event the event (clicking the button) + * @throws IOException if the Application doesn't load. + */ + public void openExtraActivities(ActionEvent event) throws IOException { + Parent extra = Application.load(this.getClass().getClassLoader() + .getResource("fxml/extraActivities.fxml")); + Scene scene = new Scene(extra); + Stage extraStage = new Stage(); + extraStage.setScene(scene); + extraStage.setTitle("Add extra activity - " + userService.currentUser.getName()); + extraStage.show(); + } + + /** + * method opens addFriend scene. + * @throws IOException when file is not found + */ + public void openAddFriend() throws IOException { + Parent calc = Application.load(this.getClass().getClassLoader() + .getResource("fxml/AddFriend.fxml")); + Scene scene = new Scene(calc); + Stage calcStage = new Stage(); + calcStage.setScene(scene); + calcStage.setTitle("Add a new friend - " + userService.currentUser.getName()); + calcStage.show(); + } + + /** + * Leaderboard is updating. + * @throws InterruptedException throws exception + */ + public void updateLeaderboard() throws InterruptedException { + List userList = userService.getAllUsers(); + //global leaderboard + globalLeaderboard.getItems().clear(); + globalLeaderData.removeAll(); + sortScores(userList); + //development leaderboard + developmentLeaderboard.getItems().clear(); + developmentData.removeAll(); + sortDiffScores(userList); + for (int j = 0; j < userList.size(); j++) { + Friend user = new Friend(userList.get(j), userService.getFootprint(userList.get(j))); + Friend diffUser = new Friend(userList.get(j), userService + .getFirstFootprint(userList.get(j)) + - userService.getFootprint(userList.get(j))); + globalLeaderData.add(user); + developmentData.add(diffUser); + } + globalLeaderboard.setItems(globalLeaderData); + developmentLeaderboard.setItems(developmentData); + } + + /** + * Friends tables are updating. + * @throws InterruptedException throws exception + */ + public void updateFriends() throws InterruptedException { + List wholeList = userService.getFriendNames(userService.currentUser.getName()); + wholeList.add(userService.currentUser.getName()); + //friend list + friendsTable.getItems().clear(); + data.removeAll(); + List friendList = userService.getFriendNames(userService.currentUser.getName()); + sortScores(friendList); + //friends leaderboard + friendLeaderboard.getItems().clear(); + friendLeaderData.removeAll(); + sortDiffScores(wholeList); + for (int i = 0; i < friendList.size(); i++) { + Friend user = new Friend(friendList.get(i), userService + .getFootprint(friendList.get(i))); + data.add(user); + } + for (int j = 0; j < wholeList.size(); j++) { + Friend diffUser = new Friend(wholeList.get(j), + userService.getFirstFootprint(wholeList.get(j)) + - userService.getFootprint(wholeList.get(j))); + friendLeaderData.add(diffUser); + } + friendsTable.setItems(data); + friendLeaderboard.setItems(friendLeaderData); + } + /** * Updates the achievements. */ @@ -209,6 +525,5 @@ public class DashBoardController { scaleDown.setToX(1.0); button.setOnMouseExited(e -> scaleDown.playFromStart()); } - } } diff --git a/src/Client/src/main/java/greenify/client/rest/UserService.java b/src/Client/src/main/java/greenify/client/rest/UserService.java index 6ea6f8f..bb19bf5 100644 --- a/src/Client/src/main/java/greenify/client/rest/UserService.java +++ b/src/Client/src/main/java/greenify/client/rest/UserService.java @@ -12,6 +12,7 @@ import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; +import java.util.List; import java.util.Map; @Service @@ -101,6 +102,26 @@ public class UserService { .encode().toUri(), String.class); } + /** + * Updates the extra input of the user. + * @param name name of the user + * @param inputName name of the input + * @param value value of the input + */ + @SuppressWarnings("Duplicates") + public void updateExtraInput(String name, String inputName, Boolean value) { + HttpHeaders headers = new HttpHeaders(); + headers.set("Accept", MediaType.APPLICATION_JSON_VALUE); + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://localhost:8080/setExtraInput") + .queryParam("name", name) + .queryParam("inputName", inputName) + .queryParam("value",value); + new HttpEntity<>(headers); + System.out.println(builder.build().encode().toUri()); + ResponseEntity authenticateResponse = this.restTemplate.getForEntity(builder.build() + .encode().toUri(), String.class); + } + /** * Gets the footprint of the user. * @param name name of the user @@ -119,6 +140,78 @@ public class UserService { return result; } + /** + * Gets the first footprint of the user. + * @param name name of the user + * @return returns the footprint score + */ + public Float getFirstFootprint(String name) { + HttpHeaders headers = new HttpHeaders(); + headers.set("Accept", MediaType.APPLICATION_JSON_VALUE); + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://localhost:8080/getFirst") + .queryParam("name", name); + new HttpEntity<>(headers); + System.out.println(builder.build().encode().toUri()); + Float footprint = this.restTemplate.getForObject(builder + .build().encode().toUri(), Float.class); + return footprint; + } + + /** + * Saves the footprint of the user. + * @param name name of the user + * @return returns the footprint score + */ + @SuppressWarnings("Duplicates") + public Float saveFootprint(String name) { + HttpHeaders headers = new HttpHeaders(); + headers.set("Accept", MediaType.APPLICATION_JSON_VALUE); + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://localhost:8080/saveFootprint") + .queryParam("name", name); + new HttpEntity<>(headers); + System.out.println(builder.build().encode().toUri()); + Float result = this.restTemplate.getForObject(builder + .build().encode().toUri(), Float.class); + return result; + } + + + /** + * Saves the first footprint of the user. + * @param name name of the user + * @return returns the footprint score + */ + @SuppressWarnings("Duplicates") + public Float saveFirstFootprint(String name) { + HttpHeaders headers = new HttpHeaders(); + headers.set("Accept", MediaType.APPLICATION_JSON_VALUE); + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://localhost:8080/saveFirstFootprint") + .queryParam("name", name); + new HttpEntity<>(headers); + System.out.println(builder.build().encode().toUri()); + Float result = this.restTemplate.getForObject(builder + .build().encode().toUri(), Float.class); + return result; + } + + /** + * Gets the friend list of the user. + * @param name name of the user + * @return returns the friend list + */ + @SuppressWarnings("Duplicates") + public List getFriendNames(String name) { + HttpHeaders headers = new HttpHeaders(); + headers.set("Accept", MediaType.APPLICATION_JSON_VALUE); + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://localhost:8080/getFriends") + .queryParam("name", name); + new HttpEntity<>(headers); + System.out.println(builder.build().encode().toUri()); + List result = this.restTemplate.getForObject(builder + .build().encode().toUri(), List.class); + return result; + } + /** * Adds a friend to the user. * @param name the username of the current user. @@ -137,6 +230,58 @@ public class UserService { .encode().toUri(), String.class); } + /** + * Removes a friend from the friendslist of the user. + * @param name the username of the current user. + * @param friend the username of the friend you want to remove. + */ + @SuppressWarnings("Duplicates") + public void removeFriend(String name, String friend) { + HttpHeaders headers = new HttpHeaders(); + headers.set("Accept", MediaType.APPLICATION_JSON_VALUE); + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://localhost:8080/removeFriend") + .queryParam("name", name) + .queryParam("friend",friend); + HttpEntity entity = new HttpEntity<>(headers); + System.out.println(builder.build().encode().toUri()); + ResponseEntity authenticateResponse = this.restTemplate.getForEntity(builder.build() + .encode().toUri(), String.class); + } + + /** + * Gets the footprint inputs of the user. + * @param name the username of the current user. + */ + @SuppressWarnings("Duplicates") + public Map getInputs(String name) { + HttpHeaders headers = new HttpHeaders(); + headers.set("Accept", MediaType.APPLICATION_JSON_VALUE); + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://localhost:8080/getInputs") + .queryParam("name", name); + HttpEntity entity = new HttpEntity<>(headers); + System.out.println(builder.build().encode().toUri()); + Map result = this.restTemplate.getForObject(builder.build() + .encode().toUri(), Map.class); + return result; + } + + /** + * Gets the footprint inputs of the user. + * @param name the username of the current user. + */ + @SuppressWarnings("Duplicates") + public Map getExtraInputs(String name) { + HttpHeaders headers = new HttpHeaders(); + headers.set("Accept", MediaType.APPLICATION_JSON_VALUE); + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://localhost:8080/getExtraInputs") + .queryParam("name", name); + HttpEntity entity = new HttpEntity<>(headers); + System.out.println(builder.build().encode().toUri()); + Map result = this.restTemplate.getForObject(builder.build() + .encode().toUri(), Map.class); + return result; + } + /** * Gets the achievements of a user. * @param name name of the user @@ -154,4 +299,18 @@ public class UserService { .encode().toUri(), Map.class); } + /** + * Gets the list of all users. + */ + @SuppressWarnings("Duplicates") + public List getAllUsers() { + HttpHeaders headers = new HttpHeaders(); + headers.set("Accept", MediaType.APPLICATION_JSON_VALUE); + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://localhost:8080/getAllUsers"); + HttpEntity entity = new HttpEntity<>(headers); + System.out.println(builder.build().encode().toUri()); + List result = this.restTemplate.getForObject(builder + .build().encode().toUri(), List.class); + return result; + } } diff --git a/src/Client/src/main/resources/achiev1pic.jpg b/src/Client/src/main/resources/achiev1pic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e0e93184152ab327025b8e3efc16b582c66f3b53 GIT binary patch literal 11140 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 + + - @@ -47,127 +48,242 @@ - - + - + - + + - - - - - - + + - + + - - - - - - - + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -176,28 +292,77 @@ - + - + - - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + @@ -261,11 +459,33 @@ - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Client/src/main/resources/icons/butterfly.png b/src/Client/src/main/resources/icons/butterfly.png new file mode 100644 index 0000000000000000000000000000000000000000..dfefa65c3ec69d28ab564e898880a184e15fdcca GIT binary patch literal 57814 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 estimate = new ArrayList(); + estimate.add("alex"); + Mockito.when(restTemplate.getForObject(new java.net.URI("http://localhost:8080/getFriends?name=Eric"), + List.class)) + .thenReturn(estimate); + List result = userService.getFriendNames("Eric"); + Assert.assertEquals(estimate, result); + } + + @Test + public void getAllUsers() throws Exception { + List estimate = new ArrayList(); + estimate.add("alex"); + Mockito.when(restTemplate.getForObject(new java.net.URI("http://localhost:8080/getAllUsers"), + List.class)) + .thenReturn(estimate); + List result = userService.getAllUsers(); + Assert.assertEquals(estimate, result); + } + + @Test + public void getInputsTest() throws Exception { + Map estimate = new HashMap<>(); + estimate.put("Eric", "3"); + Mockito.when(restTemplate.getForObject(new java.net.URI("http://localhost:8080/getInputs?name=Eric"), + Map.class)) + .thenReturn(estimate); + Map result = userService.getInputs("Eric"); + Assert.assertEquals(estimate, result); + } + + @Test + public void getExtraInputsTest() throws Exception { + Map estimate = new HashMap<>(); + estimate.put("solar_panels", true); + Mockito.when(restTemplate.getForObject(new java.net.URI("http://localhost:8080/getExtraInputs?name=Eric"), + Map.class)) + .thenReturn(estimate); + Map result = userService.getExtraInputs("Eric"); + Assert.assertEquals(estimate, result); + } + @Test public void setInputTest() throws Exception { userService.updateInput("Eric", "input_size", "5"); Mockito.verify(userService).updateInput("Eric", "input_size", "5"); } + @Test + public void setExtraInputTest() throws Exception { + userService.updateExtraInput("Eric", "solar_panels", true); + Mockito.verify(userService).updateExtraInput("Eric", "solar_panels", true); + } + @Test public void addFriendTest() throws Exception { userService.addFriend("Eric", "Ceren"); Mockito.verify(userService).addFriend("Eric", "Ceren"); } + @Test + public void removeFriendTest() throws Exception { + userService.addFriend("Eric", "Ceren"); + Mockito.verify(userService).addFriend("Eric", "Ceren"); + userService.removeFriend("Eric", "Ceren"); + Mockito.verify(userService).removeFriend("Eric", "Ceren"); + } + @Test public void getAchievementsTest() throws Exception { userService.getAchievements("mika"); diff --git a/src/Server/src/main/java/greenify/server/InputValidator.java b/src/Server/src/main/java/greenify/server/InputValidator.java index b7dc6a1..eeb5dc6 100644 --- a/src/Server/src/main/java/greenify/server/InputValidator.java +++ b/src/Server/src/main/java/greenify/server/InputValidator.java @@ -4,127 +4,130 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; public class InputValidator { private static final List inputItems = Arrays.asList( - new InputItem("input_location", false, "Chicago"), - new InputItem("input_location_mode", false, "1"), - new InputItem("input_size", false, "3"), - new InputItem("input_income", false, "3000"), - new InputItem("input_population", false, "1"), - new InputItem("input_changed", false, "0"), - new InputItem("input_footprint_household_adults", false, "0"), - new InputItem("input_footprint_household_children", false, "0"), - new InputItem("input_footprint_transportation_num_vehicles", false, "1"), - new InputItem("input_footprint_transportation_miles1", false, "16100", false), - new InputItem("input_footprint_transportation_mpg1", false, "22", false), - new InputItem("input_footprint_transportation_fuel1", false, "0", false), - new InputItem("input_footprint_transportation_miles2", false, "0", false), - new InputItem("input_footprint_transportation_fuel2", false, "0", false), - new InputItem("input_footprint_transportation_mpg2", false, "0", false), - new InputItem("input_footprint_transportation_miles3", false, "0", false), - new InputItem("input_footprint_transportation_fuel3", false, "0", false), - new InputItem("input_footprint_transportation_mpg3", false, "0", false), - new InputItem("input_footprint_transportation_miles4", false, "0", false), - new InputItem("input_footprint_transportation_fuel4", false, "0", false), - new InputItem("input_footprint_transportation_mpg4", false, "0", false), - new InputItem("input_footprint_transportation_miles5", false, "0", false), - new InputItem("input_footprint_transportation_fuel5", false, "0", false), - new InputItem("input_footprint_transportation_mpg5", false, "0", false), - new InputItem("input_footprint_transportation_miles6", false, "0", false), - new InputItem("input_footprint_transportation_fuel6", false, "0", false), - new InputItem("input_footprint_transportation_mpg6", false, "0", false), - new InputItem("input_footprint_transportation_miles7", false, "0", false), - new InputItem("input_footprint_transportation_fuel7", false, "0", false), - new InputItem("input_footprint_transportation_mpg7", false, "0", false), - new InputItem("input_footprint_transportation_miles8", false, "0", false), - new InputItem("input_footprint_transportation_fuel8", false, "0", false), - new InputItem("input_footprint_transportation_mpg8", false, "0", false), - new InputItem("input_footprint_transportation_miles9", false, "0", false), - new InputItem("input_footprint_transportation_fuel9", false, "0", false), - new InputItem("input_footprint_transportation_mpg9", false, "0", false), - new InputItem("input_footprint_transportation_miles10", false, "0", false), - new InputItem("input_footprint_transportation_fuel10", false, "0", false), - new InputItem("input_footprint_transportation_mpg10", false, "0", false), - new InputItem("input_footprint_transportation_groundtype", false, "0"), - new InputItem("input_footprint_transportation_publictrans", false, "436"), - new InputItem("input_footprint_transportation_bus", false, "174"), - new InputItem("input_footprint_transportation_transit", false, "131"), - new InputItem("input_footprint_transportation_commuter", false, "87"), - new InputItem("input_footprint_transportation_intercity", false, "44"), - new InputItem("input_footprint_transportation_airtype", false, "0"), - new InputItem("input_footprint_transportation_airtotal", false, "6"), - new InputItem("input_footprint_transportation_airshort", false, "3"), - new InputItem("input_footprint_transportation_airmedium", false, "3"), - new InputItem("input_footprint_transportation_airlong", false, "0"), - new InputItem("input_footprint_transportation_airextended", false, "0"), - new InputItem("input_footprint_housing_cdd", false, "40000"), - new InputItem("input_footprint_housing_hdd", false, "40000"), - new InputItem("input_footprint_housing_electricity_type", false, "0"), - new InputItem("input_footprint_housing_electricity_dollars", false, "1200"), - new InputItem("input_footprint_housing_electricity_kwh", false, "12632"), - new InputItem("input_footprint_housing_cleanpercent", false, "0"), - new InputItem("input_footprint_housing_naturalgas_type", false, "0"), - new InputItem("input_footprint_housing_naturalgas_dollars", false, "600"), - new InputItem("input_footprint_housing_naturalgas_therms", false, "472"), - new InputItem("input_footprint_housing_naturalgas_cuft", false, "472444"), - new InputItem("input_footprint_housing_heatingoil_type", false, "0"), - new InputItem("input_footprint_housing_heatingoil_dollars", false, "220"), - new InputItem("input_footprint_housing_heatingoil_gallons", false, "73"), - new InputItem("input_footprint_housing_heatingoil_dollars_per_gallon", false, "40000"), - new InputItem("input_footprint_housing_squarefeet", false, "1850"), - new InputItem("input_footprint_housing_watersewage", false, "100"), - new InputItem("input_footprint_housing_gco2_per_kwh", false, "0"), - new InputItem("input_footprint_shopping_food_meatfisheggs_default", true, "2.4"), - new InputItem("input_footprint_shopping_food_meat_beefpork_default", true, "1.1"), - new InputItem("input_footprint_shopping_food_meat_poultry_default", true, "0.7"), - new InputItem("input_footprint_shopping_food_meat_fish_default", true, "0.3"), - new InputItem("input_footprint_shopping_food_meat_other_default", true, "0.3"), - new InputItem("input_footprint_shopping_food_fruitvegetables_default", true, "3.5"), - new InputItem("input_footprint_shopping_food_dairy_default", true, "2.2"), - new InputItem("input_footprint_shopping_food_cereals_default", true, "4.1"), - new InputItem("input_footprint_shopping_food_otherfood_default", true, "3.4"), - new InputItem("input_footprint_shopping_food_meattype", true, "0"), - new InputItem("input_footprint_shopping_food_meatfisheggs", true, "2.4"), - new InputItem("input_footprint_shopping_food_meat_beefpork", true, "2.4"), - new InputItem("input_footprint_shopping_food_meat_poultry", true, "2.4"), - new InputItem("input_footprint_shopping_food_meat_fish", true, "2.4"), - new InputItem("input_footprint_shopping_food_meat_other", true, "2.4"), - new InputItem("input_footprint_shopping_food_cereals", true, "4.1"), - new InputItem("input_footprint_shopping_food_dairy", true, "2.2"), - new InputItem("input_footprint_shopping_food_fruitvegetables", true, "3.5"), - new InputItem("input_footprint_shopping_food_otherfood", true, "3.4"), - new InputItem("input_footprint_shopping_goods_default_furnitureappliances", false, "1310"), - new InputItem("input_footprint_shopping_goods_default_clothing", false, "1310"), - new InputItem("input_footprint_shopping_goods_default_other_entertainment", false, "1310"), - new InputItem("input_footprint_shopping_goods_default_other_office", false, "1310"), - new InputItem("input_footprint_shopping_goods_default_other_personalcare", false, "1310"), - new InputItem("input_footprint_shopping_goods_default_other_autoparts", false, "1310"), - new InputItem("input_footprint_shopping_goods_default_other_medical", false, "1310"), - new InputItem("input_footprint_shopping_goods_type", false, "1310"), - new InputItem("input_footprint_shopping_goods_total", false, "1310"), - new InputItem("input_footprint_shopping_goods_furnitureappliances", false, "362"), - new InputItem("input_footprint_shopping_goods_clothing", false, "391"), - new InputItem("input_footprint_shopping_goods_other_type", false, "0"), - new InputItem("input_footprint_shopping_goods_other_total", false, "1311"), - new InputItem("input_footprint_shopping_goods_other_entertainment", false, "200"), - new InputItem("input_footprint_shopping_goods_other_office", false, "38"), - new InputItem("input_footprint_shopping_goods_other_personalcare", false, "103"), - new InputItem("input_footprint_shopping_goods_other_autoparts", false, "45"), - new InputItem("input_footprint_shopping_goods_other_medical", false, "172"), - new InputItem("input_footprint_shopping_services_type", false, "0"), - new InputItem("input_footprint_shopping_services_total", false, "2413"), - new InputItem("input_footprint_shopping_services_healthcare", false, "841"), - new InputItem("input_footprint_shopping_services_education", false, "122"), - new InputItem("input_footprint_shopping_services_communications", false, "163"), - new InputItem("input_footprint_shopping_services_vehicleservices", false, "180"), - new InputItem("input_footprint_shopping_services_finance", false, "566"), - new InputItem("input_footprint_shopping_services_household", false, "28"), - new InputItem("input_footprint_shopping_services_charity", false, "146"), - new InputItem("input_footprint_shopping_services_miscservices", false, "114"), - new InputItem("internal_state_abbreviation", false, "US") + new InputItem("input_location", false, "Chicago"), + new InputItem("input_location_mode", false, "1"), + new InputItem("input_size", false, "3"), + new InputItem("input_income", false, "3000"), + new InputItem("input_population", false, "1"), + new InputItem("input_changed", false, "0"), + new InputItem("input_footprint_household_adults", false, "0"), + new InputItem("input_footprint_household_children", false, "0"), + new InputItem("input_footprint_transportation_num_vehicles", false, "10"), + new InputItem("input_footprint_transportation_miles1", false, "16100", false), + new InputItem("input_footprint_transportation_mpg1", false, "22", false), + new InputItem("input_footprint_transportation_fuel1", false, "0", false), + new InputItem("input_footprint_transportation_miles2", false, "0", false), + new InputItem("input_footprint_transportation_fuel2", false, "0", false), + new InputItem("input_footprint_transportation_mpg2", false, "0", false), + new InputItem("input_footprint_transportation_miles3", false, "0", false), + new InputItem("input_footprint_transportation_fuel3", false, "0", false), + new InputItem("input_footprint_transportation_mpg3", false, "0", false), + new InputItem("input_footprint_transportation_miles4", false, "0", false), + new InputItem("input_footprint_transportation_fuel4", false, "0", false), + new InputItem("input_footprint_transportation_mpg4", false, "0", false), + new InputItem("input_footprint_transportation_miles5", false, "0", false), + new InputItem("input_footprint_transportation_fuel5", false, "0", false), + new InputItem("input_footprint_transportation_mpg5", false, "0", false), + new InputItem("input_footprint_transportation_miles6", false, "0", false), + new InputItem("input_footprint_transportation_fuel6", false, "0", false), + new InputItem("input_footprint_transportation_mpg6", false, "0", false), + new InputItem("input_footprint_transportation_miles7", false, "0", false), + new InputItem("input_footprint_transportation_fuel7", false, "0", false), + new InputItem("input_footprint_transportation_mpg7", false, "0", false), + new InputItem("input_footprint_transportation_miles8", false, "0", false), + new InputItem("input_footprint_transportation_fuel8", false, "0", false), + new InputItem("input_footprint_transportation_mpg8", false, "0", false), + new InputItem("input_footprint_transportation_miles9", false, "0", false), + new InputItem("input_footprint_transportation_fuel9", false, "0", false), + new InputItem("input_footprint_transportation_mpg9", false, "0", false), + new InputItem("input_footprint_transportation_miles10", false, "0", false), + new InputItem("input_footprint_transportation_fuel10", false, "0", false), + new InputItem("input_footprint_transportation_mpg10", false, "0", false), + new InputItem("input_footprint_transportation_groundtype", false, "0"), + new InputItem("input_footprint_transportation_publictrans", false, "436"), + new InputItem("input_footprint_transportation_bus", false, "174"), + new InputItem("input_footprint_transportation_transit", false, "131"), + new InputItem("input_footprint_transportation_commuter", false, "87"), + new InputItem("input_footprint_transportation_intercity", false, "44"), + new InputItem("input_footprint_transportation_airtype", false, "0"), + new InputItem("input_footprint_transportation_airtotal", false, "6"), + new InputItem("input_footprint_transportation_airshort", false, "3"), + new InputItem("input_footprint_transportation_airmedium", false, "3"), + new InputItem("input_footprint_transportation_airlong", false, "0"), + new InputItem("input_footprint_transportation_airextended", false, "0"), + new InputItem("input_footprint_housing_cdd", false, "40000"), + new InputItem("input_footprint_housing_hdd", false, "40000"), + new InputItem("input_footprint_housing_electricity_type", false, "0"), + new InputItem("input_footprint_housing_electricity_dollars", false, "1200"), + new InputItem("input_footprint_housing_electricity_kwh", false, "12632"), + new InputItem("input_footprint_housing_cleanpercent", false, "0"), + new InputItem("input_footprint_housing_naturalgas_type", false, "0"), + new InputItem("input_footprint_housing_naturalgas_dollars", false, "600"), + new InputItem("input_footprint_housing_naturalgas_therms", false, "472"), + new InputItem("input_footprint_housing_naturalgas_cuft", false, "472444"), + new InputItem("input_footprint_housing_heatingoil_type", false, "0"), + new InputItem("input_footprint_housing_heatingoil_dollars", false, "220"), + new InputItem("input_footprint_housing_heatingoil_gallons", false, "73"), + new InputItem("input_footprint_housing_heatingoil_dollars_per_gallon", false, "40000"), + new InputItem("input_footprint_housing_squarefeet", false, "1850"), + new InputItem("input_footprint_housing_watersewage", false, "100"), + new InputItem("input_footprint_housing_gco2_per_kwh", false, "0"), + new InputItem("input_footprint_shopping_food_meatfisheggs_default", true, "2.4"), + new InputItem("input_footprint_shopping_food_meat_beefpork_default", true, "1.1"), + new InputItem("input_footprint_shopping_food_meat_poultry_default", true, "0.7"), + new InputItem("input_footprint_shopping_food_meat_fish_default", true, "0.3"), + new InputItem("input_footprint_shopping_food_meat_other_default", true, "0.3"), + new InputItem("input_footprint_shopping_food_fruitvegetables_default", true, "3.5"), + new InputItem("input_footprint_shopping_food_dairy_default", true, "2.2"), + new InputItem("input_footprint_shopping_food_cereals_default", true, "4.1"), + new InputItem("input_footprint_shopping_food_otherfood_default", true, "3.4"), + new InputItem("input_footprint_shopping_food_meattype", true, "0"), + new InputItem("input_footprint_shopping_food_meatfisheggs", true, "2.4"), + new InputItem("input_footprint_shopping_food_meat_beefpork", true, "2.4"), + new InputItem("input_footprint_shopping_food_meat_poultry", true, "2.4"), + new InputItem("input_footprint_shopping_food_meat_fish", true, "2.4"), + new InputItem("input_footprint_shopping_food_meat_other", true, "2.4"), + new InputItem("input_footprint_shopping_food_cereals", true, "4.1"), + new InputItem("input_footprint_shopping_food_dairy", true, "2.2"), + new InputItem("input_footprint_shopping_food_fruitvegetables", true, "3.5"), + new InputItem("input_footprint_shopping_food_otherfood", true, "3.4"), + new InputItem("input_footprint_shopping_goods_default_furnitureappliances", + false, "1310"), + new InputItem("input_footprint_shopping_goods_default_clothing", false, "1310"), + new InputItem("input_footprint_shopping_goods_default_other_entertainment", + false, "1310"), + new InputItem("input_footprint_shopping_goods_default_other_office", false, "1310"), + new InputItem( + "input_footprint_shopping_goods_default_other_personalcare", false, "1310"), + new InputItem("input_footprint_shopping_goods_default_other_autoparts", + false, "1310"), + new InputItem("input_footprint_shopping_goods_default_other_medical", false, "1310"), + new InputItem("input_footprint_shopping_goods_type", false, "1310"), + new InputItem("input_footprint_shopping_goods_total", false, "1310"), + new InputItem("input_footprint_shopping_goods_furnitureappliances", false, "362"), + new InputItem("input_footprint_shopping_goods_clothing", false, "391"), + new InputItem("input_footprint_shopping_goods_other_type", false, "0"), + new InputItem("input_footprint_shopping_goods_other_total", false, "1311"), + new InputItem("input_footprint_shopping_goods_other_entertainment", false, "200"), + new InputItem("input_footprint_shopping_goods_other_office", false, "38"), + new InputItem("input_footprint_shopping_goods_other_personalcare", false, "103"), + new InputItem("input_footprint_shopping_goods_other_autoparts", false, "45"), + new InputItem("input_footprint_shopping_goods_other_medical", false, "172"), + new InputItem("input_footprint_shopping_services_type", false, "0"), + new InputItem("input_footprint_shopping_services_total", false, "2413"), + new InputItem("input_footprint_shopping_services_healthcare", false, "841"), + new InputItem("input_footprint_shopping_services_education", false, "122"), + new InputItem("input_footprint_shopping_services_communications", false, "163"), + new InputItem("input_footprint_shopping_services_vehicleservices", false, "180"), + new InputItem("input_footprint_shopping_services_finance", false, "566"), + new InputItem("input_footprint_shopping_services_household", false, "28"), + new InputItem("input_footprint_shopping_services_charity", false, "146"), + new InputItem("input_footprint_shopping_services_miscservices", false, "114"), + new InputItem("internal_state_abbreviation", false, "US") ); /** @@ -149,7 +152,7 @@ public class InputValidator { item = inputItem; } } - if (Objects.requireNonNull(item).getFloat()) { + if (item.getFloat()) { try { Float.parseFloat(value); } catch (NumberFormatException | NullPointerException nfe) { @@ -177,4 +180,17 @@ public class InputValidator { } return map; } -} + + /** + * This method gets extra values. + * @return the map of default values + */ + public static Map getExtraValues() { + Map map = new HashMap() { }; + map.put("local_produce", false); + map.put("bike", false); + map.put("temperature", false); + map.put("solar_panels", false); + return map; + } +} \ No newline at end of file diff --git a/src/Server/src/main/java/greenify/server/data/model/User.java b/src/Server/src/main/java/greenify/server/data/model/User.java index e31bb11..1c5a2ea 100644 --- a/src/Server/src/main/java/greenify/server/data/model/User.java +++ b/src/Server/src/main/java/greenify/server/data/model/User.java @@ -6,8 +6,8 @@ import greenify.server.InputValidator; import lombok.Data; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; @@ -16,7 +16,6 @@ import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; -import javax.persistence.JoinColumn; import javax.persistence.ManyToMany; import javax.persistence.Table; import javax.validation.constraints.NotNull; @@ -28,7 +27,7 @@ public class User { @Id @NotNull - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.TABLE) private Long id; @NotNull @@ -40,12 +39,17 @@ public class User { @NotNull private Float footPrint = 0.0f; + @NotNull + private Float firstFootprint = 0.0f; + @ElementCollection private Map footPrintInputs = new HashMap<>(); + @ElementCollection + private Map extraInputs = new HashMap<>(); + @ManyToMany - @JoinColumn - private Collection friends; + private List friends; @ElementCollection private Map achievements; @@ -63,7 +67,8 @@ public class User { this.name = name; this.password = password; this.setFootPrintInputs(InputValidator.getDefaultValues()); - this.friends = new ArrayList<>(); + this.setExtraInputs(InputValidator.getExtraValues()); + this.friends = new ArrayList(); this.setAchievements(AllAchievements.getDefaults()); } @@ -131,6 +136,22 @@ public class User { this.footPrint = footPrint; } + /** + * This method gets the first footPrint of user. + * @return the footprint of the user + */ + public Float getFirstFootprint() { + return firstFootprint; + } + + /** + * This method sets the footprint of a user. + * @param firstFootprint footprint of a user + */ + public void setFirstFootprint(Float firstFootprint) { + this.firstFootprint = firstFootprint; + } + /** * This method gets the footprint inputs of the user. * @return footprint inputs of the user @@ -147,28 +168,44 @@ public class User { this.footPrintInputs = footPrintInputs; } + /** + * This method gets the extra inputs of the user. + * @return extra inputs of the user + */ + public Map getExtraInputs() { + return extraInputs; + } + + /** + * This method sets the extra inputs of the user. + * @param extraInputs footprint inputs of the user + */ + public void setExtraInputs(Map extraInputs) { + this.extraInputs = extraInputs; + } + /** * This method gets the friends of the user. * @return friends list of the user */ - public ArrayList getFriends() { - return (ArrayList)this.friends; + public List getFriends() { + return this.friends; } /** * This method sets the friend list of the user. * @param friends friend list of the user */ - public void setFriends(Collection friends) { + public void setFriends(List friends) { this.friends = friends; } /** - * Adds a friend to the friends list of the user. + * Adds a friend to the friendslist of the user. * @param user the friend you want to add. */ public void addFriend(User user) { - if (user.equals(this)) { + if (user.equals(this) || friends.contains(user)) { throw new ApplicationException("Cannot add yourself as a friend"); } else { friends.add(user); @@ -176,6 +213,19 @@ public class User { } } + /** + * Removes a friend from the friendslist of the user. + * @param user the friend you want to remove. + */ + public void removeFriend(User user) { + if (!friends.contains(user)) { + throw new ApplicationException("This user is not your friend!"); + } else { + friends.remove(user); + System.out.print("Friend removed"); + } + } + /** * This method sets the achievements of the user. * @param achievements achievements of the user @@ -202,21 +252,6 @@ public class User { + this.password + ")"; } - /** - * Returns the name and score of the friends in JSON. Needed for the leader board. - * @return a JSON object of the friend list with only names and scores. - */ - public String friendsToString() { - String result = "friends=["; - for (User u : friends) { - result += "{name=" + u.getName() + ", footprint=" + u.getFootPrint() + "}, "; - } - if (result.endsWith(", ")) { - return result.substring(0, result.lastIndexOf(",")) + "]"; - } - return result + "]"; - } - /** This method checks whether two users are equal or not. * * @param other an other user * @return users are (not) equal diff --git a/src/Server/src/main/java/greenify/server/rest/UserController.java b/src/Server/src/main/java/greenify/server/rest/UserController.java index 7a0af13..d60f933 100644 --- a/src/Server/src/main/java/greenify/server/rest/UserController.java +++ b/src/Server/src/main/java/greenify/server/rest/UserController.java @@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.util.List; import java.util.Map; @RestController @@ -52,6 +53,20 @@ public class UserController { userService.setInput(name, inputName, value); } + + /** + * This method sets extra input for a user. + * @param name name of the user + * @param inputName name of the input of the user + * @param value value of the input + */ + @RequestMapping("/setExtraInput") + public void setExtraInput(@RequestParam(value = "name") String name, + @RequestParam(value = "inputName") String inputName, + @RequestParam(value = "value") Boolean value) { + userService.setExtraInput(name, inputName, value); + } + /** * This method gets input for a user. * @param name name of the user @@ -74,16 +89,93 @@ public class UserController { } /** - * This method adds friend for a user. + * This method saves footprint for a user. * @param name name of the user - * + */ + @RequestMapping("/saveFootprint") + public Float saveFootprint(@RequestParam(value = "name") String name) { + Float footprint = userService.saveFootprint(name); + return footprint; + } + + /** + * This method saves first footprint for a user. + * @param name name of the user + */ + @RequestMapping("/saveFirstFootprint") + public Float saveFirstFootprint(@RequestParam(value = "name") String name) { + Float footprint = userService.saveFirstFootprint(name); + return footprint; + } + + /** + * This method gets first footprint for a user. + * @param name name of the user + */ + @RequestMapping("/getFirst") + public Float getFirstFootprint(@RequestParam(value = "name") String name) { + System.out.println("hello"); + Float footprint = userService.getFirstFootprint(name); + return footprint; + } + + /** + * This method gets friend list for a user. + * @param name name of the user + */ + @RequestMapping("/getFriends") + public List getFriendNames(@RequestParam(value = "name") String name) { + List friends = userService.getFriends(name); + return friends; + } + + /** + * This method gets the list of all users. + */ + @RequestMapping("/getAllUsers") + public List getAllUsers() { + List users = userService.getAllUsers(); + return users; + } + + /** + * This method gets the input map of the user. + */ + @RequestMapping("/getInputs") + public Map getInputs(@RequestParam(value = "name") String name) { + return userService.getInputMap(name); + } + + /** + * This method gets the extra inputs map of the user. + */ + @RequestMapping("/getExtraInputs") + public Map getExtraInputs(@RequestParam(value = "name") String name) { + return userService.getExtraInputMap(name); + } + + /** + * This method adds a friend to a user. + * @param name name of the user + * @param friend the name of the user you want to add as a friend. */ @RequestMapping("/addFriend") public void addFriend(@RequestParam(value = "name") String name, - @RequestParam(value = "friend") String friend) { + @RequestParam(value = "friend") String friend) { userService.addFriend(name, friend); } + /** + * This method removes a friend from a user. + * @param name name of the user + * @param friend name of the friend you want to remove + */ + @RequestMapping("/removeFriend") + public void removeFriend(@RequestParam(value = "name") String name, + @RequestParam(value = "friend") String friend) { + userService.removeFriend(name, friend); + } + /** * This method gets all achievements of a user. * @param name name of the user diff --git a/src/Server/src/main/java/greenify/server/service/UserService.java b/src/Server/src/main/java/greenify/server/service/UserService.java index 7669597..5f41849 100644 --- a/src/Server/src/main/java/greenify/server/service/UserService.java +++ b/src/Server/src/main/java/greenify/server/service/UserService.java @@ -10,9 +10,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ResponseBody; +import java.util.ArrayList; +import java.util.List; import java.util.Map; @Service @@ -69,28 +69,35 @@ public class UserService { } /** -<<<<<<< HEAD * Adds a friend to the friendlist of the user. * @param name the username of the user * @param friend the name of the friend you want to add. + * @throws ApplicationException if the user is not in the database. */ public void addFriend(String name, String friend) { User user = userRepository.findByName(name); User add = userRepository.findByName(friend); - if (add == null) { + if (add == null ) { throw new ApplicationException("User does not exist"); } user.addFriend(add); + userRepository.save(user); } /** - * Returns the friendlist of the user in JSON. + * Removes a friend from the friendlist of the user. * @param name the username of the user - * @return a userDTO of the logged in user + * @param friend the name of the friend you want to remove. + * @throws ApplicationException if the user is not in the database. */ - public String getLeaderboard(String name) { + public void removeFriend(String name, String friend) { User user = userRepository.findByName(name); - return user.friendsToString(); + User remove = userRepository.findByName(friend); + if (remove == null ) { + throw new ApplicationException("User does not exist"); + } + user.removeFriend(remove); + userRepository.save(user); } /** @@ -108,15 +115,29 @@ public class UserService { && InputValidator.isValidItemValue(inputName, value)) { user.getFootPrintInputs().put(inputName, value); userRepository.save(user); - user.setFootPrint(calculatorService.calculateFootprint(user)); achievementService.updateAchievements(user); - userRepository.save(user); } else { throw new ApplicationException("Invalid input"); } } } + /** + * This method sets extra input for a user. + * @param name name of the user + * @param inputName name of the input of the user + * @param value value of the input + */ + public void setExtraInput(String name, String inputName, Boolean value) { + User user = userRepository.findByName(name); + if (user == null) { + throw new ApplicationException("User does not exist"); + } else { + user.getExtraInputs().put(inputName, value); + userRepository.save(user); + } + } + /** * This method gets the input value of an input. * @param name of the user @@ -132,6 +153,50 @@ public class UserService { } } + /** + * This method gets the map of the inputs. + * @param name of the user + * @return input map + */ + public Map getInputMap(String name) { + User user = userRepository.findByName(name); + return user.getFootPrintInputs(); + } + + /** + * This method gets the map of extra inputs. + * @param name of the user + * @return extra input map + */ + public Map getExtraInputMap(String name) { + User user = userRepository.findByName(name); + return user.getExtraInputs(); + } + + /** + * This method saves the footprint of a user. + * @param name name of the user + * @return footprint of the user + */ + public Float saveFootprint(String name) { + User user = userRepository.findByName(name); + user.setFootPrint(calculatorService.calculateFootprint(user)); + userRepository.save(user); + return user.getFootPrint(); + } + + /** + * This method saves the first footprint of a user. + * @param name name of the user + * @return footprint of the user + */ + public Float saveFirstFootprint(String name) { + User user = userRepository.findByName(name); + user.setFirstFootprint(calculatorService.calculateFootprint(user)); + userRepository.save(user); + return user.getFootPrint(); + } + /** * This method gets the footprint of a user. * @param name name of the user @@ -139,11 +204,34 @@ public class UserService { */ public Float getFootprint(String name) { User user = userRepository.findByName(name); - user.setFootPrint(calculatorService.calculateFootprint(user)); - userRepository.save(user); return user.getFootPrint(); } + /** + * This method gets the first footprint of a user. + * @param name name of the user + * @return first footprint of the user + */ + public Float getFirstFootprint(String name) { + User user = userRepository.findByName(name); + return user.getFirstFootprint(); + } + + /** + * This method gets the friends of a user. + * @param name name of the user + * @return list of the friends + */ + public List getFriends(String name) { + List result = new ArrayList<>(); + User user = userRepository.findByName(name); + List friends = user.getFriends(); + for (User person : friends) { + result.add(person.getName()); + } + return result; + } + /** * This methods sets a achievement. * @param name name of the user @@ -189,14 +277,16 @@ public class UserService { return user.getAchievements(); } - /** - * This method gets a JSON of XML with all users. - * @return JSON/XML of all users + * This method gets the list of all users. + * @return list of all users */ - @GetMapping(path = "/all") - @ResponseBody - public Iterable getAllUsers() { - return userRepository.findAll(); + public List getAllUsers() { + List result = new ArrayList<>(); + Iterable allUsers = userRepository.findAll(); + for (User person : allUsers) { + result.add(person.getName()); + } + return result; } } diff --git a/src/Server/src/test/java/InputValidatorTest.java b/src/Server/src/test/java/InputValidatorTest.java index 6b56ece..8f1239f 100644 --- a/src/Server/src/test/java/InputValidatorTest.java +++ b/src/Server/src/test/java/InputValidatorTest.java @@ -151,7 +151,7 @@ public class InputValidatorTest { put("input_footprint_shopping_services_charity", "146"); put("input_footprint_shopping_services_miscservices", "114"); put("internal_state_abbreviation", "US"); - } + } }; assertTrue(map.size() == InputValidator.getDefaultValues().size()); } diff --git a/src/Server/src/test/java/greenify/server/data/model/UserTest.java b/src/Server/src/test/java/greenify/server/data/model/UserTest.java index ad47984..146d6d8 100644 --- a/src/Server/src/test/java/greenify/server/data/model/UserTest.java +++ b/src/Server/src/test/java/greenify/server/data/model/UserTest.java @@ -6,12 +6,12 @@ import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import greenify.common.ApplicationException; - import greenify.server.AllAchievements; + import org.junit.Test; import java.util.ArrayList; -import java.util.Collection; +import java.util.List; public class UserTest { @@ -101,7 +101,7 @@ public class UserTest { User second = new User(1L, "merel", "password"); assertEquals(first.getFriends(), second.getFriends()); first.addFriend(second); - ArrayList test = new ArrayList<>(); + ArrayList test = new ArrayList(); test.add(second); assertEquals(first.getFriends(), test); } @@ -110,21 +110,47 @@ public class UserTest { public void addYourselfTest() { User test = new User(1L, "greenify", "password"); assertEquals(test.getFriends(), new ArrayList()); - assertThrows(ApplicationException.class, () -> test.addFriend(test)); + assertThrows(ApplicationException.class, () -> { + test.addFriend(test); + }); } + @Test + public void addTwiceTest() { + User test = new User(1L, "greenify", "password"); + List friendList = new ArrayList<>(); + friendList.add(test); + User user = new User(1L, "green", "pass"); + user.setFriends(friendList); + assertThrows(ApplicationException.class, () -> { + user.addFriend(test); + }); + } @Test - public void friendsToStringTest() { - User first = new User(1L, "greenify", "password"); - User second = new User(1L, "merel", "password"); - first.addFriend(second); - assertEquals(first.friendsToString(), "friends=[{name=merel, footprint=0.0}]"); + public void removeFriendValidTest() { + User test = new User(1L, "greenify", "password"); + List friendList = new ArrayList<>(); + friendList.add(test); + User user = new User(1L, "green", "pass"); + user.setFriends(friendList); + assertEquals(user.getFriends(), friendList); + user.removeFriend(test); + assertEquals(user.getFriends(), new ArrayList()); + } + + @Test + public void removeFriendInvalidTest() { + User user = new User(1L, "greenify", "password"); + User test = new User(2L, "user", "pass"); + assertThrows(ApplicationException.class, () -> { + user.removeFriend(test); + }); } @Test public void setFriendTest() { - Collection friends = new ArrayList<>(); + List friends = new ArrayList(); User first = new User(1L, "greenify", "password"); User second = new User(1L, "merel", "password"); friends.add(second); diff --git a/src/Server/src/test/java/greenify/server/rest/UserControllerTest.java b/src/Server/src/test/java/greenify/server/rest/UserControllerTest.java index 012f4a5..0f868ae 100644 --- a/src/Server/src/test/java/greenify/server/rest/UserControllerTest.java +++ b/src/Server/src/test/java/greenify/server/rest/UserControllerTest.java @@ -78,6 +78,25 @@ public class UserControllerTest { assertEquals("7", arg3Captor.getValue()); } + @Test + public void setExtraInputTest() throws Exception { + ArgumentCaptor arg1Captor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor arg2Captor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor arg3Captor = ArgumentCaptor.forClass(Boolean.class); + mvc.perform(get("/setExtraInput") + .param("name", "ceren") + .param("inputName", "input_size") + .param("value", "true") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()); + verify(userService, times(1)) + .setExtraInput(arg1Captor.capture(), arg2Captor.capture(), arg3Captor.capture()); + assertEquals("ceren", arg1Captor.getValue()); + assertEquals("input_size", arg2Captor.getValue()); + assertEquals(true, arg3Captor.getValue()); + } + @Test public void addFriendTest() throws Exception { ArgumentCaptor arg1Captor = ArgumentCaptor.forClass(String.class); @@ -94,6 +113,68 @@ public class UserControllerTest { assertEquals("merel", arg2Captor.getValue()); } + @Test + public void removeFriendTest() throws Exception { + ArgumentCaptor arg1Captor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor arg2Captor = ArgumentCaptor.forClass(String.class); + mvc.perform(get("/removeFriend") + .param("name", "ceren") + .param("friend", "merel") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()); + verify(userService, times(1)) + .removeFriend(arg1Captor.capture(), arg2Captor.capture()); + assertEquals("ceren", arg1Captor.getValue()); + assertEquals("merel", arg2Captor.getValue()); + } + + @Test + public void getInputMapTest() throws Exception { + ArgumentCaptor arg1Captor = ArgumentCaptor.forClass(String.class); + mvc.perform(get("/getInputs") + .param("name", "ceren") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()); + verify(userService, times(1)) + .getInputMap(arg1Captor.capture()); + assertEquals("ceren", arg1Captor.getValue()); + } + + @Test + public void getExtraInputMapTest() throws Exception { + ArgumentCaptor arg1Captor = ArgumentCaptor.forClass(String.class); + mvc.perform(get("/getExtraInputs") + .param("name", "ceren") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()); + verify(userService, times(1)) + .getExtraInputMap(arg1Captor.capture()); + assertEquals("ceren", arg1Captor.getValue()); + } + + @Test + public void getAllUsersTest() throws Exception { + mvc.perform(get("/getAllUsers") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @Test + public void getFriendNamesTest() throws Exception { + ArgumentCaptor arg1Captor = ArgumentCaptor.forClass(String.class); + mvc.perform(get("/getFriends") + .param("name", "ceren") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()); + verify(userService, times(1)).getFriends(arg1Captor.capture()); + assertEquals("ceren", arg1Captor.getValue()); + } + @Test public void getInputTest() throws Exception { ArgumentCaptor arg1Captor = ArgumentCaptor.forClass(String.class); @@ -121,6 +202,42 @@ public class UserControllerTest { assertEquals("ceren", arg1Captor.getValue()); } + @Test + public void getFirstFootprintTest() throws Exception { + ArgumentCaptor arg1Captor = ArgumentCaptor.forClass(String.class); + mvc.perform(get("/getFirst") + .param("name", "ceren") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()); + verify(userService, times(1)).getFirstFootprint(arg1Captor.capture()); + assertEquals("ceren", arg1Captor.getValue()); + } + + @Test + public void saveFootprintTest() throws Exception { + ArgumentCaptor arg1Captor = ArgumentCaptor.forClass(String.class); + mvc.perform(get("/saveFootprint") + .param("name", "ceren") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()); + verify(userService, times(1)).saveFootprint(arg1Captor.capture()); + assertEquals("ceren", arg1Captor.getValue()); + } + + @Test + public void saveFirstFootprintTest() throws Exception { + ArgumentCaptor arg1Captor = ArgumentCaptor.forClass(String.class); + mvc.perform(get("/saveFirstFootprint") + .param("name", "ceren") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()); + verify(userService, times(1)).saveFirstFootprint(arg1Captor.capture()); + assertEquals("ceren", arg1Captor.getValue()); + } + @Test public void getAchievementsTest() throws Exception { ArgumentCaptor arg1Captor = ArgumentCaptor.forClass(String.class); @@ -132,4 +249,5 @@ public class UserControllerTest { verify(userService, times(1)).getAchievements(arg1Captor.capture()); assertEquals("mika", arg1Captor.getValue()); } + } diff --git a/src/Server/src/test/java/greenify/server/service/UserServiceTest.java b/src/Server/src/test/java/greenify/server/service/UserServiceTest.java index 5cc0950..69f6a08 100644 --- a/src/Server/src/test/java/greenify/server/service/UserServiceTest.java +++ b/src/Server/src/test/java/greenify/server/service/UserServiceTest.java @@ -9,8 +9,10 @@ import greenify.common.UserDto; import greenify.server.AllAchievements; import greenify.server.data.model.User; import greenify.server.data.repository.UserRepository; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.TestConfiguration; @@ -19,6 +21,9 @@ import org.springframework.context.annotation.Bean; import org.springframework.test.context.junit4.SpringRunner; import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; @RunWith(SpringRunner.class) public class UserServiceTest { @@ -91,11 +96,27 @@ public class UserServiceTest { .get("input_footprint_shopping_food_dairy_default")); } + @Test + public void setExtraInputTest() { + User alex = new User(1L, "alex", "password"); + when(userRepository.findByName(alex.getName())) + .thenReturn(alex); + userService.setExtraInput("alex", "solar_panels", true); + assertEquals(true, alex.getExtraInputs() + .get("solar_panels")); + } + @Test public void setInputNullTest() { assertThrows(ApplicationException.class, () -> userService.setInput(null, "hello", "5.5")); } + @Test + public void setExtraInputNullTest() { + assertThrows(ApplicationException.class, () -> userService + .setExtraInput(null, "hello", true)); + } + @Test public void setInputApplicationTestItem() { assertThrows(ApplicationException.class, () -> userService @@ -122,7 +143,8 @@ public class UserServiceTest { when(calculatorService.calculateFootprint(alex)) .thenReturn(15f); userService.setInput("alex", "input_footprint_shopping_food_dairy_default", "6.5"); - assertEquals(15f, alex.getFootPrint(), 0.0); + Assert.assertTrue(alex.getFootPrintInputs() + .get("input_footprint_shopping_food_dairy_default").equals("6.5")); } @Test @@ -136,6 +158,28 @@ public class UserServiceTest { .getInput("alex", "input_footprint_shopping_food_dairy_default")); } + @Test + public void getInputMapTest() { + Map map = new HashMap<>(); + User alex = new User(1L, "alex", "password"); + when(userRepository.findByName(alex.getName())) + .thenReturn(alex); + alex.setFootPrintInputs(map); + assertEquals(map, userService + .getInputMap("alex")); + } + + @Test + public void getExtraInputMapTest() { + Map map = new HashMap<>(); + User alex = new User(1L, "alex", "password"); + when(userRepository.findByName(alex.getName())) + .thenReturn(alex); + alex.setExtraInputs(map); + assertEquals(map, userService + .getExtraInputMap("alex")); + } + @Test public void getInputExceptionTest() { assertThrows(ApplicationException.class, () -> userService.getInput("alex", "hello")); @@ -143,18 +187,71 @@ public class UserServiceTest { @Test public void getFootprintTest() { + User alex = new User(1L, "alex", "password"); + alex.setFootPrint(15F); + when(userRepository.findByName(alex.getName())) + .thenReturn(alex); + Assertions.assertEquals(15F, userService.getFootprint("alex")); + } + + @Test + public void getFirstFootprintTest() { + User alex = new User(1L, "alex", "password"); + alex.setFirstFootprint(15F); + when(userRepository.findByName(alex.getName())) + .thenReturn(alex); + Assertions.assertEquals(15F, userService.getFirstFootprint("alex")); + } + + @Test + public void saveFootprintTest() { User alex = new User(1L, "alex", "password"); when(userRepository.findByName(alex.getName())) .thenReturn(alex); when(calculatorService.calculateFootprint(alex)) .thenReturn(15f); - userService.setInput("alex", "input_footprint_shopping_food_dairy_default", "6.5"); - assertEquals(15f, userService.getFootprint("alex"), 0.0); + userService.saveFootprint("alex"); + Assertions.assertEquals(15f, userService.saveFootprint("alex")); + } + + @Test + public void saveFirstFootprintTest() { + User lola = new User(1L, "lola", "password"); + when(userRepository.findByName(lola.getName())) + .thenReturn(lola); + when(calculatorService.calculateFootprint(lola)) + .thenReturn(0f); + userService.saveFirstFootprint("lola"); + Assertions.assertEquals(0f, userService.saveFirstFootprint("lola")); + } + + @Test + public void getFriendsTest() { + User alex = new User(1L, "alex", "password"); + User lola = new User(2L, "lola", "pass"); + when(userRepository.findByName(alex.getName())) + .thenReturn(alex); + when(userRepository.findByName(lola.getName())) + .thenReturn(lola); + alex.addFriend(lola); + List friendList = new ArrayList<>(); + friendList.add("lola"); + assertEquals(friendList, userService.getFriends("alex")); } @Test public void getAllUserTest() { - assertEquals(userRepository.findAll(), userService.getAllUsers()); + User alex = new User(1L, "alex", "password"); + User lola = new User(2L, "lola", "pass"); + Iterable users = new ArrayList<>(); + ((ArrayList) users).add(alex); + ((ArrayList) users).add(lola); + when(userRepository.findAll()) + .thenReturn(users); + List userList = new ArrayList<>(); + userList.add("alex"); + userList.add("lola"); + assertEquals(userList, userService.getAllUsers()); } @Test @@ -174,16 +271,26 @@ public class UserServiceTest { } @Test - public void addFriendsExceptionTest() { - assertThrows(ApplicationException.class, () -> userService.addFriend("greenify", null)); + public void removeFriendTest() { + User alex = userRepository.findByName("alex"); + User lola = userRepository.findByName("lola"); + assertEquals(lola.getFriends(), alex.getFriends()); + userService.addFriend("alex", "lola"); + ArrayList test = new ArrayList(); + test.add(lola); + assertEquals(alex.getFriends(), test); + userService.removeFriend("alex", "lola"); + assertEquals(lola.getFriends(), alex.getFriends()); } @Test - public void leaderboardTest() { - User alex = userRepository.findByName("alex"); - User lola = userRepository.findByName("lola"); - userService.addFriend("alex", "lola"); - assertEquals(userService.getLeaderboard("alex"), "friends=[{name=lola, footprint=0.0}]"); + public void removeFriendNullTest() { + assertThrows(ApplicationException.class, () -> userService.removeFriend("alex", null)); + } + + @Test + public void addFriendNullFriendTest() { + assertThrows(ApplicationException.class, () -> userService.addFriend("alex", null)); } @Test From 82eb5575ee6e151e78f42e161a68e03275c3c6ef Mon Sep 17 00:00:00 2001 From: mlwauben Date: Thu, 4 Apr 2019 08:00:47 +0200 Subject: [PATCH 10/10] FIX:: checkstyle errors (except Cyclomatic Complexity ones) --- .../src/main/java/greenify/client/Hints.java | 2 +- .../server/service/CalculatorService.java | 4 ++++ .../server/service/CalculatorServiceTest.java | 22 ++++++++++--------- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/Client/src/main/java/greenify/client/Hints.java b/src/Client/src/main/java/greenify/client/Hints.java index 34aa3fb..95f010d 100644 --- a/src/Client/src/main/java/greenify/client/Hints.java +++ b/src/Client/src/main/java/greenify/client/Hints.java @@ -56,7 +56,7 @@ public class Hints { } /** - * This method returns a random hint from the list of hints. + * This method gets a random hint from the list of hints. * @return the random hint. */ public String randomHint() { diff --git a/src/Server/src/main/java/greenify/server/service/CalculatorService.java b/src/Server/src/main/java/greenify/server/service/CalculatorService.java index 4258c3b..26ee5ca 100644 --- a/src/Server/src/main/java/greenify/server/service/CalculatorService.java +++ b/src/Server/src/main/java/greenify/server/service/CalculatorService.java @@ -77,6 +77,10 @@ public class CalculatorService { return footprint; } + /** + * This method adds extra input to the user. + * @param user name of the user + */ public void addExtras(User user) { if (user.getExtraInputs().get("local_produce")) { user.setFootPrint(user.getFootPrint() - 2); diff --git a/src/Server/src/test/java/greenify/server/service/CalculatorServiceTest.java b/src/Server/src/test/java/greenify/server/service/CalculatorServiceTest.java index d252949..caace32 100644 --- a/src/Server/src/test/java/greenify/server/service/CalculatorServiceTest.java +++ b/src/Server/src/test/java/greenify/server/service/CalculatorServiceTest.java @@ -96,19 +96,21 @@ public class CalculatorServiceTest { public void addExtrasTest() throws URISyntaxException { User user = new User(1L,"greenify", "password"); Map map = new HashMap() {{ - put("local_produce", false); - put("bike", false); - put("temperature", false); - put("solar_panels", false); - }}; + put("local_produce", false); + put("bike", false); + put("temperature", false); + put("solar_panels", false); + } + }; user.setExtraInputs(map); user.setFootPrint(50f); Map secondMap = new HashMap() {{ - put("local_produce", true); - put("bike", true); - put("temperature", true); - put("solar_panels", true); - }}; + put("local_produce", true); + put("bike", true); + put("temperature", true); + put("solar_panels", true); + } + }; user.setExtraInputs(secondMap); calculatorService.addExtras(user); mockServer.verify();