diff options
Diffstat (limited to 'app/models')
| -rw-r--r-- | app/models/ability.rb | 1 | ||||
| -rw-r--r-- | app/models/merge_request.rb | 2 | ||||
| -rw-r--r-- | app/models/note.rb | 6 | ||||
| -rw-r--r-- | app/models/project.rb | 83 | ||||
| -rw-r--r-- | app/models/project_hook.rb | 3 | ||||
| -rw-r--r-- | app/models/project_services/slack_message.rb | 95 | ||||
| -rw-r--r-- | app/models/project_services/slack_service.rb | 67 | ||||
| -rw-r--r-- | app/models/snippet.rb | 2 | ||||
| -rw-r--r-- | app/models/user.rb | 16 |
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] |
