diff options
author | Orangerot <purple@orangerot.dev> | 2024-12-27 12:51:34 +0100 |
---|---|---|
committer | Orangerot <purple@orangerot.dev> | 2024-12-27 14:17:54 +0100 |
commit | 695270eaa752b37f6cc65a7aff99ff6755a73906 (patch) | |
tree | 316f70bb462bc055107cef9e8f42e1f23b691996 /main.go |
Initial commit
Diffstat (limited to 'main.go')
-rw-r--r-- | main.go | 274 |
1 files changed, 274 insertions, 0 deletions
@@ -0,0 +1,274 @@ +package main + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "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("127.0.0.1:8080", nil) + if err != nil { + println(err) + } +} |