2012-02-28 13:09:23 +00:00
|
|
|
class Event < ActiveRecord::Base
|
2015-02-05 22:20:55 +00:00
|
|
|
include Sortable
|
2016-10-27 04:48:26 +00:00
|
|
|
default_scope { reorder(nil).where.not(author_id: nil) }
|
2012-03-07 08:13:43 +00:00
|
|
|
|
2013-02-13 11:48:16 +00:00
|
|
|
CREATED = 1
|
|
|
|
UPDATED = 2
|
|
|
|
CLOSED = 3
|
|
|
|
REOPENED = 4
|
|
|
|
PUSHED = 5
|
|
|
|
COMMENTED = 6
|
|
|
|
MERGED = 7
|
|
|
|
JOINED = 8 # User joined project
|
|
|
|
LEFT = 9 # User left project
|
2015-08-31 04:51:34 +00:00
|
|
|
DESTROYED = 10
|
2016-10-06 15:19:27 +00:00
|
|
|
EXPIRED = 11 # User left project due to expiry
|
2012-02-28 14:01:14 +00:00
|
|
|
|
2016-09-16 14:05:12 +00:00
|
|
|
RESET_PROJECT_ACTIVITY_INTERVAL = 1.hour
|
|
|
|
|
2017-04-19 23:04:56 +00:00
|
|
|
delegate :name, :email, :public_email, :username, to: :author, prefix: true, allow_nil: true
|
2012-09-27 06:20:36 +00:00
|
|
|
delegate :title, to: :issue, prefix: true, allow_nil: true
|
|
|
|
delegate :title, to: :merge_request, prefix: true, allow_nil: true
|
2014-05-29 14:55:55 +00:00
|
|
|
delegate :title, to: :note, prefix: true, allow_nil: true
|
2012-09-27 06:20:36 +00:00
|
|
|
|
2012-09-27 20:23:11 +00:00
|
|
|
belongs_to :author, class_name: "User"
|
2012-02-28 13:09:23 +00:00
|
|
|
belongs_to :project
|
2012-08-10 22:07:50 +00:00
|
|
|
belongs_to :target, polymorphic: true
|
2012-02-28 14:01:14 +00:00
|
|
|
|
2012-04-03 23:49:58 +00:00
|
|
|
# For Hash only
|
|
|
|
serialize :data
|
2012-02-28 14:01:14 +00:00
|
|
|
|
2014-06-17 18:23:43 +00:00
|
|
|
# Callbacks
|
|
|
|
after_create :reset_project_activity
|
2017-05-04 01:44:39 +00:00
|
|
|
after_create :set_last_repository_updated_at, if: :push?
|
2014-06-17 18:23:43 +00:00
|
|
|
|
2012-10-09 00:10:04 +00:00
|
|
|
# Scopes
|
2015-11-11 14:17:12 +00:00
|
|
|
scope :recent, -> { reorder(id: :desc) }
|
2013-02-13 11:48:16 +00:00
|
|
|
scope :code_push, -> { where(action: PUSHED) }
|
2016-01-25 15:56:23 +00:00
|
|
|
|
|
|
|
scope :in_projects, ->(projects) do
|
2017-02-24 19:56:34 +00:00
|
|
|
where(project_id: projects.pluck(:id)).recent
|
2016-01-25 15:56:23 +00:00
|
|
|
end
|
|
|
|
|
2017-02-13 14:19:03 +00:00
|
|
|
scope :with_associations, -> { includes(:author, :project, project: :namespace).preload(:target) }
|
2015-08-31 04:51:34 +00:00
|
|
|
scope :for_milestone_id, ->(milestone_id) { where(target_type: "Milestone", target_id: milestone_id) }
|
2012-02-29 20:38:24 +00:00
|
|
|
|
2012-10-09 00:10:04 +00:00
|
|
|
class << self
|
2016-11-04 14:15:43 +00:00
|
|
|
# Update Gitlab::ContributionsCalendar#activity_dates if this changes
|
2015-03-22 20:55:00 +00:00
|
|
|
def contributions
|
2017-01-26 17:59:50 +00:00
|
|
|
where("action = ? OR (target_type IN (?) AND action IN (?)) OR (target_type = ? AND action = ?)",
|
|
|
|
Event::PUSHED,
|
2017-02-22 17:46:57 +00:00
|
|
|
%w(MergeRequest Issue), [Event::CREATED, Event::CLOSED, Event::MERGED],
|
2017-01-26 17:59:50 +00:00
|
|
|
"Note", Event::COMMENTED)
|
2015-03-22 20:55:00 +00:00
|
|
|
end
|
2015-11-11 16:14:47 +00:00
|
|
|
|
2015-11-18 11:25:37 +00:00
|
|
|
def limit_recent(limit = 20, offset = nil)
|
|
|
|
recent.limit(limit).offset(offset)
|
|
|
|
end
|
2012-07-20 05:39:34 +00:00
|
|
|
end
|
|
|
|
|
2016-03-24 17:24:22 +00:00
|
|
|
def visible_to_user?(user = nil)
|
2016-11-16 14:17:09 +00:00
|
|
|
if push? || commit_note?
|
2016-11-04 14:15:43 +00:00
|
|
|
Ability.allowed?(user, :download_code, project)
|
2012-12-14 19:39:55 +00:00
|
|
|
elsif membership_changed?
|
|
|
|
true
|
2015-02-13 11:01:28 +00:00
|
|
|
elsif created_project?
|
|
|
|
true
|
2016-03-24 17:20:47 +00:00
|
|
|
elsif issue? || issue_note?
|
2016-08-08 18:55:13 +00:00
|
|
|
Ability.allowed?(user, :read_issue, note? ? note_target : target)
|
2016-10-04 12:52:08 +00:00
|
|
|
elsif merge_request? || merge_request_note?
|
|
|
|
Ability.allowed?(user, :read_merge_request, note? ? note_target : target)
|
2012-12-14 19:39:55 +00:00
|
|
|
else
|
2016-10-04 12:52:08 +00:00
|
|
|
milestone?
|
2012-12-14 19:39:55 +00:00
|
|
|
end
|
2012-03-01 18:47:57 +00:00
|
|
|
end
|
|
|
|
|
2012-09-14 15:46:40 +00:00
|
|
|
def project_name
|
|
|
|
if project
|
2013-06-22 13:00:39 +00:00
|
|
|
project.name_with_namespace
|
2012-09-14 15:46:40 +00:00
|
|
|
else
|
2012-09-30 13:04:43 +00:00
|
|
|
"(deleted project)"
|
2012-09-14 15:46:40 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-10-01 13:39:19 +00:00
|
|
|
def target_title
|
2016-05-08 18:05:45 +00:00
|
|
|
target.try(:title)
|
2015-02-13 11:00:12 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def created?
|
|
|
|
action == CREATED
|
2012-10-01 13:39:19 +00:00
|
|
|
end
|
|
|
|
|
2012-02-29 20:38:24 +00:00
|
|
|
def push?
|
2015-02-13 11:00:12 +00:00
|
|
|
action == PUSHED && valid_push?
|
2012-02-29 20:38:24 +00:00
|
|
|
end
|
|
|
|
|
2012-04-01 21:24:45 +00:00
|
|
|
def merged?
|
2015-02-13 11:00:12 +00:00
|
|
|
action == MERGED
|
2012-04-01 21:24:45 +00:00
|
|
|
end
|
|
|
|
|
2012-03-07 08:13:43 +00:00
|
|
|
def closed?
|
2015-02-13 11:00:12 +00:00
|
|
|
action == CLOSED
|
2012-03-07 08:13:43 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def reopened?
|
2015-02-13 11:00:12 +00:00
|
|
|
action == REOPENED
|
|
|
|
end
|
|
|
|
|
|
|
|
def joined?
|
|
|
|
action == JOINED
|
|
|
|
end
|
|
|
|
|
|
|
|
def left?
|
|
|
|
action == LEFT
|
|
|
|
end
|
|
|
|
|
2016-10-06 15:19:27 +00:00
|
|
|
def expired?
|
|
|
|
action == EXPIRED
|
|
|
|
end
|
|
|
|
|
2015-08-31 04:51:34 +00:00
|
|
|
def destroyed?
|
|
|
|
action == DESTROYED
|
|
|
|
end
|
|
|
|
|
2015-02-13 11:00:12 +00:00
|
|
|
def commented?
|
|
|
|
action == COMMENTED
|
|
|
|
end
|
|
|
|
|
|
|
|
def membership_changed?
|
2016-10-06 15:19:27 +00:00
|
|
|
joined? || left? || expired?
|
2012-03-07 08:13:43 +00:00
|
|
|
end
|
|
|
|
|
2015-02-13 11:01:28 +00:00
|
|
|
def created_project?
|
2015-08-31 04:51:34 +00:00
|
|
|
created? && !target && target_type.nil?
|
2015-02-13 11:01:28 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def created_target?
|
|
|
|
created? && target
|
|
|
|
end
|
|
|
|
|
2012-12-14 17:33:33 +00:00
|
|
|
def milestone?
|
|
|
|
target_type == "Milestone"
|
|
|
|
end
|
|
|
|
|
|
|
|
def note?
|
2016-07-06 08:08:42 +00:00
|
|
|
target.is_a?(Note)
|
2012-12-14 17:33:33 +00:00
|
|
|
end
|
|
|
|
|
2012-09-14 15:46:40 +00:00
|
|
|
def issue?
|
2012-04-01 21:24:45 +00:00
|
|
|
target_type == "Issue"
|
2012-02-29 20:38:24 +00:00
|
|
|
end
|
|
|
|
|
2012-09-14 15:46:40 +00:00
|
|
|
def merge_request?
|
2012-04-01 21:24:45 +00:00
|
|
|
target_type == "MergeRequest"
|
2012-03-05 22:29:40 +00:00
|
|
|
end
|
|
|
|
|
2015-02-13 11:00:12 +00:00
|
|
|
def milestone
|
|
|
|
target if milestone?
|
2012-09-09 20:18:28 +00:00
|
|
|
end
|
|
|
|
|
2012-09-14 15:46:40 +00:00
|
|
|
def issue
|
2015-02-13 11:00:12 +00:00
|
|
|
target if issue?
|
2012-03-01 20:43:04 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def merge_request
|
2015-02-13 11:00:12 +00:00
|
|
|
target if merge_request?
|
2012-03-01 20:43:04 +00:00
|
|
|
end
|
|
|
|
|
2014-05-29 14:55:55 +00:00
|
|
|
def note
|
2015-02-13 11:00:12 +00:00
|
|
|
target if note?
|
2014-05-29 14:55:55 +00:00
|
|
|
end
|
|
|
|
|
2012-04-01 21:24:45 +00:00
|
|
|
def action_name
|
2015-02-13 11:00:12 +00:00
|
|
|
if push?
|
|
|
|
if new_ref?
|
|
|
|
"pushed new"
|
|
|
|
elsif rm_ref?
|
|
|
|
"deleted"
|
|
|
|
else
|
|
|
|
"pushed to"
|
|
|
|
end
|
|
|
|
elsif closed?
|
2012-04-01 21:24:45 +00:00
|
|
|
"closed"
|
|
|
|
elsif merged?
|
2013-04-06 12:53:35 +00:00
|
|
|
"accepted"
|
2012-09-09 20:18:28 +00:00
|
|
|
elsif joined?
|
|
|
|
'joined'
|
2012-09-09 21:27:47 +00:00
|
|
|
elsif left?
|
|
|
|
'left'
|
2016-10-06 15:19:27 +00:00
|
|
|
elsif expired?
|
|
|
|
'removed due to membership expiration from'
|
2015-08-31 04:51:34 +00:00
|
|
|
elsif destroyed?
|
|
|
|
'destroyed'
|
2015-02-13 11:00:12 +00:00
|
|
|
elsif commented?
|
|
|
|
"commented on"
|
2015-02-13 11:01:28 +00:00
|
|
|
elsif created_project?
|
2015-12-02 09:56:05 +00:00
|
|
|
if project.external_import?
|
2015-04-06 12:51:41 +00:00
|
|
|
"imported"
|
|
|
|
else
|
|
|
|
"created"
|
|
|
|
end
|
2012-09-14 15:46:40 +00:00
|
|
|
else
|
2012-04-01 21:24:45 +00:00
|
|
|
"opened"
|
2012-02-29 20:38:24 +00:00
|
|
|
end
|
|
|
|
end
|
2013-01-02 21:35:11 +00:00
|
|
|
|
|
|
|
def valid_push?
|
2013-11-13 12:21:03 +00:00
|
|
|
data[:ref] && ref_name.present?
|
2014-12-29 09:36:57 +00:00
|
|
|
rescue
|
2013-01-02 21:35:11 +00:00
|
|
|
false
|
|
|
|
end
|
|
|
|
|
|
|
|
def tag?
|
2015-03-10 10:51:36 +00:00
|
|
|
Gitlab::Git.tag_ref?(data[:ref])
|
2013-01-02 21:35:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def branch?
|
2015-03-10 10:51:36 +00:00
|
|
|
Gitlab::Git.branch_ref?(data[:ref])
|
2013-01-02 21:35:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def new_ref?
|
2015-03-10 10:51:36 +00:00
|
|
|
Gitlab::Git.blank_ref?(commit_from)
|
2013-01-02 21:35:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def rm_ref?
|
2015-03-10 10:51:36 +00:00
|
|
|
Gitlab::Git.blank_ref?(commit_to)
|
2013-01-02 21:35:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def md_ref?
|
|
|
|
!(rm_ref? || new_ref?)
|
|
|
|
end
|
|
|
|
|
|
|
|
def commit_from
|
|
|
|
data[:before]
|
|
|
|
end
|
|
|
|
|
|
|
|
def commit_to
|
|
|
|
data[:after]
|
|
|
|
end
|
|
|
|
|
|
|
|
def ref_name
|
|
|
|
if tag?
|
|
|
|
tag_name
|
|
|
|
else
|
|
|
|
branch_name
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def branch_name
|
2015-03-10 10:51:36 +00:00
|
|
|
@branch_name ||= Gitlab::Git.ref_name(data[:ref])
|
2013-01-02 21:35:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def tag_name
|
2015-03-10 10:51:36 +00:00
|
|
|
@tag_name ||= Gitlab::Git.ref_name(data[:ref])
|
2013-01-02 21:35:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
# Max 20 commits from push DESC
|
|
|
|
def commits
|
2013-11-25 15:59:12 +00:00
|
|
|
@commits ||= (data[:commits] || []).reverse
|
2013-01-02 21:35:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def commits_count
|
|
|
|
data[:total_commits_count] || commits.count || 0
|
|
|
|
end
|
|
|
|
|
|
|
|
def ref_type
|
|
|
|
tag? ? "tag" : "branch"
|
|
|
|
end
|
|
|
|
|
|
|
|
def push_with_commits?
|
2015-03-17 14:51:14 +00:00
|
|
|
!commits.empty? && commit_from && commit_to
|
2013-01-02 21:35:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def last_push_to_non_root?
|
|
|
|
branch? && project.default_branch != branch_name
|
|
|
|
end
|
|
|
|
|
2013-08-19 19:12:59 +00:00
|
|
|
def target_iid
|
|
|
|
target.respond_to?(:iid) ? target.iid : target_id
|
|
|
|
end
|
|
|
|
|
2016-05-12 20:31:53 +00:00
|
|
|
def commit_note?
|
2016-11-16 14:17:09 +00:00
|
|
|
note? && target && target.for_commit?
|
2013-01-02 21:35:11 +00:00
|
|
|
end
|
|
|
|
|
2016-03-24 17:20:47 +00:00
|
|
|
def issue_note?
|
2016-05-08 18:46:43 +00:00
|
|
|
note? && target && target.for_issue?
|
2016-03-24 17:20:47 +00:00
|
|
|
end
|
|
|
|
|
2016-10-04 12:52:08 +00:00
|
|
|
def merge_request_note?
|
|
|
|
note? && target && target.for_merge_request?
|
|
|
|
end
|
|
|
|
|
2016-05-12 20:37:00 +00:00
|
|
|
def project_snippet_note?
|
2016-11-16 14:17:09 +00:00
|
|
|
note? && target && target.for_snippet?
|
2013-03-25 11:58:09 +00:00
|
|
|
end
|
|
|
|
|
2013-01-02 21:35:11 +00:00
|
|
|
def note_target
|
|
|
|
target.noteable
|
|
|
|
end
|
|
|
|
|
|
|
|
def note_target_id
|
2016-05-12 20:31:53 +00:00
|
|
|
if commit_note?
|
2013-01-02 21:35:11 +00:00
|
|
|
target.commit_id
|
|
|
|
else
|
|
|
|
target.noteable_id.to_s
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-05-12 21:47:45 +00:00
|
|
|
def note_target_reference
|
|
|
|
return unless note_target
|
|
|
|
|
|
|
|
# Commit#to_reference returns the full SHA, but we want the short one here
|
|
|
|
if commit_note?
|
|
|
|
note_target.short_id
|
2013-08-19 19:53:11 +00:00
|
|
|
else
|
2016-05-12 21:47:45 +00:00
|
|
|
note_target.to_reference
|
|
|
|
end
|
2013-08-19 19:53:11 +00:00
|
|
|
end
|
|
|
|
|
2013-01-02 21:35:11 +00:00
|
|
|
def note_target_type
|
|
|
|
if target.noteable_type.present?
|
|
|
|
target.noteable_type.titleize
|
|
|
|
else
|
|
|
|
"Wall"
|
|
|
|
end.downcase
|
|
|
|
end
|
2013-08-20 18:31:37 +00:00
|
|
|
|
|
|
|
def body?
|
|
|
|
if push?
|
2016-06-15 22:27:54 +00:00
|
|
|
push_with_commits? || rm_ref?
|
2013-08-20 18:31:37 +00:00
|
|
|
elsif note?
|
|
|
|
true
|
|
|
|
else
|
|
|
|
target.respond_to? :title
|
|
|
|
end
|
|
|
|
end
|
2014-06-17 18:23:43 +00:00
|
|
|
|
|
|
|
def reset_project_activity
|
2016-09-16 14:05:12 +00:00
|
|
|
return unless project
|
|
|
|
|
2016-10-04 15:22:58 +00:00
|
|
|
# Don't bother updating if we know the project was updated recently.
|
2016-09-20 02:59:29 +00:00
|
|
|
return if recent_update?
|
2016-09-16 14:05:12 +00:00
|
|
|
|
2016-10-04 15:22:58 +00:00
|
|
|
# At this point it's possible for multiple threads/processes to try to
|
|
|
|
# update the project. Only one query should actually perform the update,
|
|
|
|
# hence we add the extra WHERE clause for last_activity_at.
|
2017-02-22 22:50:15 +00:00
|
|
|
Project.unscoped.where(id: project_id).
|
|
|
|
where('last_activity_at <= ?', RESET_PROJECT_ACTIVITY_INTERVAL.ago).
|
|
|
|
update_all(last_activity_at: created_at)
|
2016-09-20 02:59:29 +00:00
|
|
|
end
|
|
|
|
|
2016-11-24 10:25:23 +00:00
|
|
|
def authored_by?(user)
|
|
|
|
user ? author_id == user.id : false
|
|
|
|
end
|
|
|
|
|
2016-09-20 02:59:29 +00:00
|
|
|
private
|
|
|
|
|
|
|
|
def recent_update?
|
|
|
|
project.last_activity_at > RESET_PROJECT_ACTIVITY_INTERVAL.ago
|
|
|
|
end
|
2017-05-04 01:44:39 +00:00
|
|
|
|
|
|
|
def set_last_repository_updated_at
|
|
|
|
Project.unscoped.where(id: project_id).
|
|
|
|
update_all(last_repository_updated_at: created_at)
|
|
|
|
end
|
2012-02-28 13:09:23 +00:00
|
|
|
end
|