Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TNT-158] postSingIn 구현 완료 #44

Merged
merged 12 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from 11 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
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,4 @@ Signing/
master.key

# PList
# => 전체 plist를 다 제외함.
# **/*.plist
# Support/*.plist
GoogleService-Info.plist
3 changes: 0 additions & 3 deletions TnT/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,4 @@ Signing/
master.key

# PList
# => 전체 plist를 다 제외함.
# **/*.plist
# Support/*.plist
GoogleService-Info.plist
20 changes: 19 additions & 1 deletion TnT/Projects/DIContainer/Sources/DIContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import Data

// MARK: - Swift-Dependencies
private enum UserUseCaseKey: DependencyKey {
static let liveValue: UserUseCase = DefaultUserUseCase(userRepository: UserRepositoryImpl())
static let liveValue: UserUseCase = DefaultUserUseCase(userRepostiory: UserRepositoryImpl())
}

private enum UserUseCaseRepoKey: DependencyKey {
static let liveValue: UserRepository = DefaultUserUseCase(userRepostiory: UserRepositoryImpl())
}

private enum TraineeUseCaseKey: DependencyKey {
Expand All @@ -22,15 +26,29 @@ private enum TraineeUseCaseKey: DependencyKey {
)
}

private enum SocialUseCaseKey: DependencyKey {
static let liveValue: SocialLoginUseCase = SocialLoginUseCase(socialLoginRepository: SocialLogInRepositoryImpl(loginManager: SNSLoginManager()))
}

