Skip to content

Commit

Permalink
[Feat] sopt-makers#149 - 플레이그라운드 인증 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
L-j-h-c committed Apr 16, 2023
1 parent 700090e commit e6476ec
Showing 8 changed files with 189 additions and 21 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] = [
6 changes: 6 additions & 0 deletions SOPT-iOS/Projects/Core/Sources/Literals/ExternalURL.swift
Original file line number Diff line number Diff line change
@@ -18,4 +18,10 @@ public struct ExternalURL {
public static let serviceProposal = "https://forms.gle/L2HpRCvFMh9VvcA57"
public static let findEmail = "https://forms.gle/XkVFMUPsWWV1DXU38"
}

public struct Playground {
public static func login(state: String = "") -> String {
return "https://sopt-internal-dev.pages.dev/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"
}
Original file line number Diff line number Diff line change
@@ -16,6 +16,8 @@ public struct UserDefaultKeyList {
@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 {
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,61 @@ 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)
}

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 +203,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
@@ -0,0 +1,96 @@
//
// SceneDelegate+HandleURL.swift
// SOPT-iOS
//
// Created by Junho Lee on 2023/04/16.
// Copyright © 2023 SOPT-iOS. All rights reserved.
//

import UIKit

import Core
import AuthFeatureInterface

// MARK: Handle URLs

extension SceneDelegate {
func parseContexts(openURLContexts URLContexts: Set<UIOpenURLContext>) {
for context in URLContexts {
print("url: \(context.url.absoluteURL)")
print("scheme: \(String(describing: context.url.scheme))")
print("host: \(String(describing: context.url.host))")
print("path: \(context.url.path)")
print("query: \(String(describing: context.url.query))")
print("components: \(context.url.pathComponents)")

guard let _url = URLContexts.first?.url,
context.url.host() ?? "" == URLHandler.makers else {
return
}
handleURL(url: _url)
}
}

private func handleURL(url: URL) {
print("")
print("==============================")
print("URL Handling 시작")
print("==============================")
print("")

let urlStr = url.absoluteString
let components = URLComponents(string: urlStr)
let schemeData = components?.scheme ?? ""
let parameter = components?.query ?? ""

print("")
print("==============================")
print("[Scheme 접속 및 파라미터 값 확인]")
print("urlStr : ", urlStr)
print("scheme : ", schemeData)
print("query : ", parameter)
print("==============================")
print("")

let purePath = url.pathComponents[safe: 1] ?? ""
let handler = URLHandler.init(rawValue: purePath)
switch handler {
case .playgroundLogin:
redirectSignInVC(url: urlStr)
default: return
}
}

func redirectSignInVC(url: String) {
var signInControllable = container.makeSignInVC()
signInControllable.skipAnimation = true
for item in parseParameter(url: url) {
if item.query == "state" {
signInControllable.requestState = item.value
continue
}

if item.query == "code" {
signInControllable.accessCode = item.value
continue
}
}
self.window?.rootViewController = signInControllable.viewController
self.window?.makeKeyAndVisible()
}
}

extension SceneDelegate {
func parseParameter(url: String) -> [(query: String, value: String)] {
let components = URLComponents(string: url)
let params = components?.query ?? ""
guard params.count > 0 && params != "",
let items = components?.queryItems else {
return []
}
return items.map {
($0.name, $0.value ?? "")
}
}
}

Original file line number Diff line number Diff line change
@@ -24,10 +24,14 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
window = UIWindow(frame: scene.coordinateSpace.bounds)
window?.windowScene = scene
// let rootVC = container.makeShowAttendanceVC().viewController
let rootVC = container.makeMainVC(userType: .active).viewController
let rootVC = container.makeSplashVC().viewController
window?.rootViewController = UINavigationController(rootViewController: rootVC)
window?.makeKeyAndVisible()
}

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
parseContexts(openURLContexts: URLContexts)
}

func sceneDidDisconnect(_ scene: UIScene) {}

0 comments on commit e6476ec

Please sign in to comment.