aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAKP <tom@tdpain.net>2022-04-14 21:11:59 +0100
committerAKP <tom@tdpain.net>2022-04-14 21:11:59 +0100
commit9318987a49b698819edc9641c4d19637beb2131e (patch)
tree8c4673e5eb26a57f6b99cadacf5f4aea6b41b865
parent06515b424c23862cf82220d97cb1380366c2e6d9 (diff)
Add support for OPML export
Signed-off-by: AKP <tom@tdpain.net>
-rw-r--r--CHANGELOG.md2
-rw-r--r--walrss/internal/core/feeds.go13
-rw-r--r--walrss/internal/core/opml/opml.go60
-rw-r--r--walrss/internal/http/exportImport.go21
-rw-r--r--walrss/internal/http/http.go2
-rw-r--r--walrss/internal/urls/urls.go3
6 files changed, 101 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cb49c46..f8af81a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
+### Added
+* Support for OPML exports
## [0.1.0] - 2022-04-14
Initial release
diff --git a/walrss/internal/core/feeds.go b/walrss/internal/core/feeds.go
index c9e4022..3aefd4c 100644
--- a/walrss/internal/core/feeds.go
+++ b/walrss/internal/core/feeds.go
@@ -2,6 +2,7 @@ package core
import (
"errors"
+ "github.com/codemicro/walrss/walrss/internal/core/opml"
"github.com/codemicro/walrss/walrss/internal/db"
"github.com/codemicro/walrss/walrss/internal/state"
"github.com/lithammer/shortuuid/v4"
@@ -74,3 +75,15 @@ func UpdateFeed(st *state.State, feed *db.Feed) error {
}
return nil
}
+
+func ExportFeedsForUser(st *state.State, userID string) ([]byte, error) {
+ var feeds []*db.Feed
+ user, err := GetUserByID(st, userID)
+ if err != nil {
+ return nil, err
+ }
+ if err := st.Data.Find(&feeds, bh.Where("UserID").Eq(userID)); err != nil {
+ return nil, err
+ }
+ return opml.FromFeeds(feeds, user.Email).ToBytes()
+}
diff --git a/walrss/internal/core/opml/opml.go b/walrss/internal/core/opml/opml.go
new file mode 100644
index 0000000..809a6b8
--- /dev/null
+++ b/walrss/internal/core/opml/opml.go
@@ -0,0 +1,60 @@
+package opml
+
+import (
+ "encoding/xml"
+ "github.com/codemicro/walrss/walrss/internal/db"
+ "time"
+)
+
+type OPML struct {
+ XMLName xml.Name `xml:"opml"`
+ Version string `xml:"version,attr"`
+ Head struct {
+ Title string `xml:"title"`
+ DateCreated time.Time `xml:"dateCreated,omitempty"`
+ OwnerEmail string `xml:"ownerEmail,omitempty"`
+ } `xml:"head"`
+ Body struct {
+ Outlines []*Outline `xml:"outline"`
+ } `xml:"body"`
+}
+
+// Outline holds all information about an outline.
+type Outline struct {
+ Outlines []*Outline `xml:"outline"`
+ Text string `xml:"text,attr"`
+ Title string `xml:"title,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ XMLURL string `xml:"xmlUrl,attr,omitempty"`
+}
+
+func FromBytes(x []byte) (*OPML, error) {
+ o := new(OPML)
+ if err := xml.Unmarshal(x, o); err != nil {
+ return nil, err
+ }
+ return o, nil
+}
+
+func (o *OPML) ToBytes() ([]byte, error) {
+ return xml.Marshal(o)
+}
+
+func FromFeeds(feeds []*db.Feed, userEmailAddress string) *OPML {
+ o := new(OPML)
+ o.Version = "2.0"
+ o.Head.Title = "Walrss feed export"
+ o.Head.OwnerEmail = userEmailAddress
+ o.Head.DateCreated = time.Now().UTC()
+
+ for _, feed := range feeds {
+ o.Body.Outlines = append(o.Body.Outlines, &Outline{
+ Text: feed.Name,
+ Title: feed.Name,
+ Type: "rss",
+ XMLURL: feed.URL,
+ })
+ }
+
+ return o
+}
diff --git a/walrss/internal/http/exportImport.go b/walrss/internal/http/exportImport.go
new file mode 100644
index 0000000..89b2ecf
--- /dev/null
+++ b/walrss/internal/http/exportImport.go
@@ -0,0 +1,21 @@
+package http
+
+import (
+ "github.com/codemicro/walrss/walrss/internal/core"
+ "github.com/gofiber/fiber/v2"
+)
+
+func (s *Server) exportAsOPML(ctx *fiber.Ctx) error {
+ currentUserID := getCurrentUserID(ctx)
+ if currentUserID == "" {
+ return requestStandardSignIn(ctx)
+ }
+
+ exported, err := core.ExportFeedsForUser(s.state, currentUserID)
+ if err != nil {
+ return err
+ }
+
+ ctx.Set(fiber.HeaderContentType, "application/xml")
+ return ctx.Send(exported)
+}
diff --git a/walrss/internal/http/http.go b/walrss/internal/http/http.go
index 72a8634..295a91f 100644
--- a/walrss/internal/http/http.go
+++ b/walrss/internal/http/http.go
@@ -91,6 +91,8 @@ func (s *Server) registerHandlers() {
s.app.Post(urls.SendTestEmail, s.sendTestEmail)
+ s.app.Get(urls.ExportAsOPML, s.exportAsOPML)
+
s.app.Use(urls.Statics, static.NewHandler())
}
diff --git a/walrss/internal/urls/urls.go b/walrss/internal/urls/urls.go
index 2edcc2e..835bbc7 100644
--- a/walrss/internal/urls/urls.go
+++ b/walrss/internal/urls/urls.go
@@ -18,6 +18,9 @@ const (
EditFeedItem = Edit + "/feed/:id"
CancelEditFeedItem = Edit + "/feed/:id/cancel"
+ Export = "/export"
+ ExportAsOPML = Export + "/opml"
+
New = "/new"
NewFeedItem = New + "/feed"