webapi_preferences.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. package state
  2. import (
  3. "context"
  4. "database/sql"
  5. "encoding/json"
  6. "errors"
  7. "time"
  8. "github.com/mk6i/retro-aim-server/wire"
  9. )
  10. // WebPreferenceManager handles Web API user preferences.
  11. type WebPreferenceManager struct {
  12. store *SQLiteUserStore
  13. }
  14. // NewWebPreferenceManager creates a new WebPreferenceManager.
  15. func (s *SQLiteUserStore) NewWebPreferenceManager() *WebPreferenceManager {
  16. return &WebPreferenceManager{store: s}
  17. }
  18. // SetPreferences stores user preferences in the database.
  19. func (m *WebPreferenceManager) SetPreferences(ctx context.Context, screenName IdentScreenName, prefs map[string]interface{}) error {
  20. prefsJSON, err := json.Marshal(prefs)
  21. if err != nil {
  22. return err
  23. }
  24. now := time.Now().Unix()
  25. q := `
  26. INSERT INTO web_preferences (screen_name, preferences, created_at, updated_at)
  27. VALUES (?, ?, ?, ?)
  28. ON CONFLICT (screen_name)
  29. DO UPDATE SET preferences = excluded.preferences, updated_at = excluded.updated_at
  30. `
  31. _, err = m.store.db.ExecContext(ctx, q, screenName.String(), string(prefsJSON), now, now)
  32. return err
  33. }
  34. // GetPreferences retrieves user preferences from the database.
  35. func (m *WebPreferenceManager) GetPreferences(ctx context.Context, screenName IdentScreenName) (map[string]interface{}, error) {
  36. q := `
  37. SELECT preferences
  38. FROM web_preferences
  39. WHERE screen_name = ?
  40. `
  41. var prefsJSON string
  42. err := m.store.db.QueryRowContext(ctx, q, screenName.String()).Scan(&prefsJSON)
  43. if err != nil {
  44. if errors.Is(err, sql.ErrNoRows) {
  45. // Return empty preferences if none exist
  46. return make(map[string]interface{}), nil
  47. }
  48. return nil, err
  49. }
  50. var prefs map[string]interface{}
  51. if err := json.Unmarshal([]byte(prefsJSON), &prefs); err != nil {
  52. return nil, err
  53. }
  54. return prefs, nil
  55. }
  56. // WebPermitDenyManager handles Web API permit/deny list management.
  57. type WebPermitDenyManager struct {
  58. store *SQLiteUserStore
  59. }
  60. // NewWebPermitDenyManager creates a new WebPermitDenyManager.
  61. func (s *SQLiteUserStore) NewWebPermitDenyManager() *WebPermitDenyManager {
  62. return &WebPermitDenyManager{store: s}
  63. }
  64. // SetPDMode sets the permit/deny mode for a user.
  65. func (m *WebPermitDenyManager) SetPDMode(ctx context.Context, screenName IdentScreenName, mode wire.FeedbagPDMode) error {
  66. q := `
  67. INSERT INTO buddyListMode (screenName, clientSidePDMode)
  68. VALUES (?, ?)
  69. ON CONFLICT (screenName)
  70. DO UPDATE SET clientSidePDMode = excluded.clientSidePDMode
  71. `
  72. _, err := m.store.db.ExecContext(ctx, q, screenName.String(), int(mode))
  73. return err
  74. }
  75. // GetPDMode retrieves the permit/deny mode for a user.
  76. func (m *WebPermitDenyManager) GetPDMode(ctx context.Context, screenName IdentScreenName) (wire.FeedbagPDMode, error) {
  77. q := `
  78. SELECT clientSidePDMode
  79. FROM buddyListMode
  80. WHERE screenName = ?
  81. `
  82. var mode int
  83. err := m.store.db.QueryRowContext(ctx, q, screenName.String()).Scan(&mode)
  84. if err != nil {
  85. if errors.Is(err, sql.ErrNoRows) {
  86. // Default to PermitAll if not set
  87. return wire.FeedbagPDModePermitAll, nil
  88. }
  89. return 0, err
  90. }
  91. return wire.FeedbagPDMode(mode), nil
  92. }
  93. // GetPermitList retrieves the permit list for a user.
  94. func (m *WebPermitDenyManager) GetPermitList(ctx context.Context, screenName IdentScreenName) ([]IdentScreenName, error) {
  95. q := `
  96. SELECT them
  97. FROM clientSideBuddyList
  98. WHERE me = ? AND isPermit = 1
  99. `
  100. rows, err := m.store.db.QueryContext(ctx, q, screenName.String())
  101. if err != nil {
  102. return nil, err
  103. }
  104. defer rows.Close()
  105. var users []IdentScreenName
  106. for rows.Next() {
  107. var user string
  108. if err := rows.Scan(&user); err != nil {
  109. return nil, err
  110. }
  111. users = append(users, NewIdentScreenName(user))
  112. }
  113. return users, rows.Err()
  114. }
  115. // GetDenyList retrieves the deny list for a user.
  116. func (m *WebPermitDenyManager) GetDenyList(ctx context.Context, screenName IdentScreenName) ([]IdentScreenName, error) {
  117. q := `
  118. SELECT them
  119. FROM clientSideBuddyList
  120. WHERE me = ? AND isDeny = 1
  121. `
  122. rows, err := m.store.db.QueryContext(ctx, q, screenName.String())
  123. if err != nil {
  124. return nil, err
  125. }
  126. defer rows.Close()
  127. var users []IdentScreenName
  128. for rows.Next() {
  129. var user string
  130. if err := rows.Scan(&user); err != nil {
  131. return nil, err
  132. }
  133. users = append(users, NewIdentScreenName(user))
  134. }
  135. return users, rows.Err()
  136. }
  137. // AddPermitBuddy adds a user to the permit list.
  138. func (m *WebPermitDenyManager) AddPermitBuddy(ctx context.Context, me IdentScreenName, them IdentScreenName) error {
  139. q := `
  140. INSERT INTO clientSideBuddyList (me, them, isPermit)
  141. VALUES (?, ?, 1)
  142. ON CONFLICT (me, them) DO UPDATE SET isPermit = 1
  143. `
  144. _, err := m.store.db.ExecContext(ctx, q, me.String(), them.String())
  145. return err
  146. }
  147. // RemovePermitBuddy removes a user from the permit list.
  148. func (m *WebPermitDenyManager) RemovePermitBuddy(ctx context.Context, me IdentScreenName, them IdentScreenName) error {
  149. q := `
  150. UPDATE clientSideBuddyList
  151. SET isPermit = 0
  152. WHERE me = ? AND them = ?
  153. `
  154. _, err := m.store.db.ExecContext(ctx, q, me.String(), them.String())
  155. return err
  156. }
  157. // AddDenyBuddy adds a user to the deny list.
  158. func (m *WebPermitDenyManager) AddDenyBuddy(ctx context.Context, me IdentScreenName, them IdentScreenName) error {
  159. q := `
  160. INSERT INTO clientSideBuddyList (me, them, isDeny)
  161. VALUES (?, ?, 1)
  162. ON CONFLICT (me, them) DO UPDATE SET isDeny = 1
  163. `
  164. _, err := m.store.db.ExecContext(ctx, q, me.String(), them.String())
  165. return err
  166. }
  167. // RemoveDenyBuddy removes a user from the deny list.
  168. func (m *WebPermitDenyManager) RemoveDenyBuddy(ctx context.Context, me IdentScreenName, them IdentScreenName) error {
  169. q := `
  170. UPDATE clientSideBuddyList
  171. SET isDeny = 0
  172. WHERE me = ? AND them = ?
  173. `
  174. _, err := m.store.db.ExecContext(ctx, q, me.String(), them.String())
  175. return err
  176. }