You can now add feeds to the database
This commit is contained in:
parent
1fa8351d11
commit
a5b6352a4c
24 changed files with 1049 additions and 20 deletions
|
|
@ -16,6 +16,7 @@ exclude_dir = [
|
||||||
"tests",
|
"tests",
|
||||||
".git",
|
".git",
|
||||||
".vscode",
|
".vscode",
|
||||||
|
"data",
|
||||||
]
|
]
|
||||||
exclude_file = []
|
exclude_file = []
|
||||||
exclude_regex = ["_test.go"]
|
exclude_regex = ["_test.go"]
|
||||||
|
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -22,5 +22,4 @@ tmp/
|
||||||
.env
|
.env
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
*.db
|
data/
|
||||||
*.sqlite3
|
|
||||||
|
|
|
||||||
20
.vscode/settings.json
vendored
20
.vscode/settings.json
vendored
|
|
@ -31,6 +31,7 @@
|
||||||
"homerouter",
|
"homerouter",
|
||||||
"hotspot",
|
"hotspot",
|
||||||
"huaweimobilewifi",
|
"huaweimobilewifi",
|
||||||
|
"jackc",
|
||||||
"ldflags",
|
"ldflags",
|
||||||
"leftright",
|
"leftright",
|
||||||
"levelname",
|
"levelname",
|
||||||
|
|
@ -49,6 +50,7 @@
|
||||||
"pacman",
|
"pacman",
|
||||||
"PGHOST",
|
"PGHOST",
|
||||||
"PGPORT",
|
"PGPORT",
|
||||||
|
"pgtype",
|
||||||
"PGUSER",
|
"PGUSER",
|
||||||
"Prés",
|
"Prés",
|
||||||
"psql",
|
"psql",
|
||||||
|
|
@ -67,6 +69,7 @@
|
||||||
"stylesheet",
|
"stylesheet",
|
||||||
"sunt",
|
"sunt",
|
||||||
"tdewolff",
|
"tdewolff",
|
||||||
|
"Timestamptz",
|
||||||
"tmpl",
|
"tmpl",
|
||||||
"tplinkap",
|
"tplinkap",
|
||||||
"tplinkeap",
|
"tplinkeap",
|
||||||
|
|
@ -79,5 +82,20 @@
|
||||||
"webmail",
|
"webmail",
|
||||||
"XOXO",
|
"XOXO",
|
||||||
"zerolog"
|
"zerolog"
|
||||||
]
|
],
|
||||||
|
"terminal.integrated.env.windows": {
|
||||||
|
"GOOSE_DRIVER": "postgres",
|
||||||
|
"GOOSE_DBSTRING": "user=feedvault password=feedvault dbname=feedvault sslmode=disable",
|
||||||
|
"GOOSE_MIGRATION_DIR": "${workspaceFolder}/sql/schema"
|
||||||
|
},
|
||||||
|
"terminal.integrated.env.linux": {
|
||||||
|
"GOOSE_DRIVER": "postgres",
|
||||||
|
"GOOSE_DBSTRING": "user=feedvault password=feedvault dbname=feedvault sslmode=disable",
|
||||||
|
"GOOSE_MIGRATION_DIR": "${workspaceFolder}/sql/schema"
|
||||||
|
},
|
||||||
|
"terminal.integrated.env.osx": {
|
||||||
|
"GOOSE_DRIVER": "postgres",
|
||||||
|
"GOOSE_DBSTRING": "user=feedvault password=feedvault dbname=feedvault sslmode=disable",
|
||||||
|
"GOOSE_MIGRATION_DIR": "${workspaceFolder}/sql/schema"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
17
README.md
17
README.md
|
|
@ -22,18 +22,25 @@ _Note: Some features are currently in development._
|
||||||
- Add your favorite feeds to start archiving content.
|
- Add your favorite feeds to start archiving content.
|
||||||
- Explore, manage, and enjoy your centralized feed archive.
|
- Explore, manage, and enjoy your centralized feed archive.
|
||||||
|
|
||||||
## Docker
|
|
||||||
|
|
||||||
Please see [Docker.md](Docker.md).
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
All contributions are welcome regardless of skill level or experience.
|
All contributions are welcome regardless of skill level or experience.
|
||||||
|
|
||||||
Please read the [CONTRIBUTING.md](CONTRIBUTING.md) file for more information on how to contribute to FeedVault.
|
Please create a new issue before submitting a big pull request. I am probably okay with anything, but I don't want you to waste your time on something that I won't accept.
|
||||||
|
|
||||||
|
Try to minimize the number of dependencies you add to the project. If you need to add a new dependency, please create an issue first.
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
|
|
||||||
For any inquiries or support, please create an issue on GitHub.
|
For any inquiries or support, please create an issue on GitHub.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
- I use [goose](https://github.com/pressly/goose) and [sqlc](https://github.com/sqlc-dev/sqlc) for database migrations and queries.
|
||||||
|
- To create a new migration, run `goose create <migration_name> sql`. Then, edit the file in `sql/schema/<date>_<migration_name>.sql` and run `goose up` to apply the migration.
|
||||||
|
- You will have to install `goose` first. See the [Goose documentation](https://pressly.github.io/goose/installation/).
|
||||||
|
- You will also have to install `sqlc`. See the [sqlc documentation](https://docs.sqlc.dev/en/latest/overview/install.html).
|
||||||
|
- You have to set some environment variables for this. See [.vscode/settings.json](.vscode/settings.json) for local development.
|
||||||
|
- To generate new queries, run `sqlc generate`.
|
||||||
|
|
||||||
Thank you for using FeedVault! Happy archiving!
|
Thank you for using FeedVault! Happy archiving!
|
||||||
|
|
|
||||||
32
db/db.go
Normal file
32
db/db.go
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.25.0
|
||||||
|
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
|
"github.com/jackc/pgx/v5/pgconn"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DBTX interface {
|
||||||
|
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
|
||||||
|
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
|
||||||
|
QueryRow(context.Context, string, ...interface{}) pgx.Row
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(db DBTX) *Queries {
|
||||||
|
return &Queries{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Queries struct {
|
||||||
|
db DBTX
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) WithTx(tx pgx.Tx) *Queries {
|
||||||
|
return &Queries{
|
||||||
|
db: tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
148
db/feeds.sql.go
Normal file
148
db/feeds.sql.go
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.25.0
|
||||||
|
// source: feeds.sql
|
||||||
|
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const CountFeeds = `-- name: CountFeeds :one
|
||||||
|
SELECT
|
||||||
|
COUNT(*)
|
||||||
|
FROM
|
||||||
|
feeds
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) CountFeeds(ctx context.Context) (int64, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CountFeeds)
|
||||||
|
var count int64
|
||||||
|
err := row.Scan(&count)
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const CreateFeed = `-- name: CreateFeed :one
|
||||||
|
INSERT INTO
|
||||||
|
feeds (
|
||||||
|
"url",
|
||||||
|
created_at,
|
||||||
|
updated_at,
|
||||||
|
deleted_at,
|
||||||
|
title,
|
||||||
|
"description",
|
||||||
|
link,
|
||||||
|
feed_link,
|
||||||
|
links,
|
||||||
|
updated,
|
||||||
|
updated_parsed,
|
||||||
|
published,
|
||||||
|
published_parsed,
|
||||||
|
"language",
|
||||||
|
copyright,
|
||||||
|
generator,
|
||||||
|
categories,
|
||||||
|
custom,
|
||||||
|
feed_type,
|
||||||
|
feed_version
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
$9,
|
||||||
|
$10,
|
||||||
|
$11,
|
||||||
|
$12,
|
||||||
|
$13,
|
||||||
|
$14,
|
||||||
|
$15,
|
||||||
|
$16,
|
||||||
|
$17,
|
||||||
|
$18,
|
||||||
|
$19,
|
||||||
|
$20
|
||||||
|
) RETURNING id, url, created_at, updated_at, deleted_at, title, description, link, feed_link, links, updated, updated_parsed, published, published_parsed, language, copyright, generator, categories, custom, feed_type, feed_version
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateFeedParams struct {
|
||||||
|
Url string `json:"url"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Title pgtype.Text `json:"title"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
Link pgtype.Text `json:"link"`
|
||||||
|
FeedLink pgtype.Text `json:"feed_link"`
|
||||||
|
Links []string `json:"links"`
|
||||||
|
Updated pgtype.Text `json:"updated"`
|
||||||
|
UpdatedParsed pgtype.Timestamp `json:"updated_parsed"`
|
||||||
|
Published pgtype.Text `json:"published"`
|
||||||
|
PublishedParsed pgtype.Timestamp `json:"published_parsed"`
|
||||||
|
Language pgtype.Text `json:"language"`
|
||||||
|
Copyright pgtype.Text `json:"copyright"`
|
||||||
|
Generator pgtype.Text `json:"generator"`
|
||||||
|
Categories []string `json:"categories"`
|
||||||
|
Custom []byte `json:"custom"`
|
||||||
|
FeedType pgtype.Text `json:"feed_type"`
|
||||||
|
FeedVersion pgtype.Text `json:"feed_version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateFeed(ctx context.Context, arg CreateFeedParams) (Feed, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CreateFeed,
|
||||||
|
arg.Url,
|
||||||
|
arg.CreatedAt,
|
||||||
|
arg.UpdatedAt,
|
||||||
|
arg.DeletedAt,
|
||||||
|
arg.Title,
|
||||||
|
arg.Description,
|
||||||
|
arg.Link,
|
||||||
|
arg.FeedLink,
|
||||||
|
arg.Links,
|
||||||
|
arg.Updated,
|
||||||
|
arg.UpdatedParsed,
|
||||||
|
arg.Published,
|
||||||
|
arg.PublishedParsed,
|
||||||
|
arg.Language,
|
||||||
|
arg.Copyright,
|
||||||
|
arg.Generator,
|
||||||
|
arg.Categories,
|
||||||
|
arg.Custom,
|
||||||
|
arg.FeedType,
|
||||||
|
arg.FeedVersion,
|
||||||
|
)
|
||||||
|
var i Feed
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Url,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.DeletedAt,
|
||||||
|
&i.Title,
|
||||||
|
&i.Description,
|
||||||
|
&i.Link,
|
||||||
|
&i.FeedLink,
|
||||||
|
&i.Links,
|
||||||
|
&i.Updated,
|
||||||
|
&i.UpdatedParsed,
|
||||||
|
&i.Published,
|
||||||
|
&i.PublishedParsed,
|
||||||
|
&i.Language,
|
||||||
|
&i.Copyright,
|
||||||
|
&i.Generator,
|
||||||
|
&i.Categories,
|
||||||
|
&i.Custom,
|
||||||
|
&i.FeedType,
|
||||||
|
&i.FeedVersion,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
237
db/models.go
Normal file
237
db/models.go
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.25.0
|
||||||
|
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Enclosure struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Url pgtype.Text `json:"url"`
|
||||||
|
Length pgtype.Text `json:"length"`
|
||||||
|
Type pgtype.Text `json:"type"`
|
||||||
|
ItemID int32 `json:"item_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Feed struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
Url string `json:"url"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Title pgtype.Text `json:"title"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
Link pgtype.Text `json:"link"`
|
||||||
|
FeedLink pgtype.Text `json:"feed_link"`
|
||||||
|
Links []string `json:"links"`
|
||||||
|
Updated pgtype.Text `json:"updated"`
|
||||||
|
UpdatedParsed pgtype.Timestamp `json:"updated_parsed"`
|
||||||
|
Published pgtype.Text `json:"published"`
|
||||||
|
PublishedParsed pgtype.Timestamp `json:"published_parsed"`
|
||||||
|
Language pgtype.Text `json:"language"`
|
||||||
|
Copyright pgtype.Text `json:"copyright"`
|
||||||
|
Generator pgtype.Text `json:"generator"`
|
||||||
|
Categories []string `json:"categories"`
|
||||||
|
Custom []byte `json:"custom"`
|
||||||
|
FeedType pgtype.Text `json:"feed_type"`
|
||||||
|
FeedVersion pgtype.Text `json:"feed_version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FeedAuthor struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Name pgtype.Text `json:"name"`
|
||||||
|
Email pgtype.Text `json:"email"`
|
||||||
|
Uri pgtype.Text `json:"uri"`
|
||||||
|
FeedID int32 `json:"feed_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FeedDublinCore struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Title []string `json:"title"`
|
||||||
|
Creator []string `json:"creator"`
|
||||||
|
Author []string `json:"author"`
|
||||||
|
Subject []string `json:"subject"`
|
||||||
|
Description []string `json:"description"`
|
||||||
|
Publisher []string `json:"publisher"`
|
||||||
|
Contributor []string `json:"contributor"`
|
||||||
|
Date []string `json:"date"`
|
||||||
|
Type []string `json:"type"`
|
||||||
|
Format []string `json:"format"`
|
||||||
|
Identifier []string `json:"identifier"`
|
||||||
|
Source []string `json:"source"`
|
||||||
|
Language []string `json:"language"`
|
||||||
|
Relation []string `json:"relation"`
|
||||||
|
Coverage []string `json:"coverage"`
|
||||||
|
Rights []string `json:"rights"`
|
||||||
|
FeedID int32 `json:"feed_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FeedExtension struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Name pgtype.Text `json:"name"`
|
||||||
|
Value pgtype.Text `json:"value"`
|
||||||
|
Attrs []byte `json:"attrs"`
|
||||||
|
Children []byte `json:"children"`
|
||||||
|
FeedID int32 `json:"feed_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FeedImage struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Url pgtype.Text `json:"url"`
|
||||||
|
Title pgtype.Text `json:"title"`
|
||||||
|
FeedID int32 `json:"feed_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FeedItune struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Author pgtype.Text `json:"author"`
|
||||||
|
Block pgtype.Text `json:"block"`
|
||||||
|
Explicit pgtype.Text `json:"explicit"`
|
||||||
|
Keywords pgtype.Text `json:"keywords"`
|
||||||
|
Subtitle pgtype.Text `json:"subtitle"`
|
||||||
|
Summary pgtype.Text `json:"summary"`
|
||||||
|
Image pgtype.Text `json:"image"`
|
||||||
|
Complete pgtype.Text `json:"complete"`
|
||||||
|
NewFeedUrl pgtype.Text `json:"new_feed_url"`
|
||||||
|
Type pgtype.Text `json:"type"`
|
||||||
|
FeedID int32 `json:"feed_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Item struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Title pgtype.Text `json:"title"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
Content pgtype.Text `json:"content"`
|
||||||
|
Link pgtype.Text `json:"link"`
|
||||||
|
Links []string `json:"links"`
|
||||||
|
Updated pgtype.Text `json:"updated"`
|
||||||
|
UpdatedParsed pgtype.Timestamp `json:"updated_parsed"`
|
||||||
|
Published pgtype.Text `json:"published"`
|
||||||
|
PublishedParsed pgtype.Timestamp `json:"published_parsed"`
|
||||||
|
Guid pgtype.Text `json:"guid"`
|
||||||
|
Categories []string `json:"categories"`
|
||||||
|
Custom []byte `json:"custom"`
|
||||||
|
FeedID int32 `json:"feed_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ItemAuthor struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Name pgtype.Text `json:"name"`
|
||||||
|
Email pgtype.Text `json:"email"`
|
||||||
|
Uri pgtype.Text `json:"uri"`
|
||||||
|
ItemID int32 `json:"item_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ItemDublinCore struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Title []string `json:"title"`
|
||||||
|
Creator []string `json:"creator"`
|
||||||
|
Author []string `json:"author"`
|
||||||
|
Subject []string `json:"subject"`
|
||||||
|
Description []string `json:"description"`
|
||||||
|
Publisher []string `json:"publisher"`
|
||||||
|
Contributor []string `json:"contributor"`
|
||||||
|
Date []string `json:"date"`
|
||||||
|
Type []string `json:"type"`
|
||||||
|
Format []string `json:"format"`
|
||||||
|
Identifier []string `json:"identifier"`
|
||||||
|
Source []string `json:"source"`
|
||||||
|
Language []string `json:"language"`
|
||||||
|
Relation []string `json:"relation"`
|
||||||
|
Coverage []string `json:"coverage"`
|
||||||
|
Rights []string `json:"rights"`
|
||||||
|
ItemID int32 `json:"item_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ItemExtension struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Name pgtype.Text `json:"name"`
|
||||||
|
Value pgtype.Text `json:"value"`
|
||||||
|
Attrs []byte `json:"attrs"`
|
||||||
|
Children []byte `json:"children"`
|
||||||
|
ItemID int32 `json:"item_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ItemImage struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Url pgtype.Text `json:"url"`
|
||||||
|
Title pgtype.Text `json:"title"`
|
||||||
|
ItemID int32 `json:"item_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ItemItune struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Author pgtype.Text `json:"author"`
|
||||||
|
Block pgtype.Text `json:"block"`
|
||||||
|
Duration pgtype.Text `json:"duration"`
|
||||||
|
Explicit pgtype.Text `json:"explicit"`
|
||||||
|
Keywords pgtype.Text `json:"keywords"`
|
||||||
|
Subtitle pgtype.Text `json:"subtitle"`
|
||||||
|
Summary pgtype.Text `json:"summary"`
|
||||||
|
Image pgtype.Text `json:"image"`
|
||||||
|
IsClosedCaptioned pgtype.Text `json:"is_closed_captioned"`
|
||||||
|
Episode pgtype.Text `json:"episode"`
|
||||||
|
Season pgtype.Text `json:"season"`
|
||||||
|
Order pgtype.Text `json:"order"`
|
||||||
|
EpisodeType pgtype.Text `json:"episode_type"`
|
||||||
|
ItemID int32 `json:"item_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ItunesCategory struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Text pgtype.Text `json:"text"`
|
||||||
|
Subcategory pgtype.Text `json:"subcategory"`
|
||||||
|
ItunesID int32 `json:"itunes_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ItunesOwner struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamp `json:"deleted_at"`
|
||||||
|
Email pgtype.Text `json:"email"`
|
||||||
|
Name pgtype.Text `json:"name"`
|
||||||
|
ItunesID int32 `json:"itunes_id"`
|
||||||
|
}
|
||||||
16
db/querier.go
Normal file
16
db/querier.go
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.25.0
|
||||||
|
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Querier interface {
|
||||||
|
CountFeeds(ctx context.Context) (int64, error)
|
||||||
|
CreateFeed(ctx context.Context, arg CreateFeedParams) (Feed, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Querier = (*Queries)(nil)
|
||||||
54
feeds.go
54
feeds.go
|
|
@ -2,12 +2,60 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/TheLovinator1/FeedVault/db"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
"github.com/mmcdole/gofeed"
|
"github.com/mmcdole/gofeed"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func makeCreateFeedParams(feedURL string, feed *gofeed.Feed) db.CreateFeedParams {
|
||||||
|
links := make([]string, len(feed.Items))
|
||||||
|
for i, item := range feed.Items {
|
||||||
|
links[i] = item.Link
|
||||||
|
}
|
||||||
|
|
||||||
|
var updatedTime time.Time
|
||||||
|
if feed.UpdatedParsed != nil {
|
||||||
|
updatedTime = *feed.UpdatedParsed
|
||||||
|
}
|
||||||
|
var publishedTime time.Time
|
||||||
|
if feed.PublishedParsed != nil {
|
||||||
|
publishedTime = *feed.PublishedParsed
|
||||||
|
}
|
||||||
|
|
||||||
|
feedCustom, err := json.Marshal(feed.Custom)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error marshalling feed custom data:", err)
|
||||||
|
feedCustom = []byte("{}")
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.CreateFeedParams{
|
||||||
|
Url: feedURL,
|
||||||
|
CreatedAt: pgtype.Timestamp{Time: time.Now(), Valid: true},
|
||||||
|
UpdatedAt: pgtype.Timestamp{Time: time.Now(), Valid: true},
|
||||||
|
DeletedAt: pgtype.Timestamp{Valid: false},
|
||||||
|
Title: pgtype.Text{String: feed.Title, Valid: feed.Title != ""},
|
||||||
|
Description: pgtype.Text{String: feed.Description, Valid: feed.Description != ""},
|
||||||
|
Link: pgtype.Text{String: feed.Link, Valid: feed.Link != ""},
|
||||||
|
FeedLink: pgtype.Text{String: feed.FeedLink, Valid: feed.FeedLink != ""},
|
||||||
|
Links: links,
|
||||||
|
Updated: pgtype.Text{String: feed.Updated, Valid: feed.Updated != ""},
|
||||||
|
UpdatedParsed: pgtype.Timestamp{Time: updatedTime, Valid: !updatedTime.IsZero()},
|
||||||
|
Published: pgtype.Text{String: feed.Published, Valid: feed.Published != ""},
|
||||||
|
PublishedParsed: pgtype.Timestamp{Time: publishedTime, Valid: !publishedTime.IsZero()},
|
||||||
|
Language: pgtype.Text{String: feed.Language, Valid: feed.Language != ""},
|
||||||
|
Copyright: pgtype.Text{String: feed.Copyright, Valid: feed.Copyright != ""},
|
||||||
|
Generator: pgtype.Text{String: feed.Generator, Valid: feed.Generator != ""},
|
||||||
|
Categories: feed.Categories,
|
||||||
|
Custom: feedCustom,
|
||||||
|
FeedType: pgtype.Text{String: feed.FeedType, Valid: feed.FeedType != ""},
|
||||||
|
FeedVersion: pgtype.Text{String: feed.FeedVersion, Valid: feed.FeedVersion != ""},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func AddFeedToDB(feedURL string) error {
|
func AddFeedToDB(feedURL string) error {
|
||||||
// Cancel the request after 60 seconds if it hasn't finished
|
// Cancel the request after 60 seconds if it hasn't finished
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||||
|
|
@ -22,6 +70,12 @@ func AddFeedToDB(feedURL string) error {
|
||||||
return fmt.Errorf("Error parsing feed: %s", err)
|
return fmt.Errorf("Error parsing feed: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the feed to the database
|
||||||
|
_, err = DB.CreateFeed(ctx, makeCreateFeedParams(feedURL, feed))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error adding feed to database: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println(feed.Title)
|
fmt.Println(feed.Title)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
feedvault.db
Normal file
BIN
feedvault.db
Normal file
Binary file not shown.
12
go.mod
12
go.mod
|
|
@ -2,15 +2,21 @@ module github.com/TheLovinator1/FeedVault
|
||||||
|
|
||||||
go 1.22.0
|
go 1.22.0
|
||||||
|
|
||||||
require github.com/mmcdole/gofeed v1.2.1
|
require (
|
||||||
|
github.com/jackc/pgx/v5 v5.5.3
|
||||||
|
github.com/mmcdole/gofeed v1.2.1
|
||||||
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/PuerkitoBio/goquery v1.8.0 // indirect
|
github.com/PuerkitoBio/goquery v1.8.0 // indirect
|
||||||
github.com/andybalholm/cascadia v1.3.1 // indirect
|
github.com/andybalholm/cascadia v1.3.1 // indirect
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/mmcdole/goxpp v1.1.0 // indirect
|
github.com/mmcdole/goxpp v1.1.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
golang.org/x/net v0.4.0 // indirect
|
golang.org/x/crypto v0.17.0 // indirect
|
||||||
golang.org/x/text v0.5.0 // indirect
|
golang.org/x/net v0.10.0 // indirect
|
||||||
|
golang.org/x/text v0.14.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
23
go.sum
23
go.sum
|
|
@ -6,6 +6,14 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.3 h1:Ces6/M3wbDXYpM8JyyPD57ivTtJACFZJd885pdIaV2s=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.3/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
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/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/mmcdole/gofeed v1.2.1 h1:tPbFN+mfOLcM1kDF1x2c/N68ChbdBatkppdzf/vDe1s=
|
github.com/mmcdole/gofeed v1.2.1 h1:tPbFN+mfOLcM1kDF1x2c/N68ChbdBatkppdzf/vDe1s=
|
||||||
|
|
@ -21,17 +29,24 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||||
|
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
||||||
22
handlers.go
22
handlers.go
|
|
@ -18,7 +18,10 @@ func ApiHandler(w http.ResponseWriter, _ *http.Request) {
|
||||||
Content: "<p>Here be dragons.</p>",
|
Content: "<p>Here be dragons.</p>",
|
||||||
}
|
}
|
||||||
html := FullHTML(htmlData)
|
html := FullHTML(htmlData)
|
||||||
w.Write([]byte(html))
|
_, err := w.Write([]byte(html))
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error writing response:", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func FeedsHandler(w http.ResponseWriter, _ *http.Request) {
|
func FeedsHandler(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
|
@ -31,7 +34,10 @@ func FeedsHandler(w http.ResponseWriter, _ *http.Request) {
|
||||||
Content: "<p>Here be </p>",
|
Content: "<p>Here be </p>",
|
||||||
}
|
}
|
||||||
html := FullHTML(htmlData)
|
html := FullHTML(htmlData)
|
||||||
w.Write([]byte(html))
|
_, err := w.Write([]byte(html))
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error writing response:", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddFeedHandler(w http.ResponseWriter, r *http.Request) {
|
func AddFeedHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
@ -81,7 +87,11 @@ func AddFeedHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
html := FullHTML(htmlData)
|
html := FullHTML(htmlData)
|
||||||
w.Write([]byte(html))
|
_, err = w.Write([]byte(html))
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error writing response:", err)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func IndexHandler(w http.ResponseWriter, _ *http.Request) {
|
func IndexHandler(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
|
@ -158,7 +168,11 @@ func IndexHandler(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
|
||||||
func UploadOpmlHandler(w http.ResponseWriter, r *http.Request) {
|
func UploadOpmlHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
// Parse the form and get the file
|
// Parse the form and get the file
|
||||||
r.ParseMultipartForm(10 << 20) // 10 MB
|
err := r.ParseMultipartForm(10 << 20) // 10 MB
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Error parsing form", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
file, _, err := r.FormFile("file")
|
file, _, err := r.FormFile("file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "No file provided", http.StatusBadRequest)
|
http.Error(w, "No file provided", http.StatusBadRequest)
|
||||||
|
|
|
||||||
9
html.go
9
html.go
|
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
@ -165,7 +166,13 @@ func buildErrorList(parseResults []ParseResult) string {
|
||||||
|
|
||||||
func FullHTML(h HTMLData) string {
|
func FullHTML(h HTMLData) string {
|
||||||
statusMsg := buildErrorList(h.ParseResult)
|
statusMsg := buildErrorList(h.ParseResult)
|
||||||
feedCount := 0
|
|
||||||
|
feedCount, err := DB.CountFeeds(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("DB.CountFeeds(): %v", err)
|
||||||
|
feedCount = 0
|
||||||
|
}
|
||||||
|
|
||||||
databaseSize, err := GetDBSize()
|
databaseSize, err := GetDBSize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
databaseSize = "0 KiB"
|
databaseSize = "0 KiB"
|
||||||
|
|
|
||||||
23
main.go
23
main.go
|
|
@ -1,14 +1,37 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/TheLovinator1/FeedVault/db"
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
conn *pgx.Conn
|
||||||
|
DB *db.Queries
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() { log.SetFlags(log.LstdFlags | log.Lshortfile) }
|
func init() { log.SetFlags(log.LstdFlags | log.Lshortfile) }
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// Open a database connection
|
||||||
|
conn, err := pgx.Connect(ctx, "postgresql://localhost/feedvault?user=feedvault&password=feedvault")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("pgx.Connect(): %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
DB = db.New(conn)
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
defer conn.Close(context.Background())
|
||||||
|
|
||||||
log.Print("Starting server")
|
log.Print("Starting server")
|
||||||
|
|
||||||
// Create a new ServeMux
|
// Create a new ServeMux
|
||||||
|
|
|
||||||
53
sql/queries/feeds.sql
Normal file
53
sql/queries/feeds.sql
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
-- name: CreateFeed :one
|
||||||
|
INSERT INTO
|
||||||
|
feeds (
|
||||||
|
"url",
|
||||||
|
created_at,
|
||||||
|
updated_at,
|
||||||
|
deleted_at,
|
||||||
|
title,
|
||||||
|
"description",
|
||||||
|
link,
|
||||||
|
feed_link,
|
||||||
|
links,
|
||||||
|
updated,
|
||||||
|
updated_parsed,
|
||||||
|
published,
|
||||||
|
published_parsed,
|
||||||
|
"language",
|
||||||
|
copyright,
|
||||||
|
generator,
|
||||||
|
categories,
|
||||||
|
custom,
|
||||||
|
feed_type,
|
||||||
|
feed_version
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
$9,
|
||||||
|
$10,
|
||||||
|
$11,
|
||||||
|
$12,
|
||||||
|
$13,
|
||||||
|
$14,
|
||||||
|
$15,
|
||||||
|
$16,
|
||||||
|
$17,
|
||||||
|
$18,
|
||||||
|
$19,
|
||||||
|
$20
|
||||||
|
) RETURNING *;
|
||||||
|
|
||||||
|
-- name: CountFeeds :one
|
||||||
|
SELECT
|
||||||
|
COUNT(*)
|
||||||
|
FROM
|
||||||
|
feeds;
|
||||||
73
sql/schema/20240214043229_feeds.sql
Normal file
73
sql/schema/20240214043229_feeds.sql
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
-- Create table feeds if not exists
|
||||||
|
CREATE TABLE IF NOT EXISTS feeds (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
"url" TEXT NOT NULL,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP DEFAULT NULL,
|
||||||
|
-- From gofeed: https://github.com/mmcdole/gofeed/blob/master/feed.go
|
||||||
|
title TEXT,
|
||||||
|
"description" TEXT,
|
||||||
|
link TEXT,
|
||||||
|
feed_link TEXT,
|
||||||
|
links TEXT [],
|
||||||
|
updated TEXT,
|
||||||
|
updated_parsed TIMESTAMP,
|
||||||
|
published TEXT,
|
||||||
|
published_parsed TIMESTAMP,
|
||||||
|
-- Authors - See feed_authors
|
||||||
|
"language" TEXT,
|
||||||
|
-- Image - See feed_images
|
||||||
|
copyright TEXT,
|
||||||
|
generator TEXT,
|
||||||
|
categories TEXT [],
|
||||||
|
-- Dublin Core - See feed_dublin_cores
|
||||||
|
-- Itunes - See feed_itunes
|
||||||
|
-- Extensions - See feed_extensions
|
||||||
|
custom JSONB,
|
||||||
|
-- Items - See items
|
||||||
|
feed_type TEXT,
|
||||||
|
feed_version TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Feed item
|
||||||
|
-- https://github.com/mmcdole/gofeed/blob/master/feed.go#L49
|
||||||
|
CREATE TABLE IF NOT EXISTS items (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP DEFAULT NULL,
|
||||||
|
-- From gofeed:
|
||||||
|
title TEXT,
|
||||||
|
"description" TEXT,
|
||||||
|
content TEXT,
|
||||||
|
link TEXT,
|
||||||
|
links TEXT [],
|
||||||
|
updated TEXT,
|
||||||
|
updated_parsed TIMESTAMP,
|
||||||
|
published TEXT,
|
||||||
|
published_parsed TIMESTAMP,
|
||||||
|
-- Authors - See item_authors
|
||||||
|
"guid" TEXT,
|
||||||
|
-- Image - See item_images
|
||||||
|
categories TEXT [],
|
||||||
|
-- Enclosures - See enclosures
|
||||||
|
-- Dublin Core - See item_dublin_cores
|
||||||
|
-- Itunes - See item_itunes
|
||||||
|
-- Extensions - See item_extensions
|
||||||
|
custom JSONB,
|
||||||
|
-- Link to feed
|
||||||
|
feed_id INTEGER NOT NULL,
|
||||||
|
CONSTRAINT fk_feed_id FOREIGN KEY (feed_id) REFERENCES feeds (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose StatementEnd
|
||||||
|
-- +goose Down
|
||||||
|
-- +goose StatementBegin
|
||||||
|
DROP TABLE IF EXISTS feeds;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS items;
|
||||||
|
|
||||||
|
-- +goose StatementEnd
|
||||||
44
sql/schema/20240215232236_extensions.sql
Normal file
44
sql/schema/20240215232236_extensions.sql
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
-- Extensions for feeds
|
||||||
|
-- https://github.com/mmcdole/gofeed/blob/master/extensions/extensions.go#L3
|
||||||
|
CREATE TABLE IF NOT EXISTS feed_extensions (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP DEFAULT NULL,
|
||||||
|
-- From gofeed:
|
||||||
|
"name" TEXT,
|
||||||
|
"value" TEXT,
|
||||||
|
attrs JSONB,
|
||||||
|
children JSONB,
|
||||||
|
-- Link to feed
|
||||||
|
feed_id INTEGER NOT NULL,
|
||||||
|
CONSTRAINT fk_feed_id FOREIGN KEY (feed_id) REFERENCES feeds (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Extensions for items
|
||||||
|
-- https://github.com/mmcdole/gofeed/blob/master/extensions/extensions.go#L3
|
||||||
|
CREATE TABLE IF NOT EXISTS item_extensions (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP DEFAULT NULL,
|
||||||
|
-- From gofeed:
|
||||||
|
"name" TEXT,
|
||||||
|
"value" TEXT,
|
||||||
|
attrs JSONB,
|
||||||
|
children JSONB,
|
||||||
|
-- Link to feed item (Also called feed entry)
|
||||||
|
item_id INTEGER NOT NULL,
|
||||||
|
CONSTRAINT fk_item_id FOREIGN KEY (item_id) REFERENCES items (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose StatementEnd
|
||||||
|
-- +goose Down
|
||||||
|
-- +goose StatementBegin
|
||||||
|
DROP TABLE IF EXISTS feed_extensions;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS item_extensions;
|
||||||
|
|
||||||
|
-- +goose StatementEnd
|
||||||
42
sql/schema/20240215232245_authors.sql
Normal file
42
sql/schema/20240215232245_authors.sql
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
-- Person for feeds
|
||||||
|
-- https://github.com/mmcdole/gofeed/blob/master/feed.go#L73
|
||||||
|
CREATE TABLE IF NOT EXISTS feed_authors (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP DEFAULT NULL,
|
||||||
|
-- From gofeed:
|
||||||
|
"name" TEXT,
|
||||||
|
email TEXT,
|
||||||
|
uri TEXT,
|
||||||
|
-- Link to feed
|
||||||
|
feed_id INTEGER NOT NULL,
|
||||||
|
CONSTRAINT fk_feed_id FOREIGN KEY (feed_id) REFERENCES feeds (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Person for items
|
||||||
|
-- https://github.com/mmcdole/gofeed/blob/master/feed.go#L73
|
||||||
|
CREATE TABLE IF NOT EXISTS item_authors (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP DEFAULT NULL,
|
||||||
|
-- From gofeed:
|
||||||
|
"name" TEXT,
|
||||||
|
email TEXT,
|
||||||
|
uri TEXT,
|
||||||
|
-- Link to feed item (Also called feed entry)
|
||||||
|
item_id INTEGER NOT NULL,
|
||||||
|
CONSTRAINT fk_item_id FOREIGN KEY (item_id) REFERENCES items (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose StatementEnd
|
||||||
|
-- +goose Down
|
||||||
|
-- +goose StatementBegin
|
||||||
|
DROP TABLE IF EXISTS feed_authors;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS item_authors;
|
||||||
|
|
||||||
|
-- +goose StatementEnd
|
||||||
40
sql/schema/20240215232251_images.sql
Normal file
40
sql/schema/20240215232251_images.sql
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
-- Image for feeds
|
||||||
|
-- https://github.com/mmcdole/gofeed/blob/master/feed.go#L80
|
||||||
|
CREATE TABLE IF NOT EXISTS feed_images (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP DEFAULT NULL,
|
||||||
|
-- From gofeed:
|
||||||
|
"url" TEXT,
|
||||||
|
title TEXT,
|
||||||
|
-- Link to feed
|
||||||
|
feed_id INTEGER NOT NULL,
|
||||||
|
CONSTRAINT fk_feed_id FOREIGN KEY (feed_id) REFERENCES feeds (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Image for items
|
||||||
|
-- https://github.com/mmcdole/gofeed/blob/master/feed.go#L80
|
||||||
|
CREATE TABLE IF NOT EXISTS item_images (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP DEFAULT NULL,
|
||||||
|
-- From gofeed:
|
||||||
|
"url" TEXT,
|
||||||
|
title TEXT,
|
||||||
|
-- Link to feed item (Also called feed entry)
|
||||||
|
item_id INTEGER NOT NULL,
|
||||||
|
CONSTRAINT fk_item_id FOREIGN KEY (item_id) REFERENCES items (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose StatementEnd
|
||||||
|
-- +goose Down
|
||||||
|
-- +goose StatementBegin
|
||||||
|
DROP TABLE IF EXISTS feed_images;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS item_images;
|
||||||
|
|
||||||
|
-- +goose StatementEnd
|
||||||
68
sql/schema/20240215232259_dublin_cores.sql
Normal file
68
sql/schema/20240215232259_dublin_cores.sql
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
-- Dublin Core for feeds
|
||||||
|
-- https://github.com/mmcdole/gofeed/blob/master/extensions/dublincore.go#L5
|
||||||
|
CREATE TABLE IF NOT EXISTS feed_dublin_cores (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP DEFAULT NULL,
|
||||||
|
-- From gofeed:
|
||||||
|
title TEXT [],
|
||||||
|
creator TEXT [],
|
||||||
|
author TEXT [],
|
||||||
|
"subject" TEXT [],
|
||||||
|
"description" TEXT [],
|
||||||
|
publisher TEXT [],
|
||||||
|
contributor TEXT [],
|
||||||
|
"date" TEXT [],
|
||||||
|
"type" TEXT [],
|
||||||
|
format TEXT [],
|
||||||
|
identifier TEXT [],
|
||||||
|
source TEXT [],
|
||||||
|
"language" TEXT [],
|
||||||
|
relation TEXT [],
|
||||||
|
coverage TEXT [],
|
||||||
|
rights TEXT [],
|
||||||
|
-- Link to feed
|
||||||
|
feed_id INTEGER NOT NULL,
|
||||||
|
CONSTRAINT fk_feed_id FOREIGN KEY (feed_id) REFERENCES feeds (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Dublin Core for items
|
||||||
|
-- https://github.com/mmcdole/gofeed/blob/master/extensions/dublincore.go#L5
|
||||||
|
CREATE TABLE IF NOT EXISTS item_dublin_cores (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP DEFAULT NULL,
|
||||||
|
-- From gofeed:
|
||||||
|
title TEXT [],
|
||||||
|
creator TEXT [],
|
||||||
|
author TEXT [],
|
||||||
|
"subject" TEXT [],
|
||||||
|
"description" TEXT [],
|
||||||
|
publisher TEXT [],
|
||||||
|
contributor TEXT [],
|
||||||
|
"date" TEXT [],
|
||||||
|
"type" TEXT [],
|
||||||
|
format TEXT [],
|
||||||
|
identifier TEXT [],
|
||||||
|
source TEXT [],
|
||||||
|
"language" TEXT [],
|
||||||
|
relation TEXT [],
|
||||||
|
coverage TEXT [],
|
||||||
|
rights TEXT [],
|
||||||
|
-- Link to feed item (Also called feed entry)
|
||||||
|
item_id INTEGER NOT NULL,
|
||||||
|
CONSTRAINT fk_item_id FOREIGN KEY (item_id) REFERENCES items (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose StatementEnd
|
||||||
|
-- +goose Down
|
||||||
|
-- +goose StatementBegin
|
||||||
|
DROP TABLE IF EXISTS feed_dublin_cores;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS item_dublin_cores;
|
||||||
|
|
||||||
|
-- +goose StatementEnd
|
||||||
94
sql/schema/20240215232318_itunes.sql
Normal file
94
sql/schema/20240215232318_itunes.sql
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
-- Itunes for feeds
|
||||||
|
-- https://github.com/mmcdole/gofeed/blob/master/extensions/itunes.go#L5
|
||||||
|
CREATE TABLE IF NOT EXISTS feed_itunes (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP DEFAULT NULL,
|
||||||
|
-- From gofeed:
|
||||||
|
author TEXT,
|
||||||
|
"block" TEXT,
|
||||||
|
"explicit" TEXT,
|
||||||
|
keywords TEXT,
|
||||||
|
-- Owner
|
||||||
|
subtitle TEXT,
|
||||||
|
summary TEXT,
|
||||||
|
"image" TEXT,
|
||||||
|
complete TEXT,
|
||||||
|
new_feed_url TEXT,
|
||||||
|
"type" TEXT,
|
||||||
|
-- Link to feed
|
||||||
|
feed_id INTEGER NOT NULL,
|
||||||
|
CONSTRAINT fk_feed_id FOREIGN KEY (feed_id) REFERENCES feeds (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Itunes for items
|
||||||
|
-- https://github.com/mmcdole/gofeed/blob/master/extensions/itunes.go#L22
|
||||||
|
CREATE TABLE IF NOT EXISTS item_itunes (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP DEFAULT NULL,
|
||||||
|
-- From gofeed:
|
||||||
|
author TEXT,
|
||||||
|
"block" TEXT,
|
||||||
|
duration TEXT,
|
||||||
|
"explicit" TEXT,
|
||||||
|
keywords TEXT,
|
||||||
|
subtitle TEXT,
|
||||||
|
summary TEXT,
|
||||||
|
"image" TEXT,
|
||||||
|
is_closed_captioned TEXT,
|
||||||
|
episode TEXT,
|
||||||
|
season TEXT,
|
||||||
|
"order" TEXT,
|
||||||
|
episode_type TEXT,
|
||||||
|
-- Link to feed item (Also called feed entry)
|
||||||
|
item_id INTEGER NOT NULL,
|
||||||
|
CONSTRAINT fk_item_id FOREIGN KEY (item_id) REFERENCES items (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Itunes categories
|
||||||
|
-- https://github.com/mmcdole/gofeed/blob/master/extensions/itunes.go#L39
|
||||||
|
CREATE TABLE IF NOT EXISTS itunes_categories (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP DEFAULT NULL,
|
||||||
|
-- From gofeed:
|
||||||
|
"text" TEXT,
|
||||||
|
subcategory TEXT,
|
||||||
|
-- Link to itunes
|
||||||
|
itunes_id INTEGER NOT NULL,
|
||||||
|
CONSTRAINT fk_itunes_id FOREIGN KEY (itunes_id) REFERENCES feed_itunes (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Itunes owners
|
||||||
|
-- https://github.com/mmcdole/gofeed/blob/master/extensions/itunes.go#L45
|
||||||
|
CREATE TABLE IF NOT EXISTS itunes_owners (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP DEFAULT NULL,
|
||||||
|
-- From gofeed:
|
||||||
|
email TEXT,
|
||||||
|
"name" TEXT,
|
||||||
|
-- Link to itunes
|
||||||
|
itunes_id INTEGER NOT NULL,
|
||||||
|
CONSTRAINT fk_itunes_id FOREIGN KEY (itunes_id) REFERENCES feed_itunes (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose StatementEnd
|
||||||
|
-- +goose Down
|
||||||
|
-- +goose StatementBegin
|
||||||
|
DROP TABLE IF EXISTS feed_itunes;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS item_itunes;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS itunes_categories;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS itunes_owners;
|
||||||
|
|
||||||
|
-- +goose StatementEnd
|
||||||
24
sql/schema/20240215232334_enclousures.sql
Normal file
24
sql/schema/20240215232334_enclousures.sql
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
-- Enclosures
|
||||||
|
-- https://github.com/mmcdole/gofeed/blob/master/feed.go#L86
|
||||||
|
CREATE TABLE IF NOT EXISTS enclosures (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP DEFAULT NULL,
|
||||||
|
-- From gofeed:
|
||||||
|
"url" TEXT,
|
||||||
|
"length" TEXT,
|
||||||
|
"type" TEXT,
|
||||||
|
-- Link to feed item (Also called feed entry)
|
||||||
|
item_id INTEGER NOT NULL,
|
||||||
|
CONSTRAINT fk_item_id FOREIGN KEY (item_id) REFERENCES items (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose StatementEnd
|
||||||
|
-- +goose Down
|
||||||
|
-- +goose StatementBegin
|
||||||
|
DROP TABLE IF EXISTS enclosures;
|
||||||
|
|
||||||
|
-- +goose StatementEnd
|
||||||
14
sqlc.yaml
Normal file
14
sqlc.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
version: "2"
|
||||||
|
sql:
|
||||||
|
- engine: "postgresql"
|
||||||
|
queries: "sql/queries"
|
||||||
|
schema: "sql/schema"
|
||||||
|
gen:
|
||||||
|
go:
|
||||||
|
out: "db"
|
||||||
|
sql_package: "pgx/v5"
|
||||||
|
emit_prepared_queries: true
|
||||||
|
emit_interface: true
|
||||||
|
emit_empty_slices: true
|
||||||
|
emit_exported_queries: true
|
||||||
|
emit_json_tags: true
|
||||||
Loading…
Add table
Add a link
Reference in a new issue