Newer
Older
tampopo-server / src / main / java / org / ntlab / tampoposerver / services / FriendService.java
package org.ntlab.tampoposerver.services;

import org.ntlab.tampoposerver.models.FriendPair;
import org.ntlab.tampoposerver.models.FriendRequest;
import org.ntlab.tampoposerver.models.User;
import org.ntlab.tampoposerver.repositories.FriendRepository;
import org.ntlab.tampoposerver.repositories.FriendRequestRepository;
import org.ntlab.tampoposerver.repositories.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Optional;

// MEMO: ユーザーのトークンを認証するところはUserRepositoryに任せる
// MEMO: フレンド系の操作で認証が必要な場合はここで対応する
@Service
public class FriendService {
    private final UserRepository userRepository;
    private final FriendRepository friendRepository;
    private final FriendRequestRepository friendRequestRepository;

    @Autowired
    public FriendService(UserRepository userRepository, FriendRepository friendRepository, FriendRequestRepository friendRequestRepository) {
        this.userRepository = userRepository;
        this.friendRepository = friendRepository;
        this.friendRequestRepository = friendRequestRepository;
    }

    /**
     * 新しいフレンドリクエストを作成する
     *
     * @param token      APIリクエストをしてきたユーザーの認証用トークン
     * @param senderId   フレンドリクエストを送ったユーザーのユーザーID
     * @param receiverId フレンドリクエストを受け取ったユーザーのユーザーID
     * @return 作成されたフレンドリクエストのインスタンス(tokenに対応したユーザーがsenderIdでもreceiverIdにも関係しない場合は{@code Optional.empty()})
     * @apiNote {@code token} が有効かどうか、{@code senderId}と{@code receiverId}に対応したユーザーがそれぞれ存在するかどうかは別に判定が必要
     */
    public Optional<FriendRequest> createFriendRequest(String token, String senderId, String receiverId) {
        User sender = userRepository.getUser(senderId);
        User receiver = userRepository.getUser(receiverId);
        if (!sender.getToken().equals(token) && !receiver.getToken().equals(token)) {
            return Optional.empty();
        }
        FriendRequest newRequest = friendRequestRepository.create(new FriendRequest(senderId, receiverId));
        return Optional.of(newRequest);
    }

    /**
     * ユーザー自身に関連するフレンドリクエストをすべて返す
     *
     * @param token ユーザー認証用のトークン
     * @return ユーザー自身に関連するすべてのフレンドリクエストのインスタンス(リクエストがなければ空のリスト)
     * @apiNote {@code token} が有効かどうかは別に判定が必要
     */
    public ArrayList<FriendRequest> getFriendRequests(String token) {
        ArrayList<FriendRequest> results = new ArrayList<>();
        Collection<FriendRequest> allRequests = friendRequestRepository.findAll();
        for (FriendRequest request : allRequests) {
            User sender = userRepository.getUser(request.getSenderId());
            User receiver = userRepository.getUser(request.getReceiverId());
            if (sender.getToken().equals(token) || receiver.getToken().equals(token)) {
                results.add(request);
            }
        }
        return results;
    }

    /**
     * 指定したフレンドリクエストを削除する
     *
     * @param token           APIリクエストをしてきたユーザーの認証用トークン
     * @param friendRequestId 削除する対象のフレンドリクエストのID
     * @return 削除に成功したらtrue, それ以外はfalse
     * @apiNote {@code token} が有効かどうかは別に判定が必要
     */
    public boolean removeFriendRequest(String token, int friendRequestId) {
        FriendRequest targetRequest = friendRequestRepository.find(friendRequestId);
        if (targetRequest == null) {
            return false;
        }

        User sender = userRepository.getUser(targetRequest.getSenderId());
        User receiver = userRepository.getUser(targetRequest.getReceiverId());
        if (!sender.getToken().equals(token) && !receiver.getToken().equals(token)) {
            return false;
        }
        return friendRequestRepository.delete(friendRequestId);
    }

