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),
 | 
						|
		)
 | 
						|
	}
 | 
						|
}
 |