Skip to content
Open
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
@@ -1,67 +1,15 @@
package com.assu.server.domain.certification.component;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


import org.springframework.stereotype.Component;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
//
// @Slf4j // ⭐️ SLF4j 로그 사용을 위해 추가
// @Component
// public class CertificationSessionManager {
// private final Map<Long, Set<Long>> sessionUserMap = new ConcurrentHashMap<>();
//
// public void openSession(Long sessionId) {
// sessionUserMap.put(sessionId, ConcurrentHashMap.newKeySet());
// // ⭐️ 로그 추가
// log.info("✅ New certification session opened. SessionID: {}", sessionId);
// }
//
// public void addUserToSession(Long sessionId, Long userId) {
// Set<Long> users = sessionUserMap.computeIfAbsent(sessionId, k -> {
// log.warn("Attempted to add user to a non-existent session. Creating new set for SessionID: {}", k);
// return ConcurrentHashMap.newKeySet();
// });
//
// boolean isAdded = users.add(userId);
//
// // ⭐️ 요청하신 멤버 추가 확인 로그
// if (isAdded) {
// log.info("👤 User added to session. SessionID: {}, UserID: {}. Current participants: {}",
// sessionId, userId, users.size());
// } else {
// log.info("👤 User already in session. SessionID: {}, UserID: {}. Current participants: {}",
// sessionId, userId, users.size());
// }
// }
//
// public int getCurrentUserCount(Long sessionId) {
// return sessionUserMap.getOrDefault(sessionId, Set.of()).size();
// }
//
// public boolean hasUser(Long sessionId, Long userId) {
// return sessionUserMap.getOrDefault(sessionId, Set.of()).contains(userId);
// }
//
// public List<Long> snapshotUserIds(Long sessionId) {
// return List.copyOf(sessionUserMap.getOrDefault(sessionId, Set.of()));
// }
//
//
//
// public void removeSession(Long sessionId) {
// sessionUserMap.remove(sessionId);
// // ⭐️ 로그 추가
// log.info("❌ Certification session removed. SessionID: {}", sessionId);
// }
// }

@Component
@RequiredArgsConstructor
public class CertificationSessionManager {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -35,41 +35,6 @@ public Message<?> preSend(Message<?> message, MessageChannel channel) {
log.info("Authentication set: {}", authentication);
}
}

return message;
}

// @Override
// public Message<?> preSend(Message<?> message, MessageChannel channel) {
// StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
// log.info("StompCommand: {}", accessor.getCommand()); // StompCommand 로그 추가
//
// if (StompCommand.CONNECT.equals(accessor.getCommand())) {
// log.info("CONNECT command received.");
// // 프론트에서 connect 시 Authorization 헤더 넣어야 함
// String authHeader = accessor.getFirstNativeHeader("Authorization");
// log.info("Authorization Header: {}", authHeader); // Authorization 헤더 로그 추가
//
// if (authHeader != null && authHeader.startsWith("Bearer ")) {
// String token = jwtUtil.getTokenFromHeader(authHeader);
// log.info("Extracted Token: {}", token); // 추출된 토큰 로그 추가
//
// // JwtUtil 이용해서 Authentication 복원
// Authentication authentication = jwtUtil.getAuthentication(token);
// log.info("Authentication restored: {}", authentication); // 복원된 인증 정보 로그 추가
//
// // WebSocket 세션에 Authentication(UserPrincipal) 저장
// accessor.setUser(authentication);
// log.info("User principal set on accessor.");
// } else {
// log.warn("Authorization header is missing or not in Bearer format.");
// }
// } else if (StompCommand.SEND.equals(accessor.getCommand())) {
// // SEND 명령어에 대한 로그 추가 (메시지 전송 시)
// Object payload = message.getPayload();
// log.info("SEND command received. Destination: {}, Payload: {}", accessor.getDestination(), payload);
// }
//
// return message;
// }
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
package com.assu.server.domain.certification.controller;

