Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ [Feature] 개인 페이지 수정하기(어드민) API #856 #941

Merged
merged 6 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@

@Repository
public interface AgendaProfileAdminRepository extends JpaRepository<AgendaProfile, Long> {


@Query("SELECT a FROM AgendaProfile a WHERE a.intraId = :intraId")
Optional<AgendaProfile> findByIntraId(String intraId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package gg.agenda.api.admin.agendaprofile.controller;

import javax.validation.Valid;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import gg.agenda.api.admin.agendaprofile.controller.request.AgendaProfileChangeAdminReqDto;
import gg.agenda.api.admin.agendaprofile.service.AgendaProfileAdminService;
import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
@RequestMapping("/agenda/admin/profile")
public class AgendaProfileAdminController {
private final AgendaProfileAdminService agendaProfileAdminService;

/**
* 관리자 개인 프로필 변경 API
*
* @param intraId 수정할 사용자의 intra_id
* @param reqDto 변경할 프로필 정보
* @return HTTP 상태 코드와 빈 응답
*/
@PatchMapping
public ResponseEntity<String> agendaProfileModify(
@RequestParam String intraId,
@RequestBody @Valid AgendaProfileChangeAdminReqDto reqDto) {
agendaProfileAdminService.modifyAgendaProfile(intraId, reqDto);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package gg.agenda.api.admin.agendaprofile.controller.request;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.URL;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = lombok.AccessLevel.PROTECTED)
public class AgendaProfileChangeAdminReqDto {

@NotBlank
@Size(max = 50, message = "userContent의 길이가 허용된 범위를 초과합니다.")
private String userContent;

@URL
@Size(max = 200, message = "userGithub의 길이가 허용된 범위를 초과합니다.")
private String userGithub;

@NotBlank
private String userLocation;

@Builder
public AgendaProfileChangeAdminReqDto(String userContent, String userGithub, String userLocation) {
this.userContent = userContent;
this.userGithub = userGithub;
this.userLocation = userLocation;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package gg.agenda.api.admin.agendaprofile.service;

import static gg.utils.exception.ErrorCode.*;

import javax.transaction.Transactional;

import org.springframework.stereotype.Service;

import gg.admin.repo.agenda.AgendaProfileAdminRepository;
import gg.agenda.api.admin.agendaprofile.controller.request.AgendaProfileChangeAdminReqDto;
import gg.data.agenda.AgendaProfile;
import gg.data.agenda.type.Location;
import gg.utils.exception.custom.NotExistException;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class AgendaProfileAdminService {
private final AgendaProfileAdminRepository agendaProfileAdminRepository;

/**
* AgendaProfile 변경 메서드
* @param intraId 로그인한 유저의 id
* @param reqDto 변경할 프로필 정보
*/
@Transactional
public void modifyAgendaProfile(String intraId, AgendaProfileChangeAdminReqDto reqDto) {
AgendaProfile agendaProfile = agendaProfileAdminRepository.findByIntraId(intraId)
.orElseThrow(() -> new NotExistException(AGENDA_PROFILE_NOT_FOUND));

agendaProfile.updateProfileAdmin(reqDto.getUserContent(), reqDto.getUserGithub(),
Location.valueOfLocation(reqDto.getUserLocation()));
agendaProfileAdminRepository.save(agendaProfile);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class AgendaProfileChangeReqDto {
private String userContent;

@URL
@Size(max = 100, message = "userGithub의 길이가 허용된 범위를 초과합니다.")
@Size(max = 200, message = "userGithub의 길이가 허용된 범위를 초과합니다.")
private String userGithub;

@Builder
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package gg.agenda.api.admin.agendaprofile;

import static gg.data.agenda.type.Location.*;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

import javax.transaction.Transactional;

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.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import com.fasterxml.jackson.databind.ObjectMapper;

import gg.admin.repo.agenda.AgendaProfileAdminRepository;
import gg.agenda.api.AgendaMockData;
import gg.agenda.api.admin.agendaprofile.controller.request.AgendaProfileChangeAdminReqDto;
import gg.data.agenda.AgendaProfile;
import gg.data.agenda.type.Location;
import gg.data.user.User;
import gg.data.user.type.RoleType;
import gg.utils.TestDataUtils;
import gg.utils.annotation.IntegrationTest;

@IntegrationTest
@Transactional
@AutoConfigureMockMvc
public class AgendaProfileControllerAdminTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private TestDataUtils testDataUtils;
@Autowired
private AgendaMockData agendaMockData;
@Autowired
private AgendaProfileAdminRepository agendaProfileAdminRepository;
User user;
String accessToken;

@Nested
@DisplayName("개인 프로필 정보 변경")
class UpdateAgendaProfile {
@BeforeEach
void beforeEach() {
user = testDataUtils.createNewAdminUser(RoleType.ADMIN);
accessToken = testDataUtils.getLoginAccessTokenFromUser(user);
}

@Test
@DisplayName("유효한 정보로 개인 프로필을 변경합니다.")
void updateProfileWithValidData() throws Exception {
// Given
AgendaProfile agendaProfile = agendaMockData.createAgendaProfile(user, SEOUL);
agendaMockData.createTicket(agendaProfile);
AgendaProfileChangeAdminReqDto requestDto = new AgendaProfileChangeAdminReqDto("Valid user content",
"https://github.com/validUser", "SEOUL");
String content = objectMapper.writeValueAsString(requestDto);
// When
mockMvc.perform(patch("/agenda/admin/profile")
.param("intraId", user.getIntraId())
.header("Authorization", "Bearer " + accessToken)
.contentType(MediaType.APPLICATION_JSON)
.content(content))
.andExpect(status().isNoContent());
// Then
AgendaProfile result = agendaProfileAdminRepository.findByIntraId(user.getIntraId()).orElseThrow(null);
assertThat(result.getContent()).isEqualTo(requestDto.getUserContent());
assertThat(result.getGithubUrl()).isEqualTo(requestDto.getUserGithub());
assertThat(result.getLocation().name()).isEqualTo(requestDto.getUserLocation());
}

@Test
@DisplayName("ENUM 이외의 지역 정보가 들어온 경우 MIX로 저장합니다.")
void updateProfileWithInvalidLocation() throws Exception {
// Given
agendaMockData.createAgendaProfile(user, SEOUL);
AgendaProfileChangeAdminReqDto requestDto = new AgendaProfileChangeAdminReqDto("Valid user content",
"https://github.com/validUser", "INVALID_LOCATION");
String content = objectMapper.writeValueAsString(requestDto);

// When
mockMvc.perform(patch("/agenda/admin/profile")
.param("intraId", user.getIntraId())
.header("Authorization", "Bearer " + accessToken)
.contentType(MediaType.APPLICATION_JSON)
.content(content))
.andExpect(status().isNoContent());

// Then
AgendaProfile result = agendaProfileAdminRepository.findByIntraId(user.getIntraId()).orElseThrow();
assertThat(result.getLocation()).isEqualTo(Location.MIX);
}

@Test
@DisplayName("userContent 없이 개인 프로필을 변경합니다.")
void updateProfileWithoutUserContent() throws Exception {
// Given
AgendaProfileChangeAdminReqDto requestDto = new AgendaProfileChangeAdminReqDto("",
"https://github.com/validUser", "SEOUL");
String content = objectMapper.writeValueAsString(requestDto);
// When & Then
mockMvc.perform(patch("/agenda/admin/profile")
.header("Authorization", "Bearer " + accessToken)
.contentType(MediaType.APPLICATION_JSON)
.content(content))
.andExpect(status().isBadRequest());
}

@Test
@DisplayName("잘못된 형식의 userGithub로 개인 프로필을 변경합니다.")
void updateProfileWithInvalidUserGithub() throws Exception {
// Given
AgendaProfileChangeAdminReqDto requestDto = new AgendaProfileChangeAdminReqDto("Valid user content",
"invalidGithubUrl", "SEOUL");
String content = objectMapper.writeValueAsString(requestDto);
// When & Then
mockMvc.perform(patch("/agenda/admin/profile")
.header("Authorization", "Bearer " + accessToken)
.contentType(MediaType.APPLICATION_JSON)
.content(content))
.andExpect(status().isBadRequest());
}

@Test
@DisplayName("userContent가 허용된 길이를 초과하여 개인 프로필을 변경합니다.")
void updateProfileWithExceededUserContentLength() throws Exception {
// Given
String longContent = "a".repeat(1001); // Assuming the limit is 1000 characters
AgendaProfileChangeAdminReqDto requestDto = new AgendaProfileChangeAdminReqDto(longContent,
"https://github.com/validUser", "SEOUL");
String content = objectMapper.writeValueAsString(requestDto);
// When & Then
mockMvc.perform(patch("/agenda/admin/profile")
.header("Authorization", "Bearer " + accessToken)
.contentType(MediaType.APPLICATION_JSON)
.content(content))
.andExpect(status().isBadRequest());
}

@Test
@DisplayName("userGithub가 허용된 길이를 초과하여 개인 프로필을 변경합니다.")
void updateProfileWithExceededUserGithubLength() throws Exception {
// Given
String longGithubUrl = "https://github.com/" + "a".repeat(256); // Assuming the limit is 255 characters
AgendaProfileChangeAdminReqDto requestDto = new AgendaProfileChangeAdminReqDto("Valid user content",
longGithubUrl, "SEOUL");

String content = objectMapper.writeValueAsString(requestDto);

// When & Then
mockMvc.perform(patch("/agenda/admin/profile")
.header("Authorization", "Bearer " + accessToken)
.contentType(MediaType.APPLICATION_JSON)
.content(content))
.andExpect(status().isBadRequest());
}
}

}



6 changes: 6 additions & 0 deletions gg-data/src/main/java/gg/data/agenda/AgendaProfile.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,10 @@ public void updateProfile(String content, String githubUrl) {
this.content = content;
this.githubUrl = githubUrl;
}

public void updateProfileAdmin(String content, String githubUrl, Location location) {
this.content = content;
this.githubUrl = githubUrl;
this.location = location;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ public GroupedOpenApi agendaGroup() {
.build();
}

@Bean
public GroupedOpenApi agendaAdminGroup() {
return GroupedOpenApi.builder()
.group("agenda admin")
.pathsToMatch("/agenda/admin/**")
.packagesToScan("gg.agenda.api.admin")
.build();
}

@Bean
public GroupedOpenApi partyGroup() {
return GroupedOpenApi.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ protected void configure(HttpSecurity http) throws Exception {
.authorizeRequests()
.antMatchers("/pingpong/admin/**").hasRole("ADMIN")
.antMatchers("/party/admin/**").hasRole("ADMIN")
.antMatchers("/agenda/admin/**").hasRole("ADMIN")
.antMatchers("/admin/recruitments/**").hasRole("ADMIN")
.antMatchers(HttpMethod.PUT, "/pingpong/users/{intraId}").hasAnyRole("USER", "ADMIN")
.antMatchers(HttpMethod.POST, "/pingpong/match").hasAnyRole("USER", "ADMIN")
Expand Down
14 changes: 14 additions & 0 deletions gg-utils/src/testFixtures/java/gg/utils/TestDataUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,20 @@ public User createNewUser() {
return user;
}

public User createNewAdminUser(RoleType roleType) {
String randomId = UUID.randomUUID().toString().substring(0, 30);
User user = User.builder()
.eMail("email")
.intraId(randomId)
.racketType(RacketType.PENHOLDER)
.snsNotiOpt(SnsType.NONE)
.roleType(roleType)
.totalExp(1000)
.build();
userRepository.save(user);
return user;
}

public User createNewUser(String intraId) {
User user = User.builder()
.eMail("email")
Expand Down
Loading