// MARK: - DependencyValues
public extension DependencyValues {
var userUseCase: UserUseCase {
get { self[UserUseCaseKey.self] }
set { self[UserUseCaseKey.self] = newValue }
}

var userUseRepoCase: UserRepository {
get { self[UserUseCaseRepoKey.self] }
set { self[UserUseCaseRepoKey.self] = newValue }
}

var traineeUseCase: TraineeUseCase {
get { self[TraineeUseCaseKey.self] }
set { self[TraineeUseCaseKey.self] = newValue }
}

var socialLogInUseCase: SocialLoginUseCase {
get { self[SocialUseCaseKey.self] }
set { self[SocialUseCaseKey.self] = newValue }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// SocialLogInRepositoryImpl.swift
// Data
//
// Created by 박서연 on 1/29/25.
// Copyright © 2025 yapp25thTeamTnT. All rights reserved.
//

import Foundation
import Dependencies

import Domain

public enum LoginError: Error {
case invalidCredentials
case networkFailure
case kakaoError
case appleError
case unknown(message: String)
}

public struct SocialLogInRepositoryImpl: SocialLoginRepository {

public let loginManager: SNSLoginManager

public init(loginManager: SNSLoginManager) {
self.loginManager = loginManager
}

public func appleLogin() async -> AppleLoginInfo? {
let result = await loginManager.appleLogin()

return result
}

public func kakaoLogin() async -> KakaoLoginInfo? {
let result = await loginManager.kakaoLogin()
return result
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import Domain

/// 사용자 관련 네트워크 요청을 처리하는 UserRepository 구현체
public struct UserRepositoryImpl: UserRepository {

private let networkService: NetworkService = .shared

public init() {}
Expand Down
119 changes: 119 additions & 0 deletions TnT/Projects/Domain/Sources/Entity/SocailLoginEntity.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
//
// PostSocailEntity.swift
// Domain
//
// Created by 박서연 on 1/31/25.
// Copyright © 2025 yapp25thTeamTnT. All rights reserved.
//

import Foundation

/// 소셜 로그인 요청 DTO
public struct PostSocailEntity: Equatable {
/// 소셜 로그인 타입 (KAKAO, APPLE)
let socialType: String
/// FCM 토큰
let fcmToken: String
/// 소셜 액세스 토큰
let socialAccessToken: String?
/// 애플 인가 코드 (Apple 로그인 시 필요)
let authorizationCode: String?
/// 애플 ID 토큰 (Apple 로그인 시 필요)
let idToken: String?

public init(
socialType: String,
fcmToken: String,
socialAccessToken: String?,
authorizationCode: String?,
idToken: String?
) {
self.socialType = socialType
self.fcmToken = fcmToken
self.socialAccessToken = socialAccessToken
self.authorizationCode = authorizationCode
self.idToken = idToken
}
}

/// 소셜 로그인 응답 DTO
public struct PostSocialLoginResEntity: Equatable {
/// 세션 ID
public let sessionId: String?
/// 소셜 로그인 ID
public let socialId: String
/// 소셜 이메일
public let socialEmail: String
/// 소셜 로그인 타입 (KAKAO, APPLE)
public let socialType: String
/// 가입 여부 (`true`: 이미 가입됨, `false`: 미가입)
public let isSignUp: Bool
}

/// 회원가입 요청 DTO
public struct PostSignUpReqEntity {
/// FCM 토큰
let fcmToken: String
/// 회원 타입 (trainer, trainee)
let memberType: String
/// 소셜 로그인 타입 (KAKAO, APPLE)
let socialType: String
/// 소셜 로그인 ID
let socialId: String
/// 소셜 로그인 이메일
let socialEmail: String
/// 서비스 이용 약관 동의 여부
let serviceAgreement: Bool
/// 개인정보 수집 동의 여부
let collectionAgreement: Bool
/// 광고성 알림 수신 동의 여부
let advertisementAgreement: Bool
/// 푸시 알림 수신 동의 여부
let pushAgreement: Bool
/// 회원 이름
let name: String
/// 생년월일 (yyyy-MM-dd)
let birthday: String?
/// 키 (cm)
let height: Double?
/// 몸무게 (kg, 소수점 1자리까지 가능)
let weight: Double?
/// 트레이너에게 전달할 주의사항
let cautionNote: String?
/// PT 목적 (체중 감량, 근력 향상 등)
let goalContents: [String]?

public init(
fcmToken: String,
memberType: String,
socialType: String,
socialId: String,
socialEmail: String,
serviceAgreement: Bool,
collectionAgreement: Bool,
advertisementAgreement: Bool,
pushAgreement: Bool,
name: String,
birthday: String?,
height: Double?,
weight: Double?,
cautionNote: String?,
goalContents: [String]?
) {
self.fcmToken = fcmToken
self.memberType = memberType
self.socialType = socialType
self.socialId = socialId
self.socialEmail = socialEmail
self.serviceAgreement = serviceAgreement
self.collectionAgreement = collectionAgreement
self.advertisementAgreement = advertisementAgreement
self.pushAgreement = pushAgreement
self.name = name
self.birthday = birthday
self.height = height
self.weight = weight
self.cautionNote = cautionNote
self.goalContents = goalContents
}
}
53 changes: 53 additions & 0 deletions TnT/Projects/Domain/Sources/Mapper/PostSocialMapper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// PostSocialMapper.swift
// Domain
//
// Created by 박서연 on 1/31/25.
// Copyright © 2025 yapp25thTeamTnT. All rights reserved.
//

import Foundation

public struct PostSocialMapper {
public static func toDTO(from entity: PostSocailEntity) -> PostSocialLoginReqDTO {
return PostSocialLoginReqDTO(
socialType: entity.socialType,
fcmToken: entity.fcmToken,
socialAccessToken: entity.socialAccessToken,
authorizationCode: entity.authorizationCode,
idToken: entity.idToken
)
}

public static func toEntity(from dto: PostSocialLoginReqDTO) -> PostSocailEntity {
return PostSocailEntity(
socialType: dto.socialType,
fcmToken: dto.fcmToken,
socialAccessToken: dto.socialAccessToken,
authorizationCode: dto.authorizationCode,
idToken: dto.idToken
)
}

/// `PostSocialLoginResDTO` → `PostSocialLoginResEntity` 변환
public static func toResEntity(from dto: PostSocialLoginResDTO) -> PostSocialLoginResEntity {
return PostSocialLoginResEntity(
sessionId: dto.sessionId,
socialId: dto.socialId,
socialEmail: dto.socialEmail,
socialType: dto.socialType,
isSignUp: dto.isSignUp
)
}

/// `PostSocialLoginResEntity` → `PostSocialLoginResDTO` 변환
public static func toDTO(from entity: PostSocialLoginResEntity) -> PostSocialLoginResDTO {
return PostSocialLoginResDTO(
sessionId: entity.sessionId,
socialId: entity.socialId,
socialEmail: entity.socialEmail,
socialType: entity.socialType,
isSignUp: entity.isSignUp
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,4 @@ public protocol SocialLoginRepository {
func appleLogin() async -> AppleLoginInfo?
/// 카카오 로그인을 수행합니다
func kakaoLogin() async -> KakaoLoginInfo?
/// 카카오 로그아웃을 수행합니다
func kakaoLogout() async
}
26 changes: 26 additions & 0 deletions TnT/Projects/Domain/Sources/UseCase/SocialLoginUseCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// SocialLoginUseCase.swift
// Domain
//
// Created by 박서연 on 1/29/25.
// Copyright © 2025 yapp25thTeamTnT. All rights reserved.
//

import Foundation

public struct SocialLoginUseCase {

private let socialLoginRepository: SocialLoginRepository

public init(socialLoginRepository: SocialLoginRepository) {
self.socialLoginRepository = socialLoginRepository
}

public func appleLogin() async -> AppleLoginInfo? {
return await socialLoginRepository.appleLogin()
}

public func kakaoLogin() async -> KakaoLoginInfo? {
return await socialLoginRepository.kakaoLogin()
}
}
23 changes: 19 additions & 4 deletions TnT/Projects/Domain/Sources/UseCase/UserUseCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import Dependencies
import Foundation

// MARK: - UserUseCase 프로토콜
public protocol UserUseCase {
Expand All @@ -27,13 +28,15 @@ public protocol UserUseCase {
}

// MARK: - Default 구현체
public struct DefaultUserUseCase: UserUseCase {
private let userRepository: UserRepository
public struct DefaultUserUseCase: UserRepository, UserUseCase {

public init(userRepository: UserRepository) {
self.userRepository = userRepository
public let userRepostiory: UserRepository

public init(userRepostiory: UserRepository) {
self.userRepostiory = userRepostiory
}

// MARK: - Usecase
public func validateUserName(_ name: String) -> Bool {
return !name.isEmpty && UserPolicy.userNameInput.textValidation(name)
}
Expand Down Expand Up @@ -62,3 +65,15 @@ public struct DefaultUserUseCase: UserUseCase {
return UserPolicy.maxPrecautionLength
}
}

// MARK: - Repository
extension DefaultUserUseCase {
public func postSocialLogin(_ reqDTO: PostSocialLoginReqDTO) async throws -> PostSocialLoginResDTO {
return try await userRepostiory.postSocialLogin(reqDTO)
}

public func postSignUp(_ reqDTO: PostSignUpReqDTO, profileImage: Data?) async throws -> PostSignUpResDTO {
return try await userRepostiory.postSignUp(reqDTO, profileImage: profileImage)
}
}

Loading