mirror of
https://github.com/miniflux/v2.git
synced 2025-08-01 17:38:37 +00:00
Add Fever API
This commit is contained in:
parent
ae62e543d3
commit
bc20e0884b
24 changed files with 984 additions and 37 deletions
|
@ -9,24 +9,47 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq"
|
||||
|
||||
"github.com/miniflux/miniflux2/helper"
|
||||
"github.com/miniflux/miniflux2/model"
|
||||
)
|
||||
|
||||
// EntryQueryBuilder builds a SQL query to fetch entries.
|
||||
type EntryQueryBuilder struct {
|
||||
store *Storage
|
||||
feedID int64
|
||||
userID int64
|
||||
timezone string
|
||||
categoryID int64
|
||||
status string
|
||||
notStatus string
|
||||
order string
|
||||
direction string
|
||||
limit int
|
||||
offset int
|
||||
entryID int64
|
||||
store *Storage
|
||||
feedID int64
|
||||
userID int64
|
||||
timezone string
|
||||
categoryID int64
|
||||
status string
|
||||
notStatus string
|
||||
order string
|
||||
direction string
|
||||
limit int
|
||||
offset int
|
||||
entryID int64
|
||||
greaterThanEntryID int64
|
||||
entryIDs []int64
|
||||
before *time.Time
|
||||
}
|
||||
|
||||
// Before add condition base on the entry date.
|
||||
func (e *EntryQueryBuilder) Before(date *time.Time) *EntryQueryBuilder {
|
||||
e.before = date
|
||||
return e
|
||||
}
|
||||
|
||||
// WithGreaterThanEntryID adds a condition > entryID.
|
||||
func (e *EntryQueryBuilder) WithGreaterThanEntryID(entryID int64) *EntryQueryBuilder {
|
||||
e.greaterThanEntryID = entryID
|
||||
return e
|
||||
}
|
||||
|
||||
// WithEntryIDs adds a condition to fetch only the given entry IDs.
|
||||
func (e *EntryQueryBuilder) WithEntryIDs(entryIDs []int64) *EntryQueryBuilder {
|
||||
e.entryIDs = entryIDs
|
||||
return e
|
||||
}
|
||||
|
||||
// WithEntryID set the entryID.
|
||||
|
@ -195,6 +218,44 @@ func (e *EntryQueryBuilder) GetEntries() (model.Entries, error) {
|
|||
return entries, nil
|
||||
}
|
||||
|
||||
// GetEntryIDs returns a list of entry IDs that match the condition.
|
||||
func (e *EntryQueryBuilder) GetEntryIDs() ([]int64, error) {
|
||||
debugStr := "[EntryQueryBuilder:GetEntryIDs] userID=%d, feedID=%d, categoryID=%d, status=%s, order=%s, direction=%s, offset=%d, limit=%d"
|
||||
defer helper.ExecutionTime(time.Now(), fmt.Sprintf(debugStr, e.userID, e.feedID, e.categoryID, e.status, e.order, e.direction, e.offset, e.limit))
|
||||
|
||||
query := `
|
||||
SELECT
|
||||
e.id
|
||||
FROM entries e
|
||||
LEFT JOIN feeds f ON f.id=e.feed_id
|
||||
WHERE %s %s
|
||||
`
|
||||
|
||||
args, conditions := e.buildCondition()
|
||||
query = fmt.Sprintf(query, conditions, e.buildSorting())
|
||||
// log.Println(query)
|
||||
|
||||
rows, err := e.store.db.Query(query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get entries: %v", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var entryIDs []int64
|
||||
for rows.Next() {
|
||||
var entryID int64
|
||||
|
||||
err := rows.Scan(&entryID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to fetch entry row: %v", err)
|
||||
}
|
||||
|
||||
entryIDs = append(entryIDs, entryID)
|
||||
}
|
||||
|
||||
return entryIDs, nil
|
||||
}
|
||||
|
||||
func (e *EntryQueryBuilder) buildCondition() ([]interface{}, string) {
|
||||
args := []interface{}{e.userID}
|
||||
conditions := []string{"e.user_id = $1"}
|
||||
|
@ -214,6 +275,16 @@ func (e *EntryQueryBuilder) buildCondition() ([]interface{}, string) {
|
|||
args = append(args, e.entryID)
|
||||
}
|
||||
|
||||
if e.greaterThanEntryID != 0 {
|
||||
conditions = append(conditions, fmt.Sprintf("e.id > $%d", len(args)+1))
|
||||
args = append(args, e.greaterThanEntryID)
|
||||
}
|
||||
|
||||
if e.entryIDs != nil {
|
||||
conditions = append(conditions, fmt.Sprintf("e.id=ANY($%d)", len(args)+1))
|
||||
args = append(args, pq.Array(e.entryIDs))
|
||||
}
|
||||
|
||||
if e.status != "" {
|
||||
conditions = append(conditions, fmt.Sprintf("e.status=$%d", len(args)+1))
|
||||
args = append(args, e.status)
|
||||
|
@ -224,6 +295,11 @@ func (e *EntryQueryBuilder) buildCondition() ([]interface{}, string) {
|
|||
args = append(args, e.notStatus)
|
||||
}
|
||||
|
||||
if e.before != nil {
|
||||
conditions = append(conditions, fmt.Sprintf("e.published_at < $%d", len(args)+1))
|
||||
args = append(args, e.before)
|
||||
}
|
||||
|
||||
return args, strings.Join(conditions, " AND ")
|
||||
}
|
||||
|
||||
|
|
|
@ -101,6 +101,37 @@ func (s *Storage) CreateFeedIcon(feed *model.Feed, icon *model.Icon) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Icons returns all icons tht belongs to a user.
|
||||
func (s *Storage) Icons(userID int64) (model.Icons, error) {
|
||||
defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:Icons] userID=%d", userID))
|
||||
query := `
|
||||
SELECT
|
||||
icons.id, icons.hash, icons.mime_type, icons.content
|
||||
FROM icons
|
||||
LEFT JOIN feed_icons ON feed_icons.icon_id=icons.id
|
||||
LEFT JOIN feeds ON feeds.id=feed_icons.feed_id
|
||||
WHERE feeds.user_id=$1
|
||||
`
|
||||
|
||||
rows, err := s.db.Query(query, userID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to fetch icons: %v", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var icons model.Icons
|
||||
for rows.Next() {
|
||||
var icon model.Icon
|
||||
err := rows.Scan(&icon.ID, &icon.Hash, &icon.MimeType, &icon.Content)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to fetch icons row: %v", err)
|
||||
}
|
||||
icons = append(icons, &icon)
|
||||
}
|
||||
|
||||
return icons, nil
|
||||
}
|
||||
|
||||
func normalizeMimeType(mimeType string) string {
|
||||
mimeType = strings.ToLower(mimeType)
|
||||
switch mimeType {
|
||||
|
|
|
@ -11,6 +11,28 @@ import (
|
|||
"github.com/miniflux/miniflux2/model"
|
||||
)
|
||||
|
||||
// UserByFeverToken returns a user by using the Fever API token.
|
||||
func (s *Storage) UserByFeverToken(token string) (*model.User, error) {
|
||||
query := `
|
||||
SELECT
|
||||
users.id, users.is_admin, users.timezone
|
||||
FROM users
|
||||
LEFT JOIN integrations ON integrations.user_id=users.id
|
||||
WHERE integrations.fever_enabled='t' AND integrations.fever_token=$1
|
||||
`
|
||||
|
||||
var user model.User
|
||||
err := s.db.QueryRow(query, token).Scan(&user.ID, &user.IsAdmin, &user.Timezone)
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
return nil, nil
|
||||
case err != nil:
|
||||
return nil, fmt.Errorf("unable to fetch user: %v", err)
|
||||
}
|
||||
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// Integration returns user integration settings.
|
||||
func (s *Storage) Integration(userID int64) (*model.Integration, error) {
|
||||
query := `SELECT
|
||||
|
@ -21,7 +43,11 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
|
|||
pinboard_mark_as_unread,
|
||||
instapaper_enabled,
|
||||
instapaper_username,
|
||||
instapaper_password
|
||||
instapaper_password,
|
||||
fever_enabled,
|
||||
fever_username,
|
||||
fever_password,
|
||||
fever_token
|
||||
FROM integrations
|
||||
WHERE user_id=$1
|
||||
`
|
||||
|
@ -35,6 +61,10 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
|
|||
&integration.InstapaperEnabled,
|
||||
&integration.InstapaperUsername,
|
||||
&integration.InstapaperPassword,
|
||||
&integration.FeverEnabled,
|
||||
&integration.FeverUsername,
|
||||
&integration.FeverPassword,
|
||||
&integration.FeverToken,
|
||||
)
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
|
@ -56,8 +86,12 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
|
|||
pinboard_mark_as_unread=$4,
|
||||
instapaper_enabled=$5,
|
||||
instapaper_username=$6,
|
||||
instapaper_password=$7
|
||||
WHERE user_id=$8
|
||||
instapaper_password=$7,
|
||||
fever_enabled=$8,
|
||||
fever_username=$9,
|
||||
fever_password=$10,
|
||||
fever_token=$11
|
||||
WHERE user_id=$12
|
||||
`
|
||||
_, err := s.db.Exec(
|
||||
query,
|
||||
|
@ -68,6 +102,10 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
|
|||
integration.InstapaperEnabled,
|
||||
integration.InstapaperUsername,
|
||||
integration.InstapaperPassword,
|
||||
integration.FeverEnabled,
|
||||
integration.FeverUsername,
|
||||
integration.FeverPassword,
|
||||
integration.FeverToken,
|
||||
integration.UserID,
|
||||
)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue