mirror of
https://github.com/Xevion/banner.git
synced 2025-12-14 22:11:04 -06:00
docs: add trivial documentation for all types, functions, packages etc.
This commit is contained in:
@@ -20,10 +20,12 @@ import (
|
||||
"resty.dev/v3"
|
||||
)
|
||||
|
||||
// API provides a client for interacting with the Banner API.
|
||||
type API struct {
|
||||
config *config.Config
|
||||
}
|
||||
|
||||
// New creates a new API client with the given configuration.
|
||||
func New(config *config.Config) *API {
|
||||
return &API{config: config}
|
||||
}
|
||||
@@ -34,7 +36,7 @@ var (
|
||||
expiryTime = 25 * time.Minute
|
||||
)
|
||||
|
||||
// SessionMiddleware creates a Resty middleware that resets the session timer on each Banner API call.
|
||||
// SessionMiddleware creates a Resty middleware that resets the session timer on each successful Banner API call.
|
||||
func SessionMiddleware(c *resty.Client, r *resty.Response) error {
|
||||
// log.Debug().Str("url", r.Request.RawRequest.URL.Path).Msg("Session middleware")
|
||||
|
||||
@@ -48,8 +50,8 @@ func SessionMiddleware(c *resty.Client, r *resty.Response) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateSession generates a new session ID (nonce) for use with the Banner API.
|
||||
// Don't use this function directly, use GetSession instead.
|
||||
// GenerateSession generates a new session ID for use with the Banner API.
|
||||
// This function should not be used directly; use EnsureSession instead.
|
||||
func GenerateSession() string {
|
||||
return internal.RandomString(5) + internal.Nonce()
|
||||
}
|
||||
@@ -57,7 +59,7 @@ func GenerateSession() string {
|
||||
var terms []BannerTerm
|
||||
var lastTermUpdate time.Time
|
||||
|
||||
// TryReloadTerms attempts to reload the terms if they are not loaded or the last update was more than 24 hours ago
|
||||
// TryReloadTerms attempts to reload the terms if they are not loaded or if the last update was more than 24 hours ago.
|
||||
func (a *API) TryReloadTerms() error {
|
||||
if len(terms) > 0 && time.Since(lastTermUpdate) < 24*time.Hour {
|
||||
return nil
|
||||
@@ -74,8 +76,9 @@ func (a *API) TryReloadTerms() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsTermArchived checks if the given term is archived
|
||||
// TODO: Add error, switch missing term logic to error
|
||||
// IsTermArchived checks if the given term is archived (view only).
|
||||
//
|
||||
// TODO: Add error handling for when a term does not exist.
|
||||
func (a *API) IsTermArchived(term string) bool {
|
||||
// Ensure the terms are loaded
|
||||
err := a.TryReloadTerms()
|
||||
@@ -106,21 +109,25 @@ func (a *API) EnsureSession() string {
|
||||
return latestSession
|
||||
}
|
||||
|
||||
// Pair represents a key-value pair from the Banner API.
|
||||
type Pair struct {
|
||||
Code string `json:"code"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// BannerTerm represents a term in the Banner system.
|
||||
type BannerTerm Pair
|
||||
|
||||
// Instructor represents an instructor in the Banner system.
|
||||
type Instructor Pair
|
||||
|
||||
// Archived returns true if the term is in it's archival state (view only)
|
||||
// Archived returns true if the term is in an archival (view-only) state.
|
||||
func (term BannerTerm) Archived() bool {
|
||||
return strings.Contains(term.Description, "View Only")
|
||||
}
|
||||
|
||||
// GetTerms retrieves and parses the term information for a given search term.
|
||||
// Page number must be at least 1.
|
||||
// GetTerms retrieves a list of terms from the Banner API.
|
||||
// The page number must be at least 1.
|
||||
func (a *API) GetTerms(search string, page int, maxResults int) ([]BannerTerm, error) {
|
||||
// Ensure offset is valid
|
||||
if page <= 0 {
|
||||
@@ -148,8 +155,8 @@ func (a *API) GetTerms(search string, page int, maxResults int) ([]BannerTerm, e
|
||||
return *terms, nil
|
||||
}
|
||||
|
||||
// SelectTerm selects the given term in the Banner system.
|
||||
// This function completes the initial term selection process, which is required before any other API calls can be made with the session ID.
|
||||
// SelectTerm selects a term in the Banner system for the given session.
|
||||
// This is required before other API calls can be made.
|
||||
func (a *API) SelectTerm(term string, sessionID string) error {
|
||||
form := url.Values{
|
||||
"term": {term},
|
||||
@@ -192,8 +199,8 @@ func (a *API) SelectTerm(term string, sessionID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPartOfTerms retrieves and parses the part of term information for a given term.
|
||||
// Ensure that the offset is greater than 0.
|
||||
// GetPartOfTerms retrieves a list of parts of a term from the Banner API.
|
||||
// The page number must be at least 1.
|
||||
func (a *API) GetPartOfTerms(search string, term int, offset int, maxResults int) ([]BannerTerm, error) {
|
||||
// Ensure offset is valid
|
||||
if offset <= 0 {
|
||||
@@ -223,10 +230,7 @@ func (a *API) GetPartOfTerms(search string, term int, offset int, maxResults int
|
||||
return *terms, nil
|
||||
}
|
||||
|
||||
// GetInstructors retrieves and parses the instructor information for a given search term.
|
||||
// In my opinion, it is unclear what providing the term does, as the results should be the same regardless of the term.
|
||||
// This function is included for completeness, but probably isn't useful.
|
||||
// Ensure that the offset is greater than 0.
|
||||
// GetInstructors retrieves a list of instructors from the Banner API.
|
||||
func (a *API) GetInstructors(search string, term string, offset int, maxResults int) ([]Instructor, error) {
|
||||
// Ensure offset is valid
|
||||
if offset <= 0 {
|
||||
@@ -256,11 +260,13 @@ func (a *API) GetInstructors(search string, term string, offset int, maxResults
|
||||
return *instructors, nil
|
||||
}
|
||||
|
||||
// ClassDetails represents the details of a course.
|
||||
// TODO: Finish this struct & function
|
||||
// ClassDetails represents the detailed information for a class.
|
||||
//
|
||||
// TODO: Implement this struct and the associated GetCourseDetails function.
|
||||
type ClassDetails struct {
|
||||
}
|
||||
|
||||
// GetCourseDetails retrieves the details for a specific course.
|
||||
func (a *API) GetCourseDetails(term int, crn int) (*ClassDetails, error) {
|
||||
body, err := json.Marshal(map[string]string{
|
||||
"term": strconv.Itoa(term),
|
||||
@@ -289,7 +295,7 @@ func (a *API) GetCourseDetails(term int, crn int) (*ClassDetails, error) {
|
||||
return details, nil
|
||||
}
|
||||
|
||||
// Search invokes a search on the Banner system with the given query and returns the results.
|
||||
// Search performs a search for courses with the given query and returns the results.
|
||||
func (a *API) Search(term string, query *Query, sort string, sortDescending bool) (*models.SearchResult, error) {
|
||||
a.ResetDataForm()
|
||||
|
||||
@@ -322,9 +328,8 @@ func (a *API) Search(term string, query *Query, sort string, sortDescending bool
|
||||
return searchResult, nil
|
||||
}
|
||||
|
||||
// GetSubjects retrieves and parses the subject information for a given search term.
|
||||
// The results of this response shouldn't change much, but technically could as new majors are developed, or old ones are removed.
|
||||
// Ensure that the offset is greater than 0.
|
||||
// GetSubjects retrieves a list of subjects from the Banner API.
|
||||
// The page number must be at least 1.
|
||||
func (a *API) GetSubjects(search string, term string, offset int, maxResults int) ([]Pair, error) {
|
||||
// Ensure offset is valid
|
||||
if offset <= 0 {
|
||||
@@ -354,10 +359,8 @@ func (a *API) GetSubjects(search string, term string, offset int, maxResults int
|
||||
return *subjects, nil
|
||||
}
|
||||
|
||||
// GetCampuses retrieves and parses the campus information for a given search term.
|
||||
// In my opinion, it is unclear what providing the term does, as the results should be the same regardless of the term.
|
||||
// This function is included for completeness, but probably isn't useful.
|
||||
// Ensure that the offset is greater than 0.
|
||||
// GetCampuses retrieves a list of campuses from the Banner API.
|
||||
// The page number must be at least 1.
|
||||
func (a *API) GetCampuses(search string, term int, offset int, maxResults int) ([]Pair, error) {
|
||||
// Ensure offset is valid
|
||||
if offset <= 0 {
|
||||
@@ -387,10 +390,8 @@ func (a *API) GetCampuses(search string, term int, offset int, maxResults int) (
|
||||
return *campuses, nil
|
||||
}
|
||||
|
||||
// GetInstructionalMethods retrieves and parses the instructional method information for a given search term.
|
||||
// In my opinion, it is unclear what providing the term does, as the results should be the same regardless of the term.
|
||||
// This function is included for completeness, but probably isn't useful.
|
||||
// Ensure that the offset is greater than 0.
|
||||
// GetInstructionalMethods retrieves a list of instructional methods from the Banner API.
|
||||
// The page number must be at least 1.
|
||||
func (a *API) GetInstructionalMethods(search string, term string, offset int, maxResults int) ([]Pair, error) {
|
||||
// Ensure offset is valid
|
||||
if offset <= 0 {
|
||||
@@ -419,9 +420,7 @@ func (a *API) GetInstructionalMethods(search string, term string, offset int, ma
|
||||
return *methods, nil
|
||||
}
|
||||
|
||||
// GetCourseMeetingTime retrieves the meeting time information for a course based on the given term and course reference number (CRN).
|
||||
// It makes an HTTP GET request to the appropriate API endpoint and parses the response to extract the meeting time data.
|
||||
// The function returns a MeetingTimeResponse struct containing the extracted information.
|
||||
// GetCourseMeetingTime retrieves the meeting time information for a course.
|
||||
func (a *API) GetCourseMeetingTime(term int, crn int) ([]models.MeetingTimeResponse, error) {
|
||||
type responseWrapper struct {
|
||||
Fmt []models.MeetingTimeResponse `json:"fmt"`
|
||||
@@ -446,7 +445,8 @@ func (a *API) GetCourseMeetingTime(term int, crn int) ([]models.MeetingTimeRespo
|
||||
return result.Fmt, nil
|
||||
}
|
||||
|
||||
// ResetDataForm makes a POST request that needs to be made upon before new search requests can be made.
|
||||
// ResetDataForm resets the search form in the Banner system.
|
||||
// This must be called before a new search can be performed.
|
||||
func (a *API) ResetDataForm() {
|
||||
req := a.config.Client.NewRequest()
|
||||
|
||||
@@ -456,8 +456,7 @@ func (a *API) ResetDataForm() {
|
||||
}
|
||||
}
|
||||
|
||||
// GetCourse retrieves the course information.
|
||||
// This course does not retrieve directly from the API, but rather uses scraped data stored in Redis.
|
||||
// GetCourse retrieves course information from the Redis cache.
|
||||
func (a *API) GetCourse(crn string) (*models.Course, error) {
|
||||
// Create a timeout context for Redis operations
|
||||
ctx, cancel := context.WithTimeout(a.config.Ctx, 5*time.Second)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package api provides the core functionality for interacting with the Banner API.
|
||||
package api
|
||||
|
||||
import (
|
||||
@@ -17,16 +18,19 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// PriorityMajors is a list of majors that are considered to be high priority for scraping. This list is used to determine which majors to scrape first/most often.
|
||||
// PriorityMajors is a list of majors that are considered to be high priority for scraping.
|
||||
// This list is used to determine which majors to scrape first/most often.
|
||||
PriorityMajors = []string{"CS", "CPE", "MAT", "EE", "IS"}
|
||||
// AncillaryMajors is a list of majors that are considered to be low priority for scraping. This list will not contain any majors that are in PriorityMajors.
|
||||
// AncillaryMajors is a list of majors that are considered to be low priority for scraping.
|
||||
// This list will not contain any majors that are in PriorityMajors.
|
||||
AncillaryMajors []string
|
||||
// AllMajors is a list of all majors that are available in the Banner system.
|
||||
AllMajors []string
|
||||
)
|
||||
|
||||
// Scrape scrapes the API for all courses and stores them in Redis.
|
||||
// Scrape retrieves all courses from the Banner API and stores them in Redis.
|
||||
// This is a long-running process that should be run in a goroutine.
|
||||
//
|
||||
// TODO: Switch from hardcoded term to dynamic term
|
||||
func (a *API) Scrape() error {
|
||||
// For each subject, retrieve all courses
|
||||
@@ -68,7 +72,8 @@ func (a *API) Scrape() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetExpiredSubjects returns a list of subjects that are expired and should be scraped.
|
||||
// GetExpiredSubjects returns a list of subjects that have expired and should be scraped again.
|
||||
// It checks Redis for the "scraped" status of each major for the current term.
|
||||
func (a *API) GetExpiredSubjects() ([]string, error) {
|
||||
term := Default(time.Now()).ToString()
|
||||
subjects := make([]string, 0)
|
||||
@@ -100,8 +105,8 @@ func (a *API) GetExpiredSubjects() ([]string, error) {
|
||||
return subjects, nil
|
||||
}
|
||||
|
||||
// ScrapeMajor is the scraping invocation for a specific major.
|
||||
// This function does not check whether scraping is required at this time, it is assumed that the caller has already done so.
|
||||
// ScrapeMajor scrapes all courses for a specific major.
|
||||
// This function does not check whether scraping is required at this time; it is assumed that the caller has already done so.
|
||||
func (a *API) ScrapeMajor(subject string) error {
|
||||
offset := 0
|
||||
totalClassCount := 0
|
||||
@@ -180,9 +185,7 @@ func (a *API) ScrapeMajor(subject string) error {
|
||||
}
|
||||
|
||||
// CalculateExpiry calculates the expiry time until the next scrape for a major.
|
||||
// term is the term for which the relevant course is occurring within.
|
||||
// count is the number of courses that were scraped.
|
||||
// priority is a boolean indicating whether the major is a priority major.
|
||||
// The duration is based on the number of courses, whether the major is a priority, and if the term is archived.
|
||||
func (a *API) CalculateExpiry(term string, count int, priority bool) time.Duration {
|
||||
// An hour for every 100 classes
|
||||
baseExpiry := time.Hour * time.Duration(count/100)
|
||||
@@ -222,7 +225,7 @@ func (a *API) CalculateExpiry(term string, count int, priority bool) time.Durati
|
||||
}
|
||||
|
||||
// IntakeCourse stores a course in Redis.
|
||||
// This function is mostly a stub for now, but will be used to handle change identification, notifications, and SQLite upserts in the future.
|
||||
// This function will be used to handle change identification, notifications, and SQLite upserts in the future.
|
||||
func (a *API) IntakeCourse(course models.Course) error {
|
||||
// Create a timeout context for Redis operations
|
||||
ctx, cancel := context.WithTimeout(a.config.Ctx, 5*time.Second)
|
||||
|
||||
@@ -33,7 +33,7 @@ const (
|
||||
)
|
||||
|
||||
// Query represents a search query for courses.
|
||||
// It is a builder struct that allows for chaining of methods to build a query.
|
||||
// It is a builder that allows for chaining methods to construct a query.
|
||||
type Query struct {
|
||||
subject *string
|
||||
title *string
|
||||
@@ -58,25 +58,25 @@ func NewQuery() *Query {
|
||||
return &Query{maxResults: 8, offset: 0}
|
||||
}
|
||||
|
||||
// Subject sets the subject for the query
|
||||
// Subject sets the subject for the query.
|
||||
func (q *Query) Subject(subject string) *Query {
|
||||
q.subject = &subject
|
||||
return q
|
||||
}
|
||||
|
||||
// Title sets the title for the query
|
||||
// Title sets the title for the query.
|
||||
func (q *Query) Title(title string) *Query {
|
||||
q.title = &title
|
||||
return q
|
||||
}
|
||||
|
||||
// Keywords sets the keywords for the query
|
||||
// Keywords sets the keywords for the query.
|
||||
func (q *Query) Keywords(keywords []string) *Query {
|
||||
q.keywords = &keywords
|
||||
return q
|
||||
}
|
||||
|
||||
// Keyword adds a keyword to the query
|
||||
// Keyword adds a keyword to the query.
|
||||
func (q *Query) Keyword(keyword string) *Query {
|
||||
if q.keywords == nil {
|
||||
q.keywords = &[]string{keyword}
|
||||
@@ -86,86 +86,86 @@ func (q *Query) Keyword(keyword string) *Query {
|
||||
return q
|
||||
}
|
||||
|
||||
// OpenOnly sets the open only flag for the query
|
||||
// OpenOnly sets whether to search for open courses only.
|
||||
func (q *Query) OpenOnly(openOnly bool) *Query {
|
||||
q.openOnly = &openOnly
|
||||
return q
|
||||
}
|
||||
|
||||
// TermPart sets the term part for the query
|
||||
// TermPart sets the term part for the query.
|
||||
func (q *Query) TermPart(termPart []string) *Query {
|
||||
q.termPart = &termPart
|
||||
return q
|
||||
}
|
||||
|
||||
// Campus sets the campuses for the query
|
||||
// Campus sets the campuses for the query.
|
||||
func (q *Query) Campus(campus []string) *Query {
|
||||
q.campus = &campus
|
||||
return q
|
||||
}
|
||||
|
||||
// InstructionalMethod sets the instructional methods for the query
|
||||
// InstructionalMethod sets the instructional methods for the query.
|
||||
func (q *Query) InstructionalMethod(instructionalMethod []string) *Query {
|
||||
q.instructionalMethod = &instructionalMethod
|
||||
return q
|
||||
}
|
||||
|
||||
// Attributes sets the attributes for the query
|
||||
// Attributes sets the attributes for the query.
|
||||
func (q *Query) Attributes(attributes []string) *Query {
|
||||
q.attributes = &attributes
|
||||
return q
|
||||
}
|
||||
|
||||
// Instructor sets the instructors for the query
|
||||
// Instructor sets the instructors for the query.
|
||||
func (q *Query) Instructor(instructor []uint64) *Query {
|
||||
q.instructor = &instructor
|
||||
return q
|
||||
}
|
||||
|
||||
// StartTime sets the start time for the query
|
||||
// StartTime sets the start time for the query.
|
||||
func (q *Query) StartTime(startTime time.Duration) *Query {
|
||||
q.startTime = &startTime
|
||||
return q
|
||||
}
|
||||
|
||||
// EndTime sets the end time for the query
|
||||
// EndTime sets the end time for the query.
|
||||
func (q *Query) EndTime(endTime time.Duration) *Query {
|
||||
q.endTime = &endTime
|
||||
return q
|
||||
}
|
||||
|
||||
// Credits sets the credit range for the query
|
||||
// Credits sets the credit range for the query.
|
||||
func (q *Query) Credits(low int, high int) *Query {
|
||||
q.minCredits = &low
|
||||
q.maxCredits = &high
|
||||
return q
|
||||
}
|
||||
|
||||
// MinCredits sets the minimum credits for the query
|
||||
// MinCredits sets the minimum credits for the query.
|
||||
func (q *Query) MinCredits(value int) *Query {
|
||||
q.minCredits = &value
|
||||
return q
|
||||
}
|
||||
|
||||
// MaxCredits sets the maximum credits for the query
|
||||
// MaxCredits sets the maximum credits for the query.
|
||||
func (q *Query) MaxCredits(value int) *Query {
|
||||
q.maxCredits = &value
|
||||
return q
|
||||
}
|
||||
|
||||
// CourseNumbers sets the course number range for the query
|
||||
// CourseNumbers sets the course number range for the query.
|
||||
func (q *Query) CourseNumbers(low int, high int) *Query {
|
||||
q.courseNumberRange = &Range{low, high}
|
||||
return q
|
||||
}
|
||||
|
||||
// Offset sets the offset for the query, allowing for pagination
|
||||
// Offset sets the offset for pagination.
|
||||
func (q *Query) Offset(offset int) *Query {
|
||||
q.offset = offset
|
||||
return q
|
||||
}
|
||||
|
||||
// MaxResults sets the maximum number of results for the query
|
||||
// MaxResults sets the maximum number of results to return.
|
||||
func (q *Query) MaxResults(maxResults int) *Query {
|
||||
q.maxResults = maxResults
|
||||
return q
|
||||
@@ -177,8 +177,8 @@ type Range struct {
|
||||
High int
|
||||
}
|
||||
|
||||
// FormatTimeParameter formats a time.Duration into a tuple of strings
|
||||
// This is mostly a private helper to keep the parameter formatting for both the start and end time consistent together
|
||||
// FormatTimeParameter formats a time.Duration into a tuple of strings for use in a POST request.
|
||||
// It returns the hour, minute, and meridiem (AM/PM) as separate strings.
|
||||
func FormatTimeParameter(d time.Duration) (string, string, string) {
|
||||
hourParameter, minuteParameter, meridiemParameter := "", "", ""
|
||||
|
||||
@@ -204,7 +204,7 @@ func FormatTimeParameter(d time.Duration) (string, string, string) {
|
||||
return hourParameter, minuteParameter, meridiemParameter
|
||||
}
|
||||
|
||||
// Paramify converts a Query into a map of parameters that can be used in a POST request
|
||||
// Paramify converts a Query into a map of parameters for a POST request.
|
||||
// This function assumes each query key only appears once.
|
||||
func (q *Query) Paramify() map[string]string {
|
||||
params := map[string]string{}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
log "github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// Setup makes the initial requests to set up the session cookies for the application.
|
||||
func (a *API) Setup() {
|
||||
// Makes the initial requests that sets up the session cookies for the rest of the application
|
||||
log.Info().Msg("Setting up session...")
|
||||
|
||||
@@ -18,6 +18,7 @@ const (
|
||||
Fall
|
||||
)
|
||||
|
||||
// Term represents a school term, consisting of a year and a season.
|
||||
type Term struct {
|
||||
Year uint16
|
||||
Season uint8
|
||||
@@ -32,16 +33,14 @@ func init() {
|
||||
SpringRange, SummerRange, FallRange = GetYearDayRange(loc, uint16(time.Now().Year()))
|
||||
}
|
||||
|
||||
// YearDayRange represents the start and end day of a term within a year.
|
||||
type YearDayRange struct {
|
||||
Start uint16
|
||||
End uint16
|
||||
}
|
||||
|
||||
// GetYearDayRange returns the start and end day of each term for the given year.
|
||||
// This could technically introduce race conditions, but it's more likely confusion from UTC will be a greater issue.
|
||||
// Spring: January 14th to May
|
||||
// Summer: May 25th - August 15th
|
||||
// Fall: August 18th - December 10th
|
||||
// The ranges are inclusive of the start day and exclusive of the end day.
|
||||
func GetYearDayRange(loc *time.Location, year uint16) (YearDayRange, YearDayRange, YearDayRange) {
|
||||
springStart := time.Date(int(year), time.January, 14, 0, 0, 0, 0, loc).YearDay()
|
||||
springEnd := time.Date(int(year), time.May, 1, 0, 0, 0, 0, loc).YearDay()
|
||||
@@ -62,21 +61,9 @@ func GetYearDayRange(loc *time.Location, year uint16) (YearDayRange, YearDayRang
|
||||
}
|
||||
}
|
||||
|
||||
// GetCurrentTerm returns the current term, and the next term. Only the first term is nillable.
|
||||
// YearDay ranges are inclusive of the start, and exclusive of the end.
|
||||
// You can think of the 'year' part of it as the 'school year', the second part of the 20XX-(20XX+1) phrasing.
|
||||
//
|
||||
// e.g. the Fall 2025, Spring 2026, and Summer 2026 terms all occur as part of the 2025-2026 school year. The second year, 2026, is the part used in all term identifiers.
|
||||
// So even though the Fall 2025 term occurs in 2025, it uses the 2026 year in it's term identifier.
|
||||
//
|
||||
// Fall of 2024 => 202510
|
||||
// Spring of 2025 => 202520
|
||||
// Summer of 2025 => 202530
|
||||
// Fall of 2025 => 202610
|
||||
// Spring of 2026 => 202620
|
||||
// Summer of 2026 => 202630
|
||||
//
|
||||
// Reading out 'Fall of 2024' as '202510' might be confusing, but it's correct.
|
||||
// GetCurrentTerm returns the current and next terms based on the provided time.
|
||||
// The current term can be nil if the time falls between terms.
|
||||
// The 'year' in the term corresponds to the academic year, which may differ from the calendar year.
|
||||
func GetCurrentTerm(now time.Time) (*Term, *Term) {
|
||||
literalYear := uint16(now.Year())
|
||||
dayOfYear := uint16(now.YearDay())
|
||||
@@ -112,7 +99,7 @@ func GetCurrentTerm(now time.Time) (*Term, *Term) {
|
||||
panic(fmt.Sprintf("Impossible Code Reached (dayOfYear: %d)", dayOfYear))
|
||||
}
|
||||
|
||||
// ParseTerm converts a Banner term code to a Term struct
|
||||
// ParseTerm converts a Banner term code string to a Term struct.
|
||||
func ParseTerm(code string) Term {
|
||||
year, _ := strconv.ParseUint(code[0:4], 10, 16)
|
||||
|
||||
@@ -133,7 +120,7 @@ func ParseTerm(code string) Term {
|
||||
}
|
||||
}
|
||||
|
||||
// TermToBannerTerm converts a Term struct to a Banner term code
|
||||
// ToString converts a Term struct to a Banner term code string.
|
||||
func (term Term) ToString() string {
|
||||
var season string
|
||||
switch term.Season {
|
||||
@@ -148,7 +135,7 @@ func (term Term) ToString() string {
|
||||
return fmt.Sprintf("%d%s", term.Year, season)
|
||||
}
|
||||
|
||||
// Default chooses the default term, which is the current term if it exists, otherwise the next term.
|
||||
// Default returns the default term, which is the current term if it exists, otherwise the next term.
|
||||
func Default(t time.Time) Term {
|
||||
currentTerm, nextTerm := GetCurrentTerm(t)
|
||||
if currentTerm == nil {
|
||||
|
||||
Reference in New Issue
Block a user