eintopf.info@v0.13.16/service/ical/transport.go (about) 1 // Copyright (C) 2022 The Eintopf authors 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <https://www.gnu.org/licenses/>. 15 16 package ical 17 18 import ( 19 "context" 20 "fmt" 21 "net/http" 22 23 "github.com/go-chi/chi/v5" 24 25 "eintopf.info/internal/plausible" 26 "eintopf.info/internal/xhttp" 27 "eintopf.info/service/eventsearch" 28 ) 29 30 func Routes(service Service, plausibleClient *plausible.Client) func(r chi.Router) { 31 router := router{service: service} 32 return func(r chi.Router) { 33 r.Use(plausible.MiddlewareWithName(plausibleClient, "ical")) 34 r.Get("/ical", router.getEventsIcalFeed) 35 r.Get("/events/{id}/ical", router.getEventIcal) 36 r.Get("/groups/{id}/ical", router.getGroupIcalFeed) 37 r.Get("/places/{id}/ical", router.getPlaceIcalFeed) 38 } 39 } 40 41 type router struct { 42 service Service 43 } 44 45 func (router router) getEventsIcalFeed(w http.ResponseWriter, r *http.Request) { 46 opts, err := eventsearch.OptionsFromRequest(r) 47 if err != nil { 48 xhttp.WriteBadRequest(r.Context(), w, err) 49 return 50 } 51 feed, err := router.service.Feed(r.Context(), opts) 52 if err != nil { 53 xhttp.WriteError(r.Context(), w, err) 54 return 55 } 56 err = writeIcal(r.Context(), w, "eintopf", feed) 57 if err != nil { 58 xhttp.WriteInternalError(r.Context(), w, err) 59 return 60 } 61 } 62 63 func (router router) getEventIcal(w http.ResponseWriter, r *http.Request) { 64 id := chi.URLParam(r, "id") 65 if id == "" { 66 xhttp.WriteBadRequest(r.Context(), w, fmt.Errorf("empty id")) 67 return 68 } 69 ical, err := router.service.EventIcal(r.Context(), id) 70 if err != nil { 71 xhttp.WriteError(r.Context(), w, err) 72 return 73 } 74 err = writeIcal(r.Context(), w, id, ical) 75 if err != nil { 76 xhttp.WriteInternalError(r.Context(), w, err) 77 return 78 } 79 } 80 81 func (router router) getGroupIcalFeed(w http.ResponseWriter, r *http.Request) { 82 id := chi.URLParam(r, "id") 83 if id == "" { 84 xhttp.WriteBadRequest(r.Context(), w, fmt.Errorf("empty id")) 85 return 86 } 87 ical, err := router.service.GroupFeed(r.Context(), id) 88 if err != nil { 89 xhttp.WriteError(r.Context(), w, err) 90 return 91 } 92 err = writeIcal(r.Context(), w, id, ical) 93 if err != nil { 94 xhttp.WriteInternalError(r.Context(), w, err) 95 return 96 } 97 } 98 99 func (router router) getPlaceIcalFeed(w http.ResponseWriter, r *http.Request) { 100 id := chi.URLParam(r, "id") 101 if id == "" { 102 xhttp.WriteBadRequest(r.Context(), w, fmt.Errorf("empty id")) 103 return 104 } 105 ical, err := router.service.PlaceFeed(r.Context(), id) 106 if err != nil { 107 xhttp.WriteError(r.Context(), w, err) 108 return 109 } 110 err = writeIcal(r.Context(), w, id, ical) 111 if err != nil { 112 xhttp.WriteInternalError(r.Context(), w, err) 113 return 114 } 115 } 116 117 func writeIcal(ctx context.Context, w http.ResponseWriter, filename, ical string) error { 118 w.Header().Add("Content-type", "text/calendar; charset=utf-8") 119 w.Header().Add("Content-Disposition", fmt.Sprintf("inline; filename=%s.ics", filename)) 120 _, err := w.Write([]byte(ical)) 121 if err != nil { 122 return err 123 } 124 return nil 125 }