1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package storage // import "miniflux.app/v2/internal/storage"
import (
"crypto/rand"
"database/sql"
"fmt"
"time"
"miniflux.app/v2/internal/model"
)
// CreateAppSessionWithUserPrefs creates a new application session with the given user preferences.
func (s *Storage) CreateAppSessionWithUserPrefs(userID int64) (*model.Session, error) {
user, err := s.UserByID(userID)
if err != nil {
return nil, err
}
session := model.Session{
ID: rand.Text(),
Data: &model.SessionData{
CSRF: rand.Text(),
Theme: user.Theme,
Language: user.Language,
},
}
return s.createAppSession(&session)
}
// CreateAppSession creates a new application session.
func (s *Storage) CreateAppSession() (*model.Session, error) {
session := model.Session{
ID: rand.Text(),
Data: &model.SessionData{
CSRF: rand.Text(),
},
}
return s.createAppSession(&session)
}
func (s *Storage) createAppSession(session *model.Session) (*model.Session, error) {
query := `INSERT INTO sessions (id, data) VALUES ($1, $2)`
_, err := s.db.Exec(query, session.ID, session.Data)
if err != nil {
return nil, fmt.Errorf(`store: unable to create app session: %v`, err)
}
return session, nil
}
// SetAppSessionTextField sets a text field in the session data.
func (s *Storage) SetAppSessionTextField(sessionID, field string, value any) error {
query := `
UPDATE
sessions
SET
data = jsonb_set(data, ARRAY[$2::text], to_jsonb($1::text), true)
WHERE
id=$3
`
_, err := s.db.Exec(query, value, field, sessionID)
if err != nil {
return fmt.Errorf(`store: unable to update session text field %q: %v`, field, err)
}
return nil
}
// SetAppSessionJSONField sets a JSON field in the session data.
func (s *Storage) SetAppSessionJSONField(sessionID, field string, value any) error {
query := `
UPDATE
sessions
SET
data = jsonb_set(data, ARRAY[$2::text], $1, true)
WHERE
id=$3
`
_, err := s.db.Exec(query, value, field, sessionID)
if err != nil {
return fmt.Errorf(`store: unable to update session JSON field %q: %v`, field, err)
}
return nil
}
// AppSession returns the given session.
func (s *Storage) AppSession(id string) (*model.Session, error) {
var session model.Session
query := "SELECT id, data FROM sessions WHERE id=$1"
err := s.db.QueryRow(query, id).Scan(
&session.ID,
&session.Data,
)
switch {
case err == sql.ErrNoRows:
return nil, fmt.Errorf(`store: session not found: %s`, id)
case err != nil:
return nil, fmt.Errorf(`store: unable to fetch session: %v`, err)
default:
return &session, nil
}
}
// FlushAllSessions removes all sessions from the database.
func (s *Storage) FlushAllSessions() (err error) {
_, err = s.db.Exec(`DELETE FROM user_sessions`)
if err != nil {
return err
}
_, err = s.db.Exec(`DELETE FROM sessions`)
if err != nil {
return err
}
return nil
}
// CleanOldSessions removes sessions older than specified interval (24h minimum).
func (s *Storage) CleanOldSessions(interval time.Duration) int64 {
query := `
DELETE FROM
sessions
WHERE
created_at < now() - $1::interval
`
days := max(int(interval/(24*time.Hour)), 1)
result, err := s.db.Exec(query, fmt.Sprintf("%d days", days))
if err != nil {
return 0
}
n, _ := result.RowsAffected()
return n
}
|