Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/develop' into fix/navigation-c…
Browse files Browse the repository at this point in the history
…rash
  • Loading branch information
forgotvas committed Dec 8, 2023
2 parents b5398dd + c20f7ee commit 42f3eab
Show file tree
Hide file tree
Showing 88 changed files with 3,297 additions and 306 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/add-depr-ticket-to-depr-board.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Run the workflow that adds new tickets that are either:
# - labelled "DEPR"
# - title starts with "[DEPR]"
# - body starts with "Proposal Date" (this is the first template field)
# to the org-wide DEPR project board

name: Add newly created DEPR issues to the DEPR project board

on:
issues:
types: [opened]

jobs:
routeissue:
uses: openedx/.github/.github/workflows/add-depr-ticket-to-depr-board.yml@master
secrets:
GITHUB_APP_ID: ${{ secrets.GRAPHQL_AUTH_APP_ID }}
GITHUB_APP_PRIVATE_KEY: ${{ secrets.GRAPHQL_AUTH_APP_PEM }}
SLACK_BOT_TOKEN: ${{ secrets.SLACK_ISSUE_BOT_TOKEN }}
20 changes: 20 additions & 0 deletions .github/workflows/add-remove-label-on-comment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# This workflow runs when a comment is made on the ticket
# If the comment starts with "label: " it tries to apply
# the label indicated in rest of comment.
# If the comment starts with "remove label: ", it tries
# to remove the indicated label.
# Note: Labels are allowed to have spaces and this script does
# not parse spaces (as often a space is legitimate), so the command
# "label: really long lots of words label" will apply the
# label "really long lots of words label"

name: Allows for the adding and removing of labels via comment

on:
issue_comment:
types: [created]

jobs:
add_remove_labels:
uses: openedx/.github/.github/workflows/add-remove-label-on-comment.yml@master

10 changes: 10 additions & 0 deletions .github/workflows/commitlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Run commitlint on the commit messages in a pull request.

name: Lint Commit Messages

on:
- pull_request

jobs:
commitlint:
uses: openedx/.github/.github/workflows/commitlint.yml@master
12 changes: 12 additions & 0 deletions .github/workflows/self-assign-issue.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This workflow runs when a comment is made on the ticket
# If the comment starts with "assign me" it assigns the author to the
# ticket (case insensitive)

name: Assign comment author to ticket if they say "assign me"
on:
issue_comment:
types: [created]

jobs:
self_assign_by_comment:
uses: openedx/.github/.github/workflows/self-assign-issue.yml@master
16 changes: 16 additions & 0 deletions Authorization/Authorization.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
0770DE6B28D0C035006D8A5D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0770DE6D28D0C035006D8A5D /* Localizable.strings */; };
0770DE7128D0C0E7006D8A5D /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0770DE7028D0C0E7006D8A5D /* Strings.swift */; };
5FB79D2802949372CDAF08D6 /* Pods_App_Authorization_AuthorizationTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4FAE9B7FD61FF88C9C4FE1E8 /* Pods_App_Authorization_AuthorizationTests.framework */; };
BA8B3A322AD5487300D25EF5 /* SocialAuthView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA8B3A312AD5487300D25EF5 /* SocialAuthView.swift */; };
BADB3F552AD6DFC3004D5CFA /* SocialAuthViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BADB3F542AD6DFC3004D5CFA /* SocialAuthViewModel.swift */; };
DE843D6BB1B9DDA398494890 /* Pods_App_Authorization.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47BCFB7C19382EECF15131B6 /* Pods_App_Authorization.framework */; };
E03261642AE64676002CA7EB /* StartupViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E03261632AE64676002CA7EB /* StartupViewModel.swift */; };
E03261662AE64AF4002CA7EB /* StartupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E03261652AE64AF4002CA7EB /* StartupView.swift */; };
Expand Down Expand Up @@ -78,6 +80,8 @@
96C85172770225EB81A6D2DA /* Pods-App-Authorization.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization.releasedev.xcconfig"; path = "Target Support Files/Pods-App-Authorization/Pods-App-Authorization.releasedev.xcconfig"; sourceTree = "<group>"; };
9BF6A1004A955E24527FCF0F /* Pods-App-Authorization-AuthorizationTests.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization-AuthorizationTests.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-Authorization-AuthorizationTests/Pods-App-Authorization-AuthorizationTests.releaseprod.xcconfig"; sourceTree = "<group>"; };
A99D45203C981893C104053A /* Pods-App-Authorization-AuthorizationTests.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization-AuthorizationTests.releasestage.xcconfig"; path = "Target Support Files/Pods-App-Authorization-AuthorizationTests/Pods-App-Authorization-AuthorizationTests.releasestage.xcconfig"; sourceTree = "<group>"; };
BA8B3A312AD5487300D25EF5 /* SocialAuthView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocialAuthView.swift; sourceTree = "<group>"; };
BADB3F542AD6DFC3004D5CFA /* SocialAuthViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocialAuthViewModel.swift; sourceTree = "<group>"; };
E03261632AE64676002CA7EB /* StartupViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartupViewModel.swift; sourceTree = "<group>"; };
E03261652AE64AF4002CA7EB /* StartupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartupView.swift; sourceTree = "<group>"; };
E03261672AE9F156002CA7EB /* LogistrationBottomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogistrationBottomView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -145,6 +149,7 @@
071009CC28D1E24000344290 /* Presentation */ = {
isa = PBXGroup;
children = (
BA8B3A302AD5485100D25EF5 /* SocialAuth */,
E03261622AE6464A002CA7EB /* Startup */,
020C31BD290AADA700D6DEA2 /* Base */,
071009C528D1D9FA00344290 /* Login */,
Expand Down Expand Up @@ -265,6 +270,15 @@
path = ../Pods;
sourceTree = "<group>";
};
BA8B3A302AD5485100D25EF5 /* SocialAuth */ = {
isa = PBXGroup;
children = (
BA8B3A312AD5487300D25EF5 /* SocialAuthView.swift */,
BADB3F542AD6DFC3004D5CFA /* SocialAuthViewModel.swift */,
);
path = SocialAuth;
sourceTree = "<group>";
};
E03261622AE6464A002CA7EB /* Startup */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -484,6 +498,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
BADB3F552AD6DFC3004D5CFA /* SocialAuthViewModel.swift in Sources */,
02066B442906D72400F4307E /* SignUpView.swift in Sources */,
0770DE7128D0C0E7006D8A5D /* Strings.swift in Sources */,
025F40E229D360E20064C183 /* ResetPasswordViewModel.swift in Sources */,
Expand All @@ -497,6 +512,7 @@
02F3BFE5292533720051930C /* AuthorizationRouter.swift in Sources */,
E03261662AE64AF4002CA7EB /* StartupView.swift in Sources */,
071009C728D1DA4F00344290 /* SignInViewModel.swift in Sources */,
BA8B3A322AD5487300D25EF5 /* SocialAuthView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,31 @@

import Foundation

public enum LoginMethod: String {
case password = "Password"
public enum AuthMethod: Equatable {
case password
case socailAuth(SocialAuthMethod)

public var analyticsValue: String {
switch self {
case .password:
"Password"
case .socailAuth(let socialAuthMethod):
socialAuthMethod.rawValue
}
}
}

public enum SocialAuthMethod: String {
case facebook = "Facebook"
case google = "Google"
case microsoft = "Microsoft"
case apple = "Apple"
}

//sourcery: AutoMockable
public protocol AuthorizationAnalytics {
func setUserID(_ id: String)
func userLogin(method: LoginMethod)
func userLogin(method: AuthMethod)
func signUpClicked()
func createAccountClicked()
func registrationSuccess()
Expand All @@ -28,7 +42,7 @@ public protocol AuthorizationAnalytics {
#if DEBUG
class AuthorizationAnalyticsMock: AuthorizationAnalytics {
public func setUserID(_ id: String) {}
public func userLogin(method: LoginMethod) {}
public func userLogin(method: AuthMethod) {}
public func signUpClicked() {}
public func createAccountClicked() {}
public func registrationSuccess() {}
Expand Down
11 changes: 10 additions & 1 deletion Authorization/Authorization/Presentation/Login/SignInView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@ public struct SignInView: View {
.padding(.top, 40)
}
}
if viewModel.socialAuthEnabled {
SocialAuthView(
viewModel: .init(
config: viewModel.config
) { result in
Task { await viewModel.login(with: result) }
}
)
}
Spacer()
}
.padding(.horizontal, 24)
Expand Down Expand Up @@ -180,7 +189,7 @@ struct SignInView_Previews: PreviewProvider {
static var previews: some View {
let vm = SignInViewModel(
interactor: AuthInteractor.mock,
router: AuthorizationRouterMock(),
router: AuthorizationRouterMock(),
config: ConfigMock(),
analytics: AuthorizationAnalyticsMock(),
validator: Validator()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ import Foundation
import Core
import SwiftUI
import Alamofire
import AuthenticationServices
import FacebookLogin
import GoogleSignIn
import MSAL

public class SignInViewModel: ObservableObject {

@Published private(set) var isShowProgress = false
@Published private(set) var showError: Bool = false
@Published private(set) var showAlert: Bool = false
Expand All @@ -35,7 +39,7 @@ public class SignInViewModel: ObservableObject {
private let interactor: AuthInteractorProtocol
private let analytics: AuthorizationAnalytics
private let validator: Validator

public init(
interactor: AuthInteractorProtocol,
router: AuthorizationRouter,
Expand All @@ -49,15 +53,22 @@ public class SignInViewModel: ObservableObject {
self.analytics = analytics
self.validator = validator
}


var socialAuthEnabled: Bool {
config.appleSignIn.enabled ||
config.facebook.enabled ||
config.microsoft.enabled ||
config.google.enabled
}

@MainActor
func login(username: String, password: String) async {
guard validator.isValidUsername(username) else {
errorMessage = AuthLocalization.Error.invalidEmailAddressOrUsername
return
}
guard !password.isEmpty else {
errorMessage = AuthLocalization.Error.invalidPasswordLength
errorMessage = AuthLocalization.Error.invalidPasswordLenght
return
}

Expand All @@ -68,27 +79,71 @@ public class SignInViewModel: ObservableObject {
analytics.userLogin(method: .password)
router.showMainOrWhatsNewScreen()
} catch let error {
isShowProgress = false
if error.isUpdateRequeiredError {
router.showUpdateRequiredView(showAccountLink: false)
} else if let validationError = error.validationError,
let value = validationError.data?["error_description"] as? String {
errorMessage = value
} else if case APIError.invalidGrant = error {
errorMessage = CoreLocalization.Error.invalidCredentials
} else if error.isInternetError {
errorMessage = CoreLocalization.Error.slowOrNoInternetConnection
failure(error)
}
}

@MainActor
func login(with result: Result<SocialAuthDetails, Error>) async {
switch result {
case .success(let result):
await socialLogin(
externalToken: result.response.token,
backend: result.backend,
authMethod: result.authMethod
)
case .failure(let error):
errorMessage = error.localizedDescription
}
}

@MainActor
private func socialLogin(
externalToken: String,
backend: String,
authMethod: AuthMethod
) async {
isShowProgress = true
do {
let user = try await interactor.login(externalToken: externalToken, backend: backend)
analytics.setUserID("\(user.id)")
analytics.userLogin(method: authMethod)
router.showMainOrWhatsNewScreen()
} catch let error {
failure(error, authMethod: authMethod)
}
}

@MainActor
private func failure(_ error: Error, authMethod: AuthMethod? = nil) {
isShowProgress = false
if let validationError = error.validationError,
let value = validationError.data?["error_description"] as? String {
if authMethod != .password, validationError.statusCode == 400, let authMethod = authMethod {
errorMessage = AuthLocalization.Error.accountNotRegistered(
authMethod.analyticsValue,
config.platformName
)
} else if validationError.statusCode == 403 {
errorMessage = AuthLocalization.Error.disabledAccount
} else {
errorMessage = CoreLocalization.Error.unknownError
errorMessage = value
}
} else if case APIError.invalidGrant = error {
errorMessage = CoreLocalization.Error.invalidCredentials
} else if error.isInternetError {
errorMessage = CoreLocalization.Error.slowOrNoInternetConnection
} else {
errorMessage = CoreLocalization.Error.unknownError
}
}

func trackSignUpClicked() {
analytics.signUpClicked()
}

func trackForgotPasswordClicked() {
analytics.forgotPasswordClicked()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,17 @@ public struct SignUpView: View {
.font(Theme.Fonts.titleSmall)
.foregroundColor(Theme.Colors.textPrimary)
.padding(.bottom, 20)


if viewModel.thirdPartyAuthSuccess {
Text(AuthLocalization.SignUp.successSigninLabel)
.font(Theme.Fonts.titleMedium)
.foregroundColor(Theme.Colors.textPrimary)
Text(AuthLocalization.SignUp.successSigninSublabel)
.font(Theme.Fonts.titleSmall)
.foregroundColor(Theme.Colors.textSecondary)
.padding(.bottom, 20)
}

let requiredFields = viewModel.fields.filter {$0.field.required}
let nonRequiredFields = viewModel.fields.filter {!$0.field.required}

Expand Down Expand Up @@ -98,15 +108,27 @@ public struct SignUpView: View {
}.frame(maxWidth: .infinity)
} else {
StyledButton(AuthLocalization.SignUp.createAccountBtn) {
viewModel.thirdPartyAuthSuccess = false
Task {
await viewModel.registerUser()
}
viewModel.trackCreateAccountClicked()
}
.padding(.top, 40)
.padding(.bottom, 80)
.frame(maxWidth: .infinity)
}
if viewModel.socialAuthEnabled,
!requiredFields.isEmpty {
SocialAuthView(
authType: .register,
viewModel: .init(
config: viewModel.config
) { result in
Task { await viewModel.register(with: result) }
}
)
.padding(.bottom, 30)
}
Spacer()
}
.padding(.horizontal, 24)
Expand Down
Loading

0 comments on commit 42f3eab

Please sign in to comment.