Skip to content
Snippets Groups Projects
Unverified Commit 45e333ce authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets
Browse files

Use participants from database table instead of parsing all comments

parent b2cc24ba
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -55,7 +55,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
 
def show
@participants = @issue.participants(current_user, @project)
@participants = @issue.participants
@note = @project.notes.new(noteable: @issue)
@notes = @issue.notes.inc_author.fresh
@noteable = @issue
Loading
Loading
Loading
Loading
@@ -246,7 +246,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
 
def define_show_vars
@participants = @merge_request.participants(current_user, @project)
@participants = @merge_request.participants
 
# Build a note object for comment form
@note = @project.notes.new(noteable: @merge_request)
Loading
Loading
Loading
Loading
@@ -8,7 +8,6 @@ class Commit
include StaticModel
 
attr_mentionable :safe_message
participant :author, :committer, :notes, :mentioned_users
 
attr_accessor :project
 
Loading
Loading
Loading
Loading
@@ -17,7 +17,6 @@ module Issuable
has_many :label_links, as: :target, dependent: :destroy
has_many :labels, through: :label_links
has_many :subscriptions, dependent: :destroy, as: :subscribable
# has_many :participants, dependent: :destroy, as: :target
 
validates :author, presence: true
validates :title, presence: true, length: { within: 0..255 }
Loading
Loading
@@ -47,7 +46,6 @@ module Issuable
prefix: true
 
attr_mentionable :title, :description
participant :author, :assignee, :notes, :mentioned_users
end
 
module ClassMethods
Loading
Loading
@@ -127,7 +125,7 @@ module Issuable
return subscription.subscribed
end
 
participants(user).include?(user)
participants.include?(user)
end
 
def toggle_subscription(user)
Loading
Loading
Loading
Loading
@@ -9,10 +9,6 @@
#
# class Issue < ActiveRecord::Base
# include Participable
#
# # ...
#
# participant :author, :assignee, :mentioned_users, :notes
# end
#
# issue = Issue.last
Loading
Loading
@@ -23,53 +19,14 @@
# # since Note implements Participable as well.
#
module Participable
extend ActiveSupport::Concern
module ClassMethods
def participant(*attrs)
participant_attrs.concat(attrs.map(&:to_s))
end
def participant_attrs
@participant_attrs ||= []
end
end
# Be aware that this method makes a lot of sql queries.
# Save result into variable if you are going to reuse it inside same request
def participants(current_user = self.author, project = self.project)
participants = self.class.participant_attrs.flat_map do |attr|
meth = method(attr)
value =
if meth.arity == 1 || meth.arity == -1
meth.call(current_user)
else
meth.call
end
participants_for(value, current_user, project)
end.compact.uniq
if project
participants.select! do |user|
user.can?(:read_project, project)
def participants
@participants ||=
begin
user_ids = Participant.
where(target_id: id.to_s, target_type: self.class.name).
pluck(:user_id)
User.where(id: user_ids)
end
end
participants
end
private
def participants_for(value, current_user = nil, project = nil)
case value
when User
[value]
when Enumerable, ActiveRecord::Relation
value.flat_map { |v| participants_for(v, current_user, project) }
when Participable
value.participants(current_user, project)
end
end
end
Loading
Loading
@@ -23,12 +23,10 @@ require 'file_size_validator'
class Note < ActiveRecord::Base
include Mentionable
include Gitlab::CurrentSettings
include Participable
 
default_value_for :system, false
 
attr_mentionable :note
participant :author, :mentioned_users
 
belongs_to :project
belongs_to :noteable, polymorphic: true, touch: true
Loading
Loading
Loading
Loading
@@ -2,7 +2,8 @@ class Participant < ActiveRecord::Base
belongs_to :user
belongs_to :target, polymorphic: true
 
validates :target, presence: true
validates :target_id, presence: true
validates :target_type, presence: true
validates :user_id,
uniqueness: { scope: [:target_id, :target_type] },
presence: true
Loading
Loading
Loading
Loading
@@ -49,8 +49,6 @@ class Snippet < ActiveRecord::Base
scope :expired, -> { where(["expires_at IS NOT NULL AND expires_at < ?", Time.current]) }
scope :non_expired, -> { where(["expires_at IS NULL OR expires_at > ?", Time.current]) }
 
