Skip to content
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
@@ -0,0 +1,6 @@
package sopt.comfit.company.domain;

import org.springframework.data.jpa.repository.JpaRepository;

public interface CompanyRepository extends JpaRepository<Company, Long> {
}
17 changes: 17 additions & 0 deletions src/main/java/sopt/comfit/company/exception/CompanyErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package sopt.comfit.company.exception;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import sopt.comfit.global.exception.ErrorCode;

@Getter
@RequiredArgsConstructor
public enum CompanyErrorCode implements ErrorCode {

COMPANY_NOT_FOUND(HttpStatus.NOT_FOUND, "COMPANY_404_001", "해당하는 회사를 찾을 수 없습니다");

private final HttpStatus status;
private final String prefix;
private final String message;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.beans.TypeMismatchException;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
Expand Down Expand Up @@ -169,6 +170,17 @@ public ResponseEntity<CustomErrorResponse> handleMediaTypeNotSupported(HttpMedia
return convert(CommonErrorCode.NOT_SUPPORTED_MEDIA_TYPE_ERROR);
}

/**
*데이터 정합성 예외
*unique key, FK, NOT NULL 위반
*/
@ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<CustomErrorResponse> handleDataIntegrityViolation(DataIntegrityViolationException e) {

log.warn("Data integrity violation: {}", e.getMessage());
return convert(CommonErrorCode.DATA_INTEGRITY_VIOLATION);
}

/**
* 예상치 못한 서버 오류 처리 (500)
* 위의 핸들러들로 처리되지 않은 모든 RuntimeException
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public enum CommonErrorCode implements ErrorCode {
NOT_FOUND_URI(HttpStatus.NOT_FOUND, "COMMON_006", "존재하지 않는 URI입니다."),
NOT_SUPPORTED_METHOD_ERROR(HttpStatus.METHOD_NOT_ALLOWED, "COMMON_007", "지원하지 않는 HTTP 메서드입니다."),
NOT_SUPPORTED_MEDIA_TYPE_ERROR(HttpStatus.UNSUPPORTED_MEDIA_TYPE, "COMMON_008", "지원하지 않는 미디어 타입입니다."),
DATA_INTEGRITY_VIOLATION(HttpStatus.BAD_REQUEST, "COMMON_009", "데이터 정합성 오류입니다"),
NOT_SUPPORTED_SORT_TYPE(HttpStatus.BAD_REQUEST, "COMMON_010", "지원하지 않는 정렬 타입입니다."),

// ==== 인증/인가 에러 (4xx) ====
// ==== 인증 에러 (4xx) ====
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package sopt.comfit.report.domain;

import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface AIReportRepository extends JpaRepository<AIReport, Long> {
boolean existsByCompanyIdAndUserId(Long companyId, Long userId);
}
49 changes: 49 additions & 0 deletions src/main/java/sopt/comfit/user/controller/UserController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package sopt.comfit.user.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import sopt.comfit.global.annotation.LoginUser;
import sopt.comfit.global.dto.PageDto;
import sopt.comfit.global.enums.ESort;
import sopt.comfit.user.dto.response.GetBookmarkCompany;
import sopt.comfit.user.dto.response.GetMeResponseDto;
import sopt.comfit.user.service.UserService;

@RestController
@RequestMapping("/api/v1/me")
@RequiredArgsConstructor
public class UserController implements UserSwagger {

private final UserService userService;

@Override
public GetMeResponseDto getMe (@LoginUser Long userId){
return userService.getMe(userId);
}

@Override
public Long addBookmark(@LoginUser Long userId,
@PathVariable Long companyId){
return userService.addBookmark(userId, companyId);
}

@Override
public void removeBookmark(@LoginUser Long userId,
@PathVariable Long companyId) {
userService.removeBookmark(userId, companyId);
}

@Override
public PageDto<GetBookmarkCompany> getBookmarkCompany(@LoginUser Long userId,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "LATEST") ESort sort){
Pageable pageable = PageRequest.of(page, 6);
return userService.getBookmarkCompany(userId, sort, pageable);
}

}
135 changes: 135 additions & 0 deletions src/main/java/sopt/comfit/user/controller/UserSwagger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package sopt.comfit.user.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import sopt.comfit.global.annotation.LoginUser;
import sopt.comfit.global.dto.CommonApiResponse;
import sopt.comfit.global.dto.CustomErrorResponse;
import sopt.comfit.global.dto.PageDto;
import sopt.comfit.global.enums.ESort;
import sopt.comfit.user.dto.response.GetBookmarkCompany;
import sopt.comfit.user.dto.response.GetMeResponseDto;

@Tag(name = "me", description = "사용자 관련 API")
public interface UserSwagger {

@Operation(
summary = "사용자 프로필 조회 API",
description = "사용자 프로필 조회 API입니다"
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "프로필 조회 성공",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CommonApiResponse.class))),

@ApiResponse(responseCode = "403", description = "권한 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class))),
@ApiResponse(responseCode = "401", description = "헤더값 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class))),
@ApiResponse(responseCode = "404", description = "사용자 id 값 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class)))
})
@GetMapping
@SecurityRequirement(name = "JWT")
GetMeResponseDto getMe (@LoginUser Long userId);


@Operation(
summary = "관심 기업 북마크 API",
description = "관심 기업 북마크 API입니다"
)
@ApiResponses({
@ApiResponse(responseCode = "201", description = "관심 기업 북마크 추가 성공",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CommonApiResponse.class))),

@ApiResponse(responseCode = "403", description = "권한 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class))),
@ApiResponse(responseCode = "401", description = "헤더값 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class))),
@ApiResponse(responseCode = "404", description = "사용자 id 값 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class))),
@ApiResponse(responseCode = "404", description = "회사 id 값 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class))),
@ApiResponse(responseCode = "400", description = "중복 저장 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class)))

})
@PostMapping("/companies/{companyId}")
@SecurityRequirement(name = "JWT")
@ResponseStatus(HttpStatus.CREATED)
Long addBookmark(@LoginUser Long userId,
@PathVariable Long companyId);

@Operation(
summary = "관심 기업 북마크 삭제 API",
description = "관심 기업 북마크 삭제 API입니다"
)
@ApiResponses({
@ApiResponse(responseCode = "204", description = "관심 기업 북마크 삭제 성공",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CommonApiResponse.class))),

@ApiResponse(responseCode = "403", description = "권한 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class))),
@ApiResponse(responseCode = "401", description = "헤더값 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class))),
@ApiResponse(responseCode = "404", description = "사용자 id 값 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class))),
@ApiResponse(responseCode = "404", description = "회사 id 값 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class)))
})
@DeleteMapping("/companies/{companyId}")
@SecurityRequirement(name = "JWT")
@ResponseStatus(HttpStatus.NO_CONTENT)
void removeBookmark(@LoginUser Long userId,
@PathVariable Long companyId);

@Operation(
summary = "관심 기업 북마크 조회 리스트 API",
description = "관심 기업 북마크 조회 리스트 API입니다"
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "북마크 기업 리스트 조회 성공",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CommonApiResponse.class))),

@ApiResponse(responseCode = "403", description = "권한 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class))),
@ApiResponse(responseCode = "401", description = "헤더값 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class))),
@ApiResponse(responseCode = "404", description = "사용자 id 값 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class))),
@ApiResponse(responseCode = "400", description = "지원하지 않는 정렬 값 오류",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = CustomErrorResponse.class)))

})
@GetMapping("/companies")
@SecurityRequirement(name = "JWT")
PageDto<GetBookmarkCompany> getBookmarkCompany(@LoginUser Long userId,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "LATEST") ESort sort);
}
16 changes: 16 additions & 0 deletions src/main/java/sopt/comfit/user/domain/UserCompany.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import sopt.comfit.company.domain.Company;
Expand All @@ -26,4 +27,19 @@ public class UserCompany extends BaseTimeEntity {

@Column(name = "is_connected", nullable = false)
private boolean isConnected;

@Builder(access = AccessLevel.PRIVATE)
private UserCompany(final User user,
final Company company,
final boolean isConnected) {
this.user = user;
this.company = company;
this.isConnected = isConnected;
}

public static UserCompany create(final User user,
final Company company,
final boolean isConnected) {
return new UserCompany(user, company, isConnected);
}
}
17 changes: 17 additions & 0 deletions src/main/java/sopt/comfit/user/domain/UserCompanyRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package sopt.comfit.user.domain;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface UserCompanyRepository extends JpaRepository<UserCompany, Long> {
Optional<UserCompany> findByCompanyIdAndUserId(Long companyId, Long userId);

Page<UserCompany> findByUserIdOrderByCreatedAtAsc(Long userId, Pageable pageable);

Page<UserCompany> findByUserIdOrderByCreatedAtDesc(Long userId, Pageable pageable);

Page<UserCompany> findByUserIdOrderByCompanyName(Long companyId, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package sopt.comfit.user.dto.response;

import sopt.comfit.user.domain.UserCompany;

import java.time.LocalDate;

public record GetBookmarkCompany(

Long id,

Long companyId,

String name,

LocalDate createdAt,

boolean isConnected
) {
public static GetBookmarkCompany from(UserCompany userCompany){
return new GetBookmarkCompany(
userCompany.getId(),
userCompany.getCompany().getId(),
userCompany.getCompany().getName(),
userCompany.getCreatedAt().toLocalDate(),
userCompany.isConnected()
);
}
}
29 changes: 29 additions & 0 deletions src/main/java/sopt/comfit/user/dto/response/GetMeResponseDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package sopt.comfit.user.dto.response;

import sopt.comfit.global.enums.EIndustry;
import sopt.comfit.user.domain.EEducationLevel;
import sopt.comfit.user.domain.EJob;
import sopt.comfit.user.domain.User;

public record GetMeResponseDto(

String name,

String email,

EEducationLevel educationLevel,

EIndustry firstIndustry,

EJob fistJob
) {
public static GetMeResponseDto from(User user) {
return new GetMeResponseDto(
user.getName(),
user.getEmail(),
user.getEducationLevel(),
user.getFirstIndustry(),
user.getFirstJob()
);
}
}
17 changes: 17 additions & 0 deletions src/main/java/sopt/comfit/user/exception/UserCompanyErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package sopt.comfit.user.exception;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import sopt.comfit.global.exception.ErrorCode;

@Getter
@RequiredArgsConstructor
public enum UserCompanyErrorCode implements ErrorCode {

USER_COMPANY_NOT_FOUND(HttpStatus.NOT_FOUND, "USER_COMPANY_404_001", "해당하는 북마크 기업을 찾을 수 없습니다");

private final HttpStatus status;
private final String prefix;
private final String message;
}
4 changes: 2 additions & 2 deletions src/main/java/sopt/comfit/user/exception/UserErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
@Getter
public enum UserErrorCode implements ErrorCode {

USER_NOT_FOUND(HttpStatus.NOT_FOUND, "USER_001", "해당하는 유저를 찾을 수 없습니다."),
INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "USER_002", "비밀번호가 일치하지 않습니다."),;
USER_NOT_FOUND(HttpStatus.NOT_FOUND, "USER_404_001", "해당하는 유저를 찾을 수 없습니다."),
INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "USER_400_002", "비밀번호가 일치하지 않습니다."),;



Expand Down
Loading