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

feat: added ability to handle course errors #358

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions core/src/main/java/org/openedx/core/data/api/CourseApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.openedx.core.data.model.BlocksCompletionBody
import org.openedx.core.data.model.CourseComponentStatus
import org.openedx.core.data.model.CourseDates
import org.openedx.core.data.model.CourseDatesBannerInfo
import org.openedx.core.data.model.CourseEnrollmentDetails
import org.openedx.core.data.model.CourseEnrollments
import org.openedx.core.data.model.CourseStructureModel
import org.openedx.core.data.model.HandoutsModel
Expand Down Expand Up @@ -76,4 +77,9 @@ interface CourseApi {
@Query("status") status: String? = null,
@Query("requested_fields") fields: List<String> = emptyList()
): CourseEnrollments

@GET("/api/mobile/v1/course_info/{course_id}/enrollment_details")
suspend fun getEnrollmentDetails(
@Path("course_id") courseId: String,
): CourseEnrollmentDetails
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.openedx.core.data.model

import com.google.gson.annotations.SerializedName
import org.openedx.core.domain.model.CourseAccessDetails
import org.openedx.core.utils.TimeUtils

data class CourseAccessDetails(
@SerializedName("has_unmet_prerequisites")
val hasUnmetPrerequisites: Boolean,
@SerializedName("is_too_early")
val isTooEarly: Boolean,
@SerializedName("is_staff")
val isStaff: Boolean,
@SerializedName("audit_access_expires")
val auditAccessExpires: String?,
@SerializedName("courseware_access")
val coursewareAccess: CoursewareAccess?,
) {
fun mapToDomain() = CourseAccessDetails(
hasUnmetPrerequisites = hasUnmetPrerequisites,
isTooEarly = isTooEarly,
isStaff = isStaff,
auditAccessExpires = TimeUtils.iso8601ToDate(auditAccessExpires ?: ""),
coursewareAccess = coursewareAccess?.mapToDomain(),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.openedx.core.data.model

import com.google.gson.annotations.SerializedName
import org.openedx.core.domain.model.CourseEnrollmentDetails

data class CourseEnrollmentDetails(
@SerializedName("id")
val id: String,
@SerializedName("course_updates")
val courseUpdates: String,
@SerializedName("course_handouts")
val courseHandouts: String,
@SerializedName("discussion_url")
val discussionUrl: String,
@SerializedName("course_access_details")
val courseAccessDetails: CourseAccessDetails,
@SerializedName("certificate")
val certificate: Certificate?,
@SerializedName("enrollment_details")
val enrollmentDetails: EnrollmentDetails,
@SerializedName("course_info_overview")
val courseInfoOverview: CourseInfoOverview,
) {
fun mapToDomain(): CourseEnrollmentDetails {
return CourseEnrollmentDetails(
id = id,
courseUpdates = courseUpdates,
courseHandouts = courseHandouts,
discussionUrl = discussionUrl,
courseAccessDetails = courseAccessDetails.mapToDomain(),
certificate = certificate?.mapToDomain(),
enrollmentDetails = enrollmentDetails.mapToDomain(),
courseInfoOverview = courseInfoOverview.mapToDomain(),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.openedx.core.data.model

import com.google.gson.annotations.SerializedName
import org.openedx.core.domain.model.CourseInfoOverview
import org.openedx.core.utils.TimeUtils

data class CourseInfoOverview(
@SerializedName("name")
val name: String,
@SerializedName("number")
val number: String,
@SerializedName("org")
val org: String,
@SerializedName("start")
val start: String?,
@SerializedName("start_display")
val startDisplay: String,
@SerializedName("start_type")
val startType: String,
@SerializedName("end")
val end: String?,
@SerializedName("is_self_paced")
val isSelfPaced: Boolean,
@SerializedName("media")
var media: Media?,
@SerializedName("course_sharing_utm_parameters")
val courseSharingUtmParameters: CourseSharingUtmParameters,
@SerializedName("course_about")
val courseAbout: String,
@SerializedName("course_modes")
val courseModes: List<CourseMode>,
) {
fun mapToDomain() = CourseInfoOverview(
name = name,
number = number,
org = org,
start = TimeUtils.iso8601ToDate(start ?: ""),
startDisplay = startDisplay,
startType = startType,
end = TimeUtils.iso8601ToDate(end ?: ""),
isSelfPaced = isSelfPaced,
media = media?.mapToDomain(),
courseSharingUtmParameters = courseSharingUtmParameters.mapToDomain(),
courseAbout = courseAbout,
courseModes = courseModes.map { it.mapToDomain() },
)
}
25 changes: 25 additions & 0 deletions core/src/main/java/org/openedx/core/data/model/CourseMode.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.openedx.core.data.model

import com.google.gson.annotations.SerializedName
import org.openedx.core.domain.model.CourseMode as CourseMode

data class CourseMode(
@SerializedName("slug")
val slug: String,
@SerializedName("sku")
val sku: String?,
@SerializedName("android_sku")
val androidSku: String?,
@SerializedName("ios_sku")
val iosSku: String?,
@SerializedName("min_price")
val minPrice: Int,
) {
fun mapToDomain() = CourseMode(
slug = slug,
sku = sku,
androidSku = androidSku,
iosSku = iosSku,
minPrice = minPrice,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.openedx.core.data.model

import com.google.gson.annotations.SerializedName
import org.openedx.core.domain.model.EnrollmentDetails
import org.openedx.core.utils.TimeUtils

data class EnrollmentDetails(
@SerializedName("date")
val date: String?,
@SerializedName("mode")
val mode: String,
@SerializedName("is_active")
val isActive: Boolean,
@SerializedName("upgrade_deadline")
val upgradeDeadline: String?,
) {
fun mapToDomain() = EnrollmentDetails(
created = TimeUtils.iso8601ToDate(date ?: ""),
mode = mode,
isActive = isActive,
upgradeDeadline = TimeUtils.iso8601ToDate(upgradeDeadline ?: ""),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.openedx.core.domain.model

import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import java.util.Date

@Parcelize
data class CourseAccessDetails(
val hasUnmetPrerequisites: Boolean,
val isTooEarly: Boolean,
val isStaff: Boolean,
val auditAccessExpires: Date?,
val coursewareAccess: CoursewareAccess?
) : Parcelable
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.openedx.core.domain.model

import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import java.util.Date

@Parcelize
data class CourseEnrollmentDetails(
val id: String,
val courseUpdates: String,
val courseHandouts: String,
val discussionUrl: String,
val courseAccessDetails: CourseAccessDetails,
val certificate: Certificate?,
val enrollmentDetails: EnrollmentDetails,
val courseInfoOverview: CourseInfoOverview,
) : Parcelable {
fun isUpgradable(): Boolean {
val start = courseInfoOverview.start ?: return false
val upgradeDeadline = enrollmentDetails.upgradeDeadline ?: return false
if (enrollmentDetails.mode != "audit") return false

return start < Date() && getCourseMode() != null && upgradeDeadline > Date()
}

fun getCourseMode(): CourseMode? {
return courseInfoOverview.courseModes
.firstOrNull { it.slug == "verified" && !it.androidSku.isNullOrEmpty() }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.openedx.core.domain.model

import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import java.util.Date

@Parcelize
data class CourseInfoOverview(
val name: String,
val number: String,
val org: String,
val start: Date?,
val startDisplay: String,
val startType: String,
val end: Date?,
val isSelfPaced: Boolean,
var media: Media?,
val courseSharingUtmParameters: CourseSharingUtmParameters,
val courseAbout: String,
val courseModes: List<CourseMode>,
) : Parcelable
13 changes: 13 additions & 0 deletions core/src/main/java/org/openedx/core/domain/model/CourseMode.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.openedx.core.domain.model

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
data class CourseMode(
val slug: String?,
val sku: String?,
val androidSku: String?,
val iosSku: String?,
val minPrice: Int,
) : Parcelable
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.openedx.core.domain.model

import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import java.util.Date

@Parcelize
data class EnrollmentDetails(
val created: Date?,
val mode: String,
val isActive: Boolean,
val upgradeDeadline: Date?
) : Parcelable
5 changes: 5 additions & 0 deletions core/src/main/java/org/openedx/core/utils/TimeUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,11 @@ object TimeUtils {
}
}

fun getCourseAccessFormattedDate(context: Context, date: Date): String {
val resourceManager = ResourceManager(context)
return dateToCourseDate(resourceManager, date)
}

/**
* Returns the number of days difference between the given date and the current date.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.openedx.core.data.api.CourseApi
import org.openedx.core.data.model.BlocksCompletionBody
import org.openedx.core.data.storage.CorePreferences
import org.openedx.core.domain.model.CourseComponentStatus
import org.openedx.core.domain.model.CourseEnrollmentDetails
import org.openedx.core.domain.model.CourseStructure
import org.openedx.core.exception.NoCachedDataException
import org.openedx.core.module.db.DownloadDao
Expand Down Expand Up @@ -58,6 +59,10 @@ class CourseRepository(
return courseStructure[courseId]!!
}

suspend fun getEnrollmentDetails(courseId: String): CourseEnrollmentDetails {
return api.getEnrollmentDetails(courseId = courseId).mapToDomain()
}

suspend fun getCourseStatus(courseId: String): CourseComponentStatus {
val username = preferencesManager.user?.username ?: ""
return api.getCourseStatus(username, courseId).mapToDomain()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.openedx.course.domain.interactor

import org.openedx.core.BlockType
import org.openedx.core.domain.model.Block
import org.openedx.core.domain.model.CourseEnrollmentDetails
import org.openedx.core.domain.model.CourseStructure
import org.openedx.course.data.repository.CourseRepository

Expand All @@ -16,6 +17,10 @@ class CourseInteractor(
return repository.getCourseStructure(courseId, isNeedRefresh)
}

suspend fun getEnrollmentDetails(courseId: String): CourseEnrollmentDetails {
return repository.getEnrollmentDetails(courseId = courseId)
}

suspend fun getCourseStructureForVideos(
courseId: String,
isNeedRefresh: Boolean = false
Expand Down Expand Up @@ -71,5 +76,4 @@ class CourseInteractor(
suspend fun removeDownloadModel(id: String) = repository.removeDownloadModel(id)

fun getDownloadModels() = repository.getDownloadModels()

}
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,6 @@ interface CourseRouter {
fun navigateToDownloadQueue(fm: FragmentManager, descendants: List<String> = arrayListOf())

fun navigateToVideoQuality(fm: FragmentManager, videoQualityType: VideoQualityType)

fun navigateToMain(fm: FragmentManager, courseId: String?, infoType: String?, openTab: String)
}
Loading
Loading