participant :author, :notes
def self.reference_prefix
'$'
end
Loading
Loading
Loading
Loading
@@ -7,6 +7,7 @@ module Notes
 
if note.save
notification_service.new_note(note)
update_participants(note)
 
# Skip system notes, like status changes and cross-references.
unless note.system
Loading
Loading
@@ -34,5 +35,25 @@ module Notes
note.project.execute_hooks(note_data, :note_hooks)
note.project.execute_services(note_data, :note_hooks)
end
def update_participants(note)
users = [note.author, note.mentioned_users].flatten
noteable = note.noteable
# Add users as participants only if they have access to project
users.select! do |user|
user.can?(:read_project, note.project)
end
users.each do |user|
if Participant.where(user_id: user, target_id: noteable.id.to_s, target_type: noteable.class.name).blank?
participant = Participant.new
participant.target_id = noteable.id
participant.target_type = noteable.class.name
participant.user = user
participant.save
end
end
end
end
end
Loading
Loading
@@ -132,9 +132,9 @@ class NotificationService
recipients = []
 
# Add all users participating in the thread (author, assignee, comment authors)
participants =
participants =
if target.respond_to?(:participants)
target.participants(note.author)
target.participants
else
note.mentioned_users
end
Loading
Loading
@@ -344,7 +344,7 @@ class NotificationService
 
def reject_unsubscribed_users(recipients, target)
return recipients unless target.respond_to? :subscriptions
recipients.reject do |user|
subscription = target.subscriptions.find_by_user_id(user.id)
subscription && !subscription.subscribed
Loading
Loading
@@ -362,7 +362,7 @@ class NotificationService
recipients
end
end
def new_resource_email(target, project, method)
recipients = build_recipients(target, project)
recipients.delete(target.author)
Loading
Loading
Loading
Loading
@@ -13,7 +13,7 @@ module Projects
end
 
def participants_in(type, id)
target =
target =
case type
when "Issue"
project.issues.find_by_iid(id)
Loading
Loading
@@ -22,21 +22,21 @@ module Projects
when "Commit"
project.commit(id)
end
return [] unless target
 
users = target.participants(current_user)
users = target.participants
sorted(users)
end
 
def sorted(users)
users.uniq.to_a.compact.sort_by(&:username).map do |user|
users.uniq.to_a.compact.sort_by(&:username).map do |user|
{ username: user.username, name: user.name }
end
end
 
def groups
current_user.authorized_groups.sort_by(&:path).map do |group|
current_user.authorized_groups.sort_by(&:path).map do |group|
count = group.users.count
{ username: group.path, name: group.name, count: count }
end
Loading
Loading
Loading
Loading
@@ -21,7 +21,7 @@
- if member
%span.note-role.label
= member.human_access
- if note.system
= link_to user_path(note.author) do
= image_tag avatar_icon(note.author_email), class: 'avatar s16', alt: ''
Loading
Loading
class CreateParticipants < ActiveRecord::Migration
def change
create_table :participants do |t|
t.integer :target_id, null: false
t.string :target_id, null: false
t.string :target_type, null: false
t.integer :user_id, null: false
 
Loading
Loading
Loading
Loading
@@ -331,7 +331,7 @@ ActiveRecord::Schema.define(version: 20150625153454) do
add_index "oauth_applications", ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree
 
create_table "participants", force: true do |t|
t.integer "target_id", null: false
t.string "target_id", null: false
t.string "target_type", null: false
t.integer "user_id", null: false
t.datetime "created_at"
Loading
Loading
@@ -504,12 +504,12 @@ ActiveRecord::Schema.define(version: 20150625153454) do
t.string "bitbucket_access_token"
t.string "bitbucket_access_token_secret"
t.string "location"
t.string "public_email", default: "", null: false
t.string "encrypted_otp_secret"
t.string "encrypted_otp_secret_iv"
t.string "encrypted_otp_secret_salt"
t.boolean "otp_required_for_login", default: false, null: false
t.text "otp_backup_codes"
t.string "public_email", default: "", null: false
t.integer "dashboard", default: 0
end
 
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment