Skip to content

Commit b1fda59

Browse files
frommiefguillot
authored andcommitted
feat(integration): add tags option for karakeep integration
1 parent 509b768 commit b1fda59

28 files changed

+144
-17
lines changed

internal/database/migrations.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,4 +1366,11 @@ var migrations = [...]func(tx *sql.Tx) error{
13661366
_, err = tx.Exec(sql)
13671367
return err
13681368
},
1369+
func(tx *sql.Tx) (err error) {
1370+
sql := `
1371+
ALTER TABLE integrations ADD COLUMN karakeep_tags text default '';
1372+
`
1373+
_, err = tx.Exec(sql)
1374+
return err
1375+
},
13691376
}

internal/integration/integration.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,14 +457,20 @@ func SendEntry(entry *model.Entry, userIntegrations *model.Integration) {
457457
if userIntegrations.KarakeepEnabled {
458458
slog.Debug("Sending entry to Karakeep",
459459
slog.Int64("user_id", userIntegrations.UserID),
460+
slog.String("user_tags", userIntegrations.KarakeepTags),
460461
slog.Int64("entry_id", entry.ID),
461462
slog.String("entry_url", entry.URL),
462463
)
463464

464-
client := karakeep.NewClient(userIntegrations.KarakeepAPIKey, userIntegrations.KarakeepURL)
465+
client := karakeep.NewClient(
466+
userIntegrations.KarakeepAPIKey,
467+
userIntegrations.KarakeepURL,
468+
userIntegrations.KarakeepTags,
469+
)
465470
if err := client.SaveURL(entry.URL); err != nil {
466471
slog.Error("Unable to send entry to Karakeep",
467472
slog.Int64("user_id", userIntegrations.UserID),
473+
slog.String("user_tags", userIntegrations.KarakeepTags),
468474
slog.Int64("entry_id", entry.ID),
469475
slog.String("entry_url", entry.URL),
470476
slog.Any("error", err),

internal/integration/karakeep/karakeep.go

Lines changed: 91 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,103 @@ package karakeep // import "miniflux.app/v2/internal/integration/karakeep"
66
import (
77
"bytes"
88
"encoding/json"
9+
"errors"
910
"fmt"
1011
"io"
1112
"net/http"
13+
"strings"
1214
"time"
1315

1416
"miniflux.app/v2/internal/version"
1517
)
1618

1719
const defaultClientTimeout = 10 * time.Second
1820

19-
type errorResponse struct {
20-
Code string `json:"code"`
21-
Error string `json:"error"`
21+
type Client struct {
22+
wrapped *http.Client
23+
apiEndpoint string
24+
apiToken string
25+
tags string
26+
}
27+
28+
type tagItem struct {
29+
TagName string `json:"tagName"`
2230
}
2331

2432
type saveURLPayload struct {
2533
Type string `json:"type"`
2634
URL string `json:"url"`
2735
}
2836

29-
type Client struct {
30-
wrapped *http.Client
31-
apiEndpoint string
32-
apiToken string
37+
type saveURLResponse struct {
38+
ID string `json:"id"`
3339
}
3440

35-
func NewClient(apiToken string, apiEndpoint string) *Client {
36-
return &Client{wrapped: &http.Client{Timeout: defaultClientTimeout}, apiEndpoint: apiEndpoint, apiToken: apiToken}
41+
type attachTagsPayload struct {
42+
Tags []tagItem `json:"tags"`
43+
}
44+
45+
type errorResponse struct {
46+
Code string `json:"code"`
47+
Error string `json:"error"`
48+
}
49+
50+
func NewClient(apiToken string, apiEndpoint string, tags string) *Client {
51+
return &Client{wrapped: &http.Client{Timeout: defaultClientTimeout}, apiEndpoint: apiEndpoint, apiToken: apiToken, tags: tags}
52+
}
53+
54+
func (c *Client) attachTags(entryID string) error {
55+
if c.tags == "" {
56+
return nil
57+
}
58+
59+
tagItems := make([]tagItem, 0)
60+
for tag := range strings.SplitSeq(c.tags, ",") {
61+
if trimmedTag := strings.TrimSpace(tag); trimmedTag != "" {
62+
tagItems = append(tagItems, tagItem{TagName: trimmedTag})
63+
}
64+
}
65+
66+
if len(tagItems) == 0 {
67+
return nil
68+
}
69+
70+
tagRequestBody, err := json.Marshal(&attachTagsPayload{
71+
Tags: tagItems,
72+
})
73+
if err != nil {
74+
return fmt.Errorf("karakeep: unable to encode tag request body: %v", err)
75+
}
76+
77+
tagRequest, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/%s/tags", c.apiEndpoint, entryID), bytes.NewReader(tagRequestBody))
78+
if err != nil {
79+
return fmt.Errorf("karakeep: unable to create tag request: %v", err)
80+
}
81+
82+
tagRequest.Header.Set("Authorization", "Bearer "+c.apiToken)
83+
tagRequest.Header.Set("Content-Type", "application/json")
84+
tagRequest.Header.Set("User-Agent", "Miniflux/"+version.Version)
85+
86+
tagResponse, err := c.wrapped.Do(tagRequest)
87+
if err != nil {
88+
return fmt.Errorf("karakeep: unable to send tag request: %v", err)
89+
}
90+
defer tagResponse.Body.Close()
91+
92+
if tagResponse.StatusCode != http.StatusOK && tagResponse.StatusCode != http.StatusCreated {
93+
tagResponseBody, err := io.ReadAll(tagResponse.Body)
94+
if err != nil {
95+
return fmt.Errorf("karakeep: failed to parse tag response: %s", err)
96+
}
97+
98+
var errResponse errorResponse
99+
if err := json.Unmarshal(tagResponseBody, &errResponse); err != nil {
100+
return fmt.Errorf("karakeep: unable to parse tag error response: status=%d body=%s", tagResponse.StatusCode, string(tagResponseBody))
101+
}
102+
return fmt.Errorf("karakeep: failed to attach tags: status=%d errorcode=%s %s", tagResponse.StatusCode, errResponse.Code, errResponse.Error)
103+
}
104+
105+
return nil
37106
}
38107

39108
func (c *Client) SaveURL(entryURL string) error {
@@ -77,5 +146,18 @@ func (c *Client) SaveURL(entryURL string) error {
77146
return fmt.Errorf("karakeep: failed to save URL: status=%d errorcode=%s %s", resp.StatusCode, errResponse.Code, errResponse.Error)
78147
}
79148

149+
var response saveURLResponse
150+
if err := json.Unmarshal(responseBody, &response); err != nil {
151+
return fmt.Errorf("karakeep: unable to parse response: %v", err)
152+
}
153+
154+
if response.ID == "" {
155+
return errors.New("karakeep: unable to get ID from response")
156+
}
157+
158+
if err := c.attachTags(response.ID); err != nil {
159+
return fmt.Errorf("karakeep: unable to attach tags: %v", err)
160+
}
161+
80162
return nil
81163
}

internal/locale/translations/de_DE.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@
241241
"form.integration.karakeep_activate": "Artikel in Karakeep speichern",
242242
"form.integration.karakeep_api_key": "Karakeep-API-Schlüssel",
243243
"form.integration.karakeep_url": "Karakeep-API-Endpunkt",
244+
"form.integration.karakeep_tags": "Karakeep-Tags",
244245
"form.integration.linkace_activate": "Artikel in LinkAce speichern",
245246
"form.integration.linkace_api_key": "LinkAce-API-Schlüssel",
246247
"form.integration.linkace_check_disabled": "Linkprüfung deaktivieren",

internal/locale/translations/el_EL.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@
241241
"form.integration.karakeep_activate": "Αποθήκευση άρθρων στο Karakeep",
242242
"form.integration.karakeep_api_key": "Κλειδί API Karakeep",
243243
"form.integration.karakeep_url": "Τελικό σημείο Karakeep API",
244+
"form.integration.karakeep_tags": "Ετικέτες Karakeep",
244245
"form.integration.linkace_activate": "Αποθήκευση καταχωρήσεων στο LinkAce",
245246
"form.integration.linkace_api_key": "Κλειδί API LinkAce",
246247
"form.integration.linkace_check_disabled": "Απενεργοποίηση ελέγχου συνδέσμου",

internal/locale/translations/en_US.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@
241241
"form.integration.karakeep_activate": "Save entries to Karakeep",
242242
"form.integration.karakeep_api_key": "Karakeep API key",
243243
"form.integration.karakeep_url": "Karakeep API Endpoint",
244+
"form.integration.karakeep_tags": "Karakeep Tags",
244245
"form.integration.linkace_activate": "Save entries to LinkAce",
245246
"form.integration.linkace_api_key": "LinkAce API key",
246247
"form.integration.linkace_check_disabled": "Disable link check",

internal/locale/translations/es_ES.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@
241241
"form.integration.karakeep_activate": "Enviar artículos a Karakeep",
242242
"form.integration.karakeep_api_key": "Clave de API de Karakeep",
243243
"form.integration.karakeep_url": "Acceso API de Karakeep",
244+
"form.integration.karakeep_tags": "Etiquetas de Karakeep",
244245
"form.integration.linkace_activate": "Guardar artículos en LinkAce",
245246
"form.integration.linkace_api_key": "Clave API de LinkAce",
246247
"form.integration.linkace_check_disabled": "Deshabilitar la comprobación de enlace",

internal/locale/translations/fi_FI.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@
241241
"form.integration.karakeep_activate": "Tallenna artikkelit Karakeepiin",
242242
"form.integration.karakeep_api_key": "Karakeep API-avain",
243243
"form.integration.karakeep_url": "Karakeep API-päätepiste",
244+
"form.integration.karakeep_tags": "Karakeep Tags",
244245
"form.integration.linkace_activate": "Save entries to LinkAce",
245246
"form.integration.linkace_api_key": "LinkAce API key",
246247
"form.integration.linkace_check_disabled": "Disable link check",

internal/locale/translations/fr_FR.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@
241241
"form.integration.karakeep_activate": "Sauvegarder les articles vers Karakeep",
242242
"form.integration.karakeep_api_key": "Clé d'API de Karakeep",
243243
"form.integration.karakeep_url": "URL de l'API de Karakeep",
244+
"form.integration.karakeep_tags": "Libellés Karakeep",
244245
"form.integration.linkace_activate": "Enregistrer les entrées vers LinkAce",
245246
"form.integration.linkace_api_key": "Clé d'API LinkAce",
246247
"form.integration.linkace_check_disabled": "Désactiver la vérification des liens",

internal/locale/translations/hi_IN.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@
241241
"form.integration.karakeep_activate": "Save entries to Karakeep",
242242
"form.integration.karakeep_api_key": "Karakeep API key",
243243
"form.integration.karakeep_url": "Karakeep API Endpoint",
244+
"form.integration.karakeep_tags": "Karakeep Labels",
244245
"form.integration.linkace_activate": "Save entries to LinkAce",
245246
"form.integration.linkace_api_key": "LinkAce API key",
246247
"form.integration.linkace_check_disabled": "Disable link check",

0 commit comments

Comments
 (0)