Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
5094fcb
feat: 관리자 엔티티 구현
1winhyun Dec 27, 2025
3b6eb63
feat: 관리자 관련 jwt 추가
1winhyun Dec 27, 2025
13fcbf8
feat: 관리자 로그인 기능 구현
1winhyun Dec 27, 2025
0c6739f
refactor: 관리자 로그인 기능 PermitUrlConfig 추가
1winhyun Dec 27, 2025
d8f6778
refactor: conflict 해결
1winhyun Jan 4, 2026
f628d13
feat: conflict(충돌) 해결
1winhyun Jan 4, 2026
95e55d6
Merge remote-tracking branch 'origin/refactor/#22' into refactor/#22
1winhyun Jan 4, 2026
bfddc06
refactor: CurrentManagerId 어노테이션 분리
1winhyun Jan 4, 2026
2bfd2b5
Merge remote-tracking branch 'origin/dev' into refactor/#22
1winhyun Jan 4, 2026
687c944
refactor: WebMvcConfig에 CurrentManagerIdArgumentResolver 추가
1winhyun Jan 4, 2026
2367375
refactor: StudentCouncil 관리자 승인 여부 컬럼 추가
1winhyun Jan 4, 2026
5d49fec
refactor: 학생회 회원가입 시 토큰 미발급되며 학생회 인증 여부는 false가 되도록 수정
1winhyun Jan 4, 2026
8a3d957
feat: 학생회 회원가입 요청 시 관리자 인증 및 결과 메일 전송 로직 구현
1winhyun Jan 4, 2026
1d7dfdf
refactor: 학생회 대표자 로그인 및 전용 api의 경우 학생회 조회 로직에 관리자 승인 받은 상태 조건 추가
1winhyun Jan 4, 2026
b76da83
feat: StudentCouncil에 councilName 컬럼 추가 및 학생회 이름 생성 로직 구현
1winhyun Jan 5, 2026
5126e4d
refactor: StudentCouncilSignUpRequest에 당선 사진 추가
1winhyun Jan 5, 2026
53fb30e
feat: 학생회 대표자 회원가입 요청 목록 조회 기능 구현
1winhyun Jan 5, 2026
cda307d
refactor: manager 관련 에러코드 변경
1winhyun Jan 5, 2026
49ae65d
refactor: 학생회가 작성하는 글의 업데이트, 삭제 기능 승인되지 않은 학생회는 불가능하도록 승인상태 확인 추가
1winhyun Jan 5, 2026
811b700
refactor: manager의 PasswordNotCorrectException import 경로 수정
1winhyun Jan 5, 2026
e07bc01
refactor: managerApprove 메서드명 오타 수정
1winhyun Jan 5, 2026
dbd9496
refactor: getCertifyRequestCouncil 승인 대기중인 학생회만 조회되도록 수정
1winhyun Jan 5, 2026
685b4be
refactor: PermitUrlConfig 중복 제거
1winhyun Jan 5, 2026
1284fa8
refactor: StudentCouncilSignUpRequest 당선 사진 @NotBlank 추가
1winhyun Jan 5, 2026
e9f06f9
refactor: managerApproved 컬럼 null이 될 수 없도록 설정
1winhyun Jan 5, 2026
2b698dd
refactor: approveOrDenyCouncil에서 학생회의 경우 미승인 학생회만 조회되도록 수정
1winhyun Jan 5, 2026
5f71d89
refactor: 학생회 회원가입 id 중복 검증 api 구현
1winhyun Jan 6, 2026
cebfdb1
refactor: setCouncilName을 generateCouncilName으로 메서드명 수정
1winhyun Jan 6, 2026
7e65f62
refactor: validateLoginId 앤드포인트 수정
1winhyun Jan 6, 2026
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,11 @@
package com.campus.campus.domain.council.application.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;

