diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..f4cc0af8d Binary files /dev/null and b/.DS_Store differ diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 000000000..c332f9f22 Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/main/.DS_Store b/src/main/.DS_Store new file mode 100644 index 000000000..3d9e7c3dc Binary files /dev/null and b/src/main/.DS_Store differ diff --git a/src/main/java/com/makersacademy/acebook/controller/UsersController.java b/src/main/java/com/makersacademy/acebook/controller/UsersController.java index a7c9db1d8..8176c4f45 100644 --- a/src/main/java/com/makersacademy/acebook/controller/UsersController.java +++ b/src/main/java/com/makersacademy/acebook/controller/UsersController.java @@ -6,8 +6,11 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.view.RedirectView; +import java.util.Set; + @RestController public class UsersController { @Autowired @@ -27,4 +30,25 @@ public RedirectView afterLogin() { return new RedirectView("/posts"); } + + @GetMapping("/users/friends") + public ModelAndView viewFriends() { + DefaultOidcUser principal = (DefaultOidcUser) SecurityContextHolder + .getContext() + .getAuthentication() + .getPrincipal(); + String username = (String) principal.getAttributes().get("email"); + + // Find the user by username + User currentUser = userRepository.findUserByUsername(username) + .orElseThrow(() -> new RuntimeException("User not found")); + + // Get friends + Set friends = currentUser.getFriends(); + + // Pass friends to the view named "friends" + ModelAndView mav = new ModelAndView("friends"); + mav.addObject("friends", friends); + return mav; + } } diff --git a/src/main/java/com/makersacademy/acebook/model/User.java b/src/main/java/com/makersacademy/acebook/model/User.java index 6013fbe23..0741d5c0d 100644 --- a/src/main/java/com/makersacademy/acebook/model/User.java +++ b/src/main/java/com/makersacademy/acebook/model/User.java @@ -3,6 +3,9 @@ import jakarta.persistence.*; import lombok.Data; +import java.util.HashSet; +import java.util.Set; + import static java.lang.Boolean.TRUE; @Data @@ -19,6 +22,17 @@ public User() { this.enabled = TRUE; } + // Join table to link user ID with friend ID + @ManyToMany + @JoinTable( + name = "friends", + joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "friend_id") + ) + + // Using hashset to store friends to prevent duplicates and lets us do faster access/search + private Set friends = new HashSet<>(); + public User(String username) { this.username = username; this.enabled = TRUE; diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties index 865b41e1c..926b9edf4 100644 --- a/src/main/resources/application-test.properties +++ b/src/main/resources/application-test.properties @@ -3,4 +3,4 @@ spring.datasource.username= spring.datasource.password= flyway.baseline-on-migrate=true spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false -spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect +spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 699e8575a..39af65fd8 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,5 +1,5 @@ okta: oauth2: - issuer: https://dev-edward-andress.uk.auth0.com/ - client-id: ${OKTA_CLIENT_ID} - client-secret: ${OKTA_CLIENT_SECRET} + issuer: ${ISSUER_ACEBOOK} + client-id: ${CLIENT_ID_ACEBOOK} + client-secret: ${CLIENT_SECRET_ACEBOOK} diff --git a/src/main/resources/db/migration/V4__create_friends_table.sql b/src/main/resources/db/migration/V4__create_friends_table.sql new file mode 100644 index 000000000..c999c5fd8 --- /dev/null +++ b/src/main/resources/db/migration/V4__create_friends_table.sql @@ -0,0 +1,10 @@ +CREATE TABLE friends ( + user_id bigint NOT NULL, + friend_id bigint NOT NULL, + PRIMARY KEY (user_id, friend_id), + + -- These constraints force the tables to use only existing user ids. + -- On delete cascade deletes friendships if either user or friend deletes their account. + CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, + CONSTRAINT fk_friend FOREIGN KEY (friend_id) REFERENCES users(id) ON DELETE CASCADE +); diff --git a/src/main/resources/templates/friends.html b/src/main/resources/templates/friends.html new file mode 100644 index 000000000..82a7fa8ac --- /dev/null +++ b/src/main/resources/templates/friends.html @@ -0,0 +1,13 @@ + + + + + Friends + + + + + + \ No newline at end of file diff --git a/src/test/java/com/makersacademy/acebook/feature/SignUpTest.java b/src/test/java/com/makersacademy/acebook/feature/SignUpTest.java index dcb1416bb..bf36682f9 100644 --- a/src/test/java/com/makersacademy/acebook/feature/SignUpTest.java +++ b/src/test/java/com/makersacademy/acebook/feature/SignUpTest.java @@ -1,29 +1,30 @@ package com.makersacademy.acebook.feature; import com.github.javafaker.Faker; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class SignUpTest { WebDriver driver; Faker faker; - @Before + @BeforeEach public void setup() { System.setProperty("webdriver.chrome.driver", "/usr/local/bin/chromedriver"); driver = new ChromeDriver(); faker = new Faker(); } - @After + @AfterEach public void tearDown() { - driver.close(); + driver.quit(); // safer than close() } @Test @@ -37,6 +38,7 @@ public void successfulSignUpAlsoLogsInUser() { driver.findElement(By.name("action")).click(); driver.findElement(By.name("action")).click(); String greetingText = driver.findElement(By.id("greeting")).getText(); - Assert.assertEquals("Signed in as " + email, greetingText); + + assertEquals("Signed in as " + email, greetingText); } } diff --git a/src/test/java/com/makersacademy/acebook/model/UserTest.java b/src/test/java/com/makersacademy/acebook/model/UserTest.java new file mode 100644 index 000000000..f56539abb --- /dev/null +++ b/src/test/java/com/makersacademy/acebook/model/UserTest.java @@ -0,0 +1,22 @@ +package com.makersacademy.acebook.model; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; + +import org.junit.jupiter.api.Test; + +public class UserTest { + + private User karen = new User("Karen", true); + private User zehad = new User("Zehad", true); + + @Test + public void checkWhoIsFriends() { + // Hashset friends table is not bidirectional, + // Both friends must be added each other + karen.getFriends().add(zehad); + zehad.getFriends().add(karen); + assertThat(karen.getFriends(), hasItem(zehad)); + assertThat(zehad.getFriends(), hasItem(karen)); + } +}