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
Expand Up @@ -30,7 +30,7 @@ public class ActivityLog {

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private ActivityType type; // ATTENDANCE, BOARD, BETTING 등
private ActivityType activityType; // ATTENDANCE, BOARD, BETTING 등

@Column(nullable = false, length = 30)
private String message; // "자유게시판에 글을 게시했어요"
Expand All @@ -42,10 +42,10 @@ public class ActivityLog {
private LocalDateTime createdAt;

@Builder
public ActivityLog(UUID userId, String username, ActivityType type, String message, UUID targetId, String boardName) {
public ActivityLog(UUID userId, String username, ActivityType activityType, String message, UUID targetId, String boardName) {
this.userId = userId;
this.username = username;
this.type = type;
this.activityType = activityType;
this.message = message;
Comment thread
discipline24 marked this conversation as resolved.
this.targetId = targetId;
this.boardName = boardName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
public record ActivityEvent(
UUID userId,
String username,
ActivityType type,
ActivityType activityType,
String message,
UUID targetId,
String boardName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public void handleActivityEvent(ActivityEvent event) {
ActivityLog log = activityLogRepository.save(ActivityLog.builder()
.userId(event.userId())
.username(event.username())
.type(event.type())
.activityType(event.activityType())
.message(event.message())
.targetId(event.targetId())
.boardName(event.boardName())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.sejongisc.backend.activity.repository;

import org.sejongisc.backend.activity.entity.ActivityLog;
import org.sejongisc.backend.activity.entity.ActivityType;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
Expand All @@ -15,17 +16,20 @@ public interface ActivityLogRepository extends JpaRepository<ActivityLog, Long>
// 이슈 1: 메인 대시보드 실시간 로그 (최신순 20개)
List<ActivityLog> findTop20ByOrderByCreatedAtDesc();

// 이슈 2: 마이페이지 내 활동 조회
Slice<ActivityLog> findByUserIdOrderByCreatedAtDesc(UUID userId, Pageable pageable);
// 마이페이지 내 활동 조회
@Query("SELECT a FROM ActivityLog a WHERE a.userId = :userId " +
"AND a.activityType IN :activityTypes " +
"ORDER BY a.createdAt DESC")
List<ActivityLog> findByUserIdAndActivityTypesOrderByCreatedAtDesc(UUID userId, List<ActivityType> activityTypes);
Comment thread
discipline24 marked this conversation as resolved.

// 이슈 3-1: 일일 방문자 수 통계
@Query("SELECT COUNT(DISTINCT a.userId) FROM ActivityLog a " +
"WHERE a.type = 'AUTH_LOGIN' AND a.createdAt BETWEEN :start AND :end")
"WHERE a.activityType = 'AUTH_LOGIN' AND a.createdAt BETWEEN :start AND :end")
long countDailyUniqueVisitors(LocalDateTime start, LocalDateTime end);

// 이슈 3-2: 게시판별 활동량 집계 (게시글+댓글+좋아요)
@Query("SELECT a.boardName, COUNT(a) FROM ActivityLog a " +
"WHERE a.type IN ('BOARD_POST', 'BOARD_COMMENT', 'BOARD_LIKE') " +
"WHERE a.activityType IN ('BOARD_POST', 'BOARD_COMMENT', 'BOARD_LIKE') " +
"AND a.createdAt BETWEEN :start AND :end " +
"GROUP BY a.boardName")
List<Object[]> countActivityByBoard(LocalDateTime start, LocalDateTime end);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package org.sejongisc.backend.betting.controller;
package org.sejongisc.backend.admin.controller;

import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.sejongisc.backend.betting.entity.Scope;
import org.sejongisc.backend.betting.service.BettingService;
import org.sejongisc.backend.betting.service.BettingScheduler;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/admin/bet-rounds")
public class BettingAdminController {
@Tag(
name = "00. 관리자 모의 트레이딩 관리 API",
description = "모의 트레이딩 관리 관련 API 제공"
)
public class AdminBettingController {

private final BettingService bettingService;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/board/admin")
@RequestMapping("/api/admin/board")
@Tag(
name = "00. 관리자 게시판 관리 API",
description = "게시판 생성 및 삭제 관련 API 제공"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public void checkIn(UUID userId, String username, AttendanceRoundQrTokenRequest
userId,
username,
ActivityType.ATTENDANCE,
username + "님이 " + round.getAttendanceSession().getTitle() + " 세션에 출석했습니다.",
round.getAttendanceSession().getTitle() + " 세션에 출석했습니다.",
att.getAttendanceId(),
null
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ public UserBetResponse postUserBet(UUID userId, String username, UserBetRequest
userId,
username,
ActivityType.BETTING_JOIN,
username + "님이 모의 트레이딩 " + betRound.getTitle() + "에 참여했습니다.",
"모의 트레이딩 " + betRound.getTitle() + "에 참여했습니다.",
savedBet.getUserBetId(),
null
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public void createComment(CommentRequest request, UUID userId) {
user.getUserId(),
user.getName(),
ActivityType.BOARD_COMMENT,
user.getName() + "님이 댓글을 달았습니다.",
"[" + post.getTitle() + "]에 댓글을 달았습니다.",
post.getPostId(),
post.getBoard().getBoardName()));
}
Expand Down Expand Up @@ -191,7 +191,7 @@ public void toggleLike(UUID postId, UUID userId) {
user.getUserId(),
user.getName(),
ActivityType.BOARD_LIKE,
user.getName() + "님이 좋아요를 눌렀습니다.",
"[" + post.getTitle() + "]에 좋아요를 눌렀습니다.",
post.getPostId(),
post.getBoard().getBoardName()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public void savePost(PostRequest request, UUID userId) {
userId,
user.getName(),
ActivityType.BOARD_POST,
user.getName() + "님이 " + "[" + board.getBoardName() + "] 게시판에 새 글을 작성했습니다.",
"[" + post.getTitle() + "]글을 게시했습니다.",
post.getPostId(),
board.getBoardName()
));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package org.sejongisc.backend.common.auth.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.sejongisc.backend.common.auth.dto.AuthRequest;
import org.sejongisc.backend.common.auth.dto.AuthResponse;
import org.sejongisc.backend.common.auth.dto.SignupRequest;
import org.sejongisc.backend.common.auth.dto.SignupResponse;
import org.sejongisc.backend.common.auth.service.AuthService;
import org.sejongisc.backend.common.auth.service.RefreshTokenService;
import org.sejongisc.backend.user.dto.PasswordResetConfirmRequest;
import org.sejongisc.backend.user.dto.PasswordResetSendRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseCookie;
Expand All @@ -26,7 +31,14 @@ public class AuthController {

private final AuthService authService;
private final RefreshTokenService refreshTokenService;
private final AuthCookieHelper cookieHelper; // 주입
private final AuthCookieHelper cookieHelper;

@Operation(summary = "회원 가입", description = "회장이 승인하기 전까지 PENDING 상태가 유지되며, 웹사이트를 사용할 수 없습니다.")
@ApiResponse(responseCode = "201", description = "회원가입 성공")
@PostMapping("/signup")
public ResponseEntity<SignupResponse> signup(@Valid @RequestBody SignupRequest request) {
return ResponseEntity.status(HttpStatus.CREATED).body(authService.signup(request));
}

@Operation(summary = "일반 로그인 API", description = "")
@PostMapping("/login")
Expand Down Expand Up @@ -73,4 +85,56 @@ public ResponseEntity<?> logout(@CookieValue(value = "access", required = false)
.header(HttpHeaders.SET_COOKIE, cookieHelper.deleteCookie("refresh").toString())
.body(Map.of("message", "로그아웃 성공"));
}

@Operation(
summary = "비밀번호 재설정 : 이메일로 인증코드를 전송합니다.",
description = """

## 인증(JWT): **불필요**

## 요청 바디 ( `PasswordResetSendRequest` )
- **`email`**: 가입된 이메일
- **`studentId`**: 가입된 학번

## 동작 설명
- 입력한 이메일 + 학번으로 사용자를 확인합니다.
- 일치하는 사용자가 있으면 인증코드를 생성합니다.
- 인증코드를 Redis에 일정 시간 저장합니다. (TTL 적용)
- 해당 이메일로 인증코드를 전송합니다.

## 반환값
- 성공 메시지 (`인증코드를 전송했습니다.`)
""")
@PostMapping("/password/reset/send")
public ResponseEntity<?> sendReset(@RequestBody @Valid PasswordResetSendRequest req){
authService.passwordResetSendCode(req);
return ResponseEntity.ok(Map.of("message", "인증코드를 전송했습니다."));
}

@Operation(
summary = "비밀번호 재설정 : 인증코드와 새 비밀번호를 입력받아, 비밀번호를 변경합니다.",
description = """

## 인증(JWT): **불필요**

## 요청 바디 ( `PasswordResetConfirmRequest` )
- **`email`**: 가입된 이메일
- **`studentId`**: 가입된 학번
- **`code`**: 이메일로 받은 인증코드
- **`newPassword`**: 새 비밀번호

## 동작 설명
- 이메일 + 학번으로 사용자를 다시 확인합니다.
- Redis에 저장된 인증코드와 입력한 `code`를 비교합니다.
- 인증코드가 일치하면 새 비밀번호를 정책 검증 후 암호화하여 저장합니다.
- 사용한 인증코드는 Redis에서 삭제합니다. (1회성)

## 반환값
- 성공 메시지 (`비밀번호가 변경되었습니다.`)
""")
@PostMapping("/password/reset/confirm")
public ResponseEntity<?> confirmReset(@RequestBody @Valid PasswordResetConfirmRequest req){
authService.resetPasswordByCode(req);
return ResponseEntity.ok(Map.of("message", "비밀번호가 변경되었습니다."));
}
Comment thread
discipline24 marked this conversation as resolved.
}
Loading