summaryrefslogtreecommitdiff
path: root/app/models
diff options
context:
space:
mode:
Diffstat (limited to 'app/models')
-rw-r--r--app/models/ability.rb1
-rw-r--r--app/models/merge_request.rb2
-rw-r--r--app/models/note.rb6
-rw-r--r--app/models/project.rb83
-rw-r--r--app/models/project_hook.rb3
-rw-r--r--app/models/project_services/slack_message.rb95
-rw-r--r--app/models/project_services/slack_service.rb67
-rw-r--r--app/models/snippet.rb2
-rw-r--r--app/models/user.rb16
9 files changed, 240 insertions, 35 deletions
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 69ada753d02..1afe8a4638f 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -240,6 +240,7 @@ class Ability
can_manage = group_abilities(user, group).include?(:manage_group)
if can_manage && (user != target_user)
rules << :modify
+ rules << :destroy
end
if !group.last_owner?(user) && (can_manage || (user == target_user))
rules << :destroy
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 4774cbcf3aa..7c2648d8c7a 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -133,7 +133,7 @@ class MergeRequest < ActiveRecord::Base
end
def reload_code
- if merge_request_diff && opened?
+ if merge_request_diff && open?
merge_request_diff.reload_content
end
end
diff --git a/app/models/note.rb b/app/models/note.rb
index 48c03c9d587..906de4855ab 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -199,7 +199,8 @@ class Note < ActiveRecord::Base
def downvote?
votable? && (note.start_with?('-1') ||
note.start_with?(':-1:') ||
- note.start_with?(':thumbsdown:')
+ note.start_with?(':thumbsdown:') ||
+ note.start_with?(':thumbs_down_sign:')
)
end
@@ -249,7 +250,8 @@ class Note < ActiveRecord::Base
def upvote?
votable? && (note.start_with?('+1') ||
note.start_with?(':+1:') ||
- note.start_with?(':thumbsup:')
+ note.start_with?(':thumbsup:') ||
+ note.start_with?(':thumbs_up_sign:')
)
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 47dc8a1fdb0..769ab217625 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -28,7 +28,6 @@ class Project < ActiveRecord::Base
include Gitlab::VisibilityLevel
extend Enumerize
- default_value_for :imported, false
default_value_for :archived, false
ActsAsTaggableOn.strict_case_match = true
@@ -57,15 +56,13 @@ class Project < ActiveRecord::Base
has_one :flowdock_service, dependent: :destroy
has_one :assembla_service, dependent: :destroy
has_one :gemnasium_service, dependent: :destroy
+ has_one :slack_service, dependent: :destroy
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
has_one :forked_from_project, through: :forked_project_link
-
# Merge Requests for target project should be removed with it
has_many :merge_requests, dependent: :destroy, foreign_key: "target_project_id"
-
# Merge requests from source project should be kept when source project was removed
has_many :fork_merge_requests, foreign_key: "source_project_id", class_name: MergeRequest
-
has_many :issues, -> { order "state DESC, created_at DESC" }, dependent: :destroy
has_many :services, dependent: :destroy
has_many :events, dependent: :destroy
@@ -74,10 +71,8 @@ class Project < ActiveRecord::Base
has_many :snippets, dependent: :destroy, class_name: "ProjectSnippet"
has_many :hooks, dependent: :destroy, class_name: "ProjectHook"
has_many :protected_branches, dependent: :destroy
-
has_many :users_projects, dependent: :destroy
has_many :users, through: :users_projects
-
has_many :deploy_keys_projects, dependent: :destroy
has_many :deploy_keys, through: :deploy_keys_projects
@@ -97,15 +92,12 @@ class Project < ActiveRecord::Base
validates :issues_enabled, :wall_enabled, :merge_requests_enabled,
:wiki_enabled, inclusion: { in: [true, false] }
validates :issues_tracker_id, length: { maximum: 255 }, allow_blank: true
-
validates :namespace, presence: true
validates_uniqueness_of :name, scope: :namespace_id
validates_uniqueness_of :path, scope: :namespace_id
-
validates :import_url,
format: { with: URI::regexp(%w(git http https)), message: "should be a valid url" },
if: :import?
-
validate :check_limit, on: :create
# Scopes
@@ -118,14 +110,36 @@ class Project < ActiveRecord::Base
scope :sorted_by_activity, -> { reorder("projects.last_activity_at DESC") }
scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) }
-
scope :public_only, -> { where(visibility_level: Project::PUBLIC) }
scope :public_and_internal_only, -> { where(visibility_level: Project.public_and_internal_levels) }
-
scope :non_archived, -> { where(archived: false) }
enumerize :issues_tracker, in: (Gitlab.config.issues_tracker.keys).append(:gitlab), default: :gitlab
+ state_machine :import_status, initial: :none do
+ event :import_start do
+ transition :none => :started
+ end
+
+ event :import_finish do
+ transition :started => :finished
+ end
+
+ event :import_fail do
+ transition :started => :failed
+ end
+
+ event :import_retry do
+ transition :failed => :started
+ end
+
+ state :started
+ state :finished
+ state :failed
+
+ after_transition any => :started, :do => :add_import_job
+ end
+
class << self
def public_and_internal_levels
[Project::PUBLIC, Project::INTERNAL]
@@ -164,15 +178,13 @@ class Project < ActiveRecord::Base
end
def find_with_namespace(id)
- if id.include?("/")
- id = id.split("/")
- namespace = Namespace.find_by(path: id.first)
- return nil unless namespace
-
- where(namespace_id: namespace.id).find_by(path: id.second)
- else
- where(path: id, namespace_id: nil).last
- end
+ return nil unless id.include?("/")
+
+ id = id.split("/")
+ namespace = Namespace.find_by(path: id.first)
+ return nil unless namespace
+
+ where(namespace_id: namespace.id).find_by(path: id.second)
end
def visibility_levels
@@ -202,12 +214,28 @@ class Project < ActiveRecord::Base
id && persisted?
end
+ def add_import_job
+ RepositoryImportWorker.perform_in(2.seconds, id)
+ end
+
def import?
import_url.present?
end
def imported?
- imported
+ import_finished?
+ end
+
+ def import_in_progress?
+ import? && import_status == 'started'
+ end
+
+ def import_failed?
+ import_status == 'failed'
+ end
+
+ def import_finished?
+ import_status == 'finished'
end
def check_limit
@@ -277,7 +305,7 @@ class Project < ActiveRecord::Base
end
def available_services_names
- %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium)
+ %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack)
end
def gitlab_ci?
@@ -361,18 +389,17 @@ class Project < ActiveRecord::Base
branch_name = ref.gsub("refs/heads/", "")
c_ids = self.repository.commits_between(oldrev, newrev).map(&:id)
+ # Close merge requests
+ mrs = self.merge_requests.opened.where(target_branch: branch_name).to_a
+ mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }
+ mrs.each { |merge_request| MergeRequests::MergeService.new.execute(merge_request, user, nil) }
+
# Update code for merge requests into project between project branches
mrs = self.merge_requests.opened.by_branch(branch_name).to_a
# Update code for merge requests between project and project fork
mrs += self.fork_merge_requests.opened.by_branch(branch_name).to_a
-
mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked }
- # Close merge requests
- mrs = self.merge_requests.opened.where(target_branch: branch_name).to_a
- mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }
- mrs.each { |merge_request| MergeRequests::MergeService.new.execute(merge_request, user, nil) }
-
true
end
diff --git a/app/models/project_hook.rb b/app/models/project_hook.rb
index e1c9ed01bc5..4e9b22532cb 100644
--- a/app/models/project_hook.rb
+++ b/app/models/project_hook.rb
@@ -17,9 +17,10 @@
class ProjectHook < WebHook
belongs_to :project
- attr_accessible :push_events, :issues_events, :merge_requests_events
+ attr_accessible :push_events, :issues_events, :merge_requests_events, :tag_push_events
scope :push_hooks, -> { where(push_events: true) }
+ scope :tag_push_hooks, -> { where(tag_push_events: true) }
scope :issue_hooks, -> { where(issues_events: true) }
scope :merge_request_hooks, -> { where(merge_requests_events: true) }
end
diff --git a/app/models/project_services/slack_message.rb b/app/models/project_services/slack_message.rb
new file mode 100644
index 00000000000..b2b8d6fed7a
--- /dev/null
+++ b/app/models/project_services/slack_message.rb
@@ -0,0 +1,95 @@
+require 'slack-notifier'
+
+class SlackMessage
+ def initialize(params)
+ @after = params.fetch(:after)
+ @before = params.fetch(:before)
+ @commits = params.fetch(:commits, [])
+ @project_name = params.fetch(:project_name)
+ @project_url = params.fetch(:project_url)
+ @ref = params.fetch(:ref).gsub('refs/heads/', '')
+ @username = params.fetch(:user_name)
+ end
+
+ def compose
+ format(message)
+ end
+
+ private
+
+ attr_reader :after
+ attr_reader :before
+ attr_reader :commits
+ attr_reader :project_name
+ attr_reader :project_url
+ attr_reader :ref
+ attr_reader :username
+
+ def message
+ if new_branch?
+ new_branch_message
+ elsif removed_branch?
+ removed_branch_message
+ else
+ push_message << commit_messages
+ end
+ end
+
+ def format(string)
+ Slack::Notifier::LinkFormatter.format(string)
+ end
+
+ def new_branch_message
+ "#{username} pushed new branch #{branch_link} to #{project_link}"
+ end
+
+ def removed_branch_message
+ "#{username} removed branch #{ref} from #{project_link}"
+ end
+
+ def push_message
+ "#{username} pushed to branch #{branch_link} of #{project_link} (#{compare_link})"
+ end
+
+ def commit_messages
+ commits.each_with_object('') do |commit, str|
+ str << compose_commit_message(commit)
+ end
+ end
+
+ def compose_commit_message(commit)
+ id = commit.fetch(:id)[0..5]
+ message = commit.fetch(:message)
+ url = commit.fetch(:url)
+
+ "\n - #{message} ([#{id}](#{url}))"
+ end
+
+ def new_branch?
+ before =~ /000000/
+ end
+
+ def removed_branch?
+ after =~ /000000/
+ end
+
+ def branch_url
+ "#{project_url}/commits/#{ref}"
+ end
+
+ def compare_url
+ "#{project_url}/compare/#{before}...#{after}"
+ end
+
+ def branch_link
+ "[#{ref}](#{branch_url})"
+ end
+
+ def project_link
+ "[#{project_name}](#{project_url})"
+ end
+
+ def compare_link
+ "[Compare changes](#{compare_url})"
+ end
+end
diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb
new file mode 100644
index 00000000000..754fd87db02
--- /dev/null
+++ b/app/models/project_services/slack_service.rb
@@ -0,0 +1,67 @@
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# token :string(255)
+# project_id :integer not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean default(FALSE), not null
+# project_url :string(255)
+# subdomain :string(255)
+# room :string(255)
+# api_key :string(255)
+#
+
+class SlackService < Service
+ attr_accessible :room
+ attr_accessible :subdomain
+
+ validates :room, presence: true, if: :activated?
+ validates :subdomain, presence: true, if: :activated?
+ validates :token, presence: true, if: :activated?
+
+ def title
+ 'Slack'
+ end
+
+ def description
+ 'A team communication tool for the 21st century'
+ end
+
+ def to_param
+ 'slack'
+ end
+
+ def fields
+ [
+ { type: 'text', name: 'subdomain', placeholder: '' },
+ { type: 'text', name: 'token', placeholder: '' },
+ { type: 'text', name: 'room', placeholder: 'Ex. #general' },
+ ]
+ end
+
+ def execute(push_data)
+ message = SlackMessage.new(push_data.merge(
+ project_url: project_url,
+ project_name: project_name
+ ))
+
+ notifier = Slack::Notifier.new(subdomain, token)
+ notifier.channel = room
+ notifier.ping(message.compose)
+ end
+
+ private
+
+ def project_name
+ project.name_with_namespace.gsub(/\s/, '')
+ end
+
+ def project_url
+ project.web_url
+ end
+end
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index edc179b20fd..c1c9ba257f2 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -20,6 +20,8 @@ class Snippet < ActiveRecord::Base
attr_accessible :title, :content, :file_name, :expires_at, :private
+ default_value_for :private, true
+
belongs_to :author, class_name: "User"
has_many :notes, as: :noteable, dependent: :destroy
diff --git a/app/models/user.rb b/app/models/user.rb
index 855fe58ffe8..d9f420759d2 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -185,7 +185,7 @@ class User < ActiveRecord::Base
where(conditions).first
end
end
-
+
def find_for_commit(email, name)
# Prefer email match over name match
User.where(email: email).first ||
@@ -249,7 +249,7 @@ class User < ActiveRecord::Base
def namespace_uniq
namespace_name = self.username
if Namespace.find_by(path: namespace_name)
- self.errors.add :username, "already exist"
+ self.errors.add :username, "already exists"
end
end
@@ -275,7 +275,9 @@ class User < ActiveRecord::Base
# Projects user has access to
def authorized_projects
@authorized_projects ||= begin
- project_ids = (personal_projects.pluck(:id) + groups_projects.pluck(:id) + projects.pluck(:id)).uniq
+ project_ids = personal_projects.pluck(:id)
+ project_ids += groups_projects.pluck(:id)
+ project_ids += projects.pluck(:id).uniq
Project.where(id: project_ids).joins(:namespace).order('namespaces.name ASC')
end
end
@@ -406,6 +408,14 @@ class User < ActiveRecord::Base
end
end
+ def requires_ldap_check?
+ if ldap_user?
+ !last_credential_check_at || (last_credential_check_at + 1.hour) < Time.now
+ else
+ false
+ end
+ end
+
def solo_owned_groups
@solo_owned_groups ||= owned_groups.select do |group|
group.owners == [self]