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 @@ -22,7 +22,16 @@ public enum MessageType {

// 방 관련 메시지 타입
ROOM_STATUS_CHANGE("room_status_change", "방 상태 변경"),
HOST_CHANGE("host_change", "방장 변경");
HOST_CHANGE("host_change", "방장 변경"),

// 투표 관련 메시지 타입
POLL_CREATE("poll_create", "투표 생성"),
POLL_VOTE("poll_vote", "투표 참여"),
POLL_END("poll_end", "투표 종료"),

// 유틸리티 메시지 타입
CLEAR_CHAT("clear_chat", "채팅 삭제"),
LEAVE_ROOM("leave_room", "채팅방 나가기");

private final String code;
private final String displayName;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.mzc.secondproject.serverless.domain.chatting.model;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.*;

import java.util.List;
import java.util.Map;

/**
* 채팅방 투표 모델
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamoDbBean
public class Poll {

private String pk; // ROOM#{roomId}
private String sk; // POLL#{pollId}

private String pollId;
private String roomId;
private String question;
private List<String> options;
private Map<String, Integer> votes; // optionIndex -> count
private Map<String, Integer> userVotes; // userId -> optionIndex
private String createdBy;
private String createdAt;
private Boolean isActive;
private Long ttl;

@DynamoDbPartitionKey
@DynamoDbAttribute("PK")
public String getPk() {
return pk;
}

@DynamoDbSortKey
@DynamoDbAttribute("SK")
public String getSk() {
return sk;
}

/**
* 투표 추가
*/
public boolean addVote(String userId, int optionIndex) {
if (optionIndex < 0 || optionIndex >= options.size()) {
return false;
}

// 이미 투표했는지 확인
if (userVotes.containsKey(userId)) {
return false;
}

userVotes.put(userId, optionIndex);
votes.merge(String.valueOf(optionIndex), 1, Integer::sum);
return true;
}

/**
* 사용자가 이미 투표했는지 확인
*/
public boolean hasVoted(String userId) {
return userVotes != null && userVotes.containsKey(userId);
}

/**
* 총 투표 수
*/
public int getTotalVotes() {
if (votes == null) return 0;
return votes.values().stream().mapToInt(Integer::intValue).sum();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.mzc.secondproject.serverless.domain.chatting.repository;

import com.mzc.secondproject.serverless.common.config.AwsClients;
import com.mzc.secondproject.serverless.common.config.EnvConfig;
import com.mzc.secondproject.serverless.domain.chatting.model.Poll;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.enhanced.dynamodb.model.QueryConditional;

import java.util.Optional;

/**
* Poll Repository
*/
public class PollRepository {

private static final Logger logger = LoggerFactory.getLogger(PollRepository.class);
private static final String TABLE_NAME = EnvConfig.getRequired("CHAT_TABLE_NAME");

private final DynamoDbTable<Poll> table;

public PollRepository() {
this.table = AwsClients.dynamoDbEnhanced().table(TABLE_NAME, TableSchema.fromBean(Poll.class));
}

public PollRepository(DynamoDbTable<Poll> table) {
this.table = table;
}

public void save(Poll poll) {
table.putItem(poll);
logger.debug("Saved poll: {}", poll.getPollId());
}

public Optional<Poll> findById(String roomId, String pollId) {
Key key = Key.builder()
.partitionValue("ROOM#" + roomId)
.sortValue("POLL#" + pollId)
.build();
Poll poll = table.getItem(key);
return Optional.ofNullable(poll);
}

/**
* 방의 활성 투표 조회
*/
public Optional<Poll> findActiveByRoomId(String roomId) {
return table.query(QueryConditional.sortBeginsWith(
Key.builder()
.partitionValue("ROOM#" + roomId)
.sortValue("POLL#")
.build()))
.items()
.stream()
.filter(poll -> Boolean.TRUE.equals(poll.getIsActive()))
.findFirst();
}

public void delete(String roomId, String pollId) {
Key key = Key.builder()
.partitionValue("ROOM#" + roomId)
.sortValue("POLL#" + pollId)
.build();
table.deleteItem(key);
logger.debug("Deleted poll: {}", pollId);
}
}
Loading