From 6add647ec757a1f1ea138c28d0e453350285aa2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Hells=C3=A9n?= Date: Sun, 4 Feb 2024 01:53:49 +0100 Subject: [PATCH] Add gorm models --- .gitignore | 3 + .vscode/settings.json | 3 + db.go | 34 +++++++++ go.mod | 13 +++- go.sum | 36 ++++++++++ main.go | 27 ++++++-- models.go | 157 ++++++++++++++++++++++++++++++++++++++++++ templates/base.tmpl | 2 +- 8 files changed, 266 insertions(+), 9 deletions(-) create mode 100644 db.go create mode 100644 models.go diff --git a/.gitignore b/.gitignore index 23a7c4a..8373b04 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ tmp/ # Environment variables file .env + +# Database +*.db diff --git a/.vscode/settings.json b/.vscode/settings.json index 294c171..d13f184 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,9 +8,12 @@ "feedparser", "feedvault", "gaierror", + "gofeed", + "gorm", "leftright", "levelname", "listparser", + "mmcdole", "Monero", "PGHOST", "PGPORT", diff --git a/db.go b/db.go new file mode 100644 index 0000000..8a11aa2 --- /dev/null +++ b/db.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + "log" + "os" +) + +// Get the size of the database and return as nearest human readable size +func GetDBSize() string { + fileInfo, err := os.Stat("feedvault.db") + if err != nil { + log.Println("Error getting file info:", err) + return "0 B" + } + + // Get the file size in bytes + fileSize := fileInfo.Size() + + // Convert to human readable size and append the unit (KB, MB, GB) + var size float64 + if fileSize < 1024*1024 { + size = float64(fileSize) / 1024 + return fmt.Sprintf("%.2f KB", size) + } + + if fileSize < 1024*1024*1024 { + size = float64(fileSize) / (1024 * 1024) + return fmt.Sprintf("%.2f MB", size) + } + + size = float64(fileSize) / (1024 * 1024 * 1024) + return fmt.Sprintf("%.2f GB", size) +} diff --git a/go.mod b/go.mod index a6b1ef6..d84e269 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,15 @@ module github.com/TheLovinator1/FeedVault go 1.21.6 -require github.com/go-chi/chi/v5 v5.0.11 +require ( + github.com/go-chi/chi/v5 v5.0.11 + github.com/mmcdole/gofeed v1.2.1 + gorm.io/driver/sqlite v1.5.4 + gorm.io/gorm v1.25.6 +) + +require ( + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/mattn/go-sqlite3 v1.14.22 // indirect +) diff --git a/go.sum b/go.sum index fd04e27..9545d77 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,38 @@ +github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U= +github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI= +github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= +github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA= github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mmcdole/gofeed v1.2.1 h1:tPbFN+mfOLcM1kDF1x2c/N68ChbdBatkppdzf/vDe1s= +github.com/mmcdole/gofeed v1.2.1/go.mod h1:2wVInNpgmC85q16QTTuwbuKxtKkHLCDDtf0dCmnrNr4= +github.com/mmcdole/goxpp v1.1.0 h1:WwslZNF7KNAXTFuzRtn/OKZxFLJAAyOA9w82mDz2ZGI= +github.com/mmcdole/goxpp v1.1.0/go.mod h1:v+25+lT2ViuQ7mVxcncQ8ch1URund48oH+jhjiwEgS8= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/sqlite v1.5.4 h1:IqXwXi8M/ZlPzH/947tn5uik3aYQslP9BVveoax0nV0= +gorm.io/driver/sqlite v1.5.4/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4= +gorm.io/gorm v1.25.6 h1:V92+vVda1wEISSOMtodHVRcUIOPYa2tgQtyF+DfFx+A= +gorm.io/gorm v1.25.6/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= diff --git a/main.go b/main.go index 2a52fce..3752aaf 100644 --- a/main.go +++ b/main.go @@ -8,9 +8,27 @@ import ( "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" + "gorm.io/driver/sqlite" + "gorm.io/gorm" ) +// Database connection +var db *gorm.DB + func main() { + log.Println("Starting FeedVault...") + db, err := gorm.Open(sqlite.Open("feedvault.db"), &gorm.Config{}) + if err != nil { + panic("Failed to connect to database") + } + + // Migrate the schema + err = db.AutoMigrate(&Feed{}, &Item{}, &Person{}, &Image{}, &Enclosure{}, &DublinCoreExtension{}, &ITunesFeedExtension{}, &ITunesItemExtension{}, &ITunesCategory{}, &ITunesOwner{}, &Extension{}) + if err != nil { + panic("Failed to migrate the database") + } + + // Create a new router r := chi.NewRouter() r.Use(middleware.RealIP) r.Use(middleware.Logger) @@ -40,16 +58,12 @@ type Data struct { Author string CanonicalURL string FeedCount int - DatabaseSize int + DatabaseSize string Request *http.Request } func (d *Data) GetDatabaseSizeAndFeedCount() { - // Set the database size to 0 - d.DatabaseSize = 0 - - // Set the feed count to 0 - d.FeedCount = 0 + d.DatabaseSize = GetDBSize() } func renderPage(w http.ResponseWriter, title, description, keywords, author, url, templateName string) { @@ -60,7 +74,6 @@ func renderPage(w http.ResponseWriter, title, description, keywords, author, url Author: author, CanonicalURL: url, FeedCount: 0, - DatabaseSize: 0, } data.GetDatabaseSizeAndFeedCount() diff --git a/models.go b/models.go new file mode 100644 index 0000000..ec19b77 --- /dev/null +++ b/models.go @@ -0,0 +1,157 @@ +package main + +import ( + "time" + + "gorm.io/gorm" +) + +type Feed struct { + gorm.Model + Title string `json:"title,omitempty"` + Description string `json:"description,omitempty"` + Link string `json:"link,omitempty"` + FeedLink string `json:"feedLink,omitempty"` + Links []string `gorm:"type:text[]" json:"links,omitempty"` + Updated string `json:"updated,omitempty"` + UpdatedParsed *time.Time `json:"updatedParsed,omitempty"` + Published string `json:"published,omitempty"` + PublishedParsed *time.Time `json:"publishedParsed,omitempty"` + Authors []*Person `gorm:"many2many:feed_authors;" json:"authors,omitempty"` + Language string `json:"language,omitempty"` + Image *Image `gorm:"foreignKey:ID" json:"image,omitempty"` + Copyright string `json:"copyright,omitempty"` + Generator string `json:"generator,omitempty"` + Categories []string `gorm:"type:text[]" json:"categories,omitempty"` + DublinCoreExt *DublinCoreExtension `gorm:"foreignKey:ID" json:"dcExt,omitempty"` + ITunesExt *ITunesFeedExtension `gorm:"foreignKey:ID" json:"itunesExt,omitempty"` + Extensions Extensions `gorm:"type:json" json:"extensions,omitempty"` + Custom map[string]string `gorm:"type:json" json:"custom,omitempty"` + Items []*Item `gorm:"foreignKey:ID" json:"items,omitempty"` + FeedType string `json:"feedType"` + FeedVersion string `json:"feedVersion"` +} + +type Item struct { + gorm.Model + Title string `json:"title,omitempty"` + Description string `json:"description,omitempty"` + Content string `json:"content,omitempty"` + Link string `json:"link,omitempty"` + Links []string `gorm:"type:text[]" json:"links,omitempty"` + Updated string `json:"updated,omitempty"` + UpdatedParsed *time.Time `json:"updatedParsed,omitempty"` + Published string `json:"published,omitempty"` + PublishedParsed *time.Time `json:"publishedParsed,omitempty"` + Authors []*Person `gorm:"many2many:item_authors;" json:"authors,omitempty"` + GUID string `json:"guid,omitempty"` + Image *Image `gorm:"foreignKey:ID" json:"image,omitempty"` + Categories []string `gorm:"type:text[]" json:"categories,omitempty"` + Enclosures []*Enclosure `gorm:"foreignKey:ID" json:"enclosures,omitempty"` + DublinCoreExt *DublinCoreExtension `gorm:"foreignKey:ID" json:"dcExt,omitempty"` + ITunesExt *ITunesFeedExtension `gorm:"foreignKey:ID" json:"itunesExt,omitempty"` + Extensions Extensions `gorm:"type:json" json:"extensions,omitempty"` + Custom map[string]string `gorm:"type:json" json:"custom,omitempty"` +} + +type Person struct { + gorm.Model + Name string `json:"name,omitempty"` + Email string `json:"email,omitempty"` +} + +func (Person) TableName() string { + return "feed_authors" +} + +type Image struct { + gorm.Model + URL string `json:"url,omitempty"` + Title string `json:"title,omitempty"` +} + +type Enclosure struct { + gorm.Model + URL string `json:"url,omitempty"` + Length string `json:"length,omitempty"` + Type string `json:"type,omitempty"` +} + +type DublinCoreExtension struct { + gorm.Model + Title []string `gorm:"type:text[]" json:"title,omitempty"` + Creator []string `gorm:"type:text[]" json:"creator,omitempty"` + Author []string `gorm:"type:text[]" json:"author,omitempty"` + Subject []string `gorm:"type:text[]" json:"subject,omitempty"` + Description []string `gorm:"type:text[]" json:"description,omitempty"` + Publisher []string `gorm:"type:text[]" json:"publisher,omitempty"` + Contributor []string `gorm:"type:text[]" json:"contributor,omitempty"` + Date []string `gorm:"type:text[]" json:"date,omitempty"` + Type []string `gorm:"type:text[]" json:"type,omitempty"` + Format []string `gorm:"type:text[]" json:"format,omitempty"` + Identifier []string `gorm:"type:text[]" json:"identifier,omitempty"` + Source []string `gorm:"type:text[]" json:"source,omitempty"` + Language []string `gorm:"type:text[]" json:"language,omitempty"` + Relation []string `gorm:"type:text[]" json:"relation,omitempty"` + Coverage []string `gorm:"type:text[]" json:"coverage,omitempty"` + Rights []string `gorm:"type:text[]" json:"rights,omitempty"` +} + +type ITunesFeedExtension struct { + gorm.Model + Author string `json:"author,omitempty"` + Block string `json:"block,omitempty"` + Categories []*ITunesCategory `gorm:"many2many:feed_itunes_categories;" json:"categories,omitempty"` + Explicit string `json:"explicit,omitempty"` + Keywords string `json:"keywords,omitempty"` + Owner *ITunesOwner `gorm:"foreignKey:ID" json:"owner,omitempty"` + Subtitle string `json:"subtitle,omitempty"` + Summary string `json:"summary,omitempty"` + Image string `json:"image,omitempty"` + Complete string `json:"complete,omitempty"` + NewFeedURL string `json:"newFeedUrl,omitempty"` + Type string `json:"type,omitempty"` +} + +type ITunesItemExtension struct { + gorm.Model + Author string `json:"author,omitempty"` + Block string `json:"block,omitempty"` + Duration string `json:"duration,omitempty"` + Explicit string `json:"explicit,omitempty"` + Keywords string `json:"keywords,omitempty"` + Subtitle string `json:"subtitle,omitempty"` + Summary string `json:"summary,omitempty"` + Image string `json:"image,omitempty"` + IsClosedCaptioned string `json:"isClosedCaptioned,omitempty"` + Episode string `json:"episode,omitempty"` + Season string `json:"season,omitempty"` + Order string `json:"order,omitempty"` + EpisodeType string `json:"episodeType,omitempty"` +} + +type ITunesCategory struct { + gorm.Model + Text string `json:"text,omitempty"` + Subcategory *ITunesCategory `gorm:"many2many:feed_itunes_categories;" json:"subcategory,omitempty"` +} + +func (ITunesCategory) TableName() string { + return "feed_itunes_categories" +} + +type ITunesOwner struct { + gorm.Model + Email string `json:"email,omitempty"` + Name string `json:"name,omitempty"` +} + +type Extensions map[string]map[string][]Extension + +type Extension struct { + gorm.Model + Name string `json:"name"` + Value string `json:"value"` + Attrs map[string]string `gorm:"type:json" json:"attrs"` + Children map[string][]Extension `gorm:"type:json" json:"children"` +} diff --git a/templates/base.tmpl b/templates/base.tmpl index 6678975..628d0ce 100644 --- a/templates/base.tmpl +++ b/templates/base.tmpl @@ -20,7 +20,7 @@
- Archive of web feeds. {{ .FeedCount }} feeds. ~{{ .DatabaseSize }} MB. + Archive of web feeds. {{ .FeedCount }} feeds. ~{{ .DatabaseSize }}