Skip to content
Merged
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
3 changes: 3 additions & 0 deletions Core/Core/Features/Assignments/APIAssignmentGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public struct APIAssignmentGroup: Codable, Equatable {
let id: ID
let name: String
let position: Int
let group_weight: Double?
var assignments: [APIAssignment]?
}

Expand All @@ -31,12 +32,14 @@ extension APIAssignmentGroup {
id: ID = "1",
name: String = "Assignment Group A",
position: Int = 1,
group_weight: Double? = nil,
assignments: [APIAssignment]? = nil
) -> APIAssignmentGroup {
return APIAssignmentGroup(
id: id,
name: name,
position: position,
group_weight: group_weight,
assignments: assignments
)
}
Expand Down
4 changes: 4 additions & 0 deletions Core/Core/Features/Assignments/AssignmentGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public final class AssignmentGroup: NSManagedObject {
@NSManaged public var name: String
@NSManaged public var position: Int
@NSManaged public var courseID: String
@NSManaged public var groupWeight: NSNumber?
@NSManaged public var assignments: Set<Assignment>?

@discardableResult
Expand All @@ -34,6 +35,9 @@ public final class AssignmentGroup: NSManagedObject {
model.id = item.id.value
model.name = item.name
model.position = item.position
if let groupWeight = item.group_weight {
model.groupWeight = NSNumber(value: groupWeight)
}
model.courseID = courseID

for a in item.assignments ?? [] {
Expand Down
11 changes: 7 additions & 4 deletions Core/Core/Features/Courses/APICourse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public struct APICourse: Codable, Equatable {
let start_at: Date?
let end_at: Date?
let locale: String?
var enrollments: [APIEnrollment]?
public var enrollments: [APIEnrollment]?
var grading_periods: [APIGradingPeriod]?
// let total_students: Int? // include[]=total_students
// let calendar: ?
Expand Down Expand Up @@ -106,6 +106,7 @@ public struct APICourseSettings: Codable, Equatable {
let usage_rights_required: Bool?
let syllabus_course_summary: Bool?
let restrict_quantitative_data: Bool?
let hide_final_grade: Bool?
}

public enum CourseDefaultView: String, Codable, CaseIterable {
Expand Down Expand Up @@ -216,12 +217,14 @@ extension APICourseSettings {
public static func make(
usage_rights_required: Bool = false,
syllabus_course_summary: Bool = true,
restrict_quantitative_data: Bool? = nil
restrict_quantitative_data: Bool? = nil,
hide_final_grade: Bool? = nil
) -> APICourseSettings {
APICourseSettings(
usage_rights_required: usage_rights_required,
syllabus_course_summary: syllabus_course_summary,
restrict_quantitative_data: restrict_quantitative_data
restrict_quantitative_data: restrict_quantitative_data,
hide_final_grade: hide_final_grade
)
}
}
Expand Down Expand Up @@ -337,7 +340,7 @@ public struct GetCourseRequest: APIRequestable {

var include: [Include] = defaultIncludes

init(courseID: String, include: [Include] = defaultIncludes) {
public init(courseID: String, include: [Include] = defaultIncludes) {
self.courseID = courseID
self.include = include
}
Expand Down
4 changes: 2 additions & 2 deletions Core/Core/Features/Enrollments/APIEnrollment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ public struct APIEnrollment: Codable, Equatable {
let grades: Grades?
let user: APIUser?
let computed_current_score: Double?
let computed_final_score: Double?
public let computed_final_score: Double?
let computed_current_grade: String?
let computed_current_letter_grade: String?
let computed_final_grade: String?
public let computed_final_grade: String?
// let unposted_current_grade: String?
// let unposted_final_grade: String?
// let unposted_current_score: String?
Expand Down
64 changes: 64 additions & 0 deletions Core/Core/Features/Scores/Data/CDScoresCourse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//
// This file is part of Canvas.
// Copyright (C) 2025-present Instructure, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

import CoreData

public final class CDScoresCourse: NSManagedObject {
@NSManaged public var courseID: String
@NSManaged public var enrollments: Set<CDScoresCourseEnrollment>
@NSManaged public var settings: CDScoresCourseSettings?

@discardableResult
public static func save(
_ apiEntity: APICourse,
in context: NSManagedObjectContext
) -> CDScoresCourse {
let dbEntity: CDScoresCourse = context.first(
where: #keyPath(CDScoresCourse.courseID),
equals: apiEntity.id.value
) ?? context.insert()
dbEntity.courseID = apiEntity.id.value

if let apiEnrollments = apiEntity.enrollments {
let enrollmentEntities: [CDScoresCourseEnrollment] = apiEnrollments.map { apiItem in
/// This enrollment contains the grade fields necessary to calculate grades on the dashboard.
/// This is a special enrollment that has no courseID nor enrollmentID and contains no Grade objects.
let enrollment = CDScoresCourseEnrollment.save(
courseID: dbEntity.courseID,
apiEntity: apiItem,
in: context
)
return enrollment
}
dbEntity.enrollments = Set(enrollmentEntities)
} else {
dbEntity.enrollments = []
}

if let apiSettings = apiEntity.settings {
let settingsEntity = CDScoresCourseSettings.save(
apiSettings,
course: dbEntity,
in: context
)
dbEntity.settings = settingsEntity
}

return dbEntity
}
}
60 changes: 60 additions & 0 deletions Core/Core/Features/Scores/Data/CDScoresCourseEnrollment.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// This file is part of Canvas.
// Copyright (C) 2025-present Instructure, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

import CoreData
import Foundation

public final class CDScoresCourseEnrollment: NSManagedObject {
@NSManaged public var courseID: String
@NSManaged public var computedFinalScore: NSNumber?
@NSManaged public var computedFinalGrade: String?

@discardableResult
public static func save(
courseID: String,
apiEntity: APIEnrollment,
in context: NSManagedObjectContext
) -> CDScoresCourseEnrollment {
let dbEntity: CDScoresCourseEnrollment = context.first(
where: #keyPath(CDScoresCourseEnrollment.courseID),
equals: courseID
) ?? context.insert()
dbEntity.courseID = courseID
dbEntity.computedFinalGrade = apiEntity.computed_final_grade
if let computedFinalScore = apiEntity.computed_final_score {
dbEntity.computedFinalScore = NSNumber(value: computedFinalScore)
}
return dbEntity
}

public func update(
courseID: String,
apiEntity: APIEnrollment,
in context: NSManagedObjectContext
) {
let dbEntity: CDScoresCourseEnrollment = context.first(
where: #keyPath(CDScoresCourseEnrollment.courseID),
equals: courseID
) ?? context.insert()
dbEntity.courseID = courseID
dbEntity.computedFinalGrade = apiEntity.computed_final_grade
if let computedFinalScore = apiEntity.computed_final_score {
dbEntity.computedFinalScore = NSNumber(value: computedFinalScore)
}
}
}
58 changes: 58 additions & 0 deletions Core/Core/Features/Scores/Data/CDScoresCourseSettings.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// This file is part of Canvas.
// Copyright (C) 2025-present Instructure, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

import CoreData

public final class CDScoresCourseSettings: NSManagedObject {
@NSManaged public var restrictQuantitativeData: Bool
@NSManaged public var hideFinalGrade: Bool
@NSManaged public var course: CDScoresCourse

@discardableResult
static func save(
_ item: APICourseSettings,
course: CDScoresCourse,
in context: NSManagedObjectContext
) -> CDScoresCourseSettings {
let entity: CDScoresCourseSettings = {
if let settings: CDScoresCourseSettings = context.first(
where: #keyPath(CDScoresCourseSettings.course.courseID),
equals: course.courseID
) {
return settings
}

let settings: CDScoresCourseSettings = context.insert()
settings.restrictQuantitativeData = false
settings.hideFinalGrade = false
return settings
}()

if let restrict_quantitative_data = item.restrict_quantitative_data, AppEnvironment.shared.app != .teacher {
entity.restrictQuantitativeData = restrict_quantitative_data
}

if let hideFinalGrade = item.restrict_quantitative_data {
entity.hideFinalGrade = hideFinalGrade
}

entity.course = course

return entity
}
}
56 changes: 56 additions & 0 deletions Core/Core/Features/Scores/Data/GetScoresCourseUseCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// This file is part of Canvas.
// Copyright (C) 2025-present Instructure, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

import CoreData

public class GetScoresCourseUseCase: APIUseCase {
public typealias Model = CDScoresCourse

public let courseID: String
private let include: [GetCourseRequest.Include]

public init(
courseID: String,
include: [GetCourseRequest.Include] = GetCourseRequest.defaultIncludes
) {
self.courseID = courseID
self.include = include
}

public var cacheKey: String? {
return "get-score-course-\(courseID)"
}

public var scope: Scope {
return .where(#keyPath(CDScoresCourse.courseID), equals: courseID)
}

public var request: GetCourseRequest {
return GetCourseRequest(courseID: courseID, include: include)
}

public func write(
response: APICourse?,
urlResponse _: URLResponse?,
to client: NSManagedObjectContext
) {
if let course = response {
CDScoresCourse.save(course, in: client)
}
}
}
46 changes: 46 additions & 0 deletions Core/Core/Features/Scores/Data/ScoresCourse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// This file is part of Canvas.
// Copyright (C) 2025-present Instructure, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

public struct ScoresCourse {
public let courseID: String
public let enrollments: [ScoresCourseEnrollment]
public let settings: ScoresCourseSettings

public init(
courseID: String,
enrollments: [ScoresCourseEnrollment],
settings: ScoresCourseSettings
) {
self.courseID = courseID
self.enrollments = enrollments
self.settings = settings
}

public init(from entity: CDScoresCourse) {
self.courseID = entity.courseID
self.enrollments = entity.enrollments.map(ScoresCourseEnrollment.init(from:))
if let settings = entity.settings {
self.settings = .init(from: settings)
} else {
self.settings = .init(
restrictQuantitativeData: false,
hideFinalGrade: false
)
}
}
}
Loading