c4498212dc
* main: (116 commits) Ensure avatar thumbnails are square Update useragent to recognize twitterbot/facebot Add defensive styles for non-square avatar images Update test for copy changes Missed commit AI: standardize on https://agents.md Make it clear this is just notifications, not comprehensive activity AI: configure MCP servers for Chrome, Grafana, and Sentry (#1727) Allow requests from Google Image Proxy Update to basecamp's useragent fork Clean up a little bit the CSRF reporting code Claude: production observability guidance (#1725) Prevent autoscroll to the root columns container to prevent jump on page load Include full name string so you can type your name to filter Prioritize current user and assigned users in assignment dropdown Check and report on Sec-Fetch-Site header for forgery protection bundle update Bump bootsnap from 1.18.6 to 1.19.0 Bump rails from `077c3ad` to `17f6e00` Fix cards getting stuck in edit mode ...
103 lines
3.6 KiB
Ruby
103 lines
3.6 KiB
Ruby
module Board::Accessible
|
|
extend ActiveSupport::Concern
|
|
|
|
included do
|
|
has_many :accesses, dependent: :delete_all do
|
|
def revise(granted: [], revoked: [])
|
|
transaction do
|
|
grant_to granted
|
|
revoke_from revoked
|
|
end
|
|
end
|
|
|
|
def grant_to(users)
|
|
Access.insert_all Array(users).collect { |user| { id: ActiveRecord::Type::Uuid.generate, board_id: proxy_association.owner.id, user_id: user.id, account_id: proxy_association.owner.account.id } }
|
|
end
|
|
|
|
def revoke_from(users)
|
|
destroy_by user: users unless proxy_association.owner.all_access?
|
|
end
|
|
end
|
|
|
|
has_many :users, through: :accesses
|
|
has_many :access_only_users, -> { merge(Access.access_only) }, through: :accesses, source: :user
|
|
|
|
scope :all_access, -> { where(all_access: true) }
|
|
|
|
after_create :grant_access_to_creator
|
|
after_save_commit :grant_access_to_everyone
|
|
end
|
|
|
|
def accessed_by(user)
|
|
access_for(user).accessed
|
|
end
|
|
|
|
def access_for(user)
|
|
accesses.find_by(user: user)
|
|
end
|
|
|
|
def accessible_to?(user)
|
|
access_for(user).present?
|
|
end
|
|
|
|
def clean_inaccessible_data_for(user)
|
|
return if accessible_to?(user)
|
|
|
|
mentions_for_user(user).destroy_all
|
|
notifications_for_user(user).destroy_all
|
|
watches_for(user).destroy_all
|
|
end
|
|
|
|
def watchers
|
|
users.active.where(accesses: { involvement: :watching })
|
|
end
|
|
|
|
private
|
|
def grant_access_to_creator
|
|
accesses.create(user: creator, involvement: :watching)
|
|
end
|
|
|
|
def grant_access_to_everyone
|
|
accesses.grant_to(account.users.active) if all_access_previously_changed?(to: true)
|
|
end
|
|
|
|
def mentions_for_user(user)
|
|
# Query handles 2 paths:
|
|
#
|
|
# 1. Mention->Card
|
|
# 2. Mention->Comment->Card
|
|
board_id_binary = ActiveRecord::Type::Uuid.new.serialize(id)
|
|
|
|
user.mentions
|
|
.joins("LEFT JOIN cards ON mentions.source_id = cards.id AND mentions.source_type = 'Card'")
|
|
.joins("LEFT JOIN comments ON mentions.source_id = comments.id AND mentions.source_type = 'Comment'")
|
|
.joins("LEFT JOIN cards AS comment_cards ON comments.card_id = comment_cards.id")
|
|
.where("(mentions.source_type = 'Card' AND cards.board_id = ?) OR (mentions.source_type = 'Comment' AND comment_cards.board_id = ?)", board_id_binary, board_id_binary)
|
|
end
|
|
|
|
def notifications_for_user(user)
|
|
# Query handles 2 paths:
|
|
#
|
|
# 1. Notification->Event->Card
|
|
# 2. Notification->Event->Comment->Card
|
|
#
|
|
# Notification->Event->Mention->Card and Notification->Event->Mention->Comment->Card are
|
|
# handled by destroying mentions_for_user.
|
|
uuid_type = ActiveRecord::Type.lookup(:uuid, adapter: :trilogy)
|
|
board_id_binary = uuid_type.serialize(id)
|
|
|
|
user.notifications
|
|
.joins("LEFT JOIN events ON notifications.source_id = events.id AND notifications.source_type = 'Event'")
|
|
.joins("LEFT JOIN cards AS event_cards ON events.eventable_id = event_cards.id AND events.eventable_type = 'Card'")
|
|
.joins("LEFT JOIN comments AS event_comments ON events.eventable_id = event_comments.id AND events.eventable_type = 'Comment'")
|
|
.joins("LEFT JOIN cards AS event_comment_cards ON event_comments.card_id = event_comment_cards.id")
|
|
.where("(notifications.source_type = 'Event' AND events.eventable_type = 'Card' AND event_cards.board_id = ?) OR
|
|
(notifications.source_type = 'Event' AND events.eventable_type = 'Comment' AND event_comment_cards.board_id = ?)",
|
|
board_id_binary, board_id_binary)
|
|
end
|
|
|
|
def watches_for(user)
|
|
Watch.where(card: cards, user: user)
|
|
end
|
|
end
|