Skip to content

Commit

Permalink
Remove PovioKit dep from LinkedIn pckg.
Browse files Browse the repository at this point in the history
  • Loading branch information
borut-t committed May 22, 2024
1 parent e46e340 commit fd29f5c
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 67 deletions.
4 changes: 1 addition & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ let package = Package(
.library(name: "PovioKitAuthLinkedIn", targets: ["PovioKitAuthLinkedIn"])
],
dependencies: [
.package(url: "https://github.com/poviolabs/PovioKit", .upToNextMajor(from: "4.0.0")),
.package(url: "https://github.com/google/GoogleSignIn-iOS", .upToNextMajor(from: "7.0.0")),
.package(url: "https://github.com/facebook/facebook-ios-sdk", .upToNextMajor(from: "17.0.0")),
],
Expand Down Expand Up @@ -57,8 +56,7 @@ let package = Package(
.target(
name: "PovioKitAuthLinkedIn",
dependencies: [
"PovioKitAuthCore",
.product(name: "PovioKitNetworking", package: "PovioKit")
"PovioKitAuthCore"
],
path: "Sources/LinkedIn",
resources: [.copy("../../Resources/PrivacyInfo.xcprivacy")]
Expand Down
23 changes: 0 additions & 23 deletions Sources/LinkedIn/API/EndpointEncodable.swift

This file was deleted.

5 changes: 2 additions & 3 deletions Sources/LinkedIn/API/LinkedInAPI+Endpoints.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@
//

import Foundation
import PovioKitNetworking

extension LinkedInAPI {
enum Endpoints: EndpointEncodable {
enum Endpoints {
case accessToken
case profile
case email

var path: Path {
var path: String {
switch self {
case .accessToken:
return "accessToken"
Expand Down
95 changes: 59 additions & 36 deletions Sources/LinkedIn/API/LinkedInAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,73 +7,96 @@
//

import Foundation
import PovioKitNetworking

public final class LinkedInAPI {
private let client: AlamofireNetworkClient
private let client: HttpClient = .init()

public init(client: AlamofireNetworkClient = .init()) {
self.client = client
}
public init() {}
}

public extension LinkedInAPI {
func login(with request: LinkedInAuthRequest) async throws -> LinkedInAuthResponse {
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
let jsonData = try encoder.encode(request)
let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: [])
guard let jsonDict = jsonObject as? [String: Any] else {
throw Error.invalidRequest
}

guard var components = URLComponents(string: Endpoints.accessToken.url) else {
throw Error.invalidUrl
}

let queryItems: [URLQueryItem] = jsonDict.compactMap { key, value in
(value as? String).map { .init(name: key, value: $0) }
}

components.queryItems = queryItems
guard let url = components.url else {
throw Error.invalidUrl
}

let response = try await client.request(
method: "POST",
url: url,
headers: [.init(name: "Content-Type", value: "application/x-www-form-urlencoded")]
)

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .custom { decoder in
let container = try decoder.singleValueContainer()
let secondsRemaining = try container.decode(Int.self)
return Date().addingTimeInterval(TimeInterval(secondsRemaining))
}
let decoded = try decoder.decode(LinkedInAuthResponse.self, from: response)

let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase

return try await client
.request(
method: .post,
endpoint: Endpoints.accessToken,
encode: request,
parameterEncoder: .urlEncoder(encoder: encoder)
)
.validate()
.decode(LinkedInAuthResponse.self, decoder: decoder)
.asAsync
return decoded
}

func loadProfile(with request: LinkedInProfileRequest) async throws -> LinkedInProfileResponse {
guard let url = URL(string: Endpoints.profile.url) else { throw Error.invalidUrl }

let response = try await client.request(
method: "GET",
url: url,
headers: [.init(name: "Authorization", value: "Bearer \(request.token)")]
)

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .iso8601
let decoded = try decoder.decode(LinkedInProfileResponse.self, from: response)

return try await client
.request(
method: .get,
endpoint: Endpoints.profile,
headers: ["Authorization": "Bearer \(request.token)"]
)
.validate()
.decode(LinkedInProfileResponse.self, decoder: decoder)
.asAsync
return decoded
}

func loadEmail(with request: LinkedInProfileRequest) async throws -> LinkedInEmailValueResponse {
return try await client
.request(
method: .get,
endpoint: Endpoints.email,
headers: ["Authorization": "Bearer \(request.token)"])
.validate()
.decode(LinkedInEmailResponse.self)
.compactMap { $0.elements.first?.handle }
.asAsync
guard let url = URL(string: Endpoints.email.url) else { throw Error.invalidUrl }

let response = try await client.request(
method: "GET",
url: url,
headers: [.init(name: "Authorization", value: "Bearer \(request.token)")]
)

let decoded = try JSONDecoder().decode(LinkedInEmailResponse.self, from: response)

guard let emailObject = decoded.elements.first?.handle else {
throw Error.invalidResponse
}

return emailObject
}
}

// MARK: - Error
public extension LinkedInAPI {
enum Error: Swift.Error {
case missingParameters
case invalidUrl
case invalidRequest
case invalidResponse
}
}
35 changes: 35 additions & 0 deletions Sources/LinkedIn/Core/HttpClient.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// HttpClient.swift
// PovioKitAuth
//
// Created by Borut Tomazin on 22/05/2024.
// Copyright © 2024 Povio Inc. All rights reserved.
//

import Foundation

class HttpClient {
func request(method: String, url: URL, headers: [Header]) async throws -> Data {
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = method
headers.forEach {
urlRequest.setValue($0.value, forHTTPHeaderField: $0.name)
}

let (data, response) = try await URLSession.shared.data(for: urlRequest)

if let httpResponse = response as? HTTPURLResponse,
!(200...299).contains(httpResponse.statusCode) {
throw NSError(domain: "HTTP Error", code: httpResponse.statusCode, userInfo: nil)
}

return data
}
}

extension HttpClient {
struct Header {
let name: String
let value: String
}
}
18 changes: 18 additions & 0 deletions Sources/LinkedIn/Core/URL+PovioKitAuth.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// URL+PovioKitAuth.swift
// PovioKitAuth
//
// Created by Borut Tomazin on 22/05/2024.
// Copyright © 2024 Povio Inc. All rights reserved.
//

import Foundation

extension URL: ExpressibleByStringLiteral {
public init(stringLiteral value: String) {
guard let url = URL(string: value) else {
fatalError("Invalid URL string!")
}
self = url
}
}
2 changes: 0 additions & 2 deletions Sources/LinkedIn/WebView/LinkedInWebView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
// Copyright © 2024 Povio Inc. All rights reserved.
//

import PovioKitCore
import SwiftUI
import WebKit

Expand Down Expand Up @@ -40,7 +39,6 @@ public struct LinkedInWebView: UIViewRepresentable {
public func updateUIView(_ uiView: UIViewType, context: Context) {
guard let webView = uiView as? WKWebView else { return }
guard let authURL = configuration.authorizationUrl(state: requestState) else {
Logger.error("Failed to geet auth url!")
dismiss()
return
}
Expand Down

0 comments on commit fd29f5c

Please sign in to comment.