From 43f6340a4af43c1b0952dd480197d54a15389ece Mon Sep 17 00:00:00 2001 From: aleidk Date: Wed, 18 Dec 2024 16:54:33 -0300 Subject: [PATCH] feat: add basic linkding connection --- cmd/archive.go | 15 +++---- go.mod | 1 + go.sum | 2 + internal/app/archive.go | 13 +++++- internal/app/service.go | 8 ---- internal/config/config.go | 17 ++++++++ internal/service/linkding.go | 81 ++++++++++++++++++++++++++++++++++++ internal/service/service.go | 42 +++++++++++++++++++ 8 files changed, 163 insertions(+), 16 deletions(-) delete mode 100644 internal/app/service.go create mode 100644 internal/config/config.go create mode 100644 internal/service/linkding.go create mode 100644 internal/service/service.go diff --git a/cmd/archive.go b/cmd/archive.go index 86e1d1c..c01aa51 100644 --- a/cmd/archive.go +++ b/cmd/archive.go @@ -9,10 +9,11 @@ import ( "git.alecodes.page/alecodes/miniflux-archiver/internal/app" "git.alecodes.page/alecodes/miniflux-archiver/internal/miniflux" + "git.alecodes.page/alecodes/miniflux-archiver/internal/service" ) var Services = []string{ - "linkding", + string(service.ServiceLinkding), } var ( @@ -29,13 +30,13 @@ var archiveCmd = &cobra.Command{ Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), ValidArgs: Services, Run: func(cmd *cobra.Command, args []string) { - service := args[0] + serviceOption := service.ServiceOption(args[0]) - serviceConfig := app.ServiceConfig{ - Service: service, - Host: service_host, - User: service_user, - Token: service_token, + serviceConfig := service.ServiceConfig{ + Service: serviceOption, + Host: viper.GetString("service_host"), + User: viper.GetString("service_user"), + Token: viper.GetString("service_token"), } minifluxConfig := miniflux.MinifluxConfig{ diff --git a/go.mod b/go.mod index 3a8addd..fdaf619 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/piero-vic/go-linkding v0.2.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect diff --git a/go.sum b/go.sum index 054ac6a..ba43ab9 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/piero-vic/go-linkding v0.2.0 h1:1LNIeWvYe8Kd+kaG4hsWzYH/vvQ9OaJOMoV+XvXaH+Q= +github.com/piero-vic/go-linkding v0.2.0/go.mod h1:PuwOySAQYmbq4cIDAG1bXDMQwBUuorRkbjM43RdUhao= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/internal/app/archive.go b/internal/app/archive.go index 48c8f02..9e7b97a 100644 --- a/internal/app/archive.go +++ b/internal/app/archive.go @@ -5,14 +5,20 @@ import ( "git.alecodes.page/alecodes/miniflux-archiver/internal/logger" "git.alecodes.page/alecodes/miniflux-archiver/internal/miniflux" + "git.alecodes.page/alecodes/miniflux-archiver/internal/service" ) -func Archive(minifluxConfig miniflux.MinifluxConfig, serviceConfig ServiceConfig) { +func Archive(minifluxConfig miniflux.MinifluxConfig, serviceConfig service.ServiceConfig) { mf, err := miniflux.NewMiniflux(minifluxConfig) if err != nil { logger.Fatal("Could not connect to the miniflux server: %v", err) } + externalService, err := service.ResolveService(serviceConfig) + if err != nil { + logger.Fatal(err.Error()) + } + result, err := mf.GetEntries() if err != nil { logger.Fatal("Could not retrieve entries from the miniflux feed: %v", err) @@ -20,4 +26,9 @@ func Archive(minifluxConfig miniflux.MinifluxConfig, serviceConfig ServiceConfig entry := result.Entries[0] fmt.Println(entry.Title, entry.Status, entry.Tags) + + err = externalService.Archive(entry.URL) + if err != nil { + logger.Fatal("Could not archive entry from the service: %v", err) + } } diff --git a/internal/app/service.go b/internal/app/service.go deleted file mode 100644 index cf3a046..0000000 --- a/internal/app/service.go +++ /dev/null @@ -1,8 +0,0 @@ -package app - -type ServiceConfig struct { - Service string - Host string - User string - Token string -} diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..6b2d59d --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,17 @@ +package config + +import "git.alecodes.page/alecodes/miniflux-archiver/internal/service" + +type MinifluxConfig struct { + Host string + User string + Token string + FeedId int64 +} + +type ServiceConfig struct { + Service service.ServiceOption + Host string + User string + Token string +} diff --git a/internal/service/linkding.go b/internal/service/linkding.go new file mode 100644 index 0000000..ea14253 --- /dev/null +++ b/internal/service/linkding.go @@ -0,0 +1,81 @@ +package service + +import ( + "encoding/json" + "fmt" + "net/http" + + ldApi "github.com/piero-vic/go-linkding" +) + +type Linkding struct { + ServiceConfig + client *ldApi.Client +} + +func (ld *Linkding) CheckBookmark(url string) (*ldApi.Bookmark, error) { + bookmark := &ldApi.Bookmark{} + + req, err := http.NewRequest( + http.MethodGet, + fmt.Sprintf("%v/api/bookmarks/check/?url=%d", ld.Host, url), + nil, + ) + if err != nil { + return bookmark, err + } + + req.Header.Add("Content-Type", "application/json") + req.Header.Add("Accept", "application/json") + req.Header.Add("Authorization", fmt.Sprintf("Token %s", ld.Token)) + + res, err := http.DefaultClient.Do(req) + if err != nil { + return bookmark, err + } + + defer res.Body.Close() + + if err := json.NewDecoder(res.Body).Decode(bookmark); err != nil { + return bookmark, err + } + + return bookmark, nil +} + +func (ld *Linkding) Archive(url string) error { + bookmark, err := ld.CheckBookmark(url) + + payload := ldApi.CreateBookmarkRequest{ + URL: url, + Unread: false, + TagNames: bookmark.TagNames, + } + + if payload.TagNames == nil { + payload.TagNames = []string{} + } + + if err != nil { + _, err = ld.client.UpdateBookmark(bookmark.ID, payload) + } else { + _, err = ld.client.CreateBookmark(payload) + } + + return err +} + +func (ld *Linkding) IsAvailable() (bool, error) { + _, err := ld.client.ListTags(ldApi.ListTagsParams{}) + + return err == nil, err +} + +func NewLinkding(config ServiceConfig) (*Linkding, error) { + mf := &Linkding{ + ServiceConfig: config, + client: ldApi.NewClient(config.Host, config.Token), + } + + return mf, nil +} diff --git a/internal/service/service.go b/internal/service/service.go new file mode 100644 index 0000000..25f8757 --- /dev/null +++ b/internal/service/service.go @@ -0,0 +1,42 @@ +package service + +import "fmt" + +type ServiceOption string + +const ( + ServiceLinkding ServiceOption = "linkding" +) + +type ServiceConfig struct { + Service ServiceOption + Host string + User string + Token string +} + +type Service interface { + IsAvailable() (bool, error) + Archive(string) error +} + +func ResolveService(serviceConfig ServiceConfig) (Service, error) { + var service Service + switch serviceConfig.Service { + case ServiceLinkding: + service, _ = NewLinkding(serviceConfig) + default: + return nil, fmt.Errorf("Could not determine service to connect to") + } + + if isAvailable, err := service.IsAvailable(); !isAvailable { + return nil, fmt.Errorf( + "Could not connect to the service %v in %v: %v", + serviceConfig.Service, + serviceConfig.Host, + err, + ) + } + + return service, nil +}