Skip to content

Commit

Permalink
feat: [FC-0047] FCM (openedx#461)
Browse files Browse the repository at this point in the history
* feat: firebase cloud messaging

* fix: address feedback

* fix: address feedback
  • Loading branch information
volodymyr-chekyrta authored Jun 21, 2024
1 parent 5498a1c commit b2539a6
Show file tree
Hide file tree
Showing 26 changed files with 500 additions and 155 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public class SignInViewModel: ObservableObject {
analytics.identify(id: "\(user.id)", username: user.username, email: user.email)
analytics.userLogin(method: .password)
router.showMainOrWhatsNewScreen(sourceScreen: sourceScreen)
NotificationCenter.default.post(name: .userAuthorized, object: nil)
} catch let error {
failure(error)
}
Expand Down Expand Up @@ -113,6 +114,7 @@ public class SignInViewModel: ObservableObject {
analytics.identify(id: "\(user.id)", username: user.username, email: user.email)
analytics.userLogin(method: authMethod)
router.showMainOrWhatsNewScreen(sourceScreen: sourceScreen)
NotificationCenter.default.post(name: .userAuthorized, object: nil)
} catch let error {
failure(error, authMethod: authMethod)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ public class SignUpViewModel: ObservableObject {
analytics.registrationSuccess(method: authMetod.analyticsValue)
isShowProgress = false
router.showMainOrWhatsNewScreen(sourceScreen: sourceScreen)

NotificationCenter.default.post(name: .userAuthorized, object: nil)
} catch let error {
isShowProgress = false
if case APIError.invalidGrant = error {
Expand Down Expand Up @@ -193,6 +193,7 @@ public class SignUpViewModel: ObservableObject {
analytics.userLogin(method: authMethod)
isShowProgress = false
router.showMainOrWhatsNewScreen(sourceScreen: sourceScreen)
NotificationCenter.default.post(name: .userAuthorized, object: nil)
} catch {
update(fullName: response.name, email: response.email)
self.externalToken = response.token
Expand Down
2 changes: 2 additions & 0 deletions Core/Core/Data/CoreStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Foundation
public protocol CoreStorage {
var accessToken: String? {get set}
var refreshToken: String? {get set}
var pushToken: String? {get set}
var appleSignFullName: String? {get set}
var appleSignEmail: String? {get set}
var cookiesDate: String? {get set}
Expand All @@ -25,6 +26,7 @@ public protocol CoreStorage {
public class CoreStorageMock: CoreStorage {
public var accessToken: String?
public var refreshToken: String?
public var pushToken: String?
public var appleSignFullName: String?
public var appleSignEmail: String?
public var cookiesDate: String?
Expand Down
11 changes: 10 additions & 1 deletion Core/Core/Extensions/Notification.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,24 @@
import Foundation

public extension Notification.Name {
static let userAuthorized = Notification.Name("userAuthorized")
static let userLoggedOut = Notification.Name("userLoggedOut")
static let onCourseEnrolled = Notification.Name("onCourseEnrolled")
static let onblockCompletionRequested = Notification.Name("onblockCompletionRequested")
static let onTokenRefreshFailed = Notification.Name("onTokenRefreshFailed")
static let onActualVersionReceived = Notification.Name("onActualVersionReceived")
static let onAppUpgradeAccountSettingsTapped = Notification.Name("onAppUpgradeAccountSettingsTapped")
static let onNewVersionAvaliable = Notification.Name("onNewVersionAvaliable")
static let webviewReloadNotification = Notification.Name("webviewReloadNotification")
static let onBlockCompletion = Notification.Name.init("onBlockCompletion")
static let onBlockCompletion = Notification.Name("onBlockCompletion")
static let shiftCourseDates = Notification.Name("shiftCourseDates")
static let profileUpdated = Notification.Name("profileUpdated")
static let getCourseDates = Notification.Name("getCourseDates")
static let refreshEnrollments = Notification.Name("refreshEnrollments")
}

public extension Notification {
enum UserInfoKey: String {
case isForced
}
}
6 changes: 5 additions & 1 deletion Core/Core/Network/RequestInterceptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,11 @@ final public class RequestInterceptor: Alamofire.RequestInterceptor {
}
self.requestsToRetry.removeAll()
} else {
NotificationCenter.default.post(name: .onTokenRefreshFailed, object: nil)
NotificationCenter.default.post(
name: .userLoggedOut,
object: nil,
userInfo: [Notification.UserInfoKey.isForced: true]
)
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions Dashboard/Dashboard/Presentation/ListDashboardViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class ListDashboardViewModel: ObservableObject {
private let interactor: DashboardInteractorProtocol
private let analytics: DashboardAnalytics
private var onCourseEnrolledCancellable: AnyCancellable?
private var refreshEnrollmentsCancellable: AnyCancellable?

public init(interactor: DashboardInteractorProtocol,
connectivity: ConnectivityProtocol,
Expand All @@ -46,6 +47,14 @@ public class ListDashboardViewModel: ObservableObject {
await self.getMyCourses(page: 1, refresh: true)
}
}
refreshEnrollmentsCancellable = NotificationCenter.default
.publisher(for: .refreshEnrollments)
.sink { [weak self] _ in
guard let self = self else { return }
Task {
await self.getMyCourses(page: 1, refresh: true)
}
}
}

@MainActor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class PrimaryCourseDashboardViewModel: ObservableObject {

let enrollmentPublisher = NotificationCenter.default.publisher(for: .onCourseEnrolled)
let completionPublisher = NotificationCenter.default.publisher(for: .onblockCompletionRequested)
let refreshEnrollmentsPublisher = NotificationCenter.default.publisher(for: .refreshEnrollments)

enrollmentPublisher
.sink { [weak self] _ in
Expand All @@ -64,6 +65,15 @@ public class PrimaryCourseDashboardViewModel: ObservableObject {
updateEnrollmentsIfNeeded()
}
.store(in: &cancellables)

refreshEnrollmentsPublisher
.sink { [weak self] _ in
guard let self = self else { return }
Task {
await self.getEnrollments()
}
}
.store(in: &cancellables)
}

private func updateEnrollmentsIfNeeded() {
Expand Down
8 changes: 6 additions & 2 deletions Discussion/Discussion/Data/Model/Data_CommentsResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public extension DataLayer {
public let childCount: Int
public let children: [String]
public let users: Users?
public let profileImage: ProfileImage?

enum CodingKeys: String, CodingKey {
case id = "id"
Expand All @@ -71,6 +72,7 @@ public extension DataLayer {
case childCount = "child_count"
case children = "children"
case users
case profileImage = "profile_image"
}

public init(
Expand All @@ -94,7 +96,8 @@ public extension DataLayer {
endorsedAt: String?,
childCount: Int,
children: [String],
users: Users?
users: Users?,
profileImage: ProfileImage?
) {
self.id = id
self.author = author
Expand All @@ -117,6 +120,7 @@ public extension DataLayer {
self.childCount = childCount
self.children = children
self.users = users
self.profileImage = profileImage
}
}
}
Expand All @@ -125,7 +129,7 @@ public extension DataLayer.Comments {
var domain: UserComment {
UserComment(
authorName: author ?? DiscussionLocalization.anonymous,
authorAvatar: users?.userName?.profile?.image?.imageURLLarge ?? "",
authorAvatar: users?.userName?.profile?.image?.imageURLLarge ?? profileImage?.imageURLFull ?? "",
postDate: Date(iso8601: createdAt),
postTitle: "",
postBody: rawBody,
Expand Down
5 changes: 4 additions & 1 deletion Discussion/Discussion/Data/Network/DiscussionEndpoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,10 @@ enum DiscussionEndpoint: EndPointType {
}
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getThread:
return .requestParameters(parameters: [:], encoding: URLEncoding.queryString)
return .requestParameters(
parameters: ["requested_fields": "profile_image"],
encoding: URLEncoding.queryString
)
case .getTopics:
return .requestParameters(encoding: URLEncoding.queryString)
case let .getTopic(_, topicID):
Expand Down
70 changes: 24 additions & 46 deletions Discussion/Discussion/Data/Network/DiscussionRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ public protocol DiscussionRepositoryProtocol {
func followThread(following: Bool, threadID: String) async throws
func createNewThread(newThread: DiscussionNewThread) async throws
func readBody(threadID: String) async throws
func renameThreadUser(data: Data) async throws -> DataLayer.ThreadListsResponse
func renameUsers(data: Data) async throws -> DataLayer.CommentsResponse
func renameUsersInJSON(stringJSON: String) -> String
}

public class DiscussionRepository: DiscussionRepositoryProtocol {
Expand Down Expand Up @@ -66,21 +63,20 @@ public class DiscussionRepository: DiscussionRepositoryProtocol {
let threads = try await api.requestData(DiscussionEndpoint
.getThreads(courseID: courseID, type: type, sort: sort, filter: filter, page: page))

return try await renameThreadUser(data: threads).domain
return try await renameThreadListUser(data: threads).domain
}

public func getThread(threadID: String) async throws -> UserThread {
let thread = try await api.requestData(DiscussionEndpoint
.getThread(threadID: threadID))
.mapResponse(DataLayer.ThreadList.self)
return thread.userThread
return try await renameThreadUser(data: thread).userThread
}

public func searchThreads(courseID: String, searchText: String, pageNumber: Int) async throws -> ThreadLists {
let posts = try await api.requestData(DiscussionEndpoint.searchThreads(courseID: courseID,
searchText: searchText,
pageNumber: pageNumber))
return try await renameThreadUser(data: posts).domain
return try await renameThreadListUser(data: posts).domain
}

public func getTopics(courseID: String) async throws -> Topics {
Expand Down Expand Up @@ -158,7 +154,7 @@ public class DiscussionRepository: DiscussionRepositoryProtocol {
_ = try await api.request(DiscussionEndpoint.readBody(threadID: threadID))
}

public func renameThreadUser(data: Data) async throws -> DataLayer.ThreadListsResponse {
private func renameThreadListUser(data: Data) async throws -> DataLayer.ThreadListsResponse {
var modifiedJSON = ""
let parsed = try data.mapResponse(DataLayer.ThreadListsResponse.self)

Expand All @@ -176,7 +172,25 @@ public class DiscussionRepository: DiscussionRepositoryProtocol {
}
}

public func renameUsers(data: Data) async throws -> DataLayer.CommentsResponse {
private func renameThreadUser(data: Data) async throws -> DataLayer.ThreadList {
var modifiedJSON = ""
let parsed = try data.mapResponse(DataLayer.ThreadList.self)

if let stringJSON = String(data: data, encoding: .utf8) {
modifiedJSON = renameUsersInJSON(stringJSON: stringJSON)
if let modifiedParsed = try modifiedJSON.data(using: .utf8)?.mapResponse(
DataLayer.ThreadList.self
) {
return modifiedParsed
} else {
return parsed
}
} else {
return parsed
}
}

private func renameUsers(data: Data) async throws -> DataLayer.CommentsResponse {
var modifiedJSON = ""
let parsed = try data.mapResponse(DataLayer.CommentsResponse.self)

Expand All @@ -192,7 +206,7 @@ public class DiscussionRepository: DiscussionRepositoryProtocol {
}
}

public func renameUsersInJSON(stringJSON: String) -> String {
private func renameUsersInJSON(stringJSON: String) -> String {
var modifiedJSON = stringJSON
let userNames = stringJSON.find(from: "\"users\":{\"", to: "\":{\"profile\":")
if userNames.count >= 1 {
Expand Down Expand Up @@ -478,42 +492,6 @@ public class DiscussionRepositoryMock: DiscussionRepositoryProtocol {
public func readBody(threadID: String) async throws {

}

public func renameThreadUser(data: Data) async throws -> DataLayer.ThreadListsResponse {
DataLayer.ThreadListsResponse(threads: [],
textSearchRewrite: "",
pagination: DataLayer.Pagination(next: "", previous: "", count: 0, numPages: 0) )
}

public func renameUsers(data: Data) async throws -> DataLayer.CommentsResponse {
DataLayer.CommentsResponse(
comments: [
DataLayer.Comments(id: "", author: "Bill",
authorLabel: nil,
createdAt: "25.11.2043",
updatedAt: "25.11.2043",
rawBody: "Raw Body",
renderedBody: "Rendered body",
abuseFlagged: false,
voted: true,
voteCount: 2,
editableFields: [],
canDelete: true,
threadID: "",
parentID: nil,
endorsed: false,
endorsedBy: nil,
endorsedByLabel: nil,
endorsedAt: nil,
childCount: 0,
children: [],
users: nil)
], pagination: DataLayer.Pagination(next: nil, previous: nil, count: 0, numPages: 0))
}

public func renameUsersInJSON(stringJSON: String) -> String {
return stringJSON
}
}
#endif
// swiftlint:enable all
Loading

0 comments on commit b2539a6

Please sign in to comment.