mirror of
https://github.com/Xevion/banner.git
synced 2025-12-06 21:14:26 -06:00
refactor: rearrange & rename files, fix meeting times response decode
This commit is contained in:
@@ -22,10 +22,10 @@ import (
|
|||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"resty.dev/v3"
|
"resty.dev/v3"
|
||||||
|
|
||||||
|
"banner/internal"
|
||||||
"banner/internal/api"
|
"banner/internal/api"
|
||||||
"banner/internal/bot"
|
"banner/internal/bot"
|
||||||
"banner/internal/config"
|
"banner/internal/config"
|
||||||
"banner/internal/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -57,25 +57,25 @@ func init() {
|
|||||||
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
|
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
|
||||||
|
|
||||||
// Use the custom console writer if we're in development
|
// Use the custom console writer if we're in development
|
||||||
isDevelopment := utils.GetFirstEnv("ENVIRONMENT", "RAILWAY_ENVIRONMENT")
|
isDevelopment := internal.GetFirstEnv("ENVIRONMENT", "RAILWAY_ENVIRONMENT")
|
||||||
if isDevelopment == "" {
|
if isDevelopment == "" {
|
||||||
isDevelopment = "development"
|
isDevelopment = "development"
|
||||||
}
|
}
|
||||||
|
|
||||||
if isDevelopment == "development" {
|
if isDevelopment == "development" {
|
||||||
log.Logger = zerolog.New(utils.NewConsoleWriter()).With().Timestamp().Logger()
|
log.Logger = zerolog.New(config.NewConsoleWriter()).With().Timestamp().Logger()
|
||||||
} else {
|
} else {
|
||||||
log.Logger = zerolog.New(utils.LogSplitter{Std: os.Stdout, Err: os.Stderr}).With().Timestamp().Logger()
|
log.Logger = zerolog.New(config.LogSplitter{Std: os.Stdout, Err: os.Stderr}).With().Timestamp().Logger()
|
||||||
}
|
}
|
||||||
log.Debug().Str("environment", isDevelopment).Msg("Loggers Setup")
|
log.Debug().Str("environment", isDevelopment).Msg("Loggers Setup")
|
||||||
|
|
||||||
// Set discordgo's logger to use zerolog
|
// Set discordgo's logger to use zerolog
|
||||||
discordgo.Logger = utils.DiscordGoLogger
|
discordgo.Logger = internal.DiscordGoLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
func initRedis(cfg *config.Config) {
|
func initRedis(cfg *config.Config) {
|
||||||
// Setup redis
|
// Setup redis
|
||||||
redisUrl := utils.GetFirstEnv("REDIS_URL", "REDIS_PRIVATE_URL")
|
redisUrl := internal.GetFirstEnv("REDIS_URL", "REDIS_PRIVATE_URL")
|
||||||
if redisUrl == "" {
|
if redisUrl == "" {
|
||||||
log.Fatal().Stack().Msg("REDIS_URL/REDIS_PRIVATE_URL not set")
|
log.Fatal().Stack().Msg("REDIS_URL/REDIS_PRIVATE_URL not set")
|
||||||
}
|
}
|
||||||
@@ -130,7 +130,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try to grab the environment variable, or default to development
|
// Try to grab the environment variable, or default to development
|
||||||
environment := utils.GetFirstEnv("ENVIRONMENT", "RAILWAY_ENVIRONMENT")
|
environment := internal.GetFirstEnv("ENVIRONMENT", "RAILWAY_ENVIRONMENT")
|
||||||
if environment == "" {
|
if environment == "" {
|
||||||
environment = "development"
|
environment = "development"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"banner/internal"
|
||||||
"banner/internal/config"
|
"banner/internal/config"
|
||||||
"banner/internal/models"
|
"banner/internal/models"
|
||||||
"banner/internal/utils"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -51,7 +51,7 @@ func SessionMiddleware(c *resty.Client, r *resty.Response) error {
|
|||||||
// GenerateSession generates a new session ID (nonce) for use with the Banner API.
|
// GenerateSession generates a new session ID (nonce) for use with the Banner API.
|
||||||
// Don't use this function directly, use GetSession instead.
|
// Don't use this function directly, use GetSession instead.
|
||||||
func GenerateSession() string {
|
func GenerateSession() string {
|
||||||
return utils.RandomString(5) + utils.Nonce()
|
return internal.RandomString(5) + internal.Nonce()
|
||||||
}
|
}
|
||||||
|
|
||||||
var terms []BannerTerm
|
var terms []BannerTerm
|
||||||
@@ -131,7 +131,7 @@ func (a *API) GetTerms(search string, page int, maxResults int) ([]BannerTerm, e
|
|||||||
SetQueryParam("searchTerm", search).
|
SetQueryParam("searchTerm", search).
|
||||||
SetQueryParam("offset", strconv.Itoa(page)).
|
SetQueryParam("offset", strconv.Itoa(page)).
|
||||||
SetQueryParam("max", strconv.Itoa(maxResults)).
|
SetQueryParam("max", strconv.Itoa(maxResults)).
|
||||||
SetQueryParam("_", utils.Nonce()).
|
SetQueryParam("_", internal.Nonce()).
|
||||||
SetExpectResponseContentType("application/json").
|
SetExpectResponseContentType("application/json").
|
||||||
SetResult(&[]BannerTerm{})
|
SetResult(&[]BannerTerm{})
|
||||||
|
|
||||||
@@ -206,7 +206,7 @@ func (a *API) GetPartOfTerms(search string, term int, offset int, maxResults int
|
|||||||
SetQueryParam("offset", strconv.Itoa(offset)).
|
SetQueryParam("offset", strconv.Itoa(offset)).
|
||||||
SetQueryParam("max", strconv.Itoa(maxResults)).
|
SetQueryParam("max", strconv.Itoa(maxResults)).
|
||||||
SetQueryParam("uniqueSessionId", a.EnsureSession()).
|
SetQueryParam("uniqueSessionId", a.EnsureSession()).
|
||||||
SetQueryParam("_", utils.Nonce()).
|
SetQueryParam("_", internal.Nonce()).
|
||||||
SetExpectResponseContentType("application/json").
|
SetExpectResponseContentType("application/json").
|
||||||
SetResult(&[]BannerTerm{})
|
SetResult(&[]BannerTerm{})
|
||||||
|
|
||||||
@@ -239,7 +239,7 @@ func (a *API) GetInstructors(search string, term string, offset int, maxResults
|
|||||||
SetQueryParam("offset", strconv.Itoa(offset)).
|
SetQueryParam("offset", strconv.Itoa(offset)).
|
||||||
SetQueryParam("max", strconv.Itoa(maxResults)).
|
SetQueryParam("max", strconv.Itoa(maxResults)).
|
||||||
SetQueryParam("uniqueSessionId", a.EnsureSession()).
|
SetQueryParam("uniqueSessionId", a.EnsureSession()).
|
||||||
SetQueryParam("_", utils.Nonce()).
|
SetQueryParam("_", internal.Nonce()).
|
||||||
SetExpectResponseContentType("application/json").
|
SetExpectResponseContentType("application/json").
|
||||||
SetResult(&[]Instructor{})
|
SetResult(&[]Instructor{})
|
||||||
|
|
||||||
@@ -337,7 +337,7 @@ func (a *API) GetSubjects(search string, term string, offset int, maxResults int
|
|||||||
SetQueryParam("offset", strconv.Itoa(offset)).
|
SetQueryParam("offset", strconv.Itoa(offset)).
|
||||||
SetQueryParam("max", strconv.Itoa(maxResults)).
|
SetQueryParam("max", strconv.Itoa(maxResults)).
|
||||||
SetQueryParam("uniqueSessionId", a.EnsureSession()).
|
SetQueryParam("uniqueSessionId", a.EnsureSession()).
|
||||||
SetQueryParam("_", utils.Nonce()).
|
SetQueryParam("_", internal.Nonce()).
|
||||||
SetExpectResponseContentType("application/json").
|
SetExpectResponseContentType("application/json").
|
||||||
SetResult(&[]Pair{})
|
SetResult(&[]Pair{})
|
||||||
|
|
||||||
@@ -370,7 +370,7 @@ func (a *API) GetCampuses(search string, term int, offset int, maxResults int) (
|
|||||||
SetQueryParam("offset", strconv.Itoa(offset)).
|
SetQueryParam("offset", strconv.Itoa(offset)).
|
||||||
SetQueryParam("max", strconv.Itoa(maxResults)).
|
SetQueryParam("max", strconv.Itoa(maxResults)).
|
||||||
SetQueryParam("uniqueSessionId", a.EnsureSession()).
|
SetQueryParam("uniqueSessionId", a.EnsureSession()).
|
||||||
SetQueryParam("_", utils.Nonce()).
|
SetQueryParam("_", internal.Nonce()).
|
||||||
SetExpectResponseContentType("application/json").
|
SetExpectResponseContentType("application/json").
|
||||||
SetResult(&[]Pair{})
|
SetResult(&[]Pair{})
|
||||||
|
|
||||||
@@ -403,7 +403,7 @@ func (a *API) GetInstructionalMethods(search string, term string, offset int, ma
|
|||||||
SetQueryParam("offset", strconv.Itoa(offset)).
|
SetQueryParam("offset", strconv.Itoa(offset)).
|
||||||
SetQueryParam("max", strconv.Itoa(maxResults)).
|
SetQueryParam("max", strconv.Itoa(maxResults)).
|
||||||
SetQueryParam("uniqueSessionId", a.EnsureSession()).
|
SetQueryParam("uniqueSessionId", a.EnsureSession()).
|
||||||
SetQueryParam("_", utils.Nonce()).
|
SetQueryParam("_", internal.Nonce()).
|
||||||
SetExpectResponseContentType("application/json").
|
SetExpectResponseContentType("application/json").
|
||||||
SetResult(&[]Pair{})
|
SetResult(&[]Pair{})
|
||||||
|
|
||||||
@@ -423,23 +423,27 @@ func (a *API) GetInstructionalMethods(search string, term string, offset int, ma
|
|||||||
// It makes an HTTP GET request to the appropriate API endpoint and parses the response to extract the meeting time data.
|
// 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.
|
// The function returns a MeetingTimeResponse struct containing the extracted information.
|
||||||
func (a *API) GetCourseMeetingTime(term int, crn int) ([]models.MeetingTimeResponse, error) {
|
func (a *API) GetCourseMeetingTime(term int, crn int) ([]models.MeetingTimeResponse, error) {
|
||||||
|
type responseWrapper struct {
|
||||||
|
Fmt []models.MeetingTimeResponse `json:"fmt"`
|
||||||
|
}
|
||||||
|
|
||||||
req := a.config.Client.NewRequest().
|
req := a.config.Client.NewRequest().
|
||||||
SetQueryParam("term", strconv.Itoa(term)).
|
SetQueryParam("term", strconv.Itoa(term)).
|
||||||
SetQueryParam("courseReferenceNumber", strconv.Itoa(crn)).
|
SetQueryParam("courseReferenceNumber", strconv.Itoa(crn)).
|
||||||
SetExpectResponseContentType("application/json").
|
SetExpectResponseContentType("application/json").
|
||||||
SetResult(&[]models.MeetingTimeResponse{})
|
SetResult(&responseWrapper{})
|
||||||
|
|
||||||
res, err := req.Get("/searchResults/getFacultyMeetingTimes")
|
res, err := req.Get("/searchResults/getFacultyMeetingTimes")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get meeting time: %w", err)
|
return nil, fmt.Errorf("failed to get meeting time: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
meetingTimes, ok := res.Result().(*[]models.MeetingTimeResponse)
|
result, ok := res.Result().(*responseWrapper)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("meeting times parsing failed to cast: %v", res.Result())
|
return nil, fmt.Errorf("meeting times parsing failed to cast: %v", res.Result())
|
||||||
}
|
}
|
||||||
|
|
||||||
return *meetingTimes, nil
|
return result.Fmt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetDataForm makes a POST request that needs to be made upon before new search requests can be made.
|
// ResetDataForm makes a POST request that needs to be made upon before new search requests can be made.
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"banner/internal"
|
||||||
"banner/internal/models"
|
"banner/internal/models"
|
||||||
"banner/internal/utils"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@@ -70,7 +70,7 @@ func (a *API) Scrape() error {
|
|||||||
|
|
||||||
// GetExpiredSubjects returns a list of subjects that are expired and should be scraped.
|
// GetExpiredSubjects returns a list of subjects that are expired and should be scraped.
|
||||||
func (a *API) GetExpiredSubjects() ([]string, error) {
|
func (a *API) GetExpiredSubjects() ([]string, error) {
|
||||||
term := utils.Default(time.Now()).ToString()
|
term := Default(time.Now()).ToString()
|
||||||
subjects := make([]string, 0)
|
subjects := make([]string, 0)
|
||||||
|
|
||||||
// Create a timeout context for Redis operations
|
// Create a timeout context for Redis operations
|
||||||
@@ -109,7 +109,7 @@ func (a *API) ScrapeMajor(subject string) error {
|
|||||||
for {
|
for {
|
||||||
// Build & execute the query
|
// Build & execute the query
|
||||||
query := NewQuery().Offset(offset).MaxResults(MaxPageSize * 2).Subject(subject)
|
query := NewQuery().Offset(offset).MaxResults(MaxPageSize * 2).Subject(subject)
|
||||||
term := utils.Default(time.Now()).ToString()
|
term := Default(time.Now()).ToString()
|
||||||
result, err := a.Search(term, query, "subjectDescription", false)
|
result, err := a.Search(term, query, "subjectDescription", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("search failed: %w (%s)", err, query.String())
|
return fmt.Errorf("search failed: %w (%s)", err, query.String())
|
||||||
@@ -152,7 +152,7 @@ func (a *API) ScrapeMajor(subject string) error {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
term := utils.Default(time.Now()).ToString()
|
term := Default(time.Now()).ToString()
|
||||||
|
|
||||||
// Calculate the expiry time for the scrape (1 hour for every 200 classes, random +-15%) with a minimum of 1 hour
|
// Calculate the expiry time for the scrape (1 hour for every 200 classes, random +-15%) with a minimum of 1 hour
|
||||||
var scrapeExpiry time.Duration
|
var scrapeExpiry time.Duration
|
||||||
@@ -190,7 +190,7 @@ func (a *API) CalculateExpiry(term string, count int, priority bool) time.Durati
|
|||||||
// Subjects with less than 50 classes have a reversed expiry (less classes, longer interval)
|
// Subjects with less than 50 classes have a reversed expiry (less classes, longer interval)
|
||||||
// 1 class => 12 hours, 49 classes => 1 hour
|
// 1 class => 12 hours, 49 classes => 1 hour
|
||||||
if count < 50 {
|
if count < 50 {
|
||||||
hours := utils.Slope(utils.Point{X: 1, Y: 12}, utils.Point{X: 49, Y: 1}, float64(count)).Y
|
hours := internal.Slope(internal.Point{X: 1, Y: 12}, internal.Point{X: 49, Y: 1}, float64(count)).Y
|
||||||
baseExpiry = time.Duration(hours * float64(time.Hour))
|
baseExpiry = time.Duration(hours * float64(time.Hour))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"banner/internal/utils"
|
"banner/internal"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
log "github.com/rs/zerolog/log"
|
log "github.com/rs/zerolog/log"
|
||||||
@@ -18,7 +18,7 @@ func (a *API) Setup() {
|
|||||||
|
|
||||||
for _, path := range requestQueue {
|
for _, path := range requestQueue {
|
||||||
req := a.config.Client.NewRequest().
|
req := a.config.Client.NewRequest().
|
||||||
SetQueryParam("_", utils.Nonce()).
|
SetQueryParam("_", internal.Nonce()).
|
||||||
SetExpectResponseContentType("application/json")
|
SetExpectResponseContentType("application/json")
|
||||||
|
|
||||||
res, err := req.Get(path)
|
res, err := req.Get(path)
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
package utils
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"banner/internal/config"
|
"banner/internal/config"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Term selection should yield smart results based on the current time, as well as the input provided.
|
// Term selection should yield smart results based on the current time, as well as the input provided.
|
||||||
@@ -32,9 +30,6 @@ var (
|
|||||||
func init() {
|
func init() {
|
||||||
loc, _ := time.LoadLocation(config.CentralTimezoneName)
|
loc, _ := time.LoadLocation(config.CentralTimezoneName)
|
||||||
SpringRange, SummerRange, FallRange = GetYearDayRange(loc, uint16(time.Now().Year()))
|
SpringRange, SummerRange, FallRange = GetYearDayRange(loc, uint16(time.Now().Year()))
|
||||||
|
|
||||||
currentTerm, nextTerm := GetCurrentTerm(time.Now())
|
|
||||||
log.Debug().Str("CurrentTerm", fmt.Sprintf("%+v", currentTerm)).Str("NextTerm", fmt.Sprintf("%+v", nextTerm)).Msg("GetCurrentTerm")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type YearDayRange struct {
|
type YearDayRange struct {
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package bot
|
package bot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"banner/internal"
|
||||||
"banner/internal/api"
|
"banner/internal/api"
|
||||||
"banner/internal/models"
|
"banner/internal/models"
|
||||||
"banner/internal/utils"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -40,7 +40,7 @@ var SearchCommandDefinition = &discordgo.ApplicationCommand{
|
|||||||
Options: []*discordgo.ApplicationCommandOption{
|
Options: []*discordgo.ApplicationCommandOption{
|
||||||
{
|
{
|
||||||
Type: discordgo.ApplicationCommandOptionString,
|
Type: discordgo.ApplicationCommandOptionString,
|
||||||
MinLength: utils.GetIntPointer(0),
|
MinLength: internal.GetIntPointer(0),
|
||||||
MaxLength: 48,
|
MaxLength: 48,
|
||||||
Name: "title",
|
Name: "title",
|
||||||
Description: "Course Title (exact, use autocomplete)",
|
Description: "Course Title (exact, use autocomplete)",
|
||||||
@@ -50,7 +50,7 @@ var SearchCommandDefinition = &discordgo.ApplicationCommand{
|
|||||||
{
|
{
|
||||||
Type: discordgo.ApplicationCommandOptionString,
|
Type: discordgo.ApplicationCommandOptionString,
|
||||||
Name: "code",
|
Name: "code",
|
||||||
MinLength: utils.GetIntPointer(4),
|
MinLength: internal.GetIntPointer(4),
|
||||||
Description: "Course Code (e.g. 3743, 3000-3999, 3xxx, 3000-)",
|
Description: "Course Code (e.g. 3743, 3000-3999, 3xxx, 3000-)",
|
||||||
Required: false,
|
Required: false,
|
||||||
},
|
},
|
||||||
@@ -248,8 +248,8 @@ func SearchCommandHandler(b *Bot, s *discordgo.Session, i *discordgo.Interaction
|
|||||||
Data: &discordgo.InteractionResponseData{
|
Data: &discordgo.InteractionResponseData{
|
||||||
Embeds: []*discordgo.MessageEmbed{
|
Embeds: []*discordgo.MessageEmbed{
|
||||||
{
|
{
|
||||||
Footer: utils.GetFetchedFooter(b.Config, fetch_time),
|
Footer: internal.GetFetchedFooter(b.Config, fetch_time),
|
||||||
Description: fmt.Sprintf("%d Class%s", courses.TotalCount, utils.Plural(courses.TotalCount)),
|
Description: fmt.Sprintf("%d Class%s", courses.TotalCount, internal.Plural(courses.TotalCount)),
|
||||||
Fields: fields[:min(25, len(fields))],
|
Fields: fields[:min(25, len(fields))],
|
||||||
Color: color,
|
Color: color,
|
||||||
},
|
},
|
||||||
@@ -267,7 +267,7 @@ var TermCommandDefinition = &discordgo.ApplicationCommand{
|
|||||||
Options: []*discordgo.ApplicationCommandOption{
|
Options: []*discordgo.ApplicationCommandOption{
|
||||||
{
|
{
|
||||||
Type: discordgo.ApplicationCommandOptionString,
|
Type: discordgo.ApplicationCommandOptionString,
|
||||||
MinLength: utils.GetIntPointer(0),
|
MinLength: internal.GetIntPointer(0),
|
||||||
MaxLength: 8,
|
MaxLength: 8,
|
||||||
Name: "search",
|
Name: "search",
|
||||||
Description: "Term to search for",
|
Description: "Term to search for",
|
||||||
@@ -278,7 +278,7 @@ var TermCommandDefinition = &discordgo.ApplicationCommand{
|
|||||||
Name: "page",
|
Name: "page",
|
||||||
Description: "Page Number",
|
Description: "Page Number",
|
||||||
Required: false,
|
Required: false,
|
||||||
MinValue: utils.GetFloatPointer(1),
|
MinValue: internal.GetFloatPointer(1),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -303,7 +303,7 @@ func TermCommandHandler(b *Bot, s *discordgo.Session, i *discordgo.InteractionCr
|
|||||||
termResult, err := b.API.GetTerms(searchTerm, pageNumber, 25)
|
termResult, err := b.API.GetTerms(searchTerm, pageNumber, 25)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.RespondError(s, i.Interaction, "Error while fetching terms", err)
|
internal.RespondError(s, i.Interaction, "Error while fetching terms", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,8 +328,8 @@ func TermCommandHandler(b *Bot, s *discordgo.Session, i *discordgo.InteractionCr
|
|||||||
Data: &discordgo.InteractionResponseData{
|
Data: &discordgo.InteractionResponseData{
|
||||||
Embeds: []*discordgo.MessageEmbed{
|
Embeds: []*discordgo.MessageEmbed{
|
||||||
{
|
{
|
||||||
Footer: utils.GetFetchedFooter(b.Config, fetch_time),
|
Footer: internal.GetFetchedFooter(b.Config, fetch_time),
|
||||||
Description: fmt.Sprintf("%d term%s (page %d)", len(termResult), utils.Plural(len(termResult)), pageNumber),
|
Description: fmt.Sprintf("%d term%s (page %d)", len(termResult), internal.Plural(len(termResult)), pageNumber),
|
||||||
Fields: fields[:min(25, len(fields))],
|
Fields: fields[:min(25, len(fields))],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -387,7 +387,7 @@ func TimeCommandHandler(b *Bot, s *discordgo.Session, i *discordgo.InteractionCr
|
|||||||
Data: &discordgo.InteractionResponseData{
|
Data: &discordgo.InteractionResponseData{
|
||||||
Embeds: []*discordgo.MessageEmbed{
|
Embeds: []*discordgo.MessageEmbed{
|
||||||
{
|
{
|
||||||
Footer: utils.GetFetchedFooter(b.Config, fetch_time),
|
Footer: internal.GetFetchedFooter(b.Config, fetch_time),
|
||||||
Description: "",
|
Description: "",
|
||||||
Fields: []*discordgo.MessageEmbedField{
|
Fields: []*discordgo.MessageEmbedField{
|
||||||
{
|
{
|
||||||
@@ -404,7 +404,7 @@ func TimeCommandHandler(b *Bot, s *discordgo.Session, i *discordgo.InteractionCr
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Days of Week",
|
Name: "Days of Week",
|
||||||
Value: utils.WeekdaysToString(meetingTime.Days()),
|
Value: internal.WeekdaysToString(meetingTime.Days()),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -430,7 +430,7 @@ var IcsCommandDefinition = &discordgo.ApplicationCommand{
|
|||||||
|
|
||||||
func IcsCommandHandler(b *Bot, s *discordgo.Session, i *discordgo.InteractionCreate) error {
|
func IcsCommandHandler(b *Bot, s *discordgo.Session, i *discordgo.InteractionCreate) error {
|
||||||
// Parse all options
|
// Parse all options
|
||||||
options := utils.ParseOptions(i.ApplicationCommandData().Options)
|
options := internal.ParseOptions(i.ApplicationCommandData().Options)
|
||||||
crn := options.GetInt("crn")
|
crn := options.GetInt("crn")
|
||||||
|
|
||||||
course, err := b.API.GetCourse(strconv.Itoa(int(crn)))
|
course, err := b.API.GetCourse(strconv.Itoa(int(crn)))
|
||||||
@@ -460,7 +460,7 @@ func IcsCommandHandler(b *Bot, s *discordgo.Session, i *discordgo.InteractionCre
|
|||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
log.Warn().Str("crn", course.CourseReferenceNumber).Msg("Non-meeting course requested for ICS file")
|
log.Warn().Str("crn", course.CourseReferenceNumber).Msg("Non-meeting course requested for ICS file")
|
||||||
utils.RespondError(s, i.Interaction, "The course requested does not meet at a defined moment in time.", nil)
|
internal.RespondError(s, i.Interaction, "The course requested does not meet at a defined moment in time.", nil)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package bot
|
package bot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"banner/internal/utils"
|
"banner/internal"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
@@ -13,7 +13,7 @@ func (b *Bot) RegisterHandlers() {
|
|||||||
b.Session.AddHandler(func(internalSession *discordgo.Session, interaction *discordgo.InteractionCreate) {
|
b.Session.AddHandler(func(internalSession *discordgo.Session, interaction *discordgo.InteractionCreate) {
|
||||||
// Handle commands during restart (highly unlikely, but just in case)
|
// Handle commands during restart (highly unlikely, but just in case)
|
||||||
if b.isClosing {
|
if b.isClosing {
|
||||||
err := utils.RespondError(internalSession, interaction.Interaction, "Bot is currently restarting, try again later.", nil)
|
err := internal.RespondError(internalSession, interaction.Interaction, "Bot is currently restarting, try again later.", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to respond with restart error feedback")
|
log.Error().Err(err).Msg("Failed to respond with restart error feedback")
|
||||||
}
|
}
|
||||||
@@ -28,18 +28,18 @@ func (b *Bot) RegisterHandlers() {
|
|||||||
options.Str(option.Name, fmt.Sprintf("%v", option.Value))
|
options.Str(option.Name, fmt.Sprintf("%v", option.Value))
|
||||||
}
|
}
|
||||||
|
|
||||||
event := log.Info().Str("name", name).Str("user", utils.GetUser(interaction).Username).Dict("options", options)
|
event := log.Info().Str("name", name).Str("user", internal.GetUser(interaction).Username).Dict("options", options)
|
||||||
|
|
||||||
// If the command was invoked in a guild, add guild & channel info to the log
|
// If the command was invoked in a guild, add guild & channel info to the log
|
||||||
if interaction.Member != nil {
|
if interaction.Member != nil {
|
||||||
guild := zerolog.Dict()
|
guild := zerolog.Dict()
|
||||||
guild.Str("id", interaction.GuildID)
|
guild.Str("id", interaction.GuildID)
|
||||||
guild.Str("name", utils.GetGuildName(b.Config, internalSession, interaction.GuildID))
|
guild.Str("name", internal.GetGuildName(b.Config, internalSession, interaction.GuildID))
|
||||||
event.Dict("guild", guild)
|
event.Dict("guild", guild)
|
||||||
|
|
||||||
channel := zerolog.Dict()
|
channel := zerolog.Dict()
|
||||||
channel.Str("id", interaction.ChannelID)
|
channel.Str("id", interaction.ChannelID)
|
||||||
guild.Str("name", utils.GetChannelName(b.Config, internalSession, interaction.ChannelID))
|
guild.Str("name", internal.GetChannelName(b.Config, internalSession, interaction.ChannelID))
|
||||||
event.Dict("channel", channel)
|
event.Dict("channel", channel)
|
||||||
} else {
|
} else {
|
||||||
// If the command was invoked in a DM, add the user info to the log
|
// If the command was invoked in a DM, add the user info to the log
|
||||||
@@ -58,7 +58,7 @@ func (b *Bot) RegisterHandlers() {
|
|||||||
log.Error().Stack().Str("commandName", name).Interface("detail", err).Msg("Command Handler Panic")
|
log.Error().Stack().Str("commandName", name).Interface("detail", err).Msg("Command Handler Panic")
|
||||||
|
|
||||||
// Respond with error
|
// Respond with error
|
||||||
err := utils.RespondError(internalSession, interaction.Interaction, "Unexpected Error: command handler panic", nil)
|
err := internal.RespondError(internalSession, interaction.Interaction, "Unexpected Error: command handler panic", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Str("commandName", name).Err(err).Msg("Failed to respond with panic error feedback")
|
log.Error().Stack().Str("commandName", name).Err(err).Msg("Failed to respond with panic error feedback")
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@ func (b *Bot) RegisterHandlers() {
|
|||||||
log.Error().Str("commandName", name).Err(err).Msg("Command Handler Error")
|
log.Error().Str("commandName", name).Err(err).Msg("Command Handler Error")
|
||||||
|
|
||||||
// Respond with error
|
// Respond with error
|
||||||
err = utils.RespondError(internalSession, interaction.Interaction, fmt.Sprintf("Unexpected Error: %s", err.Error()), nil)
|
err = internal.RespondError(internalSession, interaction.Interaction, fmt.Sprintf("Unexpected Error: %s", err.Error()), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Str("commandName", name).Err(err).Msg("Failed to respond with error feedback")
|
log.Error().Stack().Str("commandName", name).Err(err).Msg("Failed to respond with error feedback")
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ func (b *Bot) RegisterHandlers() {
|
|||||||
log.Error().Stack().Str("commandName", name).Msg("Command Interaction Has No Handler")
|
log.Error().Stack().Str("commandName", name).Msg("Command Interaction Has No Handler")
|
||||||
|
|
||||||
// Respond with error
|
// Respond with error
|
||||||
utils.RespondError(internalSession, interaction.Interaction, "Unexpected Error: interaction has no handler", nil)
|
internal.RespondError(internalSession, interaction.Interaction, "Unexpected Error: interaction has no handler", nil)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package bot
|
|||||||
import (
|
import (
|
||||||
"banner/internal/api"
|
"banner/internal/api"
|
||||||
"banner/internal/config"
|
"banner/internal/config"
|
||||||
"banner/internal/utils"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -28,7 +27,7 @@ func (b *Bot) SetClosing() {
|
|||||||
|
|
||||||
func (b *Bot) GetSession() (string, error) {
|
func (b *Bot) GetSession() (string, error) {
|
||||||
sessionID := b.API.EnsureSession()
|
sessionID := b.API.EnsureSession()
|
||||||
term := utils.Default(time.Now()).ToString()
|
term := api.Default(time.Now()).ToString()
|
||||||
|
|
||||||
log.Info().Str("term", term).Str("sessionID", sessionID).Msg("Setting selected term")
|
log.Info().Str("term", term).Str("sessionID", sessionID).Msg("Setting selected term")
|
||||||
err := b.API.SelectTerm(term, sessionID)
|
err := b.API.SelectTerm(term, sessionID)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package utils
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package utils
|
package internal
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package utils
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package utils
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"banner/internal/config"
|
"banner/internal/config"
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"banner/internal/utils"
|
"banner/internal"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -11,8 +11,6 @@ import (
|
|||||||
log "github.com/rs/zerolog/log"
|
log "github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const JsonContentType = "application/json"
|
|
||||||
|
|
||||||
type FacultyItem struct {
|
type FacultyItem struct {
|
||||||
BannerId string `json:"bannerId"`
|
BannerId string `json:"bannerId"`
|
||||||
Category *string `json:"category"`
|
Category *string `json:"category"`
|
||||||
@@ -114,7 +112,7 @@ func (m *MeetingTimeResponse) TimeString() string {
|
|||||||
return "???"
|
return "???"
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("%s %s-%s", utils.WeekdaysToString(m.Days()), m.StartTime().String(), m.EndTime().String())
|
return fmt.Sprintf("%s %s-%s", internal.WeekdaysToString(m.Days()), m.StartTime().String(), m.EndTime().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlaceString returns a formatted string best representing the place of the meeting time
|
// PlaceString returns a formatted string best representing the place of the meeting time
|
||||||
@@ -195,7 +193,7 @@ func (m *MeetingTimeResponse) EndDay() time.Time {
|
|||||||
|
|
||||||
// StartTime returns the start time of the meeting time as a NaiveTime object
|
// StartTime returns the start time of the meeting time as a NaiveTime object
|
||||||
// This is not cached and is parsed on each invocation. It may also panic without handling.
|
// This is not cached and is parsed on each invocation. It may also panic without handling.
|
||||||
func (m *MeetingTimeResponse) StartTime() *utils.NaiveTime {
|
func (m *MeetingTimeResponse) StartTime() *internal.NaiveTime {
|
||||||
raw := m.MeetingTime.BeginTime
|
raw := m.MeetingTime.BeginTime
|
||||||
if raw == "" {
|
if raw == "" {
|
||||||
log.Panic().Stack().Msg("Start time is empty")
|
log.Panic().Stack().Msg("Start time is empty")
|
||||||
@@ -206,12 +204,12 @@ func (m *MeetingTimeResponse) StartTime() *utils.NaiveTime {
|
|||||||
log.Panic().Stack().Err(err).Str("raw", raw).Msg("Cannot parse start time integer")
|
log.Panic().Stack().Err(err).Str("raw", raw).Msg("Cannot parse start time integer")
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils.ParseNaiveTime(value)
|
return internal.ParseNaiveTime(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndTime returns the end time of the meeting time as a NaiveTime object
|
// EndTime returns the end time of the meeting time as a NaiveTime object
|
||||||
// This is not cached and is parsed on each invocation. It may also panic without handling.
|
// This is not cached and is parsed on each invocation. It may also panic without handling.
|
||||||
func (m *MeetingTimeResponse) EndTime() *utils.NaiveTime {
|
func (m *MeetingTimeResponse) EndTime() *internal.NaiveTime {
|
||||||
raw := m.MeetingTime.EndTime
|
raw := m.MeetingTime.EndTime
|
||||||
if raw == "" {
|
if raw == "" {
|
||||||
return nil
|
return nil
|
||||||
@@ -222,7 +220,7 @@ func (m *MeetingTimeResponse) EndTime() *utils.NaiveTime {
|
|||||||
log.Panic().Stack().Err(err).Str("raw", raw).Msg("Cannot parse end time integer")
|
log.Panic().Stack().Err(err).Str("raw", raw).Msg("Cannot parse end time integer")
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils.ParseNaiveTime(value)
|
return internal.ParseNaiveTime(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RRule struct {
|
type RRule struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user