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
1 change: 1 addition & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ dependencies {


// Flyway
implementation 'org.springframework.boot:spring-boot-flyway'
implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-database-postgresql'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.example.Piroin.project.domain.assignment.entity;

import com.example.Piroin.project.domain.curriculum.entity.StudySession;
import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDate;

@Entity
@Table(name = "assignment")
Expand All @@ -14,15 +14,15 @@ public class Assignment {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "session_id")
private StudySession session;
private Integer id; // SERIAL 타입에 매칭

@Column(nullable = false)
private String title;

private String content;
}
@Column(length = 255)
private String week;

@Column(name = "session_date")
private LocalDate sessionDate; // DATE 타입에 매칭

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class AssignmentItem {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Integer id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;

Expand All @@ -33,8 +34,17 @@ public class AdminAttendanceController {
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청")
})
@PostMapping("/admin/attendance/start")
public AttendanceCodeResponse startAttendance(@PathVariable Long studySessionId) {
AttendanceCode code = attendanceService.generateCodeAndCreateAttendances(studySessionId);
public AttendanceCodeResponse startAttendance() {

// 1. 오늘 날짜 구하기 (LocalDate 활용)
LocalDate today = LocalDate.now();

// 2. 서비스가 원하는 "yyyy-MM-dd" 형식의 문자열로 포맷팅
String todayStr = today.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));

// 3. 포맷팅된 오늘 날짜 문자열을 서비스에 넘겨줍니다.
AttendanceCode code = attendanceService.generateCodeAndCreateAttendances(todayStr);

return AttendanceCodeResponse.from(code);
}

