Skip to content

Commit

Permalink
Merge pull request #67 from dancier/search-implementation
Browse files Browse the repository at this point in the history
Search implementation
  • Loading branch information
jans510 authored Dec 25, 2024
2 parents db60762 + f02600a commit da9654b
Show file tree
Hide file tree
Showing 14 changed files with 299 additions and 70 deletions.
4 changes: 2 additions & 2 deletions api/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -652,13 +652,13 @@ components:
gender:
name: gender
in: query
description: preferred gender of the dancers
description: required preferred gender of the dancers
schema:
type: string
range:
name: range
in: query
description: Range [km] in which the search for dancers should be done
description: Range [km] in which the search for dancers should be done, defaults to 20 km
schema:
type: string
schemas:
Expand Down
15 changes: 0 additions & 15 deletions src/main/java/net/dancier/dancer/core/DancerRepository.java

This file was deleted.

39 changes: 0 additions & 39 deletions src/main/java/net/dancier/dancer/core/DancerService.java

This file was deleted.

1 change: 1 addition & 0 deletions src/main/java/net/dancier/dancer/core/ProfileService.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import net.dancier.dancer.core.model.DanceProfile;
import net.dancier.dancer.core.model.Dancer;
import net.dancier.dancer.core.util.ModelMapper;
import net.dancier.dancer.dancers.DancerRepository;
import net.dancier.dancer.location.ZipCode;
import net.dancier.dancer.location.ZipCodeRepository;
import org.slf4j.Logger;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package net.dancier.dancer.chat;
package net.dancier.dancer.dancers;

import lombok.RequiredArgsConstructor;
import net.dancier.dancer.chat.dto.DancerDto;
import net.dancier.dancer.chat.dto.DancerIdsDto;
import net.dancier.dancer.core.DancerService;
import net.dancier.dancer.core.dto.PublicProfileDto;
import net.dancier.dancer.core.model.Gender;
import net.dancier.dancer.security.AuthenticatedUser;
import net.dancier.dancer.security.CurrentUser;
import org.slf4j.Logger;
Expand All @@ -12,8 +13,7 @@
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.UUID;
import java.util.*;

import static net.dancier.dancer.authentication.Constants.ROLE_USER;

