The code powering m.abunchtell.com https://m.abunchtell.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

112 lines
3.1 KiB

  1. # frozen_string_literal: true
  2. # == Schema Information
  3. #
  4. # Table name: account_conversations
  5. #
  6. # id :bigint(8) not null, primary key
  7. # account_id :bigint(8)
  8. # conversation_id :bigint(8)
  9. # participant_account_ids :bigint(8) default([]), not null, is an Array
  10. # status_ids :bigint(8) default([]), not null, is an Array
  11. # last_status_id :bigint(8)
  12. # lock_version :integer default(0), not null
  13. #
  14. class AccountConversation < ApplicationRecord
  15. after_commit :push_to_streaming_api
  16. belongs_to :account
  17. belongs_to :conversation
  18. belongs_to :last_status, class_name: 'Status'
  19. before_validation :set_last_status
  20. def participant_account_ids=(arr)
  21. self[:participant_account_ids] = arr.sort
  22. end
  23. def participant_accounts
  24. if participant_account_ids.empty?
  25. [account]
  26. else
  27. Account.where(id: participant_account_ids)
  28. end
  29. end
  30. class << self
  31. def paginate_by_id(limit, options = {})
  32. if options[:min_id]
  33. paginate_by_min_id(limit, options[:min_id]).reverse
  34. else
  35. paginate_by_max_id(limit, options[:max_id], options[:since_id])
  36. end
  37. end
  38. def paginate_by_min_id(limit, min_id = nil)
  39. query = order(arel_table[:last_status_id].asc).limit(limit)
  40. query = query.where(arel_table[:last_status_id].gt(min_id)) if min_id.present?
  41. query
  42. end
  43. def paginate_by_max_id(limit, max_id = nil, since_id = nil)
  44. query = order(arel_table[:last_status_id].desc).limit(limit)
  45. query = query.where(arel_table[:last_status_id].lt(max_id)) if max_id.present?
  46. query = query.where(arel_table[:last_status_id].gt(since_id)) if since_id.present?
  47. query
  48. end
  49. def add_status(recipient, status)
  50. conversation = find_or_initialize_by(account: recipient, conversation_id: status.conversation_id, participant_account_ids: participants_from_status(recipient, status))
  51. conversation.status_ids << status.id
  52. conversation.save
  53. conversation
  54. rescue ActiveRecord::StaleObjectError
  55. retry
  56. end
  57. def remove_status(recipient, status)
  58. conversation = find_by(account: recipient, conversation_id: status.conversation_id, participant_account_ids: participants_from_status(recipient, status))
  59. return if conversation.nil?
  60. conversation.status_ids.delete(status.id)
  61. if conversation.status_ids.empty?
  62. conversation.destroy
  63. else
  64. conversation.save
  65. end
  66. conversation
  67. rescue ActiveRecord::StaleObjectError
  68. retry
  69. end
  70. private
  71. def participants_from_status(recipient, status)
  72. ((status.active_mentions.pluck(:account_id) + [status.account_id]).uniq - [recipient.id]).sort
  73. end
  74. end
  75. private
  76. def set_last_status
  77. self.status_ids = status_ids.sort
  78. self.last_status_id = status_ids.last
  79. end
  80. def push_to_streaming_api
  81. return if destroyed? || !subscribed_to_timeline?
  82. PushConversationWorker.perform_async(id)
  83. end
  84. def subscribed_to_timeline?
  85. Redis.current.exists("subscribed:#{streaming_channel}")
  86. end
  87. def streaming_channel
  88. "timeline:direct:#{account_id}"
  89. end
  90. end