public record StudentCouncilLoginIdValidateRequest(
@Schema(description = "회원가입 id", example = "dede1234")
@NotBlank
String loginId
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public record StudentCouncilSignUpRequest(
Long collegeId,

@Schema(description = "학과 id", example = "1")
Long majorId
Long majorId,

@Schema(description = "당선 사진 url", example = "https://www.election.com.png")
@NotBlank
String electionImageUrl
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public record StudentCouncilLoginResponse(
String collegeName,

@Schema(description = "학과 이름 (없으면 null)", example = "컴퓨터공학과")
String majorName
String majorName,

@Schema(description = "학생회 이름", example = "가천대학교 총학생회")
String councilName
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public StudentCouncil createStudentCouncil(StudentCouncilSignUpRequest studentCo
.school(school)
.college(college)
.major(major)
.electionImageUrl(studentCouncilSignUpRequest.electionImageUrl())
.managerApproved(false)
.build();
}

Expand All @@ -44,7 +46,8 @@ public StudentCouncilLoginResponse toStudentCouncilLoginResponse(StudentCouncil
studentCouncil.getCouncilType(),
studentCouncil.getSchool().getSchoolName(),
studentCouncil.getCollege() != null ? studentCouncil.getCollege().getCollegeName() : null,
studentCouncil.getMajor() != null ? studentCouncil.getMajor().getMajorName() : null
studentCouncil.getMajor() != null ? studentCouncil.getMajor().getMajorName() : null,
studentCouncil.getCouncilName()
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.springframework.transaction.annotation.Transactional;

import com.campus.campus.domain.council.application.dto.request.StudentCouncilFindPasswordRequest;
import com.campus.campus.domain.council.application.dto.request.StudentCouncilLoginIdValidateRequest;
import com.campus.campus.domain.council.application.dto.request.StudentCouncilLoginRequest;
import com.campus.campus.domain.council.application.dto.request.StudentCouncilSignUpRequest;
import com.campus.campus.domain.council.application.dto.request.StudentCouncilWithdrawRequest;
Expand All @@ -23,6 +24,7 @@
import com.campus.campus.domain.council.application.exception.SignupEmailNotFoundException;
import com.campus.campus.domain.council.application.exception.StudentCouncilNotFoundException;
import com.campus.campus.domain.council.application.mapper.StudentCouncilLoginMapper;
import com.campus.campus.domain.council.application.util.CouncilNameGenerator;
import com.campus.campus.domain.council.domain.entity.StudentCouncil;
import com.campus.campus.domain.council.domain.repository.StudentCouncilRepository;
import com.campus.campus.domain.mail.application.exception.EmailVerificationNotFoundException;
Expand Down Expand Up @@ -60,13 +62,14 @@ public class CouncilLoginService {
private final SecurityConfig securityConfig;
private final PasswordEncoder passwordEncoder;
private final RedisTokenService redisTokenService;
private final CouncilNameGenerator councilNameGenerator;

@Value("${jwt.refresh.expiration-seconds}")
private long refreshTokenExpirationSeconds;

@Transactional
public StudentCouncilLoginResponse signUp(StudentCouncilSignUpRequest studentCouncilSignUpRequest) {
if(studentCouncilRepository.existsByEmailAndDeletedAtIsNotNull(studentCouncilSignUpRequest.email())){
public void signUp(StudentCouncilSignUpRequest studentCouncilSignUpRequest) {
if (studentCouncilRepository.existsByEmailAndDeletedAtIsNotNull(studentCouncilSignUpRequest.email())) {
throw new CouncilSignupForbiddenException();
}
if (studentCouncilRepository.existsByEmail(studentCouncilSignUpRequest.email())) {
Expand All @@ -88,22 +91,23 @@ public StudentCouncilLoginResponse signUp(StudentCouncilSignUpRequest studentCou
StudentCouncil studentCouncil = studentCouncilLoginMapper.createStudentCouncil(
studentCouncilSignUpRequest, school, scope.college, scope.major);

studentCouncilRepository.save(studentCouncil);

String accessToken = jwtProvider.createCouncilAccessToken(studentCouncil.getId());
String refreshToken = jwtProvider.createCouncilRefreshToken(studentCouncil.getId());
String councilName = councilNameGenerator.buildCouncilName(studentCouncil);
studentCouncil.generateCouncilName(councilName);

redisTokenService.setRefreshToken("COUNCIL", String.valueOf(studentCouncil.getId()), refreshToken,
refreshTokenExpirationSeconds);
studentCouncilRepository.save(studentCouncil);

emailVerification.use();
}

return studentCouncilLoginMapper.toStudentCouncilLoginResponse(studentCouncil, accessToken, refreshToken);
public void validateLoginId(StudentCouncilLoginIdValidateRequest studentCouncilLoginIdValidateRequest) {
if (studentCouncilRepository.existsByLoginId(studentCouncilLoginIdValidateRequest.loginId())) {
throw new LoginIdAlreadyExistsException();
}
}

public StudentCouncilLoginResponse login(StudentCouncilLoginRequest studentCouncilLoginRequest) {
StudentCouncil studentCouncil = studentCouncilRepository
.findByLoginIdAndDeletedAtIsNull(studentCouncilLoginRequest.loginId())
.findByLoginIdAndManagerApprovedIsTrueAndDeletedAtIsNull(studentCouncilLoginRequest.loginId())
.orElseThrow(StudentCouncilNotFoundException::new);

if (!passwordEncoder.matches(studentCouncilLoginRequest.password(), studentCouncil.getPassword())) {
Expand All @@ -127,7 +131,8 @@ public StudentCouncilFindIdResponse findId(String email) {
throw new SignupEmailNotFoundException();
}

StudentCouncil studentCouncil = studentCouncilRepository.findByEmailAndDeletedAtIsNull(email)
StudentCouncil studentCouncil = studentCouncilRepository
.findByEmailAndManagerApprovedIsTrueAndDeletedAtIsNull(email)
.orElseThrow(StudentCouncilNotFoundException::new);

emailVerification.use();
Expand All @@ -138,7 +143,7 @@ public StudentCouncilFindIdResponse findId(String email) {
@Transactional
public void findPassword(StudentCouncilFindPasswordRequest studentCouncilFindPasswordRequest) {
StudentCouncil studentCouncil = studentCouncilRepository
.findByLoginIdAndDeletedAtIsNull(studentCouncilFindPasswordRequest.loginId())
.findByLoginIdAndManagerApprovedIsTrueAndDeletedAtIsNull(studentCouncilFindPasswordRequest.loginId())
.orElseThrow(StudentCouncilNotFoundException::new);

if (!studentCouncilFindPasswordRequest.email().equals(studentCouncil.getEmail())) {
Expand All @@ -157,7 +162,8 @@ public void findPassword(StudentCouncilFindPasswordRequest studentCouncilFindPas

@Transactional
public void withdrawCouncil(Long councilId, StudentCouncilWithdrawRequest studentCouncilWithdrawRequest) {
StudentCouncil studentCouncil = studentCouncilRepository.findByIdAndDeletedAtIsNull(councilId)
StudentCouncil studentCouncil = studentCouncilRepository
.findByIdAndManagerApprovedIsTrueAndDeletedAtIsNull(councilId)
.orElseThrow(StudentCouncilNotFoundException::new);

if (!studentCouncilWithdrawRequest.precaution()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public class CouncilService {

@Transactional
public void changeEmail(Long councilId, StudentCouncilChangeEmailRequest studentCouncilChangeEmailRequest) {
StudentCouncil studentCouncil = studentCouncilRepository.findByIdAndDeletedAtIsNull(councilId)
StudentCouncil studentCouncil = studentCouncilRepository
.findByIdAndManagerApprovedIsTrueAndDeletedAtIsNull(councilId)
.orElseThrow(StudentCouncilNotFoundException::new);

//soft delete된 유저가 예상치 못하게 계정을 복구해야할 수도 있기에 이를 막기 위해 deleteAt이 존재하더라도 조회되게 한다.
Expand All @@ -50,7 +51,8 @@ public void changeEmail(Long councilId, StudentCouncilChangeEmailRequest student
@Transactional
public void changePassword(Long councilId,
StudentCouncilChangePasswordRequest studentCouncilChangePasswordRequest) {
StudentCouncil studentCouncil = studentCouncilRepository.findByIdAndDeletedAtIsNull(councilId)
StudentCouncil studentCouncil = studentCouncilRepository
.findByIdAndManagerApprovedIsTrueAndDeletedAtIsNull(councilId)
.orElseThrow(StudentCouncilNotFoundException::new);

if (!securityConfig.passwordEncoder()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.campus.campus.domain.council.application.util;

import org.springframework.stereotype.Component;

import com.campus.campus.domain.council.domain.entity.CouncilType;
import com.campus.campus.domain.council.domain.entity.StudentCouncil;

@Component
public class CouncilNameGenerator {
public String buildCouncilName(StudentCouncil studentCouncil) {
String schoolName = studentCouncil.getSchool() != null ? studentCouncil.getSchool().getSchoolName() : "";
CouncilType councilType = studentCouncil.getCouncilType();

return switch (councilType) {
case SCHOOL_COUNCIL -> String.format("%s 총학생회", schoolName).trim();
case COLLEGE_COUNCIL -> String.format("%s %s 학생회", schoolName, getCollegeName(studentCouncil)).trim();
case MAJOR_COUNCIL -> String.format("%s %s 학생회", schoolName, getMajorName(studentCouncil)).trim();
};
Comment on lines +10 to +18
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "StudentCouncil.java" | head -5

Repository: our-campUS/our-campUS-BE

Length of output: 150


🏁 Script executed:

cat -n ./src/main/java/com/campus/campus/domain/council/domain/entity/StudentCouncil.java

Repository: our-campUS/our-campUS-BE

Length of output: 3225


councilType@NotNull 검증 추가 권장

councilType 필드는 데이터베이스 레벨에서 nullable = false 제약이 있어 NULL 값이 저장될 수 없습니다. 다만 엔티티 수준의 유효성 검증을 강화하기 위해 @NotNull 또는 @jakarta.validation.constraints.NotNull 애너테이션을 추가하는 것이 좋습니다. 이는 메모리 상태에서의 객체 생성 시에도 안전성을 보장합니다.

🤖 Prompt for AI Agents
In
@src/main/java/com/campus/campus/domain/council/application/util/CouncilNameGenerator.java
around lines 10-18, Add a NotNull validation to the councilType field on the
StudentCouncil entity to enforce non-null at the object level: annotate the
councilType field (used by buildCouncilName in CouncilNameGenerator) with
@NotNull (or @jakarta.validation.constraints.NotNull), import the appropriate
annotation, and run/adjust any tests that construct StudentCouncil instances to
provide a councilType to satisfy the new constraint.

}

private String getCollegeName(StudentCouncil studentCouncil) {
if (studentCouncil.getCollege() == null) {
return "";
}
return studentCouncil.getCollege().getCollegeName();
}

private String getMajorName(StudentCouncil studentCouncil) {
if (studentCouncil.getMajor() == null) {
return "";
}
return studentCouncil.getMajor().getMajorName();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ public class StudentCouncil extends BaseEntity {
@JoinColumn(name = "major_id")
private Major major;

@Column(name = "council_name")
private String councilName;

@Column(name = "election_image_url")
private String electionImageUrl;

@Column(name = "manager_approved", nullable = false)
private boolean managerApproved;

@Column(name = "deleted_at")
private LocalDateTime deletedAt;

Expand All @@ -73,18 +82,15 @@ public void changePassword(String newPassword) {
this.password = newPassword;
}

public String getFullCouncilName() {
StringBuilder fullName = new StringBuilder();
if (school != null)
fullName.append(school.getSchoolName());
if (college != null)
fullName.append(" ").append(college.getCollegeName());
if (major != null)
fullName.append(" ").append(major.getMajorName());
return fullName.append(" 학생회").toString().trim();
}

public void changeEmail(String newEmail) {
this.email = newEmail;
}

public void generateCouncilName(String councilName) {
this.councilName = councilName;
}

public void managerApprove() {
this.managerApproved = true;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.campus.campus.domain.council.domain.repository;

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

import org.springframework.data.jpa.repository.JpaRepository;
Expand All @@ -9,28 +10,36 @@
import com.campus.campus.domain.council.domain.entity.StudentCouncil;

public interface StudentCouncilRepository extends JpaRepository<StudentCouncil, Long> {
Optional<StudentCouncil> findByLoginIdAndDeletedAtIsNull(String loginId);
Optional<StudentCouncil> findByLoginIdAndManagerApprovedIsTrueAndDeletedAtIsNull(String loginId);

Optional<StudentCouncil> findByLoginId(String loginId);
Optional<StudentCouncil> findByEmailAndManagerApprovedIsTrueAndDeletedAtIsNull(String email);

Optional<StudentCouncil> findByEmailAndDeletedAtIsNull(String email);
@Query("SELECT sc FROM StudentCouncil sc " +
"LEFT JOIN FETCH sc.school " +
"LEFT JOIN FETCH sc.college " +
"LEFT JOIN FETCH sc.major " +
"WHERE sc.id = :councilId AND sc.deletedAt IS NULL AND sc.managerApproved IS TRUE")
Optional<StudentCouncil> findByIdWithDetailsAndManagerApprovedIsTrueAndDeletedAtIsNull(
@Param("councilId") Long councilId);

@Query("SELECT sc FROM StudentCouncil sc " +
"LEFT JOIN FETCH sc.school " +
"LEFT JOIN FETCH sc.college " +
"LEFT JOIN FETCH sc.major " +
"WHERE sc.id = :councilId AND sc.deletedAt IS NULL")
Optional<StudentCouncil> findByIdWithDetailsAndDeletedAtIsNull(@Param("councilId") Long councilId);
"WHERE sc.deletedAt IS NULL AND sc.managerApproved IS FALSE")
List<StudentCouncil> findByManagerWithDetailsApprovedIsFalseAndDeletedAtIsNull();

boolean existsByLoginId(String loginId);

boolean existsByEmail(String email);

boolean existsByEmailAndDeletedAtIsNull(String email);

Optional<StudentCouncil> findByIdAndDeletedAtIsNull(Long councilId);
Optional<StudentCouncil> findByIdAndManagerApprovedIsTrueAndDeletedAtIsNull(Long councilId);

Optional<StudentCouncil> findByIdAndManagerApprovedIsFalseAndDeletedAtIsNull(Long councilId);

boolean existsByIdAndDeletedAtIsNull(Long councilId);
boolean existsByIdAndManagerApprovedIsTrueAndDeletedAtIsNull(Long councilId);

boolean existsByEmailAndDeletedAtIsNotNull(String email);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.springframework.web.bind.annotation.RestController;

import com.campus.campus.domain.council.application.dto.request.StudentCouncilFindPasswordRequest;
import com.campus.campus.domain.council.application.dto.request.StudentCouncilLoginIdValidateRequest;
import com.campus.campus.domain.council.application.dto.request.StudentCouncilLoginRequest;
import com.campus.campus.domain.council.application.dto.request.StudentCouncilSignUpRequest;
import com.campus.campus.domain.council.application.dto.request.StudentCouncilWithdrawRequest;
Expand All @@ -31,11 +32,19 @@ public class StudentCouncilLoginController {

@PostMapping("/signup")
@Operation(summary = "학생회 회원가입")
public CommonResponse<StudentCouncilLoginResponse> Signup(
@Valid @RequestBody StudentCouncilSignUpRequest studentCouncilSignUpRequest) {
StudentCouncilLoginResponse response = councilLoginService.signUp(studentCouncilSignUpRequest);
public CommonResponse<Void> Signup(@Valid @RequestBody StudentCouncilSignUpRequest studentCouncilSignUpRequest) {
councilLoginService.signUp(studentCouncilSignUpRequest);

return CommonResponse.success(StudentCouncilResponseCode.SIGNUP_SUCCESS, response);
return CommonResponse.success(StudentCouncilResponseCode.SIGNUP_REQUEST_SUCCESS);
}

@PostMapping("/signup/validate")
@Operation(summary = "학생회 회원가입 id 중복 검증")
public CommonResponse<Void> validateLoginId(
@Valid @RequestBody StudentCouncilLoginIdValidateRequest studentCouncilLoginIdValidateRequest) {
councilLoginService.validateLoginId(studentCouncilLoginIdValidateRequest);

return CommonResponse.success(StudentCouncilResponseCode.VALIDATE_LOGIN_ID_SUCCESS);
}

@PostMapping("/login")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
@Getter
@AllArgsConstructor
public enum StudentCouncilResponseCode implements ResponseCodeInterface {
SIGNUP_SUCCESS(200, HttpStatus.OK, "학생회 회원가입에 성공했습니다."),
SIGNUP_REQUEST_SUCCESS(200, HttpStatus.OK, "학생회 회원가입 요청에 성공했습니다."),
VALIDATE_LOGIN_ID_SUCCESS(200, HttpStatus.OK, "회원가입 로그인 id 중복 검증에 성공했습니다."),
LOGIN_SUCCESS(200, HttpStatus.OK, "학생회 로그인에 성공했습니다."),
FIND_ID_SUCCESS(200, HttpStatus.OK, "아이디 찾기에 성공했습니다."),
FIND_PASSWORD_SUCCESS(200, HttpStatus.OK, "비밀번호 재설정에 성공했습니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public NoticeResponse toNoticeResponse(StudentCouncilNotice notice, List<String>
return NoticeResponse.builder()
.id(notice.getId())
.writerId(notice.getWriter().getId())
.writerName(notice.getWriter().getFullCouncilName())
.writerName(notice.getWriter().getCouncilName())
.isWriter(notice.isWrittenByCouncil(councilId))
.title(notice.getTitle())
.content(notice.getContent())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ public NoticeResponse create(Long councilId, NoticeRequest dto) {
throw new NoticeImageLimitExceededException();
}

StudentCouncil writer = studentCouncilRepository.findByIdWithDetailsAndDeletedAtIsNull(councilId)
StudentCouncil writer = studentCouncilRepository.
findByIdWithDetailsAndManagerApprovedIsTrueAndDeletedAtIsNull(councilId)
.orElseThrow(StudentCouncilNotFoundException::new);

StudentCouncilNotice notice =
Expand Down Expand Up @@ -105,6 +106,8 @@ public Page<NoticeListItemResponse> findAll(int page, int size, Long councilId)

@Transactional
public NoticeResponse update(Long councilId, Long noticeId, NoticeRequest dto) {
studentCouncilRepository.findByIdAndManagerApprovedIsTrueAndDeletedAtIsNull(councilId)
.orElseThrow(StudentCouncilNotFoundException::new);

if (dto.imageUrls() != null && dto.imageUrls().size() > MAX_IMAGE_COUNT) {
throw new NoticeImageLimitExceededException();
Expand Down Expand Up @@ -145,6 +148,8 @@ public NoticeResponse update(Long councilId, Long noticeId, NoticeRequest dto) {

@Transactional
public void delete(Long councilId, Long noticeId) {
studentCouncilRepository.findByIdAndManagerApprovedIsTrueAndDeletedAtIsNull(councilId)
.orElseThrow(StudentCouncilNotFoundException::new);

StudentCouncilNotice notice = noticeRepository.findByIdWithFullInfo(noticeId)
.orElseThrow(NoticeNotFoundException::new);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public PostResponse toPostResponse(StudentCouncilPost post, List<String> images,
var builder = PostResponse.builder()
.id(post.getId())
.writerId(writer.getId())
.writerName(writer.getFullCouncilName())
.writerName(writer.getCouncilName())
.isWriter(post.isWrittenByCouncil(currentUserId))
.category(post.getCategory())
.title(post.getTitle())
Expand Down
Loading