diff --git a/internal/api/opml.go b/internal/api/opml.go index be1833d7..ffab8088 100644 --- a/internal/api/opml.go +++ b/internal/api/opml.go @@ -14,13 +14,13 @@ import ( func (h *handler) exportFeeds(w http.ResponseWriter, r *http.Request) { opmlHandler := opml.NewHandler(h.store) - opml, err := opmlHandler.Export(request.UserID(r)) + opmlExport, err := opmlHandler.Export(request.UserID(r)) if err != nil { json.ServerError(w, r, err) return } - xml.OK(w, r, opml) + xml.OK(w, r, opmlExport) } func (h *handler) importFeeds(w http.ResponseWriter, r *http.Request) { diff --git a/internal/cli/cli.go b/internal/cli/cli.go index f74ea5aa..a1ef7eef 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -32,6 +32,7 @@ const ( flagHealthCheckHelp = `Perform a health check on the given endpoint (the value "auto" try to guess the health check endpoint).` flagRefreshFeedsHelp = "Refresh a batch of feeds and exit" flagRunCleanupTasksHelp = "Run cleanup tasks (delete old sessions and archives old entries)" + flagExportUserFeedsHelp = "Export user feeds (provide the username as argument)" ) // Parse parses command line arguments. @@ -51,6 +52,7 @@ func Parse() { flagHealthCheck string flagRefreshFeeds bool flagRunCleanupTasks bool + flagExportUserFeeds string ) flag.BoolVar(&flagInfo, "info", false, flagInfoHelp) @@ -69,6 +71,7 @@ func Parse() { flag.StringVar(&flagHealthCheck, "healthcheck", "", flagHealthCheckHelp) flag.BoolVar(&flagRefreshFeeds, "refresh-feeds", false, flagRefreshFeedsHelp) flag.BoolVar(&flagRunCleanupTasks, "run-cleanup-tasks", false, flagRunCleanupTasksHelp) + flag.StringVar(&flagExportUserFeeds, "export-user-feeds", "", flagExportUserFeedsHelp) flag.Parse() cfg := config.NewParser() @@ -177,6 +180,11 @@ func Parse() { return } + if flagExportUserFeeds != "" { + exportUserFeeds(store, flagExportUserFeeds) + return + } + if flagFlushSessions { flushSessions(store) return diff --git a/internal/cli/export_feeds.go b/internal/cli/export_feeds.go new file mode 100644 index 00000000..0d0d5da5 --- /dev/null +++ b/internal/cli/export_feeds.go @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package cli // import "miniflux.app/v2/internal/cli" + +import ( + "fmt" + + "miniflux.app/v2/internal/reader/opml" + "miniflux.app/v2/internal/storage" +) + +func exportUserFeeds(store *storage.Storage, username string) { + user, err := store.UserByUsername(username) + if err != nil { + printErrorAndExit(fmt.Errorf("unable to find user: %w", err)) + } + + if user == nil { + printErrorAndExit(fmt.Errorf("user %q not found", username)) + } + + opmlHandler := opml.NewHandler(store) + opmlExport, err := opmlHandler.Export(user.ID) + if err != nil { + printErrorAndExit(fmt.Errorf("unable to export feeds: %w", err)) + } + + fmt.Println(opmlExport) +} diff --git a/internal/ui/opml_export.go b/internal/ui/opml_export.go index 0f5a994f..806914ef 100644 --- a/internal/ui/opml_export.go +++ b/internal/ui/opml_export.go @@ -13,11 +13,11 @@ import ( ) func (h *handler) exportFeeds(w http.ResponseWriter, r *http.Request) { - opml, err := opml.NewHandler(h.store).Export(request.UserID(r)) + opmlExport, err := opml.NewHandler(h.store).Export(request.UserID(r)) if err != nil { html.ServerError(w, r, err) return } - xml.Attachment(w, r, "feeds.opml", opml) + xml.Attachment(w, r, "feeds.opml", opmlExport) } diff --git a/miniflux.1 b/miniflux.1 index 51302e15..d28d13cc 100644 --- a/miniflux.1 +++ b/miniflux.1 @@ -1,5 +1,5 @@ .\" Manpage for miniflux. -.TH "MINIFLUX" "1" "September 24, 2023" "\ \&" "\ \&" +.TH "MINIFLUX" "1" "September 27, 2023" "\ \&" "\ \&" .SH NAME miniflux \- Minimalist and opinionated feed reader @@ -39,6 +39,13 @@ Create admin user\&. Set log level to debug\&. .RE .PP +.B \-export-user-feeds +.RS 4 +Export user feeds (provide the username as argument)\&. +.br +Example: "miniflux -export-user-feeds someone > feeds.xml"\&. +.RE +.PP .B \-flush-sessions .RS 4 Flush all sessions (disconnect users)\&.