session.go 3.2 KB

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