    /**
     * 新しくフレンドペアを作成する
     *
     * @param user0Id 片方のユーザーのユーザーID
     * @param user1Id もう一方のユーザーのユーザーID
     * @return 追加されたフレンドペアのインスタンス(エラーがあった場合は{@code Optional.empty()})
     * @apiNote {@code token} が有効かどうかは別に判定が必要
     */
    public Optional<FriendPair> createFriendPair(String user0Id, String user1Id) {
        // フレンドリクエストを検索して削除する
        FriendRequest acceptedRequest = friendRequestRepository.findAll().stream().filter((req) -> {
            return (req.getSenderId().equals(user0Id) && req.getReceiverId().equals(user1Id)) || (req.getSenderId().equals(user1Id) && req.getReceiverId().equals(user0Id));
        }).findFirst().orElse(null);
        if (acceptedRequest == null) {
            return Optional.empty();
        }
        friendRequestRepository.delete(acceptedRequest.getId());

        // フレンドを追加する
        FriendPair createdPair = friendRepository.add(new FriendPair(user0Id, user1Id));
        userRepository.addFriendPair(user0Id, createdPair);
        userRepository.addFriendPair(user1Id, createdPair);
        return Optional.of(createdPair);
    }

    /**
     * 指定したフレンドのペアを取得する
     *
     * @param token        APIリクエストをしてきたユーザーの認証用トークン
     * @param friendPairId 取得する対象のフレンドペアのID
     * @return 渡したフレンドペアのIDに対応したフレンドペア
     * @apiNote {@code token} が有効かどうかは別に判定が必要
     */
    public Optional<FriendPair> getFriendPair(String token, int friendPairId) {
        FriendPair foundPair = friendRepository.find(friendPairId);
        if (foundPair == null) {
            return Optional.empty();
        }
        User user0 = userRepository.getUser(foundPair.getUser0Id());
        User user1 = userRepository.getUser(foundPair.getUser1Id());
        if (!user0.getToken().equals(token) && !user1.getToken().equals(token)) {
            return Optional.empty();
        }
        return Optional.of(foundPair);
    }

    /**
     * 指定したフレンドのペアを削除する
     *
     * @param token        APIリクエストをしてきたユーザーの認証用トークン
     * @param friendPairId 削除する対象のフレンドペアのID
     * @return 削除に成功したらtrue, それ以外はfalse
     */
    public boolean removeFriendPair(String token, int friendPairId) {
        FriendPair foundPair = friendRepository.find(friendPairId);
        if (foundPair == null) {
            return false;
        }
        User user0 = userRepository.getUser(foundPair.getUser0Id());
        User user1 = userRepository.getUser(foundPair.getUser1Id());
        if (!user0.getToken().equals(token) && !user1.getToken().equals(token)) {
            return false;
        }

        // フレンドペアを削除する
        return friendRepository.delete(friendPairId) && userRepository.deleteFriendPair(user0.getUserId(), foundPair) && userRepository.deleteFriendPair(user1.getUserId(), foundPair);
    }

    /**
     * ユーザーIDが{@code userId}のユーザーとフレンドになっているユーザーのIDをすべて返す
     *
     * @param token  APIリクエストをしてきたユーザーの認証用トークン
     * @param userId APIリクエストをしてきたユーザーのID
     * @return ユーザーIDが {@code userId} のユーザーとフレンドになっているユーザーすべてのID
     * @apiNote ペアがない場合は空の配列、トークンとユーザーIDで認証できなければnullを返す
     */
    public ArrayList<String> getFriendIds(String token, String userId) {
        User user = userRepository.getUser(userId);
        if (user == null || !user.getToken().equals(token)) {
            return null;
        }

        ArrayList<String> friendIds = new ArrayList<>();
        for (FriendPair friendPair : user.getFriendPairs()) {
            if (friendPair.getUser0Id().equals(user.getUserId())) {
                friendIds.add(friendPair.getUser1Id());
            } else {
                friendIds.add(friendPair.getUser0Id());
            }
        }
        return friendIds;
    }
}