import java.time.LocalDateTime;

import org.springframework.http.ResponseEntity;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.assu.server.domain.certification.dto.CertificationRequestDTO;
import com.assu.server.domain.certification.dto.CertificationGroupRequestDTO;
import com.assu.server.domain.certification.dto.CertificationPersonalRequestDTO;
import com.assu.server.domain.certification.dto.CertificationResponseDTO;
import com.assu.server.domain.certification.service.CertificationService;
import com.assu.server.domain.member.entity.Member;
import com.assu.server.domain.member.repository.MemberRepository;
import com.assu.server.global.apiPayload.BaseResponse;
import com.assu.server.global.apiPayload.code.status.ErrorStatus;
import com.assu.server.global.apiPayload.code.status.SuccessStatus;
import com.assu.server.global.exception.GeneralException;
import com.assu.server.global.util.PrincipalDetails;


import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
Expand All @@ -31,7 +24,6 @@
public class CertificationController {

private final CertificationService certificationService;
private final MemberRepository memberRepository; // 지금은 그냥 임시 데이터 하드 코딩이라 여기에 둔거여

@PostMapping("/certification/session")
@Operation(
Expand All @@ -50,33 +42,40 @@ public class CertificationController {
"\n**Response:**\n" +
" - 성공 시 201(Created)와 sessionId, adminId 반환"
)
public ResponseEntity<BaseResponse<CertificationResponseDTO.getSessionIdResponse>> getSessionId(
public ResponseEntity<BaseResponse<CertificationResponseDTO>> getSessionId(
@AuthenticationPrincipal PrincipalDetails pd,
@RequestBody CertificationRequestDTO.groupRequest dto
@RequestBody CertificationGroupRequestDTO dto
) {

CertificationResponseDTO.getSessionIdResponse result = certificationService.getSessionId(dto, pd.getMember());
CertificationResponseDTO result = certificationService.getSessionId(dto, pd.getMember());

return ResponseEntity.ok(BaseResponse.onSuccess(SuccessStatus.GROUP_SESSION_CREATE, result));
}

// @MessageMapping("/certify")
// @Operation(summary = "그룹 세션 인증 api", description = "그룹에 대한 세션 인증 요청을 보냅니다.")
// public ResponseEntity<BaseResponse<Void>> certifyGroup(
// CertificationRequestDTO.groupSessionRequest dto , PrincipalDetails pd
//
// ) {
// certificationService.handleCertification(dto, pd.getMember());
//
// return ResponseEntity.ok(BaseResponse.onSuccess(SuccessStatus.GROUP_CERTIFICATION_SUCCESS, null));
// }

@PostMapping("/certification/personal")
@Operation(summary = "개인 인증 api", description = "사실 크게 필요없는데, 제휴 내역 통계를 위해 데이터를 post하는 api 입니다. "
+ "가게 별 제휴를 조회하고 people값이 null 인 제휴를 선택한 경우 그룹 인증 대신 요청하는 api 입니다.")
@Operation(
summary = "개인 인증 요청 API",
description =
"# [v1.0 (2025-09-09)](https://clumsy-seeder-416.notion.site/2471197c19ed80fd9a8dcc43fb938a5d?source=copy_link)\n" +
"- 개인 단위 인증을 위한 API입니다.\n" +
"- 그룹 인증이 아닌 경우, 통계 및 제휴 이력 적재를 목적으로 사용됩니다.\n" +
"- 가게별 제휴 조회 시 `people` 값이 null 인 경우 호출됩니다.\n" +
"\n**Request Body:**\n" +
" - `storeId` (Long, required): 인증이 발생한 스토어 ID\n" +
" - `adminId` (Long, required): 인증을 요청한 관리자 ID\n" +
" - `tableNumber` (Integer, required): 인증이 발생한 테이블 번호\n" +
"\n**Authentication:**\n" +
" - 로그인된 사용자 인증 정보 필요 (`@AuthenticationPrincipal`)\n" +
"\n**Processing:**\n" +
" - 전달받은 정보 기반으로 개인 인증 이력 저장\n" +
" - 세션 생성은 하지 않음\n" +
"\n**Response:**\n" +
" - 성공 시 200(OK)\n" +
" - 성공 메시지 반환"
)
public ResponseEntity<BaseResponse<String>> personalCertification(
@AuthenticationPrincipal PrincipalDetails pd,
@RequestBody CertificationRequestDTO.personalRequest dto
@RequestBody CertificationPersonalRequestDTO dto
) {
certificationService.certificatePersonal(dto, pd.getMember());

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

import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.assu.server.domain.certification.dto.GroupSessionRequest;
import com.assu.server.domain.certification.service.CertificationService;
import com.assu.server.domain.member.entity.Member;
import com.assu.server.global.util.PrincipalDetails;

import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

Expand All @@ -30,6 +27,16 @@ public class GroupCertificationController {
private final CertificationService certificationService;

@MessageMapping("/certify")
@Operation(
summary = "그룹 인증 요청 WebSocket API",
description = "# [v1.0 (2025-12-23)](https://clumsy-seeder-416.notion.site/x-22b1197c19ed801d99b1ddb7c5d7ee26?source=copy_link)\n" +
"- WebSocket을 통해 그룹 인증 요청을 보냅니다.\n" +
"- 로그인 필요\n" +
"- Payload는 JSON 형식입니다.\n\n" +
"**Request Payload:**\n" +
" - `adminId` (Long, required): 인증하고자 하는 제휴의 관리자 ID\n" +
" - `sessionId` (Long, required): 인증하고자 하는 그룹 세션 ID\n\n"
)
public void certifyGroup(@Payload GroupSessionRequest dto,
Principal principal) {
if (principal instanceof UsernamePasswordAuthenticationToken) {
Expand All @@ -38,15 +45,12 @@ public void certifyGroup(@Payload GroupSessionRequest dto,

try {
log.info("### SUCCESS ### 인증 요청 메시지 수신 - user: {}, adminId: {}, sessionId: {}",
principalDetails.getUsername(), dto.getAdminId(), dto.getSessionId());
principalDetails.getUsername(), dto.adminId(), dto.sessionId());

// 헤더를 직접 다룰 필요 없이, 바로 principalDetails 객체를 사용
if (principalDetails != null) {
certificationService.handleCertification(dto, principalDetails.getMember());
log.info("### SUCCESS ### 그룹 인증 처리 완료");
}
} catch (Exception e) {
log.error("### ERROR ### 인증 처리 실패", e);
}
}
}
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.assu.server.domain.certification.dto;

import com.assu.server.domain.certification.entity.AssociateCertification;
import com.assu.server.domain.certification.entity.enums.SessionStatus;
import com.assu.server.domain.member.entity.Member;
import com.assu.server.domain.store.entity.Store;

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

public record CertificationGroupRequestDTO(
@Schema(description = "1명 이상의 사람 수를 입력해주세요")
@NotNull(message= "1명 이상의 사람 수를 입력해주세요")
Integer people,
@Schema(description = "storeId를 입력해주세요")
@NotNull(message = "storeId를 입력해주세요")
Long storeId,
@Schema(description = "adminId를 입력해주세요")
@NotNull(message="adminId를 입력해주세요")
Long adminId,
@Schema(description = "00~99 사이의 tableNumber를 입력해주세요")
@NotNull(message = "00~99 사이의 tableNumber를 입력해주세요")
Integer tableNumber
) {
public AssociateCertification toAssociateCertification(Store store, Member member) {
return AssociateCertification.builder()
.store(store)
.partner(store.getPartner())
.status(SessionStatus.OPENED)
.isCertified(false)
.peopleNumber(this.people())
.tableNumber(this.tableNumber())
.student(member.getStudentProfile())
.build();
}
}
Loading