| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "net/http" |
| 5 | "strings" |
| 6 | |
| 7 | "github.com/stevedylandev/andromeda/pkg/web" |
| 8 | ) |
| 9 | |
| 10 | func (a *App) apiListCategories(w http.ResponseWriter, r *http.Request) { |
| 11 | cats, err := listCategories(a.DB) |
| 12 | if err != nil { |
| 13 | a.Log.Error("list categories", "err", err) |
| 14 | w.WriteHeader(http.StatusInternalServerError) |
| 15 | return |
| 16 | } |
| 17 | web.WriteJSON(w, http.StatusOK, cats) |
| 18 | } |
| 19 | |
| 20 | func (a *App) apiListLinks(w http.ResponseWriter, r *http.Request) { |
| 21 | cats, err := listCategories(a.DB) |
| 22 | if err != nil { |
| 23 | a.Log.Error("list categories", "err", err) |
| 24 | w.WriteHeader(http.StatusInternalServerError) |
| 25 | return |
| 26 | } |
| 27 | links, err := listLinks(a.DB) |
| 28 | if err != nil { |
| 29 | a.Log.Error("list links", "err", err) |
| 30 | w.WriteHeader(http.StatusInternalServerError) |
| 31 | return |
| 32 | } |
| 33 | filter := strings.TrimSpace(r.URL.Query().Get("category")) |
| 34 | if filter != "" { |
| 35 | var found *Category |
| 36 | for i := range cats { |
| 37 | if strings.EqualFold(cats[i].Name, filter) { |
| 38 | found = &cats[i] |
| 39 | break |
| 40 | } |
| 41 | } |
| 42 | if found == nil { |
| 43 | web.WriteError(w, http.StatusNotFound, "unknown category") |
| 44 | return |
| 45 | } |
| 46 | out := []Link{} |
| 47 | for _, l := range links { |
| 48 | if l.CategoryID == found.ID { |
| 49 | out = append(out, l) |
| 50 | } |
| 51 | } |
| 52 | web.WriteJSON(w, http.StatusOK, out) |
| 53 | return |
| 54 | } |
| 55 | grouped := map[string][]Link{} |
| 56 | for _, c := range cats { |
| 57 | items := []Link{} |
| 58 | for _, l := range links { |
| 59 | if l.CategoryID == c.ID { |
| 60 | items = append(items, l) |
| 61 | } |
| 62 | } |
| 63 | grouped[c.Name] = items |
| 64 | } |
| 65 | web.WriteJSON(w, http.StatusOK, grouped) |
| 66 | } |
| 67 | |
| 68 | func (a *App) apiCreateLink(w http.ResponseWriter, r *http.Request) { |
| 69 | var body apiCreateLinkBody |
| 70 | if !web.DecodeJSON(w, r, &body) { |
| 71 | return |
| 72 | } |
| 73 | title := strings.TrimSpace(body.Title) |
| 74 | url := strings.TrimSpace(body.URL) |
| 75 | if title == "" || url == "" { |
| 76 | web.WriteError(w, http.StatusBadRequest, "title and url required") |
| 77 | return |
| 78 | } |
| 79 | cat, err := getCategoryByName(a.DB, body.Category) |
| 80 | if err != nil { |
| 81 | a.Log.Error("get category", "err", err) |
| 82 | w.WriteHeader(http.StatusInternalServerError) |
| 83 | return |
| 84 | } |
| 85 | if cat == nil { |
| 86 | web.WriteError(w, http.StatusNotFound, "unknown category") |
| 87 | return |
| 88 | } |
| 89 | link, err := createLink(a.DB, title, url, nil, cat.ID) |
| 90 | if err != nil { |
| 91 | a.Log.Error("create link", "err", err) |
| 92 | w.WriteHeader(http.StatusInternalServerError) |
| 93 | return |
| 94 | } |
| 95 | if fav := discoverFavicon(r.Context(), url); fav != "" { |
| 96 | _ = updateLinkFavicon(a.DB, link.ID, &fav) |
| 97 | link.FaviconURL = &fav |
| 98 | } |
| 99 | web.WriteJSON(w, http.StatusCreated, link) |
| 100 | } |