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

Customizable web page login language #61

Merged
merged 9 commits into from
May 14, 2019
65 changes: 64 additions & 1 deletion LineSDK/LineSDK/Login/LoginManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import Foundation
/// Represents a login manager. You can set up the LINE SDK configuration, log in and log out the user with the
/// LINE authorization flow, and check the authorization status.
public class LoginManager {

let lock = NSLock()

/// The shared instance of the login manager. Always use this instance to interact with the login process of
Expand Down Expand Up @@ -55,6 +55,17 @@ public class LoginManager {
public var isAuthorizing: Bool {
return currentProcess != nil
}

/// Sets the preferred language used when login with the web authorization flow.
///
/// If not set, the web authentication flow shows the web page for login with user's device language or English as
/// a fallback. Once set, the web page will be displayed in the preferred language.
///
/// Note:
///
/// This property does not affect the preferred language when LINE app is used for authorization.
/// The LINE app always shows itself and the login screen following the user's device language.
public var preferredWebPageLanguage: WebPageLanguage? = nil

/// A flag to prevent setup multiple times
var setup = false
Expand Down Expand Up @@ -140,6 +151,7 @@ public class LoginManager {
configuration: LoginConfiguration.shared,
scopes: permissions,
options: options,
preferredWebPageLanguage: preferredWebPageLanguage,
viewController: viewController)
process.start()
process.onSucceed.delegate(on: self) { [unowned process] (self, result) in
Expand Down Expand Up @@ -342,3 +354,54 @@ extension LoginManager {
try payload.verify(keyPath: \.nonce, expected: process.tokenIDNonce!)
}
}

extension LoginManager {
/// Represents the language used in web page.
public struct WebPageLanguage {
public let rawValue: String

/// Creates a web page language with a given raw string language code value.
///
/// - Parameter rawValue: The value represents the language code.
public init(rawValue: String) {
self.rawValue = rawValue
}

/// The Arabic langauge.
public static let arabic = WebPageLanguage(rawValue: "ar")
/// The German langauge.
public static let german = WebPageLanguage(rawValue: "de")
/// The English langauge.
public static let english = WebPageLanguage(rawValue: "en")
/// The Spanish langauge.
public static let spanish = WebPageLanguage(rawValue: "es")
/// The French langauge.
public static let french = WebPageLanguage(rawValue: "fr")
/// The Indonesian langauge.
public static let indonesian = WebPageLanguage(rawValue: "id")
/// The Italian langauge.
public static let italian = WebPageLanguage(rawValue: "it")
/// The Japanese langauge.
public static let japanese = WebPageLanguage(rawValue: "jp")
/// The Korean langauge.
public static let korean = WebPageLanguage(rawValue: "ko")
/// The Malay langauge.
public static let malay = WebPageLanguage(rawValue: "ms")
/// The Brazilian Portuguese langauge.
public static let portugueseBrazilian = WebPageLanguage(rawValue: "pt-BR")
/// The European Portuguese langauge.
public static let portugueseEuropean = WebPageLanguage(rawValue: "pt-PT")
/// The Russian langauge.
public static let russian = WebPageLanguage(rawValue: "ru")
/// The Thai langauge.
public static let thai = WebPageLanguage(rawValue: "th")
/// The Turkish langauge.
public static let turkish = WebPageLanguage(rawValue: "tr")
/// The Vietnamese langauge.
public static let vietnamese = WebPageLanguage(rawValue: "vi")
/// The SimplifiedC Chinese langauge.
onevcat marked this conversation as resolved.
Show resolved Hide resolved
onevcat marked this conversation as resolved.
Show resolved Hide resolved
public static let chineseSimplified = WebPageLanguage(rawValue: "zh-Hans")
/// The TraditionalC Chinese langauge.
onevcat marked this conversation as resolved.
Show resolved Hide resolved
public static let chineseTraditional = WebPageLanguage(rawValue: "zh-Hant")
}
}
13 changes: 11 additions & 2 deletions LineSDK/LineSDK/Login/LoginProcess.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public class LoginProcess {
let processID: String
let nonce: String?
let botPrompt: BotPrompt?
let preferredWebPageLanguage: LoginManager.WebPageLanguage?
}

/// Observes application switching to foreground.
Expand Down Expand Up @@ -77,6 +78,7 @@ public class LoginProcess {
let configuration: LoginConfiguration
let scopes: Set<LoginPermission>
let options: LoginManagerOptions
let preferredWebPageLanguage: LoginManager.WebPageLanguage?

// Flows of login process. A flow will be `nil` until it is running, so we could tell which one should take
// responsibility to handle a url callback response.
Expand Down Expand Up @@ -116,12 +118,14 @@ public class LoginProcess {
configuration: LoginConfiguration,
scopes: Set<LoginPermission>,
options: LoginManagerOptions,
preferredWebPageLanguage: LoginManager.WebPageLanguage?,
viewController: UIViewController?)
{
self.configuration = configuration
self.processID = UUID().uuidString
self.scopes = scopes
self.options = options
self.preferredWebPageLanguage = preferredWebPageLanguage
self.presentingViewController = viewController

if scopes.contains(.openID) {
Expand All @@ -144,7 +148,8 @@ public class LoginProcess {
otp: otp,
processID: self.processID,
nonce: self.tokenIDNonce,
botPrompt: self.options.botPrompt)
botPrompt: self.options.botPrompt,
preferredWebPageLanguage: self.preferredWebPageLanguage)
if self.options.contains(.onlyWebLogin) {
self.startWebLoginFlow(parameters)
} else {
Expand Down Expand Up @@ -425,10 +430,14 @@ extension String {
extension URL {
func appendedLoginQuery(_ flowParameters: LoginProcess.FlowParameters) -> URL {
let returnUri = String.returnUri(flowParameters)
let parameters: [String: Any] = [
var parameters: [String: Any] = [
"returnUri": returnUri,
"loginChannelId": flowParameters.channelID
]
if let lang = flowParameters.preferredWebPageLanguage {
parameters["lang"] = lang.rawValue
}

let encoder = URLQueryEncoder(parameters: parameters)
return encoder.encoded(for: self)
}
Expand Down
4 changes: 4 additions & 0 deletions LineSDK/LineSDKObjC/Login/LineSDKLoginManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ public class LineSDKLoginManager: NSObject {
public var isSetupFinished: Bool { return _value.isSetupFinished }
public var isAuthorized: Bool { return _value.isAuthorized }
public var isAuthorizing: Bool { return _value.isAuthorizing }
public var preferredWebPageLanguage: String? {
get { return _value.preferredWebPageLanguage?.rawValue }
set { _value.preferredWebPageLanguage = newValue.map { .init(rawValue: $0) } }
}
public func setup(channelID: String, universalLinkURL: URL?) {
_value.setup(channelID: channelID, universalLinkURL: universalLinkURL)
}
Expand Down
10 changes: 10 additions & 0 deletions LineSDK/LineSDKObjCInterfaceTests/LineSDKModelInterfaceTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ - (void)testLoginManagerInterface {
XCTAssertFalse(manager.isSetupFinished);
XCTAssertFalse(manager.isAuthorized);
XCTAssertFalse(manager.isAuthorizing);

[manager setupWithChannelID:@"" universalLinkURL:nil];
[manager loginWithPermissions:nil
inViewController:nil
Expand All @@ -141,6 +142,15 @@ - (void)testLoginManagerInterface {
XCTAssertNotNil([LineSDKLoginManager sharedManager]);
}

- (void)testLoginManagerLangSettingInterface {
LineSDKLoginManager *manager = [LineSDKLoginManager sharedManager];
XCTAssertNil(manager.preferredWebPageLanguage);
[manager setPreferredWebPageLanguage:@"zh-Hans"];
XCTAssertEqual(manager.preferredWebPageLanguage, @"zh-Hans");
manager.preferredWebPageLanguage = nil;
XCTAssertNil(manager.preferredWebPageLanguage);
}

- (void)testHexColorInterface {
LineSDKHexColor *color = nil;
XCTAssertNil(color.rawValue);
Expand Down
48 changes: 47 additions & 1 deletion LineSDK/LineSDKTests/Login/LoginFlowTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,18 @@ class LoginFlowTests: XCTestCase, ViewControllerCompatibleTest {
otp: .init(otpId: "321", otp: "aaa"),
processID: "abc",
nonce: "kkk",
botPrompt: .normal)
botPrompt: .normal,
preferredWebPageLanguage: nil)

let parameterWithLanguage = LoginProcess.FlowParameters(
channelID: "123",
universalLinkURL: nil,
scopes: [.profile, .openID],
otp: .init(otpId: "321", otp: "aaa"),
processID: "abc",
nonce: "kkk",
botPrompt: .normal,
preferredWebPageLanguage: .chineseSimplified)

// Login URL has a double escaped query.
func testLoginQueryURLEncode() {
Expand Down Expand Up @@ -66,6 +77,41 @@ class LoginFlowTests: XCTestCase, ViewControllerCompatibleTest {
}
XCTAssertEqual(hit, 2)
}

func testLoginQueryWithLangURLEncode() {

let baseURL = URL(string: Constant.lineWebAuthUniversalURL)!
let result = baseURL.appendedLoginQuery(parameterWithLanguage)

let urlString = result.absoluteString.removingPercentEncoding
XCTAssertNotNil(urlString)

let components = URLComponents(url: result, resolvingAgainstBaseURL: false)
let items = components!.queryItems!
XCTAssertEqual(items.count, 3)

var hit = 0
for item in items {
if item.name == "loginChannelId" {
hit += 1
XCTAssertEqual(item.value, "123")
}
if (item.name == "returnUri") {
hit += 1

XCTAssertNotEqual(item.value, item.value?.removingPercentEncoding)

// Should be already fully decoded (no double encoding in the url)
XCTAssertEqual(item.value?.removingPercentEncoding,
item.value?.removingPercentEncoding?.removingPercentEncoding)
}
if item.name == "lang" {
hit += 1
XCTAssertEqual(item.value, "zh-Hans")
}
}
XCTAssertEqual(hit, 3)
}

// URL Scheme has a triple escaped query.
func testURLSchemeQueryEncode() {
Expand Down