eintopf.info@v0.13.16/web/placelist.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 web 17 18 import ( 19 "encoding/json" 20 "net/http" 21 "sort" 22 "strings" 23 "text/template" 24 25 "eintopf.info/service/indexo" 26 "eintopf.info/service/place" 27 "eintopf.info/service/search" 28 ) 29 30 // PlaceListPage renders the grouplist page. 31 func (renderer *Renderer) PlaceListPage(w http.ResponseWriter, r *http.Request) { 32 query := r.URL.Query().Get("query") 33 result, err := renderer.search.Search(r.Context(), &search.Options{ 34 Query: query, 35 Sort: "name", 36 Filters: []search.Filter{ 37 &search.TermsFilter{Field: "type", Terms: []string{"place"}}, 38 &search.BoolFilter{Field: "listed", Value: true}, 39 }, 40 }) 41 if err != nil { 42 renderer.errorPage(w, r, err) 43 return 44 } 45 46 alphabet := defaultAlphabet() 47 places := []PlaceDocument{} 48 for _, hit := range result.Hits { 49 g := PlaceDocument{} 50 err := hit.Unmarshal(&g) 51 if err != nil { 52 renderer.errorPage(w, r, err) 53 return 54 } 55 places = append(places, g) 56 57 for _, letter := range alphabet { 58 if []rune(letter.Letter)[0] == g.StartLetterRune() { 59 letter.HasItems = true 60 break 61 } 62 } 63 } 64 sort.Slice(places, func(i, j int) bool { 65 return strings.ToLower(places[i].Name) < strings.ToLower(places[j].Name) 66 }) 67 68 currentLetter := rune('A') 69 70 err = renderer.renderPage(w, r, "placelist", map[string]any{ 71 "Query": query, 72 "Places": places, 73 "Alphabet": alphabet, 74 }, template.FuncMap{ 75 "isCurrentLetter": func(letter rune) bool { 76 if currentLetter <= letter { 77 currentLetter = currentLetter + letter - currentLetter + 1 78 return true 79 } 80 return false 81 }, 82 }) 83 if err != nil { 84 renderer.errorPage(w, r, err) 85 return 86 } 87 } 88 89 type PlaceDocument indexo.PlaceDocument 90 91 func (g PlaceDocument) StartLetter() string { 92 return strings.ToUpper(string([]rune(g.Name)[0])) 93 } 94 95 func (g PlaceDocument) StartLetterRune() rune { 96 return []rune(g.StartLetter())[0] 97 } 98 99 func (p PlaceDocument) MapMarker() mapMarker { 100 return mapMarker{ID: p.ID, Name: p.Name, Lat: p.Lat, Lng: p.Lng} 101 } 102 103 type mapMarker struct { 104 ID string `json:"id"` 105 Name string `json:"name"` 106 Lat float64 `json:"lat"` 107 Lng float64 `json:"lng"` 108 } 109 110 func placestoMapMarkers(places []PlaceDocument) string { 111 c := []mapMarker{} 112 for _, p := range places { 113 if p.Lat != 0 && p.Lng != 0 { 114 c = append(c, p.MapMarker()) 115 } 116 } 117 data, err := json.Marshal(c) 118 if err != nil { 119 return "" 120 } 121 return string(data) 122 } 123 124 func placeDocumentToMapMarker(p PlaceDocument) string { 125 c := []mapMarker{p.MapMarker()} 126 data, err := json.Marshal(c) 127 if err != nil { 128 return "" 129 } 130 return string(data) 131 } 132 133 func placeToMapMarker(p *place.Place) string { 134 c := []mapMarker{{ID: p.ID, Name: p.Name, Lat: p.Lat, Lng: p.Lng}} 135 data, err := json.Marshal(c) 136 if err != nil { 137 return "" 138 } 139 return string(data) 140 }