mirror of
https://github.com/miniflux/v2.git
synced 2025-08-26 18:21:01 +00:00
feat(integration): add LinkTaco service for saving articles
This commit is contained in:
parent
983291c78b
commit
4d656d2739
31 changed files with 939 additions and 5 deletions
|
@ -72,7 +72,7 @@ Features
|
||||||
|
|
||||||
### Integrations
|
### Integrations
|
||||||
|
|
||||||
- 25+ integrations with third-party services: [Apprise](https://github.com/caronc/apprise), [Betula](https://sr.ht/~bouncepaw/betula/), [Cubox](https://cubox.cc/), [Discord](https://discord.com/), [Espial](https://github.com/jonschoning/espial), [Instapaper](https://www.instapaper.com/), [LinkAce](https://www.linkace.org/), [Linkding](https://github.com/sissbruecker/linkding), [LinkWarden](https://linkwarden.app/), [Matrix](https://matrix.org), [Notion](https://www.notion.com/), [Ntfy](https://ntfy.sh/), [Nunux Keeper](https://keeper.nunux.org/), [Pinboard](https://pinboard.in/), [Pushover](https://pushover.net), [RainDrop](https://raindrop.io/), [Readeck](https://readeck.org/en/), [Readwise Reader](https://readwise.io/read), [RssBridge](https://rss-bridge.org/), [Shaarli](https://github.com/shaarli/Shaarli), [Shiori](https://github.com/go-shiori/shiori), [Slack](https://slack.com/), [Telegram](https://telegram.org), [Wallabag](https://www.wallabag.org/), etc.
|
- 25+ integrations with third-party services: [Apprise](https://github.com/caronc/apprise), [Betula](https://sr.ht/~bouncepaw/betula/), [Cubox](https://cubox.cc/), [Discord](https://discord.com/), [Espial](https://github.com/jonschoning/espial), [Instapaper](https://www.instapaper.com/), [LinkAce](https://www.linkace.org/), [Linkding](https://github.com/sissbruecker/linkding), [LinkTaco](https://linktaco.com), [LinkWarden](https://linkwarden.app/), [Matrix](https://matrix.org), [Notion](https://www.notion.com/), [Ntfy](https://ntfy.sh/), [Nunux Keeper](https://keeper.nunux.org/), [Pinboard](https://pinboard.in/), [Pushover](https://pushover.net), [RainDrop](https://raindrop.io/), [Readeck](https://readeck.org/en/), [Readwise Reader](https://readwise.io/read), [RssBridge](https://rss-bridge.org/), [Shaarli](https://github.com/shaarli/Shaarli), [Shiori](https://github.com/go-shiori/shiori), [Slack](https://slack.com/), [Telegram](https://telegram.org), [Wallabag](https://www.wallabag.org/), etc.
|
||||||
- Bookmarklet for subscribing to websites directly from any web browser.
|
- Bookmarklet for subscribing to websites directly from any web browser.
|
||||||
- Webhooks for real-time notifications or custom integrations.
|
- Webhooks for real-time notifications or custom integrations.
|
||||||
- Compatibility with existing mobile applications using the Fever or Google Reader API.
|
- Compatibility with existing mobile applications using the Fever or Google Reader API.
|
||||||
|
|
|
@ -1135,4 +1135,20 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
|
func(tx *sql.Tx) (err error) {
|
||||||
|
sql := `
|
||||||
|
CREATE TYPE linktaco_link_visibility AS ENUM (
|
||||||
|
'PUBLIC',
|
||||||
|
'PRIVATE'
|
||||||
|
);
|
||||||
|
ALTER TABLE integrations
|
||||||
|
ADD COLUMN linktaco_enabled bool default 'f',
|
||||||
|
ADD COLUMN linktaco_api_token text default '',
|
||||||
|
ADD COLUMN linktaco_org_slug text default '',
|
||||||
|
ADD COLUMN linktaco_tags text default '',
|
||||||
|
ADD COLUMN linktaco_visibility linktaco_link_visibility default 'PUBLIC';
|
||||||
|
`
|
||||||
|
_, err = tx.Exec(sql)
|
||||||
|
return err
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"miniflux.app/v2/internal/integration/karakeep"
|
"miniflux.app/v2/internal/integration/karakeep"
|
||||||
"miniflux.app/v2/internal/integration/linkace"
|
"miniflux.app/v2/internal/integration/linkace"
|
||||||
"miniflux.app/v2/internal/integration/linkding"
|
"miniflux.app/v2/internal/integration/linkding"
|
||||||
|
"miniflux.app/v2/internal/integration/linktaco"
|
||||||
"miniflux.app/v2/internal/integration/linkwarden"
|
"miniflux.app/v2/internal/integration/linkwarden"
|
||||||
"miniflux.app/v2/internal/integration/matrixbot"
|
"miniflux.app/v2/internal/integration/matrixbot"
|
||||||
"miniflux.app/v2/internal/integration/notion"
|
"miniflux.app/v2/internal/integration/notion"
|
||||||
|
@ -242,6 +243,29 @@ func SendEntry(entry *model.Entry, userIntegrations *model.Integration) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if userIntegrations.LinktacoEnabled {
|
||||||
|
slog.Debug("Sending entry to LinkTaco",
|
||||||
|
slog.Int64("user_id", userIntegrations.UserID),
|
||||||
|
slog.Int64("entry_id", entry.ID),
|
||||||
|
slog.String("entry_url", entry.URL),
|
||||||
|
)
|
||||||
|
|
||||||
|
client := linktaco.NewClient(
|
||||||
|
userIntegrations.LinktacoAPIToken,
|
||||||
|
userIntegrations.LinktacoOrgSlug,
|
||||||
|
userIntegrations.LinktacoTags,
|
||||||
|
userIntegrations.LinktacoVisibility,
|
||||||
|
)
|
||||||
|
if err := client.CreateBookmark(entry.URL, entry.Title, entry.Content); err != nil {
|
||||||
|
slog.Error("Unable to send entry to LinkTaco",
|
||||||
|
slog.Int64("user_id", userIntegrations.UserID),
|
||||||
|
slog.Int64("entry_id", entry.ID),
|
||||||
|
slog.String("entry_url", entry.URL),
|
||||||
|
slog.Any("error", err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if userIntegrations.LinkwardenEnabled {
|
if userIntegrations.LinkwardenEnabled {
|
||||||
slog.Debug("Sending entry to linkwarden",
|
slog.Debug("Sending entry to linkwarden",
|
||||||
slog.Int64("user_id", userIntegrations.UserID),
|
slog.Int64("user_id", userIntegrations.UserID),
|
||||||
|
|
146
internal/integration/linktaco/linktaco.go
Normal file
146
internal/integration/linktaco/linktaco.go
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package linktaco // import "miniflux.app/v2/internal/integration/linktaco"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"miniflux.app/v2/internal/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultClientTimeout = 10 * time.Second
|
||||||
|
defaultGraphQLURL = "https://api.linktaco.com/query"
|
||||||
|
maxTags = 10
|
||||||
|
maxDescriptionLength = 500
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
graphqlURL string
|
||||||
|
apiToken string
|
||||||
|
orgSlug string
|
||||||
|
tags string
|
||||||
|
visibility string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(apiToken, orgSlug, tags, visibility string) *Client {
|
||||||
|
if visibility == "" {
|
||||||
|
visibility = "PUBLIC"
|
||||||
|
}
|
||||||
|
return &Client{
|
||||||
|
graphqlURL: defaultGraphQLURL,
|
||||||
|
apiToken: apiToken,
|
||||||
|
orgSlug: orgSlug,
|
||||||
|
tags: tags,
|
||||||
|
visibility: visibility,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateBookmark(entryURL, entryTitle, entryContent string) error {
|
||||||
|
if c.apiToken == "" || c.orgSlug == "" {
|
||||||
|
return fmt.Errorf("linktaco: missing API token or organization slug")
|
||||||
|
}
|
||||||
|
|
||||||
|
description := entryContent
|
||||||
|
if len(description) > maxDescriptionLength {
|
||||||
|
description = description[:maxDescriptionLength]
|
||||||
|
}
|
||||||
|
|
||||||
|
// tags (limit to 10)
|
||||||
|
tags := strings.FieldsFunc(c.tags, func(c rune) bool {
|
||||||
|
return c == ',' || c == ' '
|
||||||
|
})
|
||||||
|
if len(tags) > maxTags {
|
||||||
|
tags = tags[:maxTags]
|
||||||
|
}
|
||||||
|
// tagsStr is used in GraphQL query to pass comma separated tags
|
||||||
|
tagsStr := strings.Join(tags, ",")
|
||||||
|
|
||||||
|
mutation := `
|
||||||
|
mutation AddLink($input: LinkInput!) {
|
||||||
|
addLink(input: $input) {
|
||||||
|
id
|
||||||
|
url
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
variables := map[string]any{
|
||||||
|
"input": map[string]any{
|
||||||
|
"url": entryURL,
|
||||||
|
"title": entryTitle,
|
||||||
|
"description": description,
|
||||||
|
"orgSlug": c.orgSlug,
|
||||||
|
"visibility": c.visibility,
|
||||||
|
"unread": true,
|
||||||
|
"starred": false,
|
||||||
|
"archive": false,
|
||||||
|
"tags": tagsStr,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
requestBody, err := json.Marshal(map[string]any{
|
||||||
|
"query": mutation,
|
||||||
|
"variables": variables,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("linktaco: unable to encode request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
request, err := http.NewRequest(http.MethodPost, c.graphqlURL, bytes.NewReader(requestBody))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("linktaco: unable to create request: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Header.Set("Content-Type", "application/json")
|
||||||
|
request.Header.Set("User-Agent", "Miniflux/"+version.Version)
|
||||||
|
request.Header.Set("Authorization", "Bearer "+c.apiToken)
|
||||||
|
|
||||||
|
httpClient := &http.Client{Timeout: defaultClientTimeout}
|
||||||
|
response, err := httpClient.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("linktaco: unable to send request: %v", err)
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
if response.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("linktaco: unable to create bookmark: status=%d", response.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
var graphqlResponse struct {
|
||||||
|
Data json.RawMessage `json:"data"`
|
||||||
|
Errors []json.RawMessage `json:"errors"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewDecoder(response.Body).Decode(&graphqlResponse); err != nil {
|
||||||
|
return fmt.Errorf("linktaco: unable to decode response: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(graphqlResponse.Errors) > 0 {
|
||||||
|
// Try to extract error message
|
||||||
|
var errorMsg string
|
||||||
|
for _, errJSON := range graphqlResponse.Errors {
|
||||||
|
var errObj struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
if json.Unmarshal(errJSON, &errObj) == nil && errObj.Message != "" {
|
||||||
|
errorMsg = errObj.Message
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if errorMsg == "" {
|
||||||
|
// Fallback. Should never be reached.
|
||||||
|
errorMsg = "GraphQL error occurred (fallback message)"
|
||||||
|
}
|
||||||
|
return fmt.Errorf("linktaco: %s", errorMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
440
internal/integration/linktaco/linktaco_test.go
Normal file
440
internal/integration/linktaco/linktaco_test.go
Normal file
|
@ -0,0 +1,440 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package linktaco
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateBookmark(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
apiToken string
|
||||||
|
orgSlug string
|
||||||
|
tags string
|
||||||
|
visibility string
|
||||||
|
entryURL string
|
||||||
|
entryTitle string
|
||||||
|
entryContent string
|
||||||
|
serverResponse func(w http.ResponseWriter, r *http.Request)
|
||||||
|
wantErr bool
|
||||||
|
errContains string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "successful bookmark creation",
|
||||||
|
apiToken: "test-token",
|
||||||
|
orgSlug: "test-org",
|
||||||
|
tags: "tag1, tag2",
|
||||||
|
visibility: "PUBLIC",
|
||||||
|
entryURL: "https://example.com",
|
||||||
|
entryTitle: "Test Article",
|
||||||
|
entryContent: "Test content",
|
||||||
|
serverResponse: func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Verify authorization header
|
||||||
|
auth := r.Header.Get("Authorization")
|
||||||
|
if auth != "Bearer test-token" {
|
||||||
|
t.Errorf("Expected Authorization header 'Bearer test-token', got %s", auth)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify content type
|
||||||
|
contentType := r.Header.Get("Content-Type")
|
||||||
|
if contentType != "application/json" {
|
||||||
|
t.Errorf("Expected Content-Type 'application/json', got %s", contentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse and verify request
|
||||||
|
body, _ := io.ReadAll(r.Body)
|
||||||
|
var req map[string]interface{}
|
||||||
|
if err := json.Unmarshal(body, &req); err != nil {
|
||||||
|
t.Errorf("Failed to parse request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify mutation exists
|
||||||
|
if _, ok := req["query"]; !ok {
|
||||||
|
t.Error("Missing 'query' field in request")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return success response
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
|
"data": map[string]interface{}{
|
||||||
|
"addLink": map[string]interface{}{
|
||||||
|
"id": "123",
|
||||||
|
"url": "https://example.com",
|
||||||
|
"title": "Test Article",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "missing API token",
|
||||||
|
apiToken: "",
|
||||||
|
orgSlug: "test-org",
|
||||||
|
entryURL: "https://example.com",
|
||||||
|
entryTitle: "Test",
|
||||||
|
entryContent: "Content",
|
||||||
|
serverResponse: func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Should not be called
|
||||||
|
t.Error("Server should not be called when API token is missing")
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
errContains: "missing API token or organization slug",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "missing organization slug",
|
||||||
|
apiToken: "test-token",
|
||||||
|
orgSlug: "",
|
||||||
|
entryURL: "https://example.com",
|
||||||
|
entryTitle: "Test",
|
||||||
|
entryContent: "Content",
|
||||||
|
serverResponse: func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Should not be called
|
||||||
|
t.Error("Server should not be called when org slug is missing")
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
errContains: "missing API token or organization slug",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "GraphQL error response",
|
||||||
|
apiToken: "test-token",
|
||||||
|
orgSlug: "test-org",
|
||||||
|
entryURL: "https://example.com",
|
||||||
|
entryTitle: "Test",
|
||||||
|
entryContent: "Content",
|
||||||
|
serverResponse: func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
|
"errors": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"message": "Invalid input",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
errContains: "Invalid input",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "HTTP error status",
|
||||||
|
apiToken: "test-token",
|
||||||
|
orgSlug: "test-org",
|
||||||
|
entryURL: "https://example.com",
|
||||||
|
entryTitle: "Test",
|
||||||
|
entryContent: "Content",
|
||||||
|
serverResponse: func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
errContains: "status=401",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "private visibility permission error",
|
||||||
|
apiToken: "test-token",
|
||||||
|
orgSlug: "test-org",
|
||||||
|
visibility: "PRIVATE",
|
||||||
|
entryURL: "https://example.com",
|
||||||
|
entryTitle: "Test",
|
||||||
|
entryContent: "Content",
|
||||||
|
serverResponse: func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
|
"errors": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"message": "PRIVATE visibility requires a paid LinkTaco account",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
errContains: "PRIVATE visibility requires a paid LinkTaco account",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "content truncation",
|
||||||
|
apiToken: "test-token",
|
||||||
|
orgSlug: "test-org",
|
||||||
|
entryURL: "https://example.com",
|
||||||
|
entryTitle: "Test",
|
||||||
|
entryContent: strings.Repeat("a", 600), // Content longer than 500 chars
|
||||||
|
serverResponse: func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, _ := io.ReadAll(r.Body)
|
||||||
|
var req map[string]interface{}
|
||||||
|
json.Unmarshal(body, &req)
|
||||||
|
|
||||||
|
// Check that description was truncated
|
||||||
|
variables := req["variables"].(map[string]interface{})
|
||||||
|
input := variables["input"].(map[string]interface{})
|
||||||
|
description := input["description"].(string)
|
||||||
|
|
||||||
|
if len(description) != maxDescriptionLength {
|
||||||
|
t.Errorf("Expected description length %d, got %d", maxDescriptionLength, len(description))
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
|
"data": map[string]interface{}{
|
||||||
|
"addLink": map[string]interface{}{"id": "123"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "tag limiting",
|
||||||
|
apiToken: "test-token",
|
||||||
|
orgSlug: "test-org",
|
||||||
|
tags: "tag1,tag2,tag3,tag4,tag5,tag6,tag7,tag8,tag9,tag10,tag11,tag12",
|
||||||
|
entryURL: "https://example.com",
|
||||||
|
entryTitle: "Test",
|
||||||
|
entryContent: "Content",
|
||||||
|
serverResponse: func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, _ := io.ReadAll(r.Body)
|
||||||
|
var req map[string]interface{}
|
||||||
|
json.Unmarshal(body, &req)
|
||||||
|
|
||||||
|
// Check that only 10 tags were sent
|
||||||
|
variables := req["variables"].(map[string]interface{})
|
||||||
|
input := variables["input"].(map[string]interface{})
|
||||||
|
tags := input["tags"].(string)
|
||||||
|
|
||||||
|
tagCount := len(strings.Split(tags, ","))
|
||||||
|
if tagCount != maxTags {
|
||||||
|
t.Errorf("Expected %d tags, got %d", maxTags, tagCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
|
"data": map[string]interface{}{
|
||||||
|
"addLink": map[string]interface{}{"id": "123"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid JSON response",
|
||||||
|
apiToken: "test-token",
|
||||||
|
orgSlug: "test-org",
|
||||||
|
entryURL: "https://example.com",
|
||||||
|
entryTitle: "Test",
|
||||||
|
entryContent: "Content",
|
||||||
|
serverResponse: func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write([]byte("invalid json"))
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
errContains: "unable to decode response",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
// Create test server if we have a server response function
|
||||||
|
var serverURL string
|
||||||
|
if tt.serverResponse != nil {
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(tt.serverResponse))
|
||||||
|
defer server.Close()
|
||||||
|
serverURL = server.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create client with test server URL
|
||||||
|
client := &Client{
|
||||||
|
graphqlURL: serverURL,
|
||||||
|
apiToken: tt.apiToken,
|
||||||
|
orgSlug: tt.orgSlug,
|
||||||
|
tags: tt.tags,
|
||||||
|
visibility: tt.visibility,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call CreateBookmark
|
||||||
|
err := client.CreateBookmark(tt.entryURL, tt.entryTitle, tt.entryContent)
|
||||||
|
|
||||||
|
// Check error expectations
|
||||||
|
if tt.wantErr {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected error but got none")
|
||||||
|
} else if tt.errContains != "" && !strings.Contains(err.Error(), tt.errContains) {
|
||||||
|
t.Errorf("Expected error containing '%s', got '%s'", tt.errContains, err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewClient(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
apiToken string
|
||||||
|
orgSlug string
|
||||||
|
tags string
|
||||||
|
visibility string
|
||||||
|
expectedVisibility string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "with all parameters",
|
||||||
|
apiToken: "token",
|
||||||
|
orgSlug: "org",
|
||||||
|
tags: "tag1,tag2",
|
||||||
|
visibility: "PRIVATE",
|
||||||
|
expectedVisibility: "PRIVATE",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty visibility defaults to PUBLIC",
|
||||||
|
apiToken: "token",
|
||||||
|
orgSlug: "org",
|
||||||
|
tags: "tag1",
|
||||||
|
visibility: "",
|
||||||
|
expectedVisibility: "PUBLIC",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
client := NewClient(tt.apiToken, tt.orgSlug, tt.tags, tt.visibility)
|
||||||
|
|
||||||
|
if client.apiToken != tt.apiToken {
|
||||||
|
t.Errorf("Expected apiToken %s, got %s", tt.apiToken, client.apiToken)
|
||||||
|
}
|
||||||
|
if client.orgSlug != tt.orgSlug {
|
||||||
|
t.Errorf("Expected orgSlug %s, got %s", tt.orgSlug, client.orgSlug)
|
||||||
|
}
|
||||||
|
if client.tags != tt.tags {
|
||||||
|
t.Errorf("Expected tags %s, got %s", tt.tags, client.tags)
|
||||||
|
}
|
||||||
|
if client.visibility != tt.expectedVisibility {
|
||||||
|
t.Errorf("Expected visibility %s, got %s", tt.expectedVisibility, client.visibility)
|
||||||
|
}
|
||||||
|
if client.graphqlURL != defaultGraphQLURL {
|
||||||
|
t.Errorf("Expected graphqlURL %s, got %s", defaultGraphQLURL, client.graphqlURL)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGraphQLMutation(t *testing.T) {
|
||||||
|
// Test that the GraphQL mutation is properly formatted
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, _ := io.ReadAll(r.Body)
|
||||||
|
var req map[string]interface{}
|
||||||
|
if err := json.Unmarshal(body, &req); err != nil {
|
||||||
|
t.Fatalf("Failed to parse request: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify mutation structure
|
||||||
|
query, ok := req["query"].(string)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Missing query field")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that mutation contains expected parts
|
||||||
|
if !strings.Contains(query, "mutation AddLink") {
|
||||||
|
t.Error("Mutation should contain 'mutation AddLink'")
|
||||||
|
}
|
||||||
|
if !strings.Contains(query, "$input: LinkInput!") {
|
||||||
|
t.Error("Mutation should contain input parameter")
|
||||||
|
}
|
||||||
|
if !strings.Contains(query, "addLink(input: $input)") {
|
||||||
|
t.Error("Mutation should contain addLink call")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify variables structure
|
||||||
|
variables, ok := req["variables"].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Missing variables field")
|
||||||
|
}
|
||||||
|
|
||||||
|
input, ok := variables["input"].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Missing input in variables")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check all required fields
|
||||||
|
requiredFields := []string{"url", "title", "description", "orgSlug", "visibility", "unread", "starred", "archive", "tags"}
|
||||||
|
for _, field := range requiredFields {
|
||||||
|
if _, ok := input[field]; !ok {
|
||||||
|
t.Errorf("Missing required field: %s", field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return success
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
|
"data": map[string]interface{}{
|
||||||
|
"addLink": map[string]interface{}{
|
||||||
|
"id": "123",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
client := &Client{
|
||||||
|
graphqlURL: server.URL,
|
||||||
|
apiToken: "test-token",
|
||||||
|
orgSlug: "test-org",
|
||||||
|
tags: "test",
|
||||||
|
visibility: "PUBLIC",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := client.CreateBookmark("https://example.com", "Test Title", "Test Content")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkCreateBookmark(b *testing.B) {
|
||||||
|
// Create a mock server that always returns success
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
|
"data": map[string]interface{}{
|
||||||
|
"addLink": map[string]interface{}{
|
||||||
|
"id": "123",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
client := &Client{
|
||||||
|
graphqlURL: server.URL,
|
||||||
|
apiToken: "test-token",
|
||||||
|
orgSlug: "test-org",
|
||||||
|
tags: "tag1,tag2,tag3",
|
||||||
|
visibility: "PUBLIC",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run benchmark
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = client.CreateBookmark("https://example.com", "Test Title", "Test Content")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkTagProcessing(b *testing.B) {
|
||||||
|
// Benchmark tag splitting and limiting
|
||||||
|
tags := "tag1,tag2,tag3,tag4,tag5,tag6,tag7,tag8,tag9,tag10,tag11,tag12,tag13,tag14,tag15"
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
tagsSplitFn := func(c rune) bool {
|
||||||
|
return c == ',' || c == ' '
|
||||||
|
}
|
||||||
|
splitTags := strings.FieldsFunc(tags, tagsSplitFn)
|
||||||
|
if len(splitTags) > maxTags {
|
||||||
|
splitTags = splitTags[:maxTags]
|
||||||
|
}
|
||||||
|
_ = strings.Join(splitTags, ",")
|
||||||
|
}
|
||||||
|
}
|
|
@ -160,6 +160,7 @@
|
||||||
"error.unlink_account_without_password": "Sie müssen ein Passwort festlegen, sonst können Sie sich nicht erneut anmelden.",
|
"error.unlink_account_without_password": "Sie müssen ein Passwort festlegen, sonst können Sie sich nicht erneut anmelden.",
|
||||||
"error.user_already_exists": "Dieser Benutzer existiert bereits.",
|
"error.user_already_exists": "Dieser Benutzer existiert bereits.",
|
||||||
"error.user_mandatory_fields": "Der Benutzername ist obligatorisch.",
|
"error.user_mandatory_fields": "Der Benutzername ist obligatorisch.",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token und Organization Slug sind erforderlich.",
|
||||||
"form.api_key.label.description": "API-Schlüsselbezeichnung",
|
"form.api_key.label.description": "API-Schlüsselbezeichnung",
|
||||||
"form.category.hide_globally": "Einträge in der globalen Ungelesen-Liste ausblenden",
|
"form.category.hide_globally": "Einträge in der globalen Ungelesen-Liste ausblenden",
|
||||||
"form.category.label.title": "Titel",
|
"form.category.label.title": "Titel",
|
||||||
|
@ -250,6 +251,16 @@
|
||||||
"form.integration.linkding_bookmark": "Lesezeichen als ungelesen markieren",
|
"form.integration.linkding_bookmark": "Lesezeichen als ungelesen markieren",
|
||||||
"form.integration.linkding_endpoint": "Linkding-API-Endpunkt",
|
"form.integration.linkding_endpoint": "Linkding-API-Endpunkt",
|
||||||
"form.integration.linkding_tags": "Linkding-Tags",
|
"form.integration.linkding_tags": "Linkding-Tags",
|
||||||
|
"form.integration.linktaco_activate": "Einträge in LinkTaco speichern",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Holen Sie sich Ihr persönliches Zugriffstoken unter",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "Tags (max. 10, kommagetrennt)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Maximal 10 Tags, kommagetrennt",
|
||||||
|
"form.integration.linktaco_visibility": "Sichtbarkeit",
|
||||||
|
"form.integration.linktaco_visibility_public": "Öffentlich",
|
||||||
|
"form.integration.linktaco_visibility_private": "Privat",
|
||||||
|
"form.integration.linktaco_visibility_hint": "PRIVATE Sichtbarkeit erfordert ein kostenpflichtiges LinkTaco-Konto",
|
||||||
"form.integration.linkwarden_activate": "Artikel in Linkwarden speichern",
|
"form.integration.linkwarden_activate": "Artikel in Linkwarden speichern",
|
||||||
"form.integration.linkwarden_api_key": "Linkwarden-API-Schlüssel",
|
"form.integration.linkwarden_api_key": "Linkwarden-API-Schlüssel",
|
||||||
"form.integration.linkwarden_endpoint": "Linkwarden-Base-URL",
|
"form.integration.linkwarden_endpoint": "Linkwarden-Base-URL",
|
||||||
|
|
|
@ -160,6 +160,7 @@
|
||||||
"error.unlink_account_without_password": "Πρέπει να ορίσετε έναν κωδικό πρόσβασης διαφορετικά δεν θα μπορείτε να συνδεθείτε ξανά.",
|
"error.unlink_account_without_password": "Πρέπει να ορίσετε έναν κωδικό πρόσβασης διαφορετικά δεν θα μπορείτε να συνδεθείτε ξανά.",
|
||||||
"error.user_already_exists": "Αυτός ο χρήστης υπάρχει ήδη.",
|
"error.user_already_exists": "Αυτός ο χρήστης υπάρχει ήδη.",
|
||||||
"error.user_mandatory_fields": "Το όνομα χρήστη είναι υποχρεωτικό.",
|
"error.user_mandatory_fields": "Το όνομα χρήστη είναι υποχρεωτικό.",
|
||||||
|
"error.linktaco_missing_required_fields": "Το LinkTaco API Token και το Organization Slug είναι απαραίτητα",
|
||||||
"form.api_key.label.description": "Ετικέτα κλειδιού API",
|
"form.api_key.label.description": "Ετικέτα κλειδιού API",
|
||||||
"form.category.hide_globally": "Απόκρυψη καταχωρήσεων σε γενική λίστα μη αναγνωσμένων",
|
"form.category.hide_globally": "Απόκρυψη καταχωρήσεων σε γενική λίστα μη αναγνωσμένων",
|
||||||
"form.category.label.title": "Τίτλος",
|
"form.category.label.title": "Τίτλος",
|
||||||
|
@ -250,6 +251,16 @@
|
||||||
"form.integration.linkding_bookmark": "Σημείωση του σελιδοδείκτη ως μη αναγνωσμένου",
|
"form.integration.linkding_bookmark": "Σημείωση του σελιδοδείκτη ως μη αναγνωσμένου",
|
||||||
"form.integration.linkding_endpoint": "Τελικό σημείο Linkding API",
|
"form.integration.linkding_endpoint": "Τελικό σημείο Linkding API",
|
||||||
"form.integration.linkding_tags": "Ετικέτες Linkding",
|
"form.integration.linkding_tags": "Ετικέτες Linkding",
|
||||||
|
"form.integration.linktaco_activate": "Αποθήκευση καταχωρήσεων στο LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Λάβετε το προσωπικό σας διακριτικό πρόσβασης στο",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "Ετικέτες (μέγιστο 10, διαχωρισμένες με κόμμα)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Μέγιστο 10 ετικέτες, διαχωρισμένες με κόμμα",
|
||||||
|
"form.integration.linktaco_visibility": "Ορατότητα",
|
||||||
|
"form.integration.linktaco_visibility_public": "Δημόσια",
|
||||||
|
"form.integration.linktaco_visibility_private": "Ιδιωτική",
|
||||||
|
"form.integration.linktaco_visibility_hint": "Η ΙΔΙΩΤΙΚΗ ορατότητα απαιτεί επί πληρωμή λογαριασμό LinkTaco",
|
||||||
"form.integration.linkwarden_activate": "Αποθήκευση άρθρων στο Linkwarden",
|
"form.integration.linkwarden_activate": "Αποθήκευση άρθρων στο Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "Κλειδί API Linkwarden",
|
"form.integration.linkwarden_api_key": "Κλειδί API Linkwarden",
|
||||||
"form.integration.linkwarden_endpoint": "URL βάσης Linkwarden",
|
"form.integration.linkwarden_endpoint": "URL βάσης Linkwarden",
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
"error.different_passwords": "Passwords are not the same.",
|
"error.different_passwords": "Passwords are not the same.",
|
||||||
"error.duplicate_fever_username": "There is already someone else with the same Fever username!",
|
"error.duplicate_fever_username": "There is already someone else with the same Fever username!",
|
||||||
"error.duplicate_googlereader_username": "There is already someone else with the same Google Reader username!",
|
"error.duplicate_googlereader_username": "There is already someone else with the same Google Reader username!",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token and Organization Slug are required",
|
||||||
"error.duplicate_linked_account": "There is already someone associated with this provider!",
|
"error.duplicate_linked_account": "There is already someone associated with this provider!",
|
||||||
"error.duplicated_feed": "This feed already exists.",
|
"error.duplicated_feed": "This feed already exists.",
|
||||||
"error.empty_file": "This file is empty.",
|
"error.empty_file": "This file is empty.",
|
||||||
|
@ -250,6 +251,16 @@
|
||||||
"form.integration.linkding_bookmark": "Mark bookmark as unread",
|
"form.integration.linkding_bookmark": "Mark bookmark as unread",
|
||||||
"form.integration.linkding_endpoint": "Linkding API Endpoint",
|
"form.integration.linkding_endpoint": "Linkding API Endpoint",
|
||||||
"form.integration.linkding_tags": "Linkding Tags",
|
"form.integration.linkding_tags": "Linkding Tags",
|
||||||
|
"form.integration.linktaco_activate": "Save entries to LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Get your personal access token at",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "Tags (max 10, comma-separated)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Maximum 10 tags, comma-separated",
|
||||||
|
"form.integration.linktaco_visibility": "Visibility",
|
||||||
|
"form.integration.linktaco_visibility_public": "Public",
|
||||||
|
"form.integration.linktaco_visibility_private": "Private",
|
||||||
|
"form.integration.linktaco_visibility_hint": "PRIVATE visibility requires a paid LinkTaco account",
|
||||||
"form.integration.linkwarden_activate": "Save entries to Linkwarden",
|
"form.integration.linkwarden_activate": "Save entries to Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "Linkwarden API key",
|
"form.integration.linkwarden_api_key": "Linkwarden API key",
|
||||||
"form.integration.linkwarden_endpoint": "Linkwarden Base URL",
|
"form.integration.linkwarden_endpoint": "Linkwarden Base URL",
|
||||||
|
|
|
@ -160,6 +160,7 @@
|
||||||
"error.unlink_account_without_password": "Debe definir una contraseña, de lo contrario no podrá volver a iniciar sesión.",
|
"error.unlink_account_without_password": "Debe definir una contraseña, de lo contrario no podrá volver a iniciar sesión.",
|
||||||
"error.user_already_exists": "Este usuario ya existe.",
|
"error.user_already_exists": "Este usuario ya existe.",
|
||||||
"error.user_mandatory_fields": "El nombre de usuario es obligatorio.",
|
"error.user_mandatory_fields": "El nombre de usuario es obligatorio.",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token y Organization Slug son obligatorios.",
|
||||||
"form.api_key.label.description": "Etiqueta de clave API",
|
"form.api_key.label.description": "Etiqueta de clave API",
|
||||||
"form.category.hide_globally": "Ocultar artículos en la lista global de no leídos",
|
"form.category.hide_globally": "Ocultar artículos en la lista global de no leídos",
|
||||||
"form.category.label.title": "Título",
|
"form.category.label.title": "Título",
|
||||||
|
@ -250,6 +251,16 @@
|
||||||
"form.integration.linkding_bookmark": "Marcar marcador como no leído",
|
"form.integration.linkding_bookmark": "Marcar marcador como no leído",
|
||||||
"form.integration.linkding_endpoint": "Acceso API de Linkding",
|
"form.integration.linkding_endpoint": "Acceso API de Linkding",
|
||||||
"form.integration.linkding_tags": "Etiquetas de Linkding",
|
"form.integration.linkding_tags": "Etiquetas de Linkding",
|
||||||
|
"form.integration.linktaco_activate": "Guardar entradas en LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Obtenga su token de acceso personal en",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "Etiquetas (máx. 10, separadas por comas)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Máximo 10 etiquetas, separadas por comas",
|
||||||
|
"form.integration.linktaco_visibility": "Visibilidad",
|
||||||
|
"form.integration.linktaco_visibility_public": "Público",
|
||||||
|
"form.integration.linktaco_visibility_private": "Privado",
|
||||||
|
"form.integration.linktaco_visibility_hint": "La visibilidad PRIVADA requiere una cuenta de pago de LinkTaco",
|
||||||
"form.integration.linkwarden_activate": "Enviar artículos a Linkwarden",
|
"form.integration.linkwarden_activate": "Enviar artículos a Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "Clave de API de Linkwarden",
|
"form.integration.linkwarden_api_key": "Clave de API de Linkwarden",
|
||||||
"form.integration.linkwarden_endpoint": "URL base de Linkwarden",
|
"form.integration.linkwarden_endpoint": "URL base de Linkwarden",
|
||||||
|
|
|
@ -160,6 +160,7 @@
|
||||||
"error.unlink_account_without_password": "Sinun on määritettävä salasana, muuten et voi kirjautua uudelleen.",
|
"error.unlink_account_without_password": "Sinun on määritettävä salasana, muuten et voi kirjautua uudelleen.",
|
||||||
"error.user_already_exists": "Käyttäjä on jo olemassa.",
|
"error.user_already_exists": "Käyttäjä on jo olemassa.",
|
||||||
"error.user_mandatory_fields": "Käyttäjätunnus on pakollinen.",
|
"error.user_mandatory_fields": "Käyttäjätunnus on pakollinen.",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token ja Organization Slug vaaditaan",
|
||||||
"form.api_key.label.description": "API Key Label",
|
"form.api_key.label.description": "API Key Label",
|
||||||
"form.category.hide_globally": "Piilota artikkelit lukemattomien listassa",
|
"form.category.hide_globally": "Piilota artikkelit lukemattomien listassa",
|
||||||
"form.category.label.title": "Otsikko",
|
"form.category.label.title": "Otsikko",
|
||||||
|
@ -250,6 +251,16 @@
|
||||||
"form.integration.linkding_bookmark": "Merkitse kirjanmerkki lukemattomaksi",
|
"form.integration.linkding_bookmark": "Merkitse kirjanmerkki lukemattomaksi",
|
||||||
"form.integration.linkding_endpoint": "Linkding API-päätepiste",
|
"form.integration.linkding_endpoint": "Linkding API-päätepiste",
|
||||||
"form.integration.linkding_tags": "Linkding Tags",
|
"form.integration.linkding_tags": "Linkding Tags",
|
||||||
|
"form.integration.linktaco_activate": "Tallenna kirjoituksia LinkTacoon",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Hanki henkilökohtainen pääsytunnistesi osoitteesta",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "Tagit (enintään 10, pilkuilla erotettu)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Enintään 10 tagia, pilkuilla erotettu",
|
||||||
|
"form.integration.linktaco_visibility": "Näkyvyys",
|
||||||
|
"form.integration.linktaco_visibility_public": "Julkinen",
|
||||||
|
"form.integration.linktaco_visibility_private": "Yksityinen",
|
||||||
|
"form.integration.linktaco_visibility_hint": "YKSITYINEN näkyvyys vaatii maksullisen LinkTaco-tilin",
|
||||||
"form.integration.linkwarden_activate": "Tallenna artikkelit Linkkiin",
|
"form.integration.linkwarden_activate": "Tallenna artikkelit Linkkiin",
|
||||||
"form.integration.linkwarden_api_key": "Linkwarden API-avain",
|
"form.integration.linkwarden_api_key": "Linkwarden API-avain",
|
||||||
"form.integration.linkwarden_endpoint": "Linkwarden Base URL",
|
"form.integration.linkwarden_endpoint": "Linkwarden Base URL",
|
||||||
|
|
|
@ -160,6 +160,7 @@
|
||||||
"error.unlink_account_without_password": "Vous devez définir un mot de passe sinon vous ne pourrez plus vous connecter par la suite.",
|
"error.unlink_account_without_password": "Vous devez définir un mot de passe sinon vous ne pourrez plus vous connecter par la suite.",
|
||||||
"error.user_already_exists": "Cet utilisateur existe déjà.",
|
"error.user_already_exists": "Cet utilisateur existe déjà.",
|
||||||
"error.user_mandatory_fields": "Le nom d'utilisateur est obligatoire.",
|
"error.user_mandatory_fields": "Le nom d'utilisateur est obligatoire.",
|
||||||
|
"error.linktaco_missing_required_fields": "Le token API LinkTaco et le slug de l'organisation sont requis.",
|
||||||
"form.api_key.label.description": "Libellé de la clé d'API",
|
"form.api_key.label.description": "Libellé de la clé d'API",
|
||||||
"form.category.hide_globally": "Masquer les entrées dans la liste globale non lue",
|
"form.category.hide_globally": "Masquer les entrées dans la liste globale non lue",
|
||||||
"form.category.label.title": "Titre",
|
"form.category.label.title": "Titre",
|
||||||
|
@ -250,6 +251,16 @@
|
||||||
"form.integration.linkding_bookmark": "Marquer le lien comme non lu",
|
"form.integration.linkding_bookmark": "Marquer le lien comme non lu",
|
||||||
"form.integration.linkding_endpoint": "URL de l'API de Linkding",
|
"form.integration.linkding_endpoint": "URL de l'API de Linkding",
|
||||||
"form.integration.linkding_tags": "Libellés",
|
"form.integration.linkding_tags": "Libellés",
|
||||||
|
"form.integration.linktaco_activate": "Sauvegarder les entrées vers LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token": "Token API LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Obtenez votre token d'accès personnel sur",
|
||||||
|
"form.integration.linktaco_org_slug": "Slug de l'organisation",
|
||||||
|
"form.integration.linktaco_tags": "Tags (max. 10, séparés par des virgules)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Maximum 10 tags, séparés par des virgules",
|
||||||
|
"form.integration.linktaco_visibility": "Visibilité",
|
||||||
|
"form.integration.linktaco_visibility_public": "Public",
|
||||||
|
"form.integration.linktaco_visibility_private": "Privé",
|
||||||
|
"form.integration.linktaco_visibility_hint": "La visibilité PRIVÉE nécessite un compte LinkTaco payant",
|
||||||
"form.integration.linkwarden_activate": "Sauvegarder les articles vers Linkwarden",
|
"form.integration.linkwarden_activate": "Sauvegarder les articles vers Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "Clé d'API de Linkwarden",
|
"form.integration.linkwarden_api_key": "Clé d'API de Linkwarden",
|
||||||
"form.integration.linkwarden_endpoint": "URL de base de Linkwarden",
|
"form.integration.linkwarden_endpoint": "URL de base de Linkwarden",
|
||||||
|
|
|
@ -160,6 +160,7 @@
|
||||||
"error.unlink_account_without_password": "आपको एक पासवर्ड परिभाषित करना होगा अन्यथा आप फिर से लॉगिन नहीं कर पाएंगे।",
|
"error.unlink_account_without_password": "आपको एक पासवर्ड परिभाषित करना होगा अन्यथा आप फिर से लॉगिन नहीं कर पाएंगे।",
|
||||||
"error.user_already_exists": "यह उपयोगकर्ता पहले से ही मौजूद है।",
|
"error.user_already_exists": "यह उपयोगकर्ता पहले से ही मौजूद है।",
|
||||||
"error.user_mandatory_fields": "उपयोगकर्ता नाम अनिवार्य है।",
|
"error.user_mandatory_fields": "उपयोगकर्ता नाम अनिवार्य है।",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token और Organization Slug आवश्यक हैं",
|
||||||
"form.api_key.label.description": "एपीआई कुंजी लेबल",
|
"form.api_key.label.description": "एपीआई कुंजी लेबल",
|
||||||
"form.category.hide_globally": "वैश्विक अपठित सूची में प्रविष्टियां छिपाएं",
|
"form.category.hide_globally": "वैश्विक अपठित सूची में प्रविष्टियां छिपाएं",
|
||||||
"form.category.label.title": "शीर्षक",
|
"form.category.label.title": "शीर्षक",
|
||||||
|
@ -250,6 +251,16 @@
|
||||||
"form.integration.linkding_bookmark": "बुकमार्क को अपठित के रूप में चिह्नित करें",
|
"form.integration.linkding_bookmark": "बुकमार्क को अपठित के रूप में चिह्नित करें",
|
||||||
"form.integration.linkding_endpoint": "लिंकिंग एपीआई समापन बिंदु",
|
"form.integration.linkding_endpoint": "लिंकिंग एपीआई समापन बिंदु",
|
||||||
"form.integration.linkding_tags": "Linkding Tags",
|
"form.integration.linkding_tags": "Linkding Tags",
|
||||||
|
"form.integration.linktaco_activate": "LinkTaco में प्रविष्टियाँ सहेजें",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "अपना व्यक्तिगत पहुँच टोकन प्राप्त करें",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "टैग (अधिकतम 10, कॉमा से अलग किए गए)",
|
||||||
|
"form.integration.linktaco_tags_hint": "अधिकतम 10 टैग, कॉमा से अलग किए गए",
|
||||||
|
"form.integration.linktaco_visibility": "दृश्यता",
|
||||||
|
"form.integration.linktaco_visibility_public": "सार्वजनिक",
|
||||||
|
"form.integration.linktaco_visibility_private": "निजी",
|
||||||
|
"form.integration.linktaco_visibility_hint": "निजी दृश्यता के लिए भुगतान LinkTaco खाता आवश्यक है",
|
||||||
"form.integration.linkwarden_activate": "Save entries to Linkwarden",
|
"form.integration.linkwarden_activate": "Save entries to Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "Linkwarden API key",
|
"form.integration.linkwarden_api_key": "Linkwarden API key",
|
||||||
"form.integration.linkwarden_endpoint": "लिंकवर्डन बेस यूआरएलL",
|
"form.integration.linkwarden_endpoint": "लिंकवर्डन बेस यूआरएलL",
|
||||||
|
|
|
@ -157,6 +157,7 @@
|
||||||
"error.unlink_account_without_password": "Anda harus mengatur kata sandi atau Anda tidak bisa masuk kembali.",
|
"error.unlink_account_without_password": "Anda harus mengatur kata sandi atau Anda tidak bisa masuk kembali.",
|
||||||
"error.user_already_exists": "Pengguna ini sudah ada.",
|
"error.user_already_exists": "Pengguna ini sudah ada.",
|
||||||
"error.user_mandatory_fields": "Harus ada nama pengguna.",
|
"error.user_mandatory_fields": "Harus ada nama pengguna.",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token dan Organization Slug diperlukan",
|
||||||
"form.api_key.label.description": "Label Kunci API",
|
"form.api_key.label.description": "Label Kunci API",
|
||||||
"form.category.hide_globally": "Sembunyikan entri di daftar belum dibaca global",
|
"form.category.hide_globally": "Sembunyikan entri di daftar belum dibaca global",
|
||||||
"form.category.label.title": "Judul",
|
"form.category.label.title": "Judul",
|
||||||
|
@ -247,6 +248,16 @@
|
||||||
"form.integration.linkding_bookmark": "Tandai markah sebagai belum dibaca",
|
"form.integration.linkding_bookmark": "Tandai markah sebagai belum dibaca",
|
||||||
"form.integration.linkding_endpoint": "Titik URL API Linkding",
|
"form.integration.linkding_endpoint": "Titik URL API Linkding",
|
||||||
"form.integration.linkding_tags": "Tanda Linkding",
|
"form.integration.linkding_tags": "Tanda Linkding",
|
||||||
|
"form.integration.linktaco_activate": "Simpan entri ke LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Dapatkan token akses pribadi Anda di",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "Tag (maksimal 10, dipisahkan koma)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Maksimal 10 tag, dipisahkan koma",
|
||||||
|
"form.integration.linktaco_visibility": "Visibilitas",
|
||||||
|
"form.integration.linktaco_visibility_public": "Publik",
|
||||||
|
"form.integration.linktaco_visibility_private": "Pribadi",
|
||||||
|
"form.integration.linktaco_visibility_hint": "Visibilitas PRIBADI membutuhkan akun LinkTaco berbayar",
|
||||||
"form.integration.linkwarden_activate": "Simpan artikel ke Linkwarden",
|
"form.integration.linkwarden_activate": "Simpan artikel ke Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "Kunci API Linkwarden",
|
"form.integration.linkwarden_api_key": "Kunci API Linkwarden",
|
||||||
"form.integration.linkwarden_endpoint": "URL Dasar Linkwarden",
|
"form.integration.linkwarden_endpoint": "URL Dasar Linkwarden",
|
||||||
|
|
|
@ -160,6 +160,7 @@
|
||||||
"error.unlink_account_without_password": "Devi scegliere una password altrimenti la prossima volta non riuscirai ad accedere.",
|
"error.unlink_account_without_password": "Devi scegliere una password altrimenti la prossima volta non riuscirai ad accedere.",
|
||||||
"error.user_already_exists": "Questo utente esiste già.",
|
"error.user_already_exists": "Questo utente esiste già.",
|
||||||
"error.user_mandatory_fields": "Il nome utente è obbligatorio.",
|
"error.user_mandatory_fields": "Il nome utente è obbligatorio.",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token e Organization Slug sono richiesti",
|
||||||
"form.api_key.label.description": "Etichetta chiave API",
|
"form.api_key.label.description": "Etichetta chiave API",
|
||||||
"form.category.hide_globally": "Nascondere le voci nella lista globale dei non letti",
|
"form.category.hide_globally": "Nascondere le voci nella lista globale dei non letti",
|
||||||
"form.category.label.title": "Titolo",
|
"form.category.label.title": "Titolo",
|
||||||
|
@ -250,6 +251,16 @@
|
||||||
"form.integration.linkding_bookmark": "Segna i preferiti come non letti",
|
"form.integration.linkding_bookmark": "Segna i preferiti come non letti",
|
||||||
"form.integration.linkding_endpoint": "Endpoint dell'API di Linkding",
|
"form.integration.linkding_endpoint": "Endpoint dell'API di Linkding",
|
||||||
"form.integration.linkding_tags": "Linkding Tags",
|
"form.integration.linkding_tags": "Linkding Tags",
|
||||||
|
"form.integration.linktaco_activate": "Salva le voci in LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Ottieni il tuo token di accesso personale su",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "Tag (massimo 10, separati da virgola)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Massimo 10 tag, separati da virgola",
|
||||||
|
"form.integration.linktaco_visibility": "Visibilità",
|
||||||
|
"form.integration.linktaco_visibility_public": "Pubblico",
|
||||||
|
"form.integration.linktaco_visibility_private": "Privato",
|
||||||
|
"form.integration.linktaco_visibility_hint": "La visibilità PRIVATA richiede un account LinkTaco a pagamento",
|
||||||
"form.integration.linkwarden_activate": "Salva gli articoli su Linkwarden",
|
"form.integration.linkwarden_activate": "Salva gli articoli su Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "API key dell'account Linkwarden",
|
"form.integration.linkwarden_api_key": "API key dell'account Linkwarden",
|
||||||
"form.integration.linkwarden_endpoint": "URL di base di Linkwarden",
|
"form.integration.linkwarden_endpoint": "URL di base di Linkwarden",
|
||||||
|
|
|
@ -157,6 +157,7 @@
|
||||||
"error.unlink_account_without_password": "パスワードを設定しなければ再びログインすることはできません。",
|
"error.unlink_account_without_password": "パスワードを設定しなければ再びログインすることはできません。",
|
||||||
"error.user_already_exists": "このユーザーは既に存在します。",
|
"error.user_already_exists": "このユーザーは既に存在します。",
|
||||||
"error.user_mandatory_fields": "ユーザー名が必要です。",
|
"error.user_mandatory_fields": "ユーザー名が必要です。",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API TokenとOrganization Slugが必要です",
|
||||||
"form.api_key.label.description": "API キーラベル",
|
"form.api_key.label.description": "API キーラベル",
|
||||||
"form.category.hide_globally": "未読一覧に記事を表示しない",
|
"form.category.hide_globally": "未読一覧に記事を表示しない",
|
||||||
"form.category.label.title": "タイトル",
|
"form.category.label.title": "タイトル",
|
||||||
|
@ -247,6 +248,16 @@
|
||||||
"form.integration.linkding_bookmark": "ブックマークを未読にする",
|
"form.integration.linkding_bookmark": "ブックマークを未読にする",
|
||||||
"form.integration.linkding_endpoint": "Linkding の API Endpoint",
|
"form.integration.linkding_endpoint": "Linkding の API Endpoint",
|
||||||
"form.integration.linkding_tags": "Linkding Tags",
|
"form.integration.linkding_tags": "Linkding Tags",
|
||||||
|
"form.integration.linktaco_activate": "LinkTacoでエントリを保存する",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "パーソナルアクセストークンを取得する",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "タグ (最大10件、カンマ区切り)",
|
||||||
|
"form.integration.linktaco_tags_hint": "最大10件のタグ、カンマ区切り",
|
||||||
|
"form.integration.linktaco_visibility": "公開設定",
|
||||||
|
"form.integration.linktaco_visibility_public": "公開",
|
||||||
|
"form.integration.linktaco_visibility_private": "非公開",
|
||||||
|
"form.integration.linktaco_visibility_hint": "非公開設定には有料のLinkTacoアカウントが必要です",
|
||||||
"form.integration.linkwarden_activate": "Linkwarden に記事を保存する",
|
"form.integration.linkwarden_activate": "Linkwarden に記事を保存する",
|
||||||
"form.integration.linkwarden_api_key": "Linkwarden の API key",
|
"form.integration.linkwarden_api_key": "Linkwarden の API key",
|
||||||
"form.integration.linkwarden_endpoint": "リンクワーデン ベース URL",
|
"form.integration.linkwarden_endpoint": "リンクワーデン ベース URL",
|
||||||
|
|
|
@ -157,6 +157,7 @@
|
||||||
"error.unlink_account_without_password": "Lí it-tēng ài siat-tēng bi̍t-bé, bô lí ē bô-hoat-tō͘ koh teng-lo̍k.",
|
"error.unlink_account_without_password": "Lí it-tēng ài siat-tēng bi̍t-bé, bô lí ē bô-hoat-tō͘ koh teng-lo̍k.",
|
||||||
"error.user_already_exists": "Chit ê sú-iōng-lâng í-keng chûn-chāi.",
|
"error.user_already_exists": "Chit ê sú-iōng-lâng í-keng chûn-chāi.",
|
||||||
"error.user_mandatory_fields": "Tio̍h-ài su-li̍p kháu-chō miâ",
|
"error.user_mandatory_fields": "Tio̍h-ài su-li̍p kháu-chō miâ",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token kâh Organization Slug sio̍kêi",
|
||||||
"form.api_key.label.description": "API só-sîkhan-á",
|
"form.api_key.label.description": "API só-sîkhan-á",
|
||||||
"form.category.hide_globally": "Mài hián-sī siau-sit tī choân-he̍k ah-bōe tha̍k lia̍t-pió lāi",
|
"form.category.hide_globally": "Mài hián-sī siau-sit tī choân-he̍k ah-bōe tha̍k lia̍t-pió lāi",
|
||||||
"form.category.label.title": "Piau-tôe",
|
"form.category.label.title": "Piau-tôe",
|
||||||
|
@ -247,6 +248,16 @@
|
||||||
"form.integration.linkding_bookmark": "Chù chòe ah-bōe tha̍k",
|
"form.integration.linkding_bookmark": "Chù chòe ah-bōe tha̍k",
|
||||||
"form.integration.linkding_endpoint": "Linkding API thâu",
|
"form.integration.linkding_endpoint": "Linkding API thâu",
|
||||||
"form.integration.linkding_tags": "Linkding khan-á",
|
"form.integration.linkding_tags": "Linkding khan-á",
|
||||||
|
"form.integration.linktaco_activate": "Pó-chûn siau-sit kàu LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Chhú-tek lí ê kò-jîn chún-chhú token tī",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "khan-á (siōn-koân 10, iōng tō͘-tiám keh khui)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Siōn-koân 10 khan-á, iōng tō͘-tiám keh khui",
|
||||||
|
"form.integration.linktaco_visibility": "Kò-chhiah-kì sìa?",
|
||||||
|
"form.integration.linktaco_visibility_public": "Kò-chhiah-kì",
|
||||||
|
"form.integration.linktaco_visibility_private": "Su-lîn",
|
||||||
|
"form.integration.linktaco_visibility_hint": "Su-lîn sìa tík tio̍h-ài chù-hêng LinkTaco kháu-chō",
|
||||||
"form.integration.linkwarden_activate": "Pó-chûn siau-sit kàu Linkwarden",
|
"form.integration.linkwarden_activate": "Pó-chûn siau-sit kàu Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "Linkwarden API só-sî",
|
"form.integration.linkwarden_api_key": "Linkwarden API só-sî",
|
||||||
"form.integration.linkwarden_endpoint": "Linkwarden Base URL",
|
"form.integration.linkwarden_endpoint": "Linkwarden Base URL",
|
||||||
|
|
|
@ -160,6 +160,7 @@
|
||||||
"error.unlink_account_without_password": "Je moet een wachtwoord opgeven anders kun je niet meer inloggen.",
|
"error.unlink_account_without_password": "Je moet een wachtwoord opgeven anders kun je niet meer inloggen.",
|
||||||
"error.user_already_exists": "Deze gebruiker bestaat al.",
|
"error.user_already_exists": "Deze gebruiker bestaat al.",
|
||||||
"error.user_mandatory_fields": "Gebruikersnaam is verplicht",
|
"error.user_mandatory_fields": "Gebruikersnaam is verplicht",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token en Organization Slug zijn verplicht",
|
||||||
"form.api_key.label.description": "API-sleutel omschrijving",
|
"form.api_key.label.description": "API-sleutel omschrijving",
|
||||||
"form.category.hide_globally": "Verberg artikelen in de globale ongelezen lijst",
|
"form.category.hide_globally": "Verberg artikelen in de globale ongelezen lijst",
|
||||||
"form.category.label.title": "Titel",
|
"form.category.label.title": "Titel",
|
||||||
|
@ -250,6 +251,16 @@
|
||||||
"form.integration.linkding_bookmark": "Markeer favoriet als ongelezen",
|
"form.integration.linkding_bookmark": "Markeer favoriet als ongelezen",
|
||||||
"form.integration.linkding_endpoint": "Linkding URL",
|
"form.integration.linkding_endpoint": "Linkding URL",
|
||||||
"form.integration.linkding_tags": "Linkding tags",
|
"form.integration.linkding_tags": "Linkding tags",
|
||||||
|
"form.integration.linktaco_activate": "Artikelen opslaan in LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Verkrijg uw persoonlijke toegangstoken op",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "Tags (max 10, kommagescheiden)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Maximaal 10 tags, kommagescheiden",
|
||||||
|
"form.integration.linktaco_visibility": "Zichtbaarheid",
|
||||||
|
"form.integration.linktaco_visibility_public": "Openbaar",
|
||||||
|
"form.integration.linktaco_visibility_private": "Privé",
|
||||||
|
"form.integration.linktaco_visibility_hint": "PRIVÉ zichtbaarheid vereist een betaald LinkTaco account",
|
||||||
"form.integration.linkwarden_activate": "Artikelen opslaan in Linkwarden",
|
"form.integration.linkwarden_activate": "Artikelen opslaan in Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "Linkwarden API-sleutel",
|
"form.integration.linkwarden_api_key": "Linkwarden API-sleutel",
|
||||||
"form.integration.linkwarden_endpoint": "Linkwarden Basis URL",
|
"form.integration.linkwarden_endpoint": "Linkwarden Basis URL",
|
||||||
|
|
|
@ -163,6 +163,7 @@
|
||||||
"error.unlink_account_without_password": "Musisz zdefiniować hasło, inaczej nie będziesz mógł się ponownie zalogować.",
|
"error.unlink_account_without_password": "Musisz zdefiniować hasło, inaczej nie będziesz mógł się ponownie zalogować.",
|
||||||
"error.user_already_exists": "Ten użytkownik już istnieje.",
|
"error.user_already_exists": "Ten użytkownik już istnieje.",
|
||||||
"error.user_mandatory_fields": "Nazwa użytkownika jest obowiązkowa.",
|
"error.user_mandatory_fields": "Nazwa użytkownika jest obowiązkowa.",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token i Organization Slug są wymagane",
|
||||||
"form.api_key.label.description": "Etykieta klucza API",
|
"form.api_key.label.description": "Etykieta klucza API",
|
||||||
"form.category.hide_globally": "Ukryj wpisy na globalnej liście nieprzeczytanych",
|
"form.category.hide_globally": "Ukryj wpisy na globalnej liście nieprzeczytanych",
|
||||||
"form.category.label.title": "Tytuł",
|
"form.category.label.title": "Tytuł",
|
||||||
|
@ -253,6 +254,16 @@
|
||||||
"form.integration.linkding_bookmark": "Oznacz zakładkę jako nieprzeczytaną",
|
"form.integration.linkding_bookmark": "Oznacz zakładkę jako nieprzeczytaną",
|
||||||
"form.integration.linkding_endpoint": "Punkt końcowy API Linkding",
|
"form.integration.linkding_endpoint": "Punkt końcowy API Linkding",
|
||||||
"form.integration.linkding_tags": "Znaczniki Linkding",
|
"form.integration.linkding_tags": "Znaczniki Linkding",
|
||||||
|
"form.integration.linktaco_activate": "Zapisuj wpisy w LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Uzyskaj swój osobisty token dostępu w",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "Znaczniki (max 10, oddzielone przecinkami)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Maksymalnie 10 znaczników, oddzielone przecinkami",
|
||||||
|
"form.integration.linktaco_visibility": "Widoczność",
|
||||||
|
"form.integration.linktaco_visibility_public": "Publiczne",
|
||||||
|
"form.integration.linktaco_visibility_private": "Prywatne",
|
||||||
|
"form.integration.linktaco_visibility_hint": "Widoczność PRYWATNA wymaga płatnego konta LinkTaco",
|
||||||
"form.integration.linkwarden_activate": "Zapisuj wpisy w Linkwarden",
|
"form.integration.linkwarden_activate": "Zapisuj wpisy w Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "Klucz API do Linkwarden",
|
"form.integration.linkwarden_api_key": "Klucz API do Linkwarden",
|
||||||
"form.integration.linkwarden_endpoint": "Podstawowy adres URL Linkwardena",
|
"form.integration.linkwarden_endpoint": "Podstawowy adres URL Linkwardena",
|
||||||
|
|
|
@ -160,6 +160,7 @@
|
||||||
"error.unlink_account_without_password": "Você deve definir uma senha, senão não será possível efetuar a sessão novamente.",
|
"error.unlink_account_without_password": "Você deve definir uma senha, senão não será possível efetuar a sessão novamente.",
|
||||||
"error.user_already_exists": "Esse usuário já existe.",
|
"error.user_already_exists": "Esse usuário já existe.",
|
||||||
"error.user_mandatory_fields": "O nome de usuário é obrigatório.",
|
"error.user_mandatory_fields": "O nome de usuário é obrigatório.",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token e Organization Slug são obrigatórios",
|
||||||
"form.api_key.label.description": "Etiqueta da chave de API",
|
"form.api_key.label.description": "Etiqueta da chave de API",
|
||||||
"form.category.hide_globally": "Ocultar entradas na lista global não lida",
|
"form.category.hide_globally": "Ocultar entradas na lista global não lida",
|
||||||
"form.category.label.title": "Título",
|
"form.category.label.title": "Título",
|
||||||
|
@ -250,6 +251,16 @@
|
||||||
"form.integration.linkding_bookmark": "Salvar marcador como não lido",
|
"form.integration.linkding_bookmark": "Salvar marcador como não lido",
|
||||||
"form.integration.linkding_endpoint": "Endpoint de API do Linkding",
|
"form.integration.linkding_endpoint": "Endpoint de API do Linkding",
|
||||||
"form.integration.linkding_tags": "Linkding Tags",
|
"form.integration.linkding_tags": "Linkding Tags",
|
||||||
|
"form.integration.linktaco_activate": "Salvar itens no LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Obtenha seu token de acesso pessoal em",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "Tags (máx 10, separadas por vírgula)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Máximo 10 tags, separadas por vírgula",
|
||||||
|
"form.integration.linktaco_visibility": "Visibilidade",
|
||||||
|
"form.integration.linktaco_visibility_public": "Público",
|
||||||
|
"form.integration.linktaco_visibility_private": "Privado",
|
||||||
|
"form.integration.linktaco_visibility_hint": "Visibilidade PRIVADA requer uma conta LinkTaco paga",
|
||||||
"form.integration.linkwarden_activate": "Salvar itens no Linkwarden",
|
"form.integration.linkwarden_activate": "Salvar itens no Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "Chave de API do Linkwarden",
|
"form.integration.linkwarden_api_key": "Chave de API do Linkwarden",
|
||||||
"form.integration.linkwarden_endpoint": "URL base do Linkwarden",
|
"form.integration.linkwarden_endpoint": "URL base do Linkwarden",
|
||||||
|
|
|
@ -163,6 +163,7 @@
|
||||||
"error.unlink_account_without_password": "Trebuie să definiți o parolă, altfel nu vă veți mai putea conecta.",
|
"error.unlink_account_without_password": "Trebuie să definiți o parolă, altfel nu vă veți mai putea conecta.",
|
||||||
"error.user_already_exists": "Acest utilizator există deja.",
|
"error.user_already_exists": "Acest utilizator există deja.",
|
||||||
"error.user_mandatory_fields": "Numele utilizatorului este obligatoriu.",
|
"error.user_mandatory_fields": "Numele utilizatorului este obligatoriu.",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token și Organization Slug sunt necesare",
|
||||||
"form.api_key.label.description": "Etichetă Cheie API",
|
"form.api_key.label.description": "Etichetă Cheie API",
|
||||||
"form.category.hide_globally": "Ascunde intrările în lista globală de articole necitite",
|
"form.category.hide_globally": "Ascunde intrările în lista globală de articole necitite",
|
||||||
"form.category.label.title": "Titlu",
|
"form.category.label.title": "Titlu",
|
||||||
|
@ -253,6 +254,16 @@
|
||||||
"form.integration.linkding_bookmark": "Marchează semnele de carte ca necitite",
|
"form.integration.linkding_bookmark": "Marchează semnele de carte ca necitite",
|
||||||
"form.integration.linkding_endpoint": "Endpoint API Linkding",
|
"form.integration.linkding_endpoint": "Endpoint API Linkding",
|
||||||
"form.integration.linkding_tags": "TAG-uri Linkding",
|
"form.integration.linkding_tags": "TAG-uri Linkding",
|
||||||
|
"form.integration.linktaco_activate": "Salvează înregistrările în LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Obțineți jetonul de acces personal la",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "Tag-uri (maxim 10, separate prin virgule)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Maxim 10 tag-uri, separate prin virgule",
|
||||||
|
"form.integration.linktaco_visibility": "Vizibilitate",
|
||||||
|
"form.integration.linktaco_visibility_public": "Public",
|
||||||
|
"form.integration.linktaco_visibility_private": "Privat",
|
||||||
|
"form.integration.linktaco_visibility_hint": "Vizibilitatea PRIVATĂ necesită un cont LinkTaco plătit",
|
||||||
"form.integration.linkwarden_activate": "Salvează intrările în Linkwarden",
|
"form.integration.linkwarden_activate": "Salvează intrările în Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "Cheie API Linkwarden",
|
"form.integration.linkwarden_api_key": "Cheie API Linkwarden",
|
||||||
"form.integration.linkwarden_endpoint": "URL-ul de bază Linkwarden",
|
"form.integration.linkwarden_endpoint": "URL-ul de bază Linkwarden",
|
||||||
|
|
|
@ -163,6 +163,7 @@
|
||||||
"error.unlink_account_without_password": "Вы должны установить пароль, иначе вы не сможете войти снова.",
|
"error.unlink_account_without_password": "Вы должны установить пароль, иначе вы не сможете войти снова.",
|
||||||
"error.user_already_exists": "Этот пользователь уже существует.",
|
"error.user_already_exists": "Этот пользователь уже существует.",
|
||||||
"error.user_mandatory_fields": "Имя пользователя обязательно.",
|
"error.user_mandatory_fields": "Имя пользователя обязательно.",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token и Organization Slug обязательны",
|
||||||
"form.api_key.label.description": "Описание API-ключа",
|
"form.api_key.label.description": "Описание API-ключа",
|
||||||
"form.category.hide_globally": "Скрыть записи в глобальном списке непрочитанных",
|
"form.category.hide_globally": "Скрыть записи в глобальном списке непрочитанных",
|
||||||
"form.category.label.title": "Название",
|
"form.category.label.title": "Название",
|
||||||
|
@ -253,6 +254,16 @@
|
||||||
"form.integration.linkding_bookmark": "Помечать закладки как непрочитанное",
|
"form.integration.linkding_bookmark": "Помечать закладки как непрочитанное",
|
||||||
"form.integration.linkding_endpoint": "Конечная точка Linkding API",
|
"form.integration.linkding_endpoint": "Конечная точка Linkding API",
|
||||||
"form.integration.linkding_tags": "Теги Linkding",
|
"form.integration.linkding_tags": "Теги Linkding",
|
||||||
|
"form.integration.linktaco_activate": "Сохранять статьи в LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Получить ваш персональный токен доступа на",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "Теги (макс. 10, через запятую)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Максимум 10 тегов, через запятую",
|
||||||
|
"form.integration.linktaco_visibility": "Видимость",
|
||||||
|
"form.integration.linktaco_visibility_public": "Публично",
|
||||||
|
"form.integration.linktaco_visibility_private": "Приватно",
|
||||||
|
"form.integration.linktaco_visibility_hint": "ПРИВАТНАЯ видимость требует платного аккаунта LinkTaco",
|
||||||
"form.integration.linkwarden_activate": "Сохранять статьи в Linkwarden",
|
"form.integration.linkwarden_activate": "Сохранять статьи в Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "API-ключ Linkwarden",
|
"form.integration.linkwarden_api_key": "API-ключ Linkwarden",
|
||||||
"form.integration.linkwarden_endpoint": "Базовый URL-адрес Linkwarden",
|
"form.integration.linkwarden_endpoint": "Базовый URL-адрес Linkwarden",
|
||||||
|
|
|
@ -160,6 +160,7 @@
|
||||||
"error.unlink_account_without_password": "Bir şifre belirlemelisiniz, aksi takdirde tekrar oturum açamazsınız.",
|
"error.unlink_account_without_password": "Bir şifre belirlemelisiniz, aksi takdirde tekrar oturum açamazsınız.",
|
||||||
"error.user_already_exists": "Bu kullanıcı zaten mevcut.",
|
"error.user_already_exists": "Bu kullanıcı zaten mevcut.",
|
||||||
"error.user_mandatory_fields": "Kullanıcı adı zorunlu.",
|
"error.user_mandatory_fields": "Kullanıcı adı zorunlu.",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token ve Organization Slug gereklidir",
|
||||||
"form.api_key.label.description": "API Anahtar Etiketi",
|
"form.api_key.label.description": "API Anahtar Etiketi",
|
||||||
"form.category.hide_globally": "Genel okunmamış listesindeki girişleri gizle",
|
"form.category.hide_globally": "Genel okunmamış listesindeki girişleri gizle",
|
||||||
"form.category.label.title": "Başlık",
|
"form.category.label.title": "Başlık",
|
||||||
|
@ -250,6 +251,16 @@
|
||||||
"form.integration.linkding_bookmark": "Yer imini okunmadı olarak işaretle",
|
"form.integration.linkding_bookmark": "Yer imini okunmadı olarak işaretle",
|
||||||
"form.integration.linkding_endpoint": "Linkding API Uç Noktası",
|
"form.integration.linkding_endpoint": "Linkding API Uç Noktası",
|
||||||
"form.integration.linkding_tags": "Linkding Etiketleri",
|
"form.integration.linkding_tags": "Linkding Etiketleri",
|
||||||
|
"form.integration.linktaco_activate": "Makaleleri LinkTaco'ya kaydet",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Kişisel erişim tokenınızı edinin",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "Etiketler (maks 10, virgülle ayrılmış)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Maksimum 10 etiket, virgülle ayrılmış",
|
||||||
|
"form.integration.linktaco_visibility": "Görünürlük",
|
||||||
|
"form.integration.linktaco_visibility_public": "Genel",
|
||||||
|
"form.integration.linktaco_visibility_private": "Özel",
|
||||||
|
"form.integration.linktaco_visibility_hint": "ÖZEL görünürlük ücretli bir LinkTaco hesabı gerektirir",
|
||||||
"form.integration.linkwarden_activate": "Makaleleri Linkwarden'e kaydet",
|
"form.integration.linkwarden_activate": "Makaleleri Linkwarden'e kaydet",
|
||||||
"form.integration.linkwarden_api_key": "Linkwarden API Anahtarı",
|
"form.integration.linkwarden_api_key": "Linkwarden API Anahtarı",
|
||||||
"form.integration.linkwarden_endpoint": "Linkwarden Temel URL'si",
|
"form.integration.linkwarden_endpoint": "Linkwarden Temel URL'si",
|
||||||
|
|
|
@ -162,7 +162,8 @@
|
||||||
"error.unable_to_update_user": "Не вдається оновити користувача.",
|
"error.unable_to_update_user": "Не вдається оновити користувача.",
|
||||||
"error.unlink_account_without_password": "Ви маєте встановити пароль, щоб мати можливість увійти наступного разу",
|
"error.unlink_account_without_password": "Ви маєте встановити пароль, щоб мати можливість увійти наступного разу",
|
||||||
"error.user_already_exists": "Такий користувач вже існує.",
|
"error.user_already_exists": "Такий користувач вже існує.",
|
||||||
"error.user_mandatory_fields": "Ім’я користувача є обов’язковим.",
|
"error.user_mandatory_fields": "Ім'я користувача є обов'язковим.",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token і Organization Slug є обов'язковими",
|
||||||
"form.api_key.label.description": "Назва ключа API",
|
"form.api_key.label.description": "Назва ключа API",
|
||||||
"form.category.hide_globally": "Приховати записи в глобальному списку непрочитаного",
|
"form.category.hide_globally": "Приховати записи в глобальному списку непрочитаного",
|
||||||
"form.category.label.title": "Назва",
|
"form.category.label.title": "Назва",
|
||||||
|
@ -253,6 +254,16 @@
|
||||||
"form.integration.linkding_bookmark": "Відмічати закладку як непрочитану",
|
"form.integration.linkding_bookmark": "Відмічати закладку як непрочитану",
|
||||||
"form.integration.linkding_endpoint": "Linkding API Endpoint",
|
"form.integration.linkding_endpoint": "Linkding API Endpoint",
|
||||||
"form.integration.linkding_tags": "Linkding Tags",
|
"form.integration.linkding_tags": "Linkding Tags",
|
||||||
|
"form.integration.linktaco_activate": "Зберігати статті в LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "Отримайте ваш персональний токен доступу на",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "Теги (макс. 10, через кому)",
|
||||||
|
"form.integration.linktaco_tags_hint": "Максимум 10 тегів, через кому",
|
||||||
|
"form.integration.linktaco_visibility": "Видимість",
|
||||||
|
"form.integration.linktaco_visibility_public": "Публічно",
|
||||||
|
"form.integration.linktaco_visibility_private": "Приватно",
|
||||||
|
"form.integration.linktaco_visibility_hint": "ПРИВАТНА видимість потребує платного акаунта LinkTaco",
|
||||||
"form.integration.linkwarden_activate": "Зберігати статті до Linkwarden",
|
"form.integration.linkwarden_activate": "Зберігати статті до Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "Ключ API Linkwarden",
|
"form.integration.linkwarden_api_key": "Ключ API Linkwarden",
|
||||||
"form.integration.linkwarden_endpoint": "Базова URL-адреса Linkwarden",
|
"form.integration.linkwarden_endpoint": "Базова URL-адреса Linkwarden",
|
||||||
|
|
|
@ -157,6 +157,7 @@
|
||||||
"error.unlink_account_without_password": "您必须设置密码,否则您将无法再次登录。",
|
"error.unlink_account_without_password": "您必须设置密码,否则您将无法再次登录。",
|
||||||
"error.user_already_exists": "此用户已存在。",
|
"error.user_already_exists": "此用户已存在。",
|
||||||
"error.user_mandatory_fields": "必须填写用户名。",
|
"error.user_mandatory_fields": "必须填写用户名。",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token 和 Organization Slug 是必需的",
|
||||||
"form.api_key.label.description": "API 密钥标签",
|
"form.api_key.label.description": "API 密钥标签",
|
||||||
"form.category.hide_globally": "在全局未读列表中隐藏条目",
|
"form.category.hide_globally": "在全局未读列表中隐藏条目",
|
||||||
"form.category.label.title": "标题",
|
"form.category.label.title": "标题",
|
||||||
|
@ -247,6 +248,16 @@
|
||||||
"form.integration.linkding_bookmark": "将书签标记为未读",
|
"form.integration.linkding_bookmark": "将书签标记为未读",
|
||||||
"form.integration.linkding_endpoint": "Linkding API 端点",
|
"form.integration.linkding_endpoint": "Linkding API 端点",
|
||||||
"form.integration.linkding_tags": "Linkding 标签",
|
"form.integration.linkding_tags": "Linkding 标签",
|
||||||
|
"form.integration.linktaco_activate": "保存条目到 LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "在此获取您的个人访问令牌",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "标签(最多10个,逗号分隔)",
|
||||||
|
"form.integration.linktaco_tags_hint": "最多10个标签,逗号分隔",
|
||||||
|
"form.integration.linktaco_visibility": "可见性",
|
||||||
|
"form.integration.linktaco_visibility_public": "公开",
|
||||||
|
"form.integration.linktaco_visibility_private": "私人",
|
||||||
|
"form.integration.linktaco_visibility_hint": "私人可见性需要付费的 LinkTaco 帐户",
|
||||||
"form.integration.linkwarden_activate": "保存条目到 Linkwarden",
|
"form.integration.linkwarden_activate": "保存条目到 Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "Linkwarden API 密钥",
|
"form.integration.linkwarden_api_key": "Linkwarden API 密钥",
|
||||||
"form.integration.linkwarden_endpoint": "Linkwarden 基本 URL",
|
"form.integration.linkwarden_endpoint": "Linkwarden 基本 URL",
|
||||||
|
|
|
@ -157,6 +157,7 @@
|
||||||
"error.unlink_account_without_password": "您必須設定密碼,否則您將無法再次登入。",
|
"error.unlink_account_without_password": "您必須設定密碼,否則您將無法再次登入。",
|
||||||
"error.user_already_exists": "使用者已存在",
|
"error.user_already_exists": "使用者已存在",
|
||||||
"error.user_mandatory_fields": "必須填寫使用者名稱",
|
"error.user_mandatory_fields": "必須填寫使用者名稱",
|
||||||
|
"error.linktaco_missing_required_fields": "LinkTaco API Token 和 Organization Slug 是必需的",
|
||||||
"form.api_key.label.description": "API 金鑰標籤",
|
"form.api_key.label.description": "API 金鑰標籤",
|
||||||
"form.category.hide_globally": "在全域未讀列表中隱藏文章",
|
"form.category.hide_globally": "在全域未讀列表中隱藏文章",
|
||||||
"form.category.label.title": "標題",
|
"form.category.label.title": "標題",
|
||||||
|
@ -247,6 +248,16 @@
|
||||||
"form.integration.linkding_bookmark": "標記為未讀",
|
"form.integration.linkding_bookmark": "標記為未讀",
|
||||||
"form.integration.linkding_endpoint": "Linkding API 端點",
|
"form.integration.linkding_endpoint": "Linkding API 端點",
|
||||||
"form.integration.linkding_tags": "Linkding 標籤",
|
"form.integration.linkding_tags": "Linkding 標籤",
|
||||||
|
"form.integration.linktaco_activate": "儲存文章到 LinkTaco",
|
||||||
|
"form.integration.linktaco_api_token": "LinkTaco API Token",
|
||||||
|
"form.integration.linktaco_api_token_hint": "在此取得您的個人存取權杖",
|
||||||
|
"form.integration.linktaco_org_slug": "Organization Slug",
|
||||||
|
"form.integration.linktaco_tags": "標籤(最多10個,逗號分隔)",
|
||||||
|
"form.integration.linktaco_tags_hint": "最多10個標籤,逗號分隔",
|
||||||
|
"form.integration.linktaco_visibility": "可見性",
|
||||||
|
"form.integration.linktaco_visibility_public": "公開",
|
||||||
|
"form.integration.linktaco_visibility_private": "私人",
|
||||||
|
"form.integration.linktaco_visibility_hint": "私人可見性需要付費的 LinkTaco 帳戶",
|
||||||
"form.integration.linkwarden_activate": "儲存文章到 Linkwarden",
|
"form.integration.linkwarden_activate": "儲存文章到 Linkwarden",
|
||||||
"form.integration.linkwarden_api_key": "Linkwarden API 金鑰",
|
"form.integration.linkwarden_api_key": "Linkwarden API 金鑰",
|
||||||
"form.integration.linkwarden_endpoint": "Linkwarden 基本 URL",
|
"form.integration.linkwarden_endpoint": "Linkwarden 基本 URL",
|
||||||
|
|
|
@ -59,6 +59,11 @@ type Integration struct {
|
||||||
LinkdingAPIKey string
|
LinkdingAPIKey string
|
||||||
LinkdingTags string
|
LinkdingTags string
|
||||||
LinkdingMarkAsUnread bool
|
LinkdingMarkAsUnread bool
|
||||||
|
LinktacoEnabled bool
|
||||||
|
LinktacoAPIToken string
|
||||||
|
LinktacoOrgSlug string
|
||||||
|
LinktacoTags string
|
||||||
|
LinktacoVisibility string
|
||||||
LinkwardenEnabled bool
|
LinkwardenEnabled bool
|
||||||
LinkwardenURL string
|
LinkwardenURL string
|
||||||
LinkwardenAPIKey string
|
LinkwardenAPIKey string
|
||||||
|
|
|
@ -220,7 +220,12 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
|
||||||
rssbridge_token,
|
rssbridge_token,
|
||||||
karakeep_enabled,
|
karakeep_enabled,
|
||||||
karakeep_api_key,
|
karakeep_api_key,
|
||||||
karakeep_url
|
karakeep_url,
|
||||||
|
linktaco_enabled,
|
||||||
|
linktaco_api_token,
|
||||||
|
linktaco_org_slug,
|
||||||
|
linktaco_tags,
|
||||||
|
linktaco_visibility
|
||||||
FROM
|
FROM
|
||||||
integrations
|
integrations
|
||||||
WHERE
|
WHERE
|
||||||
|
@ -340,6 +345,11 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
|
||||||
&integration.KarakeepEnabled,
|
&integration.KarakeepEnabled,
|
||||||
&integration.KarakeepAPIKey,
|
&integration.KarakeepAPIKey,
|
||||||
&integration.KarakeepURL,
|
&integration.KarakeepURL,
|
||||||
|
&integration.LinktacoEnabled,
|
||||||
|
&integration.LinktacoAPIToken,
|
||||||
|
&integration.LinktacoOrgSlug,
|
||||||
|
&integration.LinktacoTags,
|
||||||
|
&integration.LinktacoVisibility,
|
||||||
)
|
)
|
||||||
switch {
|
switch {
|
||||||
case err == sql.ErrNoRows:
|
case err == sql.ErrNoRows:
|
||||||
|
@ -467,9 +477,14 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
|
||||||
rssbridge_token=$108,
|
rssbridge_token=$108,
|
||||||
karakeep_enabled=$109,
|
karakeep_enabled=$109,
|
||||||
karakeep_api_key=$110,
|
karakeep_api_key=$110,
|
||||||
karakeep_url=$111
|
karakeep_url=$111,
|
||||||
|
linktaco_enabled=$112,
|
||||||
|
linktaco_api_token=$113,
|
||||||
|
linktaco_org_slug=$114,
|
||||||
|
linktaco_tags=$115,
|
||||||
|
linktaco_visibility=$116
|
||||||
WHERE
|
WHERE
|
||||||
user_id=$112
|
user_id=$117
|
||||||
`
|
`
|
||||||
_, err := s.db.Exec(
|
_, err := s.db.Exec(
|
||||||
query,
|
query,
|
||||||
|
@ -584,6 +599,11 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
|
||||||
integration.KarakeepEnabled,
|
integration.KarakeepEnabled,
|
||||||
integration.KarakeepAPIKey,
|
integration.KarakeepAPIKey,
|
||||||
integration.KarakeepURL,
|
integration.KarakeepURL,
|
||||||
|
integration.LinktacoEnabled,
|
||||||
|
integration.LinktacoAPIToken,
|
||||||
|
integration.LinktacoOrgSlug,
|
||||||
|
integration.LinktacoTags,
|
||||||
|
integration.LinktacoVisibility,
|
||||||
integration.UserID,
|
integration.UserID,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -614,6 +634,7 @@ func (s *Storage) HasSaveEntry(userID int64) (result bool) {
|
||||||
readwise_enabled='t' OR
|
readwise_enabled='t' OR
|
||||||
linkace_enabled='t' OR
|
linkace_enabled='t' OR
|
||||||
linkding_enabled='t' OR
|
linkding_enabled='t' OR
|
||||||
|
linktaco_enabled='t' OR
|
||||||
linkwarden_enabled='t' OR
|
linkwarden_enabled='t' OR
|
||||||
apprise_enabled='t' OR
|
apprise_enabled='t' OR
|
||||||
shiori_enabled='t' OR
|
shiori_enabled='t' OR
|
||||||
|
|
|
@ -228,6 +228,37 @@
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
<details {{ if .form.LinktacoEnabled }}open{{ end }}>
|
||||||
|
<summary>LinkTaco</summary>
|
||||||
|
<div class="form-section">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="linktaco_enabled" value="1" {{ if .form.LinktacoEnabled }}checked{{ end }}> {{ t "form.integration.linktaco_activate" }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="form-linktaco-api-token">{{ t "form.integration.linktaco_api_token" }}</label>
|
||||||
|
<input type="password" name="linktaco_api_token" id="form-linktaco-api-token" value="{{ .form.LinktacoAPIToken }}" spellcheck="false">
|
||||||
|
<p class="hint">{{ t "form.integration.linktaco_api_token_hint" }} <a href="https://linktaco.com/oauth2/personal" target="_blank" rel="noopener noreferrer">https://linktaco.com/oauth2/personal</a></p>
|
||||||
|
|
||||||
|
<label for="form-linktaco-org-slug">{{ t "form.integration.linktaco_org_slug" }}</label>
|
||||||
|
<input type="text" name="linktaco_org_slug" id="form-linktaco-org-slug" value="{{ .form.LinktacoOrgSlug }}" placeholder="my-organization" spellcheck="false">
|
||||||
|
|
||||||
|
<label for="form-linktaco-tags">{{ t "form.integration.linktaco_tags" }}</label>
|
||||||
|
<input type="text" name="linktaco_tags" id="form-linktaco-tags" value="{{ .form.LinktacoTags }}" placeholder="miniflux, bookmarks" spellcheck="false">
|
||||||
|
<p class="hint">{{ t "form.integration.linktaco_tags_hint" }}</p>
|
||||||
|
|
||||||
|
<label for="form-linktaco-visibility">{{ t "form.integration.linktaco_visibility" }}</label>
|
||||||
|
<select name="linktaco_visibility" id="form-linktaco-visibility">
|
||||||
|
<option value="PUBLIC" {{ if eq .form.LinktacoVisibility "PUBLIC" }}selected{{ end }}>{{ t "form.integration.linktaco_visibility_public" }}</option>
|
||||||
|
<option value="PRIVATE" {{ if eq .form.LinktacoVisibility "PRIVATE" }}selected{{ end }}>{{ t "form.integration.linktaco_visibility_private" }}</option>
|
||||||
|
</select>
|
||||||
|
<p class="hint">{{ t "form.integration.linktaco_visibility_hint" }}</p>
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
<button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.update" }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
<details {{ if .form.LinkwardenEnabled }}open{{ end }}>
|
<details {{ if .form.LinkwardenEnabled }}open{{ end }}>
|
||||||
<summary>Linkwarden</summary>
|
<summary>Linkwarden</summary>
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
|
|
|
@ -62,6 +62,11 @@ type IntegrationForm struct {
|
||||||
LinkdingAPIKey string
|
LinkdingAPIKey string
|
||||||
LinkdingTags string
|
LinkdingTags string
|
||||||
LinkdingMarkAsUnread bool
|
LinkdingMarkAsUnread bool
|
||||||
|
LinktacoEnabled bool
|
||||||
|
LinktacoAPIToken string
|
||||||
|
LinktacoOrgSlug string
|
||||||
|
LinktacoTags string
|
||||||
|
LinktacoVisibility string
|
||||||
LinkwardenEnabled bool
|
LinkwardenEnabled bool
|
||||||
LinkwardenURL string
|
LinkwardenURL string
|
||||||
LinkwardenAPIKey string
|
LinkwardenAPIKey string
|
||||||
|
@ -175,6 +180,11 @@ func (i IntegrationForm) Merge(integration *model.Integration) {
|
||||||
integration.LinkdingAPIKey = i.LinkdingAPIKey
|
integration.LinkdingAPIKey = i.LinkdingAPIKey
|
||||||
integration.LinkdingTags = i.LinkdingTags
|
integration.LinkdingTags = i.LinkdingTags
|
||||||
integration.LinkdingMarkAsUnread = i.LinkdingMarkAsUnread
|
integration.LinkdingMarkAsUnread = i.LinkdingMarkAsUnread
|
||||||
|
integration.LinktacoEnabled = i.LinktacoEnabled
|
||||||
|
integration.LinktacoAPIToken = i.LinktacoAPIToken
|
||||||
|
integration.LinktacoOrgSlug = i.LinktacoOrgSlug
|
||||||
|
integration.LinktacoTags = i.LinktacoTags
|
||||||
|
integration.LinktacoVisibility = i.LinktacoVisibility
|
||||||
integration.LinkwardenEnabled = i.LinkwardenEnabled
|
integration.LinkwardenEnabled = i.LinkwardenEnabled
|
||||||
integration.LinkwardenURL = i.LinkwardenURL
|
integration.LinkwardenURL = i.LinkwardenURL
|
||||||
integration.LinkwardenAPIKey = i.LinkwardenAPIKey
|
integration.LinkwardenAPIKey = i.LinkwardenAPIKey
|
||||||
|
@ -290,6 +300,11 @@ func NewIntegrationForm(r *http.Request) *IntegrationForm {
|
||||||
LinkdingAPIKey: r.FormValue("linkding_api_key"),
|
LinkdingAPIKey: r.FormValue("linkding_api_key"),
|
||||||
LinkdingTags: r.FormValue("linkding_tags"),
|
LinkdingTags: r.FormValue("linkding_tags"),
|
||||||
LinkdingMarkAsUnread: r.FormValue("linkding_mark_as_unread") == "1",
|
LinkdingMarkAsUnread: r.FormValue("linkding_mark_as_unread") == "1",
|
||||||
|
LinktacoEnabled: r.FormValue("linktaco_enabled") == "1",
|
||||||
|
LinktacoAPIToken: r.FormValue("linktaco_api_token"),
|
||||||
|
LinktacoOrgSlug: r.FormValue("linktaco_org_slug"),
|
||||||
|
LinktacoTags: r.FormValue("linktaco_tags"),
|
||||||
|
LinktacoVisibility: r.FormValue("linktaco_visibility"),
|
||||||
LinkwardenEnabled: r.FormValue("linkwarden_enabled") == "1",
|
LinkwardenEnabled: r.FormValue("linkwarden_enabled") == "1",
|
||||||
LinkwardenURL: r.FormValue("linkwarden_url"),
|
LinkwardenURL: r.FormValue("linkwarden_url"),
|
||||||
LinkwardenAPIKey: r.FormValue("linkwarden_api_key"),
|
LinkwardenAPIKey: r.FormValue("linkwarden_api_key"),
|
||||||
|
|
|
@ -75,6 +75,11 @@ func (h *handler) showIntegrationPage(w http.ResponseWriter, r *http.Request) {
|
||||||
LinkdingAPIKey: integration.LinkdingAPIKey,
|
LinkdingAPIKey: integration.LinkdingAPIKey,
|
||||||
LinkdingTags: integration.LinkdingTags,
|
LinkdingTags: integration.LinkdingTags,
|
||||||
LinkdingMarkAsUnread: integration.LinkdingMarkAsUnread,
|
LinkdingMarkAsUnread: integration.LinkdingMarkAsUnread,
|
||||||
|
LinktacoEnabled: integration.LinktacoEnabled,
|
||||||
|
LinktacoAPIToken: integration.LinktacoAPIToken,
|
||||||
|
LinktacoOrgSlug: integration.LinktacoOrgSlug,
|
||||||
|
LinktacoTags: integration.LinktacoTags,
|
||||||
|
LinktacoVisibility: integration.LinktacoVisibility,
|
||||||
LinkwardenEnabled: integration.LinkwardenEnabled,
|
LinkwardenEnabled: integration.LinkwardenEnabled,
|
||||||
LinkwardenURL: integration.LinkwardenURL,
|
LinkwardenURL: integration.LinkwardenURL,
|
||||||
LinkwardenAPIKey: integration.LinkwardenAPIKey,
|
LinkwardenAPIKey: integration.LinkwardenAPIKey,
|
||||||
|
|
|
@ -75,6 +75,17 @@ func (h *handler) updateIntegration(w http.ResponseWriter, r *http.Request) {
|
||||||
integration.WebhookSecret = ""
|
integration.WebhookSecret = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if integrationForm.LinktacoEnabled {
|
||||||
|
if integrationForm.LinktacoAPIToken == "" || integrationForm.LinktacoOrgSlug == "" {
|
||||||
|
sess.NewFlashErrorMessage(printer.Print("error.linktaco_missing_required_fields"))
|
||||||
|
html.Redirect(w, r, route.Path(h.router, "integrations"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if integration.LinktacoVisibility == "" {
|
||||||
|
integration.LinktacoVisibility = "PUBLIC"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = h.store.UpdateIntegration(integration)
|
err = h.store.UpdateIntegration(integration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
html.ServerError(w, r, err)
|
html.ServerError(w, r, err)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue