debian-mirror-gitlab/app/models/event.rb

462 lines
9.3 KiB
Ruby
Raw Normal View History

2014-09-02 18:07:02 +05:30
class Event < ActiveRecord::Base
2015-04-26 12:48:37 +05:30
include Sortable
2017-08-17 22:00:37 +05:30
default_scope { reorder(nil).where.not(author_id: nil) }
2014-09-02 18:07:02 +05:30
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-09-25 12:07:36 +05:30
DESTROYED = 10
2017-08-17 22:00:37 +05:30
EXPIRED = 11 # User left project due to expiry
2014-09-02 18:07:02 +05:30
2017-09-10 17:25:29 +05:30
ACTIONS = HashWithIndifferentAccess.new(
created: CREATED,
updated: UPDATED,
closed: CLOSED,
reopened: REOPENED,
pushed: PUSHED,
commented: COMMENTED,
merged: MERGED,
joined: JOINED,
left: LEFT,
destroyed: DESTROYED,
expired: EXPIRED
).freeze
TARGET_TYPES = HashWithIndifferentAccess.new(
issue: Issue,
milestone: Milestone,
merge_request: MergeRequest,
note: Note,
project: Project,
snippet: Snippet,
user: User
).freeze
2016-09-29 09:46:39 +05:30
RESET_PROJECT_ACTIVITY_INTERVAL = 1.hour
2017-08-17 22:00:37 +05:30
delegate :name, :email, :public_email, :username, to: :author, prefix: true, allow_nil: true
2014-09-02 18:07:02 +05:30
delegate :title, to: :issue, prefix: true, allow_nil: true
delegate :title, to: :merge_request, prefix: true, allow_nil: true
delegate :title, to: :note, prefix: true, allow_nil: true
belongs_to :author, class_name: "User"
belongs_to :project
2017-09-10 17:25:29 +05:30
belongs_to :target, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
has_one :push_event_payload, foreign_key: :event_id
2014-09-02 18:07:02 +05:30
# For Hash only
2017-09-10 17:25:29 +05:30
serialize :data # rubocop:disable Cop/ActiveRecordSerialize
2014-09-02 18:07:02 +05:30
# Callbacks
after_create :reset_project_activity
2017-08-17 22:00:37 +05:30
after_create :set_last_repository_updated_at, if: :push?
2017-09-10 17:25:29 +05:30
after_create :replicate_event_for_push_events_migration
2014-09-02 18:07:02 +05:30
# Scopes
2015-11-26 14:37:03 +05:30
scope :recent, -> { reorder(id: :desc) }
2014-09-02 18:07:02 +05:30
scope :code_push, -> { where(action: PUSHED) }
2016-04-02 18:10:28 +05:30
2017-09-10 17:25:29 +05:30
scope :in_projects, -> (projects) do
sub_query = projects
.except(:order)
.select(1)
.where('projects.id = events.project_id')
where('EXISTS (?)', sub_query).recent
end
scope :with_associations, -> do
# We're using preload for "push_event_payload" as otherwise the association
# is not always available (depending on the query being built).
includes(:author, :project, project: :namespace)
.preload(:target, :push_event_payload)
2016-04-02 18:10:28 +05:30
end
2015-09-25 12:07:36 +05:30
scope :for_milestone_id, ->(milestone_id) { where(target_type: "Milestone", target_id: milestone_id) }
2014-09-02 18:07:02 +05:30
2017-09-10 17:25:29 +05:30
self.inheritance_column = 'action'
2014-09-02 18:07:02 +05:30
class << self
2017-09-10 17:25:29 +05:30
def model_name
ActiveModel::Name.new(self, nil, 'event')
end
def find_sti_class(action)
if action.to_i == PUSHED
PushEvent
else
Event
end
end
def subclass_from_attributes(attrs)
# Without this Rails will keep calling this method on the returned class,
# resulting in an infinite loop.
return unless self == Event
action = attrs.with_indifferent_access[inheritance_column].to_i
PushEvent if action == PUSHED
end
2016-11-24 13:41:30 +05:30
# Update Gitlab::ContributionsCalendar#activity_dates if this changes
2015-04-26 12:48:37 +05:30
def contributions
2017-08-17 22:00:37 +05:30
where("action = ? OR (target_type IN (?) AND action IN (?)) OR (target_type = ? AND action = ?)",
Event::PUSHED,
%w(MergeRequest Issue), [Event::CREATED, Event::CLOSED, Event::MERGED],
"Note", Event::COMMENTED)
2015-04-26 12:48:37 +05:30
end
2015-11-26 14:37:03 +05:30
def limit_recent(limit = 20, offset = nil)
recent.limit(limit).offset(offset)
end
2017-09-10 17:25:29 +05:30
def actions
ACTIONS.keys
end
def target_types
TARGET_TYPES.keys
end
2014-09-02 18:07:02 +05:30
end
2016-06-02 11:05:42 +05:30
def visible_to_user?(user = nil)
2016-11-24 13:41:30 +05:30
if push? || commit_note?
Ability.allowed?(user, :download_code, project)
2014-09-02 18:07:02 +05:30
elsif membership_changed?
true
2015-04-26 12:48:37 +05:30
elsif created_project?
true
2016-06-02 11:05:42 +05:30
elsif issue? || issue_note?
2016-09-29 09:46:39 +05:30
Ability.allowed?(user, :read_issue, note? ? note_target : target)
2016-11-03 12:29:30 +05:30
elsif merge_request? || merge_request_note?
Ability.allowed?(user, :read_merge_request, note? ? note_target : target)
2014-09-02 18:07:02 +05:30
else
2016-11-03 12:29:30 +05:30
milestone?
2014-09-02 18:07:02 +05:30
end
end
def project_name
if project
project.name_with_namespace
else
"(deleted project)"
end
end
def target_title
2016-06-02 11:05:42 +05:30
target.try(:title)
2015-04-26 12:48:37 +05:30
end
def created?
action == CREATED
2014-09-02 18:07:02 +05:30
end
def push?
2015-04-26 12:48:37 +05:30
action == PUSHED && valid_push?
2014-09-02 18:07:02 +05:30
end
def merged?
2015-04-26 12:48:37 +05:30
action == MERGED
2014-09-02 18:07:02 +05:30
end
def closed?
2015-04-26 12:48:37 +05:30
action == CLOSED
2014-09-02 18:07:02 +05:30
end
def reopened?
2015-04-26 12:48:37 +05:30
action == REOPENED
end
def joined?
action == JOINED
end
def left?
action == LEFT
end
2017-08-17 22:00:37 +05:30
def expired?
action == EXPIRED
end
2015-09-25 12:07:36 +05:30
def destroyed?
action == DESTROYED
end
2015-04-26 12:48:37 +05:30
def commented?
action == COMMENTED
end
def membership_changed?
2017-08-17 22:00:37 +05:30
joined? || left? || expired?
2015-04-26 12:48:37 +05:30
end
def created_project?
2015-09-25 12:07:36 +05:30
created? && !target && target_type.nil?
2015-04-26 12:48:37 +05:30
end
def created_target?
created? && target
2014-09-02 18:07:02 +05:30
end
def milestone?
target_type == "Milestone"
end
def note?
2016-08-24 12:49:21 +05:30
target.is_a?(Note)
2014-09-02 18:07:02 +05:30
end
def issue?
target_type == "Issue"
end
def merge_request?
target_type == "MergeRequest"
end
2015-04-26 12:48:37 +05:30
def milestone
target if milestone?
2014-09-02 18:07:02 +05:30
end
def issue
2015-04-26 12:48:37 +05:30
target if issue?
2014-09-02 18:07:02 +05:30
end
def merge_request
2015-04-26 12:48:37 +05:30
target if merge_request?
2014-09-02 18:07:02 +05:30
end
def note
2015-04-26 12:48:37 +05:30
target if note?
2014-09-02 18:07:02 +05:30
end
def action_name
2015-04-26 12:48:37 +05:30
if push?
if new_ref?
"pushed new"
elsif rm_ref?
"deleted"
else
"pushed to"
end
elsif closed?
2014-09-02 18:07:02 +05:30
"closed"
elsif merged?
"accepted"
elsif joined?
'joined'
elsif left?
'left'
2017-08-17 22:00:37 +05:30
elsif expired?
'removed due to membership expiration from'
2015-09-25 12:07:36 +05:30
elsif destroyed?
'destroyed'
2015-04-26 12:48:37 +05:30
elsif commented?
"commented on"
elsif created_project?
2015-12-23 02:04:40 +05:30
if project.external_import?
2015-04-26 12:48:37 +05:30
"imported"
else
"created"
end
2014-09-02 18:07:02 +05:30
else
"opened"
end
end
def valid_push?
data[:ref] && ref_name.present?
2015-04-26 12:48:37 +05:30
rescue
2014-09-02 18:07:02 +05:30
false
end
def tag?
2015-04-26 12:48:37 +05:30
Gitlab::Git.tag_ref?(data[:ref])
2014-09-02 18:07:02 +05:30
end
def branch?
2015-04-26 12:48:37 +05:30
Gitlab::Git.branch_ref?(data[:ref])
2014-09-02 18:07:02 +05:30
end
def new_ref?
2015-04-26 12:48:37 +05:30
Gitlab::Git.blank_ref?(commit_from)
2014-09-02 18:07:02 +05:30
end
def rm_ref?
2015-04-26 12:48:37 +05:30
Gitlab::Git.blank_ref?(commit_to)
2014-09-02 18:07:02 +05:30
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-04-26 12:48:37 +05:30
@branch_name ||= Gitlab::Git.ref_name(data[:ref])
2014-09-02 18:07:02 +05:30
end
def tag_name
2015-04-26 12:48:37 +05:30
@tag_name ||= Gitlab::Git.ref_name(data[:ref])
2014-09-02 18:07:02 +05:30
end
# Max 20 commits from push DESC
def commits
@commits ||= (data[:commits] || []).reverse
end
2017-09-10 17:25:29 +05:30
def commit_title
commit = commits.last
commit[:message] if commit
end
def commit_id
commit_to || commit_from
end
2014-09-02 18:07:02 +05:30
def commits_count
data[:total_commits_count] || commits.count || 0
end
def ref_type
tag? ? "tag" : "branch"
end
def push_with_commits?
2015-04-26 12:48:37 +05:30
!commits.empty? && commit_from && commit_to
2014-09-02 18:07:02 +05:30
end
def last_push_to_non_root?
branch? && project.default_branch != branch_name
end
def target_iid
target.respond_to?(:iid) ? target.iid : target_id
end
2016-06-02 11:05:42 +05:30
def commit_note?
2016-11-24 13:41:30 +05:30
note? && target && target.for_commit?
2014-09-02 18:07:02 +05:30
end
2016-06-02 11:05:42 +05:30
def issue_note?
note? && target && target.for_issue?
2014-09-02 18:07:02 +05:30
end
2016-11-03 12:29:30 +05:30
def merge_request_note?
note? && target && target.for_merge_request?
end
2016-06-02 11:05:42 +05:30
def project_snippet_note?
2016-11-24 13:41:30 +05:30
note? && target && target.for_snippet?
2014-09-02 18:07:02 +05:30
end
def note_target
target.noteable
end
def note_target_id
2016-06-02 11:05:42 +05:30
if commit_note?
2014-09-02 18:07:02 +05:30
target.commit_id
else
target.noteable_id.to_s
end
end
2016-06-02 11:05:42 +05:30
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
2014-09-02 18:07:02 +05:30
else
2016-06-02 11:05:42 +05:30
note_target.to_reference
end
2014-09-02 18:07:02 +05:30
end
def note_target_type
if target.noteable_type.present?
target.noteable_type.titleize
else
"Wall"
end.downcase
end
def body?
if push?
2017-09-10 17:25:29 +05:30
push_with_commits?
2014-09-02 18:07:02 +05:30
elsif note?
true
else
target.respond_to? :title
end
end
def reset_project_activity
2016-09-29 09:46:39 +05:30
return unless project
2016-11-03 12:29:30 +05:30
# Don't bother updating if we know the project was updated recently.
2016-09-29 09:46:39 +05:30
return if recent_update?
2016-11-03 12:29:30 +05:30
# 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-09-10 17:25:29 +05:30
Project.unscoped.where(id: project_id)
.where('last_activity_at <= ?', RESET_PROJECT_ACTIVITY_INTERVAL.ago)
.update_all(last_activity_at: created_at)
2016-09-29 09:46:39 +05:30
end
2017-08-17 22:00:37 +05:30
def authored_by?(user)
user ? author_id == user.id : false
end
2017-09-10 17:25:29 +05:30
# We're manually replicating data into the new table since database triggers
# are not dumped to db/schema.rb. This could mean that a new installation
# would not have the triggers in place, thus losing events data in GitLab
# 10.0.
def replicate_event_for_push_events_migration
new_attributes = attributes.with_indifferent_access.except(:title, :data)
EventForMigration.create!(new_attributes)
end
def to_partial_path
# We are intentionally using `Event` rather than `self.class` so that
# subclasses also use the `Event` implementation.
Event._to_partial_path
end
2016-09-29 09:46:39 +05:30
private
def recent_update?
project.last_activity_at > RESET_PROJECT_ACTIVITY_INTERVAL.ago
end
2017-08-17 22:00:37 +05:30
def set_last_repository_updated_at
2017-09-10 17:25:29 +05:30
Project.unscoped.where(id: project_id)
.update_all(last_repository_updated_at: created_at)
2017-08-17 22:00:37 +05:30
end
2014-09-02 18:07:02 +05:30
end