package main import ( "bytes" "encoding/json" "encoding/base64" "fmt" "github.com/arran4/golang-ical" "io" "net/http" "strings" "time" ) const ( API_URL = "https://api.events.ccc.de/congress/2024" ) var ROOMS []Room; type Token struct { Token string `json:"token"` } type Auth struct { Username string `json:"username"` Password string `json:"password"` } type Event struct { ID string `json:"id"` Kind string `json:"kind"` Name string `json:"name"` Slug string `json:"slug"` URL string `json:"url"` Track string `json:"track"` Assembly string `json:"assembly"` Room string `json:"room"` Location string `json:"location"` Language string `json:"language"` Description string `json:"description"` ScheduleStart time.Time `json:"schedule_start"` ScheduleDuration string `json:"schedule_duration"` ScheduleEnd time.Time `json:"schedule_end"` } // Link represents the structure of the "links" array in the JSON type Link struct { Type string `json:"type"` Name string `json:"name"` URI string `json:"uri"` URL string `json:"url"` } // Room represents the structure of the main JSON object type Room struct { ID string `json:"id"` Name string `json:"name"` Slug string `json:"slug"` RoomType string `json:"room_type"` Capacity int `json:"capacity"` Links []Link `json:"links"` Assembly string `json:"assembly"` PublicURL string `json:"public_url"` } func scrape_hub() ([]Event, error) { println("scrape hub") resp, err := http.Get(fmt.Sprintf("%s/events", API_URL)) if err != nil { fmt.Println("Error making GET request:", err) return nil, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { fmt.Println("Error reading response body:", err) return nil, err } var events []Event if err := json.Unmarshal(body, &events); err != nil { fmt.Println("Error unmarshalling JSON:", err) return nil, err } // Use the events slice here fmt.Println("Number of events:", len(events)) return events, nil } func get_rooms() ([]Room, error) { println("get rooms") resp, err := http.Get(fmt.Sprintf("%s/rooms", API_URL)) if err != nil { fmt.Println("Error making GET request:", err) return nil, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { fmt.Println("Error reading response body:", err) return nil, err } var rooms []Room if err := json.Unmarshal(body, &rooms); err != nil { fmt.Println("Error unmarshalling JSON:", err) return nil, err } // Use the events slice here fmt.Println("Number of rooms:", len(rooms)) return rooms, nil } func get_token(username string, password string) (string, error) { println("get token") jsonBytes, err := json.Marshal(Auth{Username: username, Password: password}) if err != nil { fmt.Println("Error unmarshalling JSON:", err) return "", err } resp, err := http.Post( fmt.Sprintf("%s/auth/get-token", API_URL), "application/json", bytes.NewBuffer(jsonBytes), ) if err != nil { fmt.Println("Error getting Token:", err) return "", err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { fmt.Println("Error reading response body:", err) return "", err } var token Token if err := json.Unmarshal(body, &token); err != nil { fmt.Println("Error unmarshalling JSON:", err) return "", err } println(token.Token) return token.Token, nil } func get_me_events(token string) ([]string, error) { println("get personal events") req, err := http.NewRequest( "GET", fmt.Sprintf("%s/me/events", API_URL), nil, ) req.Header.Set("Authorization", fmt.Sprintf("Token %s", token)) resp, err := (&http.Client{}).Do(req) if err != nil { fmt.Println("Error fetching personal events:", err) return nil, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { fmt.Println("Error reading response body:", err) return nil, err } println(string(body)) var uuids []string if err := json.Unmarshal(body, &uuids); err != nil { fmt.Println("Error unmarshalling JSON:", err) return nil, err } return uuids, nil } func get_schedule(w http.ResponseWriter, r *http.Request) { println("/event.ics") auth_header := r.Header.Get("Authorization") println(auth_header) if auth_header == "" { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } credentials_encoded := auth_header[len("Basic "):] credentials, err := base64.StdEncoding.DecodeString(credentials_encoded) if err != nil { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } auth := strings.SplitN(string(credentials), ":", 2) if len(auth) != 2 { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } username := auth[0] password := auth[1] println(username, password) token, err := get_token(username, password) if err != nil { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } ids, err := get_me_events(token) if err != nil { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } schedule, err := scrape_hub() if err != nil { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } var my_events []Event for _, event := range schedule { for _, id := range ids { if event.ID == id { my_events = append(my_events, event) break } } } cal := ics.NewCalendar() cal.SetMethod(ics.MethodRequest) for _, event := range my_events { var location = "" for _, room := range ROOMS { if event.Room == room.ID { location = room.Name } } cal_event := cal.AddEvent(event.ID) cal_event.SetStartAt(event.ScheduleStart) cal_event.SetEndAt(event.ScheduleEnd) cal_event.SetSummary(event.Name) cal_event.SetLocation(location) cal_event.SetDescription(ics.ToText(strings.ReplaceAll(event.Description, "\r\n", "\n"))) cal_event.SetURL(event.URL) cal_event.SetOrganizer(event.Assembly) } ics := cal.Serialize() w.Header().Set("Content-Type", "text/calendar; charset=utf-8") w.Write([]byte(ics)) } func main() { rooms, err := get_rooms() if err != nil { return } ROOMS = rooms println("Stating Server") // Start a web server to serve the iCal file http.HandleFunc("/events.ics", get_schedule) err = http.ListenAndServe(":8080", nil) if err != nil { println(err) } }