Expand Down Expand Up @@ -71,7 +81,7 @@ public String expireActiveAttendance() {
@PutMapping("/admin/users/{userId}/status")
public boolean updateUserStatus(
@Parameter(description = "사용자 ID", example = "1")
@PathVariable Long userId,
@PathVariable Integer userId,
@RequestBody UpdateUserStatusReq req) {
return attendanceService.updateUserStatus(userId, req);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ public ApiResponse<AttendanceMarkResponse> markAttendance(
content = @Content(schema = @Schema(implementation = MarkAttendanceReq.class))
)
@RequestBody MarkAttendanceReq req,
@AuthenticationPrincipal Long userId
@AuthenticationPrincipal Integer userId
) {
// [수정] 서비스 메서드 스펙 변경에 맞춰 req.getStudySessionId()를 제거했습니다.
AttendanceMarkResponse response = attendanceService.markAttendance(
userId,
req.getStudySessionId(),
Long.valueOf(userId),
req.getCode()
);

Expand Down Expand Up @@ -77,7 +77,7 @@ public ApiResponse<AttendanceMarkResponse> markAttendance(
})
@GetMapping("/user")
public ApiResponse<List<AttendanceStatusRes>> getAttendanceByUserId(@AuthenticationPrincipal Long userId) {
return ApiResponse.success(attendanceService.findByUserId(userId));
return ApiResponse.success(attendanceService.findByUserId(Math.toIntExact(userId)));
}

// 3. 특정 유저의 특정 일자 출석 정보
Expand All @@ -93,7 +93,7 @@ public ApiResponse<List<AttendanceSlotRes>> getAttendanceByUserIdAndDate(
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date,
@AuthenticationPrincipal Long userId
) {
return ApiResponse.success(attendanceService.findByUserIdAndDate(userId, date));
return ApiResponse.success(attendanceService.findByUserIdAndDate(Math.toIntExact(userId), date));
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
package com.example.Piroin.project.domain.attendance.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Schema(description = "출석 차시별 상태")
public class AttendanceSlotRes {
private Long studySessionId;

@Schema(description = "출석 코드 ID")
private Integer attendanceCodeId; // 변수명을 의미에 맞게 변경!

private Boolean status;

public AttendanceSlotRes(Long studySessionId, Boolean status) {
this.studySessionId = studySessionId;
// 생성자 파라미터와 주입부도 변경
public AttendanceSlotRes(Integer attendanceCodeId, Boolean status) {
this.attendanceCodeId = attendanceCodeId;
this.status = status;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
@NoArgsConstructor
@Schema(description = "출석 체크 요청")
public class MarkAttendanceReq {
@Schema(description = "스터디 세션 ID", example = "1")
private Long studySessionId;
// @Schema(description = "스터디 세션 ID", example = "1")
// private Long studySessionId;

@Schema(description = "출석 코드", example = "1234")
private String code;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
package com.example.Piroin.project.domain.attendance.entity;

import com.example.Piroin.project.domain.curriculum.entity.StudySession;
import com.example.Piroin.project.domain.user.entity.User;
import jakarta.persistence.*;
import lombok.*;

import javax.xml.crypto.dsig.Manifest;

@Entity
@Table(
name = "attendance",
uniqueConstraints = {
@UniqueConstraint(
name = "uq_attendance_user_session",
columnNames = {"user_id", "study_session_id"}
)
}
)
@Table(name = "attendance")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
Expand All @@ -23,22 +16,22 @@ public class Attendance {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Integer id; // SERIAL 타입에 매칭 (Long -> Integer)

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
@JoinColumn(name = "attendance_code_id", nullable = false)
private AttendanceCode attendanceCode; // attendance_code_id 매핑

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "study_session_id")
private StudySession studySession;
@JoinColumn(name = "user_id", nullable = false)
private User user; // user_id 매핑

@Column(nullable = false)
private Boolean status;
private Boolean status; // BOOLEAN 타입에 매칭

public void updateStatus(Boolean status) {
this.status = status;
}

}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.example.Piroin.project.domain.attendance.entity;

import com.example.Piroin.project.domain.curriculum.entity.StudySession;
import jakarta.persistence.*;
import lombok.*;

Expand All @@ -14,20 +13,24 @@ public class AttendanceCode {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Integer id; // SERIAL 타입에 매칭 (Long -> Integer)

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "study_session_id")
private StudySession studySession;
@Column(name = "attendance_date")
private String attendanceDate;

@Column(name = "attendance_order")
private String attendanceOrder; // '1, 2, 3' 코멘트 항목

@Column(nullable = false, length = 20)
private String code;

@Column(name = "is_expired", nullable = false)
private Boolean isExpired;
private Boolean isExpired; // BOOLEAN 타입에 매칭

@Column(name = "field3")
private String field3;

public void expire() {
this.isExpired = true;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,22 @@

public interface AttendanceCodeRepository extends JpaRepository<AttendanceCode, Long> {

@Query("""
select count(ac)
from AttendanceCode ac
where ac.studySession.sessionDate = :date
""")
int countByStudySessionDate(@Param("date") LocalDate date);

List<AttendanceCode> findByIsExpiredFalse();


// [추가] 모든 활성화된 코드를 한 번에 만료 처리 (벌크 연산)
@Modifying
@Query("update AttendanceCode ac set ac.isExpired = true where ac.isExpired = false")
void expireAllActiveCodes();

Optional<AttendanceCode> findFirstByIsExpiredFalseOrderByIdDesc();

Optional<AttendanceCode> findByCodeAndIsExpiredFalse(String code);
// Optional<AttendanceCode> findByCodeAndStudySessionId(String code, Long studySessionId);

List<AttendanceCode> findByStudySessionId(Long studySessionId);
// 특정 날짜에 발급된 코드 개수 조회
long countByAttendanceDate(String attendanceDate);

Optional<AttendanceCode> findByCodeAndStudySessionId(String code, Long studySessionId);
// 만료되지 않은 코드 목록 조회
List<AttendanceCode> findByIsExpiredFalse();

Optional<AttendanceCode> findByCode(String code);
}


Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.example.Piroin.project.domain.attendance.repository;

import com.example.Piroin.project.domain.attendance.entity.AttendanceCode;
import com.example.Piroin.project.domain.user.entity.User;
import com.example.Piroin.project.domain.attendance.entity.Attendance;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDate;
Expand All @@ -11,19 +14,33 @@

public interface AttendanceRepository extends JpaRepository<Attendance, Long> {

List<Attendance> findByUserId(Long userId);

Optional<Attendance> findByUserIdAndStudySessionId(Long userId, Long studySessionId);
// List<Attendance> findByUserId(Long userId);

boolean existsByUserIdAndStudySessionId(Long userId, Long studySessionId);
//Optional<Attendance> findByUserIdAndStudySessionId(Integer userId, Long studySessionId);

List<Attendance> findByStudySessionId(Long studySessionId);

List<Attendance> findByStudySessionIdAndStatusFalse(Long studySessionId);
// 연관관계 필드명이 attendanceCode 라면 내부 ID인 Id를 조합하여 명명
Optional<Attendance> findByUserIdAndAttendanceCodeId(Long userId, Long attendanceCodeId);

List<Attendance> findByUserIdAndStudySessionSessionDate(Long userId, LocalDate date);
//List<Attendance> findByUserIdAndStudySessionSessionDate(Integer userId, LocalDate date);

int countByUserAndStatusFalse(User user);

// 1. 특정 출석 코드 ID에 해당하는 결석 데이터 조회
List<Attendance> findByAttendanceCodeIdAndStatusFalse(Integer attendanceCodeId);

// 2. 특정 유저 ID와 출석 코드의 날짜 조건으로 조회 (엔티티 그래프 참조: attendanceCode.attendanceDate)
@Query("SELECT a FROM Attendance a WHERE a.user.id = :userId AND a.attendanceCode.attendanceDate = :attendanceDate")
List<Attendance> findByUserIdAndDate(@Param("userId") Integer userId, @Param("attendanceDate") String attendanceDate);

// 3. 특정 유저의 모든 출석 데이터 조회
List<Attendance> findByUserId(Long userId);

// 특정 날짜에 발급된 출석 코드의 개수를 세는 메서드
//long countByAttendanceDate(String attendanceDate);

// 현재 만료되지 않은(활성화된) 출석 코드 목록을 가져오는 메서드
//List<AttendanceCode> findByIsExpiredFalse();
}


Loading
Loading