session.go 2.9 KB

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