Expand All @@ -25,6 +25,17 @@ public class DancerController {

private final DancerService dancerService;

@GetMapping("")
@Secured(ROLE_USER)
public ResponseEntity<List<PublicProfileDto>> get(
@CurrentUser AuthenticatedUser authenticatedUser,
@RequestParam Gender gender,
@RequestParam(defaultValue = "20") int range
) {
log.info("Fetching list of dancers in {} km range with gender {} for user {}", range, gender, authenticatedUser.getUserId());
return ResponseEntity.ok(dancerService.getDancerList(authenticatedUser, gender, range));
}

@PostMapping("")
@Secured(ROLE_USER)
public ResponseEntity<HashMap<UUID, DancerDto>> post(
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/net/dancier/dancer/dancers/DancerRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package net.dancier.dancer.dancers;

import net.dancier.dancer.core.model.Dancer;
import net.dancier.dancer.core.model.Gender;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

public interface DancerRepository extends JpaRepository<Dancer, UUID> {

Optional<Dancer> findByUserId(UUID userid);

Boolean existsByDancerName(String dancerName);

List<Dancer> findFirst500ByGenderAndLongitudeBetweenAndLatitudeBetween(
Gender gender,
double lowerLongitude,
double upperLongitude,
double lowerLatitude,
double upperLatitude
);

}
65 changes: 65 additions & 0 deletions src/main/java/net/dancier/dancer/dancers/DancerService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package net.dancier.dancer.dancers;

import net.dancier.dancer.chat.dto.DancerDto;
import net.dancier.dancer.chat.dto.DancerIdsDto;
import net.dancier.dancer.core.dto.PublicProfileDto;
import net.dancier.dancer.core.exception.NotFoundException;
import net.dancier.dancer.core.model.Dancer;
import net.dancier.dancer.core.model.Gender;
import net.dancier.dancer.security.AuthenticatedUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.UUID;

@Service
public class DancerService {

@Autowired
DancerRepository dancerRepository;

public Dancer loadByUserId(UUID userId) {
return dancerRepository.findByUserId(userId).orElseThrow(() -> new NotFoundException("No Profile found for given user."));
}

public List<Dancer> getAllDancer() {
return dancerRepository.findAll();
}

public HashMap<UUID, DancerDto> getDancerMap(DancerIdsDto dancerIdsDto) {

HashMap<UUID, DancerDto> dancers = new HashMap<>();

dancerRepository.findAllById(dancerIdsDto.getDancerIds())
.stream()
.map(DancerDto::fromDancer)
.forEach(dancerDto -> dancers.put(dancerDto.getId(), dancerDto));

return dancers;
}

public List<PublicProfileDto> getDancerList(AuthenticatedUser authenticatedUser, Gender gender, int range) {

Dancer dancer = loadByUserId(authenticatedUser.getUserId());

// 1° in longitude in Germany (latitude 47) are 75,78 km
double longitudeRange = range/75.78;
// 1° in longitude are 112,12 km
double latitudeRange = range/112.12;

double upperLatitude = dancer.getLatitude() + latitudeRange;
double lowerLatitude = dancer.getLatitude() - latitudeRange;
double upperLongitude = dancer.getLongitude() + longitudeRange;
double lowerLongitude = dancer.getLongitude() - longitudeRange;

List<Dancer> resultList = dancerRepository.findFirst500ByGenderAndLongitudeBetweenAndLatitudeBetween(
gender, lowerLongitude, upperLongitude, lowerLatitude, upperLatitude);

return resultList.stream()
.map(PublicProfileDto::of)
.filter(d -> d.getId() != dancer.getId())
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package net.dancier.dancer.recommendation;

import lombok.RequiredArgsConstructor;
import net.dancier.dancer.core.DancerRepository;
import net.dancier.dancer.dancers.DancerRepository;
import net.dancier.dancer.core.model.Dancer;
import net.dancier.dancer.recommendation.model.BaseRecommendation;
import net.dancier.dancer.recommendation.model.RecommendationWrapper;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import lombok.RequiredArgsConstructor;
import net.dancier.dancer.authentication.model.User;
import net.dancier.dancer.authentication.repository.UserRepository;
import net.dancier.dancer.core.DancerRepository;
import net.dancier.dancer.dancers.DancerRepository;
import net.dancier.dancer.core.model.Dancer;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,17 @@
import net.dancier.dancer.AbstractPostgreSQLEnabledTest;
import net.dancier.dancer.chat.client.ChatServiceClient;
import net.dancier.dancer.chat.dto.*;
import net.dancier.dancer.core.DancerRepository;
import net.dancier.dancer.dancers.DancerRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.test.context.support.WithUserDetails;
import org.springframework.test.web.servlet.ResultActions;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
Expand Down
69 changes: 69 additions & 0 deletions src/test/java/net/dancier/dancer/dancers/DancerControllerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package net.dancier.dancer.dancers;

import net.dancier.dancer.AbstractPostgreSQLEnabledTest;
import org.junit.jupiter.api.Test;
import org.springframework.security.test.context.support.WithUserDetails;
import org.springframework.test.context.jdbc.Sql;
import java.util.List;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.isA;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@Sql(value = {"/dancers/data.sql"})
public class DancerControllerTest extends AbstractPostgreSQLEnabledTest {

@Test
@WithUserDetails("user-with-a-profile@dancier.net")
void getDancersShouldReturnFilteredProfiles() throws Exception {

mockMvc
.perform(get("/dancers")
.param("range", "20")
.param("gender", "FEMALE")
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.*", isA(List.class)))
.andExpect(jsonPath("$.*", hasSize(1)))
.andExpect(jsonPath("$[0].id").value("503ffad4-148b-4af1-8365-62315ff89b9f"))
.andExpect(jsonPath("$[0].gender").value("FEMALE"))
.andExpect(jsonPath("$[0].dancerName").value("perfect_dancer"))
.andExpect(jsonPath("$[0].aboutMe").value("Hi"))
.andExpect(jsonPath("$[0].age").isNotEmpty())
.andExpect(jsonPath("$[0].size").value("178"))
.andExpect(jsonPath("$[0].city").value("Dortmund"))
.andExpect(jsonPath("$[0].country").value("GER"));

}

@Test
@WithUserDetails("user-with-a-profile@dancier.net")
void getDancersUsingDefaultRange() throws Exception {

mockMvc
.perform(get("/dancers")
.param("gender", "FEMALE")
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.*", isA(List.class)))
.andExpect(jsonPath("$.*", hasSize(1)))
.andExpect(jsonPath("$[0].id").value("503ffad4-148b-4af1-8365-62315ff89b9f"))
.andExpect(jsonPath("$[0].gender").value("FEMALE"))
.andExpect(jsonPath("$[0].dancerName").value("perfect_dancer"))
.andExpect(jsonPath("$[0].aboutMe").value("Hi"))
.andExpect(jsonPath("$[0].age").isNotEmpty())
.andExpect(jsonPath("$[0].size").value("178"))
.andExpect(jsonPath("$[0].city").value("Dortmund"))
.andExpect(jsonPath("$[0].country").value("GER"));

}

@Test
@WithUserDetails("user-with-a-profile@dancier.net")
void shouldFailIfGenderIsNotSet() throws Exception {
mockMvc .perform(get("/dancers")
.param("range", "20")
).andExpect(status().isBadRequest());
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package net.dancier.dancer.recommendation;

import net.dancier.dancer.AbstractPostgreSQLEnabledTest;
import net.dancier.dancer.core.DancerRepository;
import net.dancier.dancer.dancers.DancerRepository;
import net.dancier.dancer.core.model.Dancer;
import net.dancier.dancer.recommendation.dto.RecommendationDto;
import org.junit.jupiter.api.BeforeEach;
Expand Down
Loading

0 comments on commit da9654b

Please sign in to comment.