linkding.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. package linkding // import "miniflux.app/integration/linkding"
  4. import (
  5. "fmt"
  6. "net/url"
  7. "strings"
  8. "miniflux.app/http/client"
  9. )
  10. // Document structure of a Linkding document
  11. type Document struct {
  12. Url string `json:"url,omitempty"`
  13. Title string `json:"title,omitempty"`
  14. TagNames []string `json:"tag_names,omitempty"`
  15. Unread bool `json:"unread,omitempty"`
  16. }
  17. // Client represents an Linkding client.
  18. type Client struct {
  19. baseURL string
  20. apiKey string
  21. tags string
  22. unread bool
  23. }
  24. // NewClient returns a new Linkding client.
  25. func NewClient(baseURL, apiKey, tags string, unread bool) *Client {
  26. return &Client{baseURL: baseURL, apiKey: apiKey, tags: tags, unread: unread}
  27. }
  28. // AddEntry sends an entry to Linkding.
  29. func (c *Client) AddEntry(title, url string) error {
  30. if c.baseURL == "" || c.apiKey == "" {
  31. return fmt.Errorf("linkding: missing credentials")
  32. }
  33. tagsSplitFn := func(c rune) bool {
  34. return c == ',' || c == ' '
  35. }
  36. doc := &Document{
  37. Url: url,
  38. Title: title,
  39. TagNames: strings.FieldsFunc(c.tags, tagsSplitFn),
  40. Unread: c.unread,
  41. }
  42. apiURL, err := getAPIEndpoint(c.baseURL, "/api/bookmarks/")
  43. if err != nil {
  44. return err
  45. }
  46. clt := client.New(apiURL)
  47. clt.WithAuthorization("Token " + c.apiKey)
  48. response, err := clt.PostJSON(doc)
  49. if err != nil {
  50. return fmt.Errorf("linkding: unable to send entry: %v", err)
  51. }
  52. if response.HasServerFailure() {
  53. return fmt.Errorf("linkding: unable to send entry, status=%d", response.StatusCode)
  54. }
  55. return nil
  56. }
  57. func getAPIEndpoint(baseURL, pathURL string) (string, error) {
  58. u, err := url.Parse(baseURL)
  59. if err != nil {
  60. return "", fmt.Errorf("linkding: invalid API endpoint: %v", err)
  61. }
  62. relative, err := url.Parse(pathURL)
  63. if err != nil {
  64. return "", fmt.Errorf("linkding: invalid API endpoint: %v", err)
  65. }
  66. u = u.ResolveReference(relative)
  67. return u.String(), nil
  68. }