Skip to content

Commit f833a5d

Browse files
committed
Improved error handling + calendar, staff info, report card list, document list, mail inbox count
1 parent 2edd109 commit f833a5d

21 files changed

+830
-84
lines changed

Sources/SwiftVue/Attendance/AttendanceParser.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ public class AttendanceParser: NSObject, XMLParserDelegate {
2626

2727
public func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
2828
self.parser.abortParsing()
29-
self.error = parseError
29+
if self.error == nil {
30+
self.error = parseError
31+
}
3032
}
3133

3234
public func parser(_ parser: XMLParser, validationErrorOccurred validationError: Error) {
@@ -64,6 +66,9 @@ public class AttendanceParser: NSObject, XMLParserDelegate {
6466
}
6567

6668
self.periodTotals.append(periodTotal)
69+
case "RT_ERROR":
70+
self.parser.abortParsing()
71+
self.error = SwiftVueError.error(from: attributeDict["ERROR_MESSAGE"])
6772
default:
6873
return
6974
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//
2+
// EventInfo.swift
3+
//
4+
//
5+
// Created by Evan Kaneshige on 12/14/23.
6+
//
7+
8+
import Foundation
9+
10+
public struct EventInfo: Hashable, Codable, Identifiable {
11+
public var id: UUID
12+
public var date: Date
13+
public var title: String
14+
public var dayType: String
15+
16+
public init(id: UUID = UUID(), date: Date, title: String, dayType: String) {
17+
self.id = id
18+
self.date = date
19+
self.title = title
20+
self.dayType = dayType
21+
}
22+
23+
internal init?(attributes: [String: String]) {
24+
guard let dateAttribute = attributes["Date"],
25+
let titleAttribute = attributes["Title"],
26+
let dayTypeAttribute = attributes["DayType"] else {
27+
return nil
28+
}
29+
30+
let dateFormatter = DateFormatter()
31+
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
32+
dateFormatter.dateFormat = "MM/dd/y"
33+
34+
guard let date = dateFormatter.date(from: dateAttribute) else {
35+
return nil
36+
}
37+
38+
self.init(date: date, title: titleAttribute, dayType: dayTypeAttribute)
39+
}
40+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//
2+
// StudentCalendar.swift
3+
//
4+
//
5+
// Created by Evan Kaneshige on 12/14/23.
6+
//
7+
8+
import Foundation
9+
10+
public struct StudentCalendar: Hashable, Codable, Identifiable {
11+
public var id: UUID
12+
public var schoolBeginDate: Date
13+
public var schoolEndDate: Date
14+
public var monthBeginDate: Date
15+
public var monthEndDate: Date
16+
public var events: [EventInfo]
17+
18+
public init(id: UUID = UUID(), schoolBeginDate: Date, schoolEndDate: Date, monthBeginDate: Date, monthEndDate: Date, events: [EventInfo]) {
19+
self.id = id
20+
self.schoolBeginDate = schoolBeginDate
21+
self.schoolEndDate = schoolEndDate
22+
self.monthBeginDate = monthBeginDate
23+
self.monthEndDate = monthEndDate
24+
self.events = events
25+
}
26+
27+
internal init?(attributes: [String: String]) {
28+
guard let schoolBeginDateAttribute = attributes["SchoolBegDate"],
29+
let schoolEndDateAttribute = attributes["SchoolEndDate"],
30+
let monthBeginDateAttribute = attributes["MonthBegDate"],
31+
let monthEndDateAttribute = attributes["MonthEndDate"] else {
32+
return nil
33+
}
34+
35+
let dateFormatter = DateFormatter()
36+
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
37+
dateFormatter.dateFormat = "MM/dd/y"
38+
39+
guard let schoolBeginDate = dateFormatter.date(from: schoolBeginDateAttribute),
40+
let schoolEndDate = dateFormatter.date(from: schoolEndDateAttribute),
41+
let monthBeginDate = dateFormatter.date(from: monthBeginDateAttribute),
42+
let monthEndDate = dateFormatter.date(from: monthEndDateAttribute) else {
43+
return nil
44+
}
45+
46+
self.init(schoolBeginDate: schoolBeginDate, schoolEndDate: schoolEndDate, monthBeginDate: monthBeginDate, monthEndDate: monthEndDate, events: [])
47+
}
48+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//
2+
// StudentCalendarParser.swift
3+
//
4+
//
5+
// Created by Evan Kaneshige on 12/14/23.
6+
//
7+
8+
import Foundation
9+
10+
public class StudentCalendarParser: NSObject, XMLParserDelegate {
11+
private var studentCalendar: StudentCalendar?
12+
private var eventInfos: [EventInfo] = []
13+
14+
private var parser: XMLParser
15+
private var error: Error?
16+
17+
public init(string: String) {
18+
self.parser = XMLParser(data: Data(string.utf8))
19+
super.init()
20+
self.parser.delegate = self
21+
self.parser.shouldProcessNamespaces = false
22+
self.parser.shouldReportNamespacePrefixes = false
23+
self.parser.shouldResolveExternalEntities = false
24+
}
25+
26+
public func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
27+
self.parser.abortParsing()
28+
if self.error == nil {
29+
self.error = parseError
30+
}
31+
}
32+
33+
public func parser(_ parser: XMLParser, validationErrorOccurred validationError: Error) {
34+
self.parser.abortParsing()
35+
self.error = validationError
36+
}
37+
38+
public func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
39+
switch elementName {
40+
case "CalendarListing":
41+
guard let studentCalendar = StudentCalendar(attributes: attributeDict) else {
42+
self.parser.abortParsing()
43+
return
44+
}
45+
46+
self.studentCalendar = studentCalendar
47+
case "EventList":
48+
guard let eventInfo = EventInfo(attributes: attributeDict) else {
49+
self.parser.abortParsing()
50+
return
51+
}
52+
53+
self.studentCalendar?.events.append(eventInfo)
54+
case "RT_ERROR":
55+
self.parser.abortParsing()
56+
self.error = SwiftVueError.error(from: attributeDict["ERROR_MESSAGE"])
57+
default:
58+
return
59+
}
60+
}
61+
62+
public func parse() throws -> StudentCalendar {
63+
self.parser.parse()
64+
65+
if let error {
66+
throw error
67+
}
68+
69+
if let studentCalendar {
70+
return studentCalendar
71+
} else {
72+
throw SwiftVueError.couldNotParseXML
73+
}
74+
}
75+
}

Sources/SwiftVue/DataProvider/DataProvider.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@ import Foundation
99

1010
public protocol DataProvider {
1111
func getMessages() async throws -> String
12-
func getCalendar() async throws -> String
12+
func getCalendar() async throws -> StudentCalendar
1313
func getAttendance() async throws -> Attendance
1414
func getGradebook(reportPeriod: Int?) async throws -> Gradebook
1515
func getClassNotes() async throws -> String
1616
func getStudentInfo() async throws -> StudentInfo
1717
func getSchedule(termIndex: Int?) async throws -> Schedule
18-
func getSchoolInfo() async throws -> String
19-
func listReportCards() async throws -> String
18+
func getStaffInfo() async throws -> [StaffInfo]
19+
func listReportCards() async throws -> [ReportCardInfo]
2020
func getReportCard(documentGUID: String) async throws -> String
21-
func listDocuments() async throws -> String
21+
func listDocuments() async throws -> [DocumentInfo]
2222
func getDocument(documentGUID: String) async throws -> String
23-
func getMailInboxCount() async throws -> String
23+
func getMailInboxCount() async throws -> MailInboxCount
2424
func verifyCredentials() async throws -> Bool
2525

2626
init(credentials: Credentials)

Sources/SwiftVue/DataProvider/PreviewDataProvider.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public class PreviewDataProvider: DataProvider {
2020
throw SwiftVueError.notImplemented("PreviewDataProvider.getMessages")
2121
}
2222

23-
public func getCalendar() async throws -> String {
23+
public func getCalendar() async throws -> StudentCalendar {
2424
guard validCredentials else { throw SwiftVueError.invalidCredentials }
2525
throw SwiftVueError.notImplemented("PreviewDataProvider.getCalendar")
2626
}
@@ -65,12 +65,12 @@ public class PreviewDataProvider: DataProvider {
6565
}
6666
}
6767

68-
public func getSchoolInfo() async throws -> String {
68+
public func getStaffInfo() async throws -> [StaffInfo] {
6969
guard validCredentials else { throw SwiftVueError.invalidCredentials }
7070
throw SwiftVueError.notImplemented("PreviewDataProvider.getSchoolInfo")
7171
}
7272

73-
public func listReportCards() async throws -> String {
73+
public func listReportCards() async throws -> [ReportCardInfo] {
7474
guard validCredentials else { throw SwiftVueError.invalidCredentials }
7575
throw SwiftVueError.notImplemented("PreviewDataProvider.listReportCards")
7676
}
@@ -80,7 +80,7 @@ public class PreviewDataProvider: DataProvider {
8080
throw SwiftVueError.notImplemented("PreviewDataProvider.getReportCard")
8181
}
8282

83-
public func listDocuments() async throws -> String {
83+
public func listDocuments() async throws -> [DocumentInfo] {
8484
guard validCredentials else { throw SwiftVueError.invalidCredentials }
8585
throw SwiftVueError.notImplemented("PreviewDataProvider.listDocuments")
8686
}
@@ -90,7 +90,7 @@ public class PreviewDataProvider: DataProvider {
9090
throw SwiftVueError.notImplemented("PreviewDataProvider.getDocument")
9191
}
9292

93-
public func getMailInboxCount() async throws -> String {
93+
public func getMailInboxCount() async throws -> MailInboxCount {
9494
guard validCredentials else { throw SwiftVueError.invalidCredentials }
9595
throw SwiftVueError.notImplemented("PreviewDataProvider.getMailInboxCount")
9696
}

Sources/SwiftVue/DataProvider/RealDataProvider.swift

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -124,17 +124,15 @@ public class RealDataProvider: DataProvider {
124124
return try await makeRequest(method: "GetPXPMessages")
125125
}
126126

127-
public func getCalendar() async throws -> String {
128-
return try await makeRequest(method: "StudentCalendar")
127+
public func getCalendar() async throws -> StudentCalendar {
128+
let result = try await makeRequest(method: "StudentCalendar")
129+
130+
return try StudentCalendarParser(string: result).parse()
129131
}
130132

131133
public func getAttendance() async throws -> Attendance {
132134
let result = try await makeRequest(method: "Attendance")
133135

134-
if !result.contains("Attendance") {
135-
throw SwiftVueError.invalidCredentials
136-
}
137-
138136
return try AttendanceParser(string: result).parse()
139137
}
140138

@@ -145,10 +143,6 @@ public class RealDataProvider: DataProvider {
145143
}
146144
let result = try await makeRequest(method: "Gradebook", params: params)
147145

148-
if !result.contains("Gradebook") {
149-
throw SwiftVueError.invalidCredentials
150-
}
151-
152146
return try GradebookParser(string: result).parse()
153147
}
154148

@@ -158,9 +152,7 @@ public class RealDataProvider: DataProvider {
158152

159153
public func getStudentInfo() async throws -> StudentInfo {
160154
let string = try await makeRequest(method: "StudentInfo")
161-
if !string.contains("StudentInfo") {
162-
throw SwiftVueError.invalidCredentials
163-
}
155+
164156
return try StudentInfoParser(string: string).parse()
165157
}
166158

@@ -170,46 +162,54 @@ public class RealDataProvider: DataProvider {
170162
params = ["TermIndex": "\(term)"]
171163
}
172164
let string = try await makeRequest(method: "StudentClassList", params: params)
173-
if !string.contains("StudentClassSchedule") {
174-
throw SwiftVueError.invalidCredentials
175-
}
165+
176166
return try ScheduleParser(string: string).parse()
177167
}
178168

179-
public func getSchoolInfo() async throws -> String {
180-
return try await makeRequest(method: "StudentSchoolInfo")
169+
public func getStaffInfo() async throws -> [StaffInfo] {
170+
let result = try await makeRequest(method: "StudentSchoolInfo")
171+
172+
return try StaffInfoParser(string: result).parse()
181173
}
182174

183-
public func listReportCards() async throws -> String {
184-
return try await makeRequest(method: "GetReportCardInitialData")
175+
public func listReportCards() async throws -> [ReportCardInfo] {
176+
let result = try await makeRequest(method: "GetReportCardInitialData")
177+
178+
return try ReportCardInfoParser(string: result).parse()
185179
}
186180

187181
public func getReportCard(documentGUID: String) async throws -> String {
188182
return try await makeRequest(method: "GetReportCardDocumentData", params: ["DocumentGU": documentGUID])
189183
}
190184

191-
public func listDocuments() async throws -> String {
192-
return try await makeRequest(method: "GetStudentDocumentInitialData")
185+
public func listDocuments() async throws -> [DocumentInfo] {
186+
let result = try await makeRequest(method: "GetStudentDocumentInitialData")
187+
188+
return try DocumentInfoParser(string: result).parse()
193189
}
194190

195191
public func getDocument(documentGUID: String) async throws -> String {
196192
return try await makeRequest(method: "GetContentOfAttachedDoc", params: ["DocumentGU": documentGUID])
197193
}
198194

199-
public func getMailInboxCount() async throws -> String {
200-
return try await makeRequest(method: "SynergyMailGetInboxCount")
195+
public func getMailInboxCount() async throws -> MailInboxCount {
196+
let result = try await makeRequest(method: "SynergyMailGetInboxCount")
197+
198+
return try MailInboxCountParser(string: result).parse()
201199
}
202200

203201
public func verifyCredentials() async throws -> Bool {
204-
let string = try await getMailInboxCount()
205-
return string.contains("SynergyMailInboxCountXML")
202+
do {
203+
let _ = try await getMailInboxCount()
204+
return true
205+
} catch SwiftVueError.invalidCredentials {
206+
return false
207+
}
206208
}
207209

208210
public static func getDistrictList(zip: String) async throws -> [DistrictInfo] {
209211
let string = try await makeRequest(method: "GetMatchingDistrictList", params: ["Key":"5E4B7859-B805-474B-A833-FDB15D205D40", "MatchToDistrictZipCode":"\(zip)"])
210-
if !string.contains("DistrictList") {
211-
throw SwiftVueError.invalidCredentials
212-
}
212+
213213
return try DistrictInfoParser(string: string).parse()
214214
}
215215
}

0 commit comments

Comments
 (0)