@@ -10,11 +10,14 @@ import (
1010 "os"
1111)
1212
13+ const defaultLumaAPIBase = "https://api.luma.com/calendar/get-items"
14+
1315type LumaEvent struct {
14- Name string `json:"name"`
15- StartAt string `json:"start_at"`
16- URL string `json:"url"`
17- GeoAddr * struct {
16+ Name string `json:"name"`
17+ StartAt string `json:"start_at"`
18+ URL string `json:"url"`
19+ CoverURL string `json:"cover_url"`
20+ GeoAddr * struct {
1821 Address string `json:"address"`
1922 ShortAddress string `json:"short_address"`
2023 } `json:"geo_address_info"`
@@ -28,78 +31,144 @@ type LumaResponse struct {
2831 Entries []LumaEntry `json:"entries"`
2932}
3033
31- type NextEvent struct {
34+ type EventItem struct {
3235 Name string `json:"name"`
3336 StartAt string `json:"start_at"`
3437 URL string `json:"url"`
3538 Location string `json:"location"`
39+ CoverURL string `json:"cover_url"`
3640}
3741
3842type Output struct {
39- Entries []NextEvent `json:"entries"`
43+ Entries []EventItem `json:"entries"`
4044}
4145
42- func NextEventHandler (w http.ResponseWriter , r * http.Request ) {
43- cal := r .URL .Query ().Get ("calendar" )
44- if cal == "" {
45- w .Write ([]byte ("missing calendar query parameter" ))
46+ func NextEventHandler (apiBase string ) http.HandlerFunc {
47+ return func (w http.ResponseWriter , r * http.Request ) {
48+ cal := r .URL .Query ().Get ("calendar" )
49+ if cal == "" {
50+ w .Write ([]byte ("missing calendar query parameter" ))
4651
47- panic ("missing calendar query parameter" )
48- }
52+ panic ("missing calendar query parameter" )
53+ }
4954
50- u := "https://api.luma.com/calendar/get-items ?" + url.Values {
51- "calendar_api_id" : {cal },
52- "period" : {"future" },
53- "pagination_limit" : {"1" },
54- }.Encode ()
55+ u := apiBase + " ?" + url.Values {
56+ "calendar_api_id" : {cal },
57+ "period" : {"future" },
58+ "pagination_limit" : {"1" },
59+ }.Encode ()
5560
56- resp , err := http .Get (u )
57- if err != nil {
58- panic (err )
59- }
60- defer resp .Body .Close ()
61+ resp , err := http .Get (u )
62+ if err != nil {
63+ panic (err )
64+ }
65+ defer resp .Body .Close ()
6166
62- body , err := io .ReadAll (resp .Body )
63- if err != nil {
64- panic (err )
65- }
67+ body , err := io .ReadAll (resp .Body )
68+ if err != nil {
69+ panic (err )
70+ }
6671
67- var lr LumaResponse
68- if err := json .Unmarshal (body , & lr ); err != nil {
69- panic (err )
70- }
72+ var lr LumaResponse
73+ if err := json .Unmarshal (body , & lr ); err != nil {
74+ panic (err )
75+ }
7176
72- output := Output {}
77+ output := Output {}
7378
74- if len (lr .Entries ) > 0 {
75- evt := lr .Entries [0 ].Event
79+ if len (lr .Entries ) > 0 {
80+ evt := lr .Entries [0 ].Event
7681
77- loc := ""
78- if evt .GeoAddr != nil {
79- loc = evt .GeoAddr .Address
80- if loc == "" {
81- loc = evt .GeoAddr .ShortAddress
82+ loc := ""
83+ if evt .GeoAddr != nil {
84+ loc = evt .GeoAddr .Address
85+ if loc == "" {
86+ loc = evt .GeoAddr .ShortAddress
87+ }
8288 }
89+
90+ output .Entries = []EventItem {{
91+ Name : evt .Name ,
92+ StartAt : evt .StartAt ,
93+ URL : evt .URL ,
94+ Location : loc ,
95+ CoverURL : evt .CoverURL ,
96+ }}
8397 }
8498
85- output .Entries = []NextEvent {{
86- Name : evt .Name ,
87- StartAt : evt .StartAt ,
88- URL : evt .URL ,
89- Location : loc ,
90- }}
91- }
99+ j , err := json .Marshal (output )
100+ if err != nil {
101+ panic (err )
102+ }
92103
93- j , err := json .Marshal (output )
94- if err != nil {
95- panic (err )
104+ fmt .Fprintf (w , "%v" , string (j ))
96105 }
106+ }
107+
108+ func EventsHandler (apiBase string ) http.HandlerFunc {
109+ return func (w http.ResponseWriter , r * http.Request ) {
110+ cal := r .URL .Query ().Get ("calendar" )
111+ if cal == "" {
112+ w .Write ([]byte ("missing calendar query parameter" ))
113+
114+ panic ("missing calendar query parameter" )
115+ }
116+
117+ u := apiBase + "?" + url.Values {
118+ "calendar_api_id" : {cal },
119+ "period" : {"future" },
120+ "pagination_limit" : {"20" },
121+ }.Encode ()
97122
98- fmt .Fprintf (w , "%v" , string (j ))
123+ resp , err := http .Get (u )
124+ if err != nil {
125+ panic (err )
126+ }
127+ defer resp .Body .Close ()
128+
129+ body , err := io .ReadAll (resp .Body )
130+ if err != nil {
131+ panic (err )
132+ }
133+
134+ var lr LumaResponse
135+ if err := json .Unmarshal (body , & lr ); err != nil {
136+ panic (err )
137+ }
138+
139+ output := Output {}
140+
141+ for _ , entry := range lr .Entries {
142+ evt := entry .Event
143+
144+ loc := ""
145+ if evt .GeoAddr != nil {
146+ loc = evt .GeoAddr .Address
147+ if loc == "" {
148+ loc = evt .GeoAddr .ShortAddress
149+ }
150+ }
151+
152+ output .Entries = append (output .Entries , EventItem {
153+ Name : evt .Name ,
154+ StartAt : evt .StartAt ,
155+ URL : evt .URL ,
156+ Location : loc ,
157+ CoverURL : evt .CoverURL ,
158+ })
159+ }
160+
161+ j , err := json .Marshal (output )
162+ if err != nil {
163+ panic (err )
164+ }
165+
166+ fmt .Fprintf (w , "%v" , string (j ))
167+ }
99168}
100169
101170func Handler (w http.ResponseWriter , r * http.Request ) {
102- NextEventHandler (w , r )
171+ NextEventHandler (defaultLumaAPIBase ). ServeHTTP ( w , r )
103172}
104173
105174func main () {
@@ -113,20 +182,30 @@ func main() {
113182 origin = "*"
114183 }
115184
116- http .HandleFunc ("/next-event" , func (w http.ResponseWriter , r * http.Request ) {
117- w .Header ().Set ("Access-Control-Allow-Origin" , origin )
118- w .Header ().Set ("Access-Control-Allow-Methods" , "GET, OPTIONS" )
119- w .Header ().Set ("Access-Control-Allow-Headers" , "Content-Type" )
120- w .Header ().Set ("Content-Type" , "application/json" )
121- w .Header ().Set ("Cache-Control" , "public, max-age=300" )
185+ apiBase := os .Getenv ("LUMA_API_BASE" )
186+ if apiBase == "" {
187+ apiBase = defaultLumaAPIBase
188+ }
189+
190+ cors := func (next http.HandlerFunc ) http.HandlerFunc {
191+ return func (w http.ResponseWriter , r * http.Request ) {
192+ w .Header ().Set ("Access-Control-Allow-Origin" , origin )
193+ w .Header ().Set ("Access-Control-Allow-Methods" , "GET, OPTIONS" )
194+ w .Header ().Set ("Access-Control-Allow-Headers" , "Content-Type" )
195+ w .Header ().Set ("Content-Type" , "application/json" )
196+ w .Header ().Set ("Cache-Control" , "public, max-age=300" )
197+
198+ if r .Method == http .MethodOptions {
199+ w .WriteHeader (http .StatusNoContent )
200+ return
201+ }
122202
123- if r .Method == http .MethodOptions {
124- w .WriteHeader (http .StatusNoContent )
125- return
203+ next (w , r )
126204 }
205+ }
127206
128- Handler ( w , r )
129- } )
207+ http . HandleFunc ( "/next-event" , cors ( NextEventHandler ( apiBase )) )
208+ http . HandleFunc ( "/events" , cors ( EventsHandler ( apiBase )) )
130209
131210 log .Printf ("listening on :%s" , port )
132211 if err := http .ListenAndServe (fmt .Sprintf (":%s" , port ), nil ); err != nil {
0 commit comments