diff --git a/bruno/Gemlog/Get Gemlog By Slug.bru b/bruno/Gemlog/Get Gemlog By Slug.bru new file mode 100644 index 0000000..f02e8a2 --- /dev/null +++ b/bruno/Gemlog/Get Gemlog By Slug.bru @@ -0,0 +1,24 @@ +meta { + name: Get Gemlog By Slug + type: http + seq: 6 +} + +get { + url: http://eisenhorn:5023/gemlog/_design/capsule/_view/post_by_slug?key="hello-from-gemlog-cli" + body: json + auth: basic +} + +params:query { + key: "hello-from-gemlog-cli" +} + +auth:basic { + username: gemlog-cli + password: {{pw}} +} + +settings { + encodeUrl: true +} diff --git a/gemlog/db.go b/gemlog/db.go index e3b0efa..bae5533 100644 --- a/gemlog/db.go +++ b/gemlog/db.go @@ -123,6 +123,69 @@ func ReadGemlogEntry(config *Config, id string) (GemlogEntry, error) { }, nil } +func ReadGemlogEntryBySlug(config *Config, slug string) (GemlogEntry, error) { + url := fmt.Sprintf("%s:%d/gemlog/_design/capsule/_view/post_by_slug?key=\"%s\"", config.CouchDB.Host, config.CouchDB.Port, slug) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return GemlogEntry{}, fmt.Errorf("failed to create request: %w", err) + } + + req.Header.Add("authorization", genBasicAuthHeader(config.CouchDB.User, config.CouchDB.Password)) + req.Header.Add("content-type", "application/json") + + res, err := http.DefaultClient.Do(req) + if err != nil { + return GemlogEntry{}, fmt.Errorf("failed to send request: %w", err) + } + defer res.Body.Close() + + body, err := io.ReadAll(res.Body) + if err != nil { + return GemlogEntry{}, fmt.Errorf("failed to read response body: %w", err) + } + + if res.StatusCode < 200 || res.StatusCode >= 300 { + return GemlogEntry{}, fmt.Errorf("unexpected status code %d: %s", res.StatusCode, string(body)) + } + + // Decode CouchDB view response + var viewResponse struct { + TotalRows int `json:"total_rows"` + Offset int `json:"offset"` + Rows []struct { + ID string `json:"id"` + Key string `json:"key"` + Value struct { + ID string `json:"_id"` + Rev string `json:"_rev"` + Title string `json:"title"` + Slug string `json:"slug"` + Date time.Time `json:"date"` + Gemtxt string `json:"gemtxt"` + } `json:"value"` + } `json:"rows"` + } + + if err := json.Unmarshal(body, &viewResponse); err != nil { + return GemlogEntry{}, fmt.Errorf("failed to parse response: %w", err) + } + + // Check if we got any results + if len(viewResponse.Rows) == 0 { + return GemlogEntry{}, fmt.Errorf("no document found with slug: %s", slug) + } + + // Extract the first (and should be only) result + doc := viewResponse.Rows[0].Value + + return GemlogEntry{ + Title: doc.Title, + Slug: doc.Slug, + Date: doc.Date, + Gemtxt: doc.Gemtxt, + }, nil +} + func DeleteGemlogEntry(config *Config, id string, rev string) error { url := fmt.Sprintf("%s:%d/gemlog/%s?rev=%s", config.CouchDB.Host, config.CouchDB.Port, id, rev) req, err := http.NewRequest("DELETE", url, nil)