129 lines
3.0 KiB
Go
129 lines
3.0 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io/fs"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/BurntSushi/toml"
|
|
"github.com/NickyBoy89/assign-notify/calendar"
|
|
"github.com/NickyBoy89/assign-notify/selection"
|
|
"github.com/NickyBoy89/assign-notify/timeline"
|
|
ics "github.com/arran4/golang-ical"
|
|
"github.com/mitchellh/go-homedir"
|
|
)
|
|
|
|
func ConstructCalendarUrl(
|
|
moodleBase, userId, authToken string,
|
|
eventTypes selection.CalendarEventType,
|
|
when timeline.CalendarEventHorizon,
|
|
) string {
|
|
return fmt.Sprintf(
|
|
"%s/calendar/export_execute.php?userid=%s&authtoken=%s&preset_what=%s&preset_time=%s",
|
|
moodleBase,
|
|
userId,
|
|
authToken,
|
|
eventTypes,
|
|
when,
|
|
)
|
|
}
|
|
|
|
// ConfigFileLocations is a list of every place that the config file could be located
|
|
// The items are explored in-order, and tildes are expanded to the user's home directory
|
|
var ConfigFileLocations = []string{
|
|
"~/.config/assign-notify/config.toml",
|
|
}
|
|
|
|
type Config struct {
|
|
MoodleRoot string `toml:"moodle_root"`
|
|
UserId string `toml:"user_id"`
|
|
AuthToken string `toml:"auth_token"`
|
|
}
|
|
|
|
func main() {
|
|
// Load the config
|
|
var configFileLocation string
|
|
for _, path := range ConfigFileLocations {
|
|
location, err := homedir.Expand(path)
|
|
if err != nil {
|
|
log.Fatalf("Unable to get home directory: %s", err)
|
|
}
|
|
|
|
if _, err := os.Stat(location); err == nil {
|
|
configFileLocation = location
|
|
} else {
|
|
// If there actually was an error, and the file wasn't just missing
|
|
// Otherwise, check the next file in the list
|
|
if !errors.Is(err, fs.ErrNotExist) {
|
|
log.Fatalf("Error accessing config file at %s: %s", location, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// No configuration was found
|
|
if configFileLocation == "" {
|
|
log.Fatalf("No configuration file found, looked in: %s", ConfigFileLocations)
|
|
}
|
|
|
|
var conf Config
|
|
confFile, err := os.Open(configFileLocation)
|
|
if err != nil {
|
|
log.Fatalf("Unable to open config %s: %s", configFileLocation, err)
|
|
}
|
|
|
|
if _, err := toml.NewDecoder(confFile).Decode(&conf); err != nil {
|
|
log.Fatalf("Error decoding %s: %s", configFileLocation, err)
|
|
}
|
|
confFile.Close()
|
|
|
|
resp, err := http.Get(ConstructCalendarUrl(
|
|
conf.MoodleRoot,
|
|
conf.UserId,
|
|
conf.AuthToken,
|
|
selection.AllEvents,
|
|
timeline.RecentAndUpcoming,
|
|
))
|
|
if err != nil {
|
|
log.Fatalf("Error requesting calendar: %s", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
cal, err := ics.ParseCalendar(resp.Body)
|
|
if err != nil {
|
|
log.Fatalf("Error parsing ICAL: %s", err)
|
|
}
|
|
|
|
// Sort the events into when their due dates are
|
|
var past, upcoming []calendar.CalendarEvent
|
|
|
|
for _, event := range cal.Events() {
|
|
calEvent, err := calendar.FromVEvent(event)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
if calEvent.EndTime.Before(time.Now()) {
|
|
past = append(past, calEvent)
|
|
} else {
|
|
upcoming = append(upcoming, calEvent)
|
|
}
|
|
}
|
|
|
|
for _, event := range upcoming {
|
|
due := time.Until(event.EndTime)
|
|
days := int(due.Hours()) / 24
|
|
hours := int(due.Hours())
|
|
fmt.Printf(
|
|
"%s: %s: due in %v days %v hours %.0f minutes\n",
|
|
event.Category.ClassName,
|
|
event.Summary,
|
|
days,
|
|
hours-(days*24),
|
|
due.Minutes()-float64(hours*60),
|
|
)
|
|
}
|
|
}
|