Skip to content

Commit

Permalink
Merge pull request #166 from L-j-h-c/feature/#149-APIChange
Browse files Browse the repository at this point in the history
[Feat] #149, #158 - 토큰 만료 로직, 플레이그라운드 로그인, 이외 여러 API 변경사항 반영
L-j-h-c authored Apr 17, 2023

Verified

This commit was signed with the committer’s verified signature.
mrgrain Momo Kornher
2 parents 52a6272 + b03873c commit a5d4e46
Showing 24 changed files with 460 additions and 57 deletions.
Original file line number Diff line number Diff line change
@@ -35,7 +35,14 @@ public extension Project {
"NSAppTransportSecurity": ["NSAllowsArbitraryLoads": true],
"ITSAppUsesNonExemptEncryption": false,
"UIUserInterfaceStyle": "Light",
"NSPhotoLibraryUsageDescription": "미션과 관련된 사진을 업로드하기 위해 갤러리 권한이 필요합니다."
"NSPhotoLibraryUsageDescription": "미션과 관련된 사진을 업로드하기 위해 갤러리 권한이 필요합니다.",
"CFBundleURLTypes": [
[
"CFBundleTypeRole": "Editor",
"CFBundleURLName": "sopt-makers",
"CFBundleURLSchemes": ["sopt-makers"]
]
]
]

static let demoInfoPlist: [String: InfoPlist.Value] = [
12 changes: 12 additions & 0 deletions SOPT-iOS/Projects/Core/Sources/Literals/ExternalURL.swift
Original file line number Diff line number Diff line change
@@ -18,4 +18,16 @@ public struct ExternalURL {
public static let serviceProposal = "https://forms.gle/L2HpRCvFMh9VvcA57"
public static let findEmail = "https://forms.gle/XkVFMUPsWWV1DXU38"
}

public struct Playground {
#if DEV || PROD
public static let main = "https://playground.sopt.org"
#else
public static let main = "https://sopt-internal-dev.pages.dev"
#endif

public static func login(state: String = "") -> String {
return "\(main)/auth/oauth?redirect_uri=sopt-makers://org.sopt.makers.iOS/oauth2redirect&state=\(state)"
}
}
}
15 changes: 15 additions & 0 deletions SOPT-iOS/Projects/Core/Sources/Literals/URLContexts.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// URLContexts.swift
// Core
//
// Created by Junho Lee on 2023/04/16.
// Copyright © 2023 SOPT-iOS. All rights reserved.
//

import Foundation

public enum URLHandler: String {
case playgroundLogin = "oauth2redirect"

public static let makers = "org.sopt.makers.iOS"
}
20 changes: 18 additions & 2 deletions SOPT-iOS/Projects/Core/Sources/Literals/UserDefaultKeyLIst.swift
Original file line number Diff line number Diff line change
@@ -10,23 +10,39 @@ import Foundation

public struct UserDefaultKeyList {
public struct Auth {
@UserDefaultWrapper<String>(key: "deviceToken") public static var deviceToken
@UserDefaultWrapper<String>(key: "endpointArnForSNS") public static var endpointArnForSNS
@UserDefaultWrapper<String>(key: "appAccessToken") public static var appAccessToken
@UserDefaultWrapper<String>(key: "appRefreshToken") public static var appRefreshToken
@UserDefaultWrapper<String>(key: "playgroundToken") public static var playgroundToken
@UserDefaultWrapper<Bool>(key: "isActiveUser") public static var isActiveUser

@UserDefaultWrapper<String>(key: "requestState") public static var requestState
}

public struct User {
@UserDefaultWrapper<String>(key: "sentence") public static var sentence
@UserDefaultWrapper<String>(key: "soptampName") public static var soptampName
}

public struct AppNotice {
@UserDefaultWrapper<String>(key: "checkedAppVersion") public static var checkedAppVersion
}
}

extension UserDefaultKeyList {
public static func clearAllUserData() {
UserDefaultKeyList.Auth.appAccessToken = nil
UserDefaultKeyList.Auth.appRefreshToken = nil
UserDefaultKeyList.Auth.playgroundToken = nil
UserDefaultKeyList.Auth.isActiveUser = false
clearSoptampUserData()
}

public static func clearSoptampUserData() {
UserDefaultKeyList.User.soptampName = nil
UserDefaultKeyList.User.sentence = nil
}
}

extension UserDefaultKeyList.Auth {
public static func getUserType() -> UserType {
guard appAccessToken != nil else {
Original file line number Diff line number Diff line change
@@ -48,17 +48,18 @@ extension SettingRepository: SettingRepositoryInterface {
return userService.changeNickname(nickname: nickname)
.map { _ in true }
.replaceError(with: false)
.handleEvents(receiveOutput: { isSuccessed in
guard isSuccessed else { return }
UserDefaultKeyList.User.soptampName = nickname
})
.eraseToAnyPublisher()
}

public func withdrawal() -> AnyPublisher<Bool, Never> {
return userService.withdrawal()
.handleEvents(receiveOutput: { status in
if status == 200 {
UserDefaultKeyList.Auth.appAccessToken = nil
UserDefaultKeyList.Auth.appRefreshToken = nil
UserDefaultKeyList.Auth.playgroundToken = nil
UserDefaultKeyList.User.sentence = nil
UserDefaultKeyList.clearAllUserData()
}
})
.map { _ in true}
31 changes: 31 additions & 0 deletions SOPT-iOS/Projects/Data/Sources/Repository/SignInRepository.swift
Original file line number Diff line number Diff line change
@@ -31,13 +31,44 @@ extension SignInRepository: SignInRepositoryInterface {

public func requestSignIn(token: String) -> AnyPublisher<Bool, Never> {
authService.signIn(token: token)
.catch({ _ in
return self.userService.reissuance()
})
.map { entity in
UserDefaultKeyList.Auth.appAccessToken = entity.accessToken
UserDefaultKeyList.Auth.appRefreshToken = entity.refreshToken
UserDefaultKeyList.Auth.playgroundToken = entity.playgroundToken
UserDefaultKeyList.Auth.isActiveUser = entity.status == .active
? true
: false
return true
}
.replaceError(with: false)
.withUnretained(self)
.flatMap { owner, isSuccessed in
guard isSuccessed else {
return Driver(Just(false))
}
return owner.fetchSoptampUser()
}
.eraseToAnyPublisher()
}

private func fetchSoptampUser() -> AnyPublisher<Bool, Never> {
return userService.fetchSoptampUser()
.replaceError(
with: .init(
nickname: "닉네임 설정 오류",
profileMessage: "설정된 한 마디가 없습니다.",
points: 0
))
.handleEvents(receiveOutput: { entity in
UserDefaultKeyList.User.soptampName = entity.nickname
UserDefaultKeyList.User.sentence = entity.profileMessage ?? "설정된 한 마디가 없습니다."
})
.map { _ in
return true
}
.eraseToAnyPublisher()
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -57,8 +57,7 @@ extension DefaultRankingUseCase: RankingUseCase {
}

private func findMyRankingIndex(model: [RankingModel]) -> Int {
// TODO: 랭킹 Index 로직 수정
let myUserName = ""
let myUserName = UserDefaultKeyList.User.soptampName
let index = model.firstIndex { model in
model.username == myUserName
} ?? 0
Original file line number Diff line number Diff line change
@@ -8,7 +8,11 @@

import BaseFeatureDependency

public protocol SignInViewControllable: ViewControllable { }
public protocol SignInViewControllable: ViewControllable {
var skipAnimation: Bool { get set }
var accessCode: String? { get set }
var requestState: String? { get set }
}

public protocol AuthFeatureViewBuildable {
func makeSignInVC() -> SignInViewControllable
Original file line number Diff line number Diff line change
@@ -27,6 +27,9 @@ public class SignInVC: UIViewController, SignInViewControllable {

public var factory: (AuthFeatureViewBuildable & MainFeatureViewBuildable)!
public var viewModel: SignInViewModel!
public var skipAnimation: Bool = false
public var accessCode: String? = nil
public var requestState: String? = nil
private var cancelBag = CancelBag()

// MARK: - UI Components
@@ -84,7 +87,7 @@ public class SignInVC: UIViewController, SignInViewControllable {

public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.showAnimation()
self.performAnimation()
}
}

@@ -134,31 +137,67 @@ extension SignInVC {
}
}

private func showAnimation() {
private func performAnimation() {
guard !skipAnimation else {
retrieveAlpha()
updateLogoY()
return
}
UIView.animate(withDuration: 0.7, delay: 0, options: .curveEaseInOut, animations: {
self.logoImageView.transform = CGAffineTransform(translationX: 0, y: -Metric.logoMutableY)
self.updateLogoY()
})
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseOut, animations: {
[self.signInButton, self.notMemberButton, self.bottomLogoImageView].forEach {
$0.alpha = 1
}
self.retrieveAlpha()
})
}

private func updateLogoY() {
logoImageView.transform = CGAffineTransform(translationX: 0, y: -Metric.logoMutableY)
}

private func retrieveAlpha() {
[signInButton, notMemberButton, bottomLogoImageView].forEach {
$0.alpha = 1
}
}
}

// MARK: - Methods

extension SignInVC {

private func bindViews() {
signInButton.publisher(for: .touchUpInside)
.withUnretained(self)
.sink { owner, _ in
owner.openPlaygroundURL()
}.store(in: self.cancelBag)

notMemberButton.publisher(for: .touchUpInside)
.withUnretained(self)
.sink { owner, _ in
owner.setRootViewToMain()
}.store(in: self.cancelBag)
}

private func bindViewModels() {
let signInFinished = Driver.just(accessCode)
.drop { [weak self] code in
return code == nil
|| self?.requestState != UserDefaultKeyList.Auth.requestState
}
.replaceNil(with: "")
.eraseToAnyPublisher()
.asDriver()

let input = SignInViewModel.Input(playgroundSignInFinished: Driver.just("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIyNiIsImV4cCI6MTY4MTE5OTY1NH0.wlceN1uUoQZYL5Uz4lOiomwLTNK2YxQ-dlv3rtZHUZM"))
let output = self.viewModel.transform(from: input, cancelBag: self.cancelBag)
let input = SignInViewModel.Input(
playgroundSignInFinished: signInFinished
)
let output = self.viewModel.transform(from: input, cancelBag: cancelBag)

output.isSignInSuccess.sink { [weak self] isSignInSuccess in
output.isSignInSuccess.sink { [weak self] isSuccessed in
guard let self = self else { return }
self.stopLoading()
if isSignInSuccess {
if isSuccessed {
self.setRootViewToMain()
}
}.store(in: self.cancelBag)
@@ -170,12 +209,13 @@ extension SignInVC {
ViewControllerUtils.setRootViewController(window: self.view.window!, viewController: navigation, withAnimation: true)
}

private func bindViews() {
// TODO: - 플그 로그인으로 연결
signInButton.publisher(for: .touchUpInside)
.withUnretained(self)
.sink { owner, _ in
owner.setRootViewToMain()
}.store(in: self.cancelBag)
private func openPlaygroundURL() {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyyMMddHHmmss"
let state = dateFormatter.string(from: Date())
UserDefaultKeyList.Auth.requestState = state
openExternalLink(urlStr: ExternalURL.Playground.login(state: state)) {
print("플레이그라운드 Open URL")
}
}
}
Original file line number Diff line number Diff line change
@@ -133,9 +133,11 @@ extension MainVC {
self.collectionView.register(AppServiceCVC.self, forCellWithReuseIdentifier: AppServiceCVC.className)
}

private func pushSoptampFeature() {
private func presentSoptampFeature() {
let vc = factory.makeMissionListVC(sceneType: .default).viewController
navigationController?.pushViewController(vc, animated: true)
let nav = UINavigationController(rootViewController: vc)
nav.modalPresentationStyle = .fullScreen
present(nav, animated: true)
}

private func pushSettingFeature() {
@@ -153,10 +155,9 @@ extension MainVC {

extension MainVC: UICollectionViewDelegate {
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// TODO: - 디버깅을 위한 임시 솝탬프 피쳐 연결
if indexPath.section == 3 {
guard viewModel.userType != .visitor else { return }
pushSoptampFeature()
presentSoptampFeature()
}
}
}
Original file line number Diff line number Diff line change
@@ -114,7 +114,7 @@ extension SettingVC {
}

private func logout() {
UserDefaultKeyList.Auth.appAccessToken = nil
UserDefaultKeyList.clearAllUserData()
self.changeRootViewController()
}

5 changes: 3 additions & 2 deletions SOPT-iOS/Projects/Modules/Network/Sources/API/StampAPI.swift
Original file line number Diff line number Diff line change
@@ -38,8 +38,9 @@ extension StampAPI: BaseAPI {
// MARK: - Path
public var path: String {
switch self {
case .fetchStampListDetail(let missionId),
.postStamp(let missionId, _),
case .fetchStampListDetail(let missionId):
return "mission/\(missionId)"
case .postStamp(let missionId, _),
.putStamp(let missionId, _):
return "/\(missionId)"
case .deleteStamp(let stampId):
Loading

0 comments on commit a5d4e46

Please sign in to comment.