Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/models')
-rw-r--r--app/models/.gitkeep0
-rw-r--r--app/models/ability.rb276
-rw-r--r--app/models/application_setting.rb61
-rw-r--r--app/models/broadcast_message.rb29
-rw-r--r--app/models/commit.rb155
-rw-r--r--app/models/concerns/internal_id.rb17
-rw-r--r--app/models/concerns/issuable.rb189
-rw-r--r--app/models/concerns/mentionable.rb89
-rw-r--r--app/models/concerns/notifiable.rb15
-rw-r--r--app/models/concerns/sortable.rb35
-rw-r--r--app/models/concerns/taskable.rb51
-rw-r--r--app/models/concerns/token_authenticatable.rb31
-rw-r--r--app/models/deploy_key.rb38
-rw-r--r--app/models/deploy_keys_project.rb29
-rw-r--r--app/models/diff_line.rb3
-rw-r--r--app/models/email.rb35
-rw-r--r--app/models/event.rb330
-rw-r--r--app/models/external_issue.rb25
-rw-r--r--app/models/forked_project_link.rb15
-rw-r--r--app/models/group.rb100
-rw-r--r--app/models/group_milestone.rb95
-rw-r--r--app/models/hooks/project_hook.rb25
-rw-r--r--app/models/hooks/service_hook.rb20
-rw-r--r--app/models/hooks/system_hook.rb19
-rw-r--r--app/models/hooks/web_hook.rb60
-rw-r--r--app/models/identity.rb19
-rw-r--r--app/models/issue.rb78
-rw-r--r--app/models/key.rb86
-rw-r--r--app/models/label_link.rb19
-rw-r--r--app/models/member.rb172
-rw-r--r--app/models/members/group_member.rb75
-rw-r--r--app/models/members/project_member.rb165
-rw-r--r--app/models/merge_request.rb368
-rw-r--r--app/models/merge_request_diff.rb171
-rw-r--r--app/models/milestone.rb93
-rw-r--r--app/models/network/commit.rb35
-rw-r--r--app/models/network/graph.rb267
-rw-r--r--app/models/note.rb609
-rw-r--r--app/models/notification.rb60
-rw-r--r--app/models/personal_snippet.rb19
-rw-r--r--app/models/project_services/asana_service.rb127
-rw-r--r--app/models/project_services/assembla_service.rb56
-rw-r--r--app/models/project_services/bamboo_service.rb137
-rw-r--r--app/models/project_services/buildkite_service.rb135
-rw-r--r--app/models/project_services/campfire_service.rb86
-rw-r--r--app/models/project_services/ci_service.rb57
-rw-r--r--app/models/project_services/custom_issue_tracker_service.rb57
-rw-r--r--app/models/project_services/emails_on_push_service.rb72
-rw-r--r--app/models/project_services/external_wiki_service.rb48
-rw-r--r--app/models/project_services/flowdock_service.rb62
-rw-r--r--app/models/project_services/gemnasium_service.rb61
-rw-r--r--app/models/project_services/gitlab_ci_service.rb128
-rw-r--r--app/models/project_services/gitlab_issue_tracker_service.rb62
-rw-r--r--app/models/project_services/hipchat_service.rb238
-rw-r--r--app/models/project_services/irker_service.rb163
-rw-r--r--app/models/project_services/issue_tracker_service.rb125
-rw-r--r--app/models/project_services/jira_service.rb58
-rw-r--r--app/models/project_services/pivotaltracker_service.rb72
-rw-r--r--app/models/project_services/pushover_service.rb125
-rw-r--r--app/models/project_services/redmine_service.rb44
-rw-r--r--app/models/project_services/slack_service.rb105
-rw-r--r--app/models/project_services/slack_service/base_message.rb31
-rw-r--r--app/models/project_services/slack_service/issue_message.rb56
-rw-r--r--app/models/project_services/slack_service/merge_message.rb60
-rw-r--r--app/models/project_services/slack_service/note_message.rb82
-rw-r--r--app/models/project_services/slack_service/push_message.rb110
-rw-r--r--app/models/project_services/teamcity_service.rb145
-rw-r--r--app/models/project_snippet.rb28
-rw-r--r--app/models/project_team.rb169
-rw-r--r--app/models/project_wiki.rb149
-rw-r--r--app/models/protected_branch.rb23
-rw-r--r--app/models/repository.rb377
-rw-r--r--app/models/service.rb153
-rw-r--r--app/models/snippet.rb103
-rw-r--r--app/models/subscription.rb21
-rw-r--r--app/models/tree.rb53
-rw-r--r--app/models/user.rb614
-rw-r--r--app/models/users_star_project.rb19
-rw-r--r--app/models/wiki_page.rb201
79 files changed, 0 insertions, 8390 deletions
diff --git a/app/models/.gitkeep b/app/models/.gitkeep
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/app/models/.gitkeep
+++ /dev/null
diff --git a/app/models/ability.rb b/app/models/ability.rb
deleted file mode 100644
index 85a15596f8d..00000000000
--- a/app/models/ability.rb
+++ /dev/null
@@ -1,276 +0,0 @@
-class Ability
- class << self
- def allowed(user, subject)
- return not_auth_abilities(user, subject) if user.nil?
- return [] unless user.kind_of?(User)
- return [] if user.blocked?
-
- case subject.class.name
- when "Project" then project_abilities(user, subject)
- when "Issue" then issue_abilities(user, subject)
- when "Note" then note_abilities(user, subject)
- when "ProjectSnippet" then project_snippet_abilities(user, subject)
- when "PersonalSnippet" then personal_snippet_abilities(user, subject)
- when "MergeRequest" then merge_request_abilities(user, subject)
- when "Group" then group_abilities(user, subject)
- when "Namespace" then namespace_abilities(user, subject)
- when "GroupMember" then group_member_abilities(user, subject)
- else []
- end.concat(global_abilities(user))
- end
-
- # List of possible abilities
- # for non-authenticated user
- def not_auth_abilities(user, subject)
- project = if subject.kind_of?(Project)
- subject
- elsif subject.respond_to?(:project)
- subject.project
- else
- nil
- end
-
- if project && project.public?
- [
- :read_project,
- :read_wiki,
- :read_issue,
- :read_milestone,
- :read_project_snippet,
- :read_project_member,
- :read_merge_request,
- :read_note,
- :download_code
- ]
- else
- group = if subject.kind_of?(Group)
- subject
- elsif subject.respond_to?(:group)
- subject.group
- else
- nil
- end
-
- if group && group.public_profile?
- [:read_group]
- else
- []
- end
- end
- end
-
- def global_abilities(user)
- rules = []
- rules << :create_group if user.can_create_group
- rules
- end
-
- def project_abilities(user, project)
- rules = []
- key = "/user/#{user.id}/project/#{project.id}"
- RequestStore.store[key] ||= begin
- team = project.team
-
- # Rules based on role in project
- if team.master?(user)
- rules.push(*project_master_rules)
-
- elsif team.developer?(user)
- rules.push(*project_dev_rules)
-
- elsif team.reporter?(user)
- rules.push(*project_report_rules)
-
- elsif team.guest?(user)
- rules.push(*project_guest_rules)
- end
-
- if project.public? || project.internal?
- rules.push(*public_project_rules)
- end
-
- if project.owner == user || user.admin?
- rules.push(*project_admin_rules)
- end
-
- if project.group && project.group.has_owner?(user)
- rules.push(*project_admin_rules)
- end
-
- if project.archived?
- rules -= project_archived_rules
- end
-
- rules
- end
- end
-
- def public_project_rules
- project_guest_rules + [
- :download_code,
- :fork_project
- ]
- end
-
- def project_guest_rules
- [
- :read_project,
- :read_wiki,
- :read_issue,
- :read_milestone,
- :read_project_snippet,
- :read_project_member,
- :read_merge_request,
- :read_note,
- :write_project,
- :write_issue,
- :write_note
- ]
- end
-
- def project_report_rules
- project_guest_rules + [
- :download_code,
- :fork_project,
- :write_project_snippet
- ]
- end
-
- def project_dev_rules
- project_report_rules + [
- :write_merge_request,
- :write_wiki,
- :modify_issue,
- :admin_issue,
- :admin_label,
- :push_code
- ]
- end
-
- def project_archived_rules
- [
- :write_merge_request,
- :push_code,
- :push_code_to_protected_branches,
- :modify_merge_request,
- :admin_merge_request
- ]
- end
-
- def project_master_rules
- project_dev_rules + [
- :push_code_to_protected_branches,
- :modify_issue,
- :modify_project_snippet,
- :modify_merge_request,
- :admin_issue,
- :admin_milestone,
- :admin_project_snippet,
- :admin_project_member,
- :admin_merge_request,
- :admin_note,
- :admin_wiki,
- :admin_project
- ]
- end
-
- def project_admin_rules
- project_master_rules + [
- :change_namespace,
- :change_visibility_level,
- :rename_project,
- :remove_project,
- :archive_project
- ]
- end
-
- def group_abilities(user, group)
- rules = []
-
- if user.admin? || group.users.include?(user) || ProjectsFinder.new.execute(user, group: group).any?
- rules << :read_group
- end
-
- # Only group masters and group owners can create new projects in group
- if group.has_master?(user) || group.has_owner?(user) || user.admin?
- rules.push(*[
- :create_projects,
- ])
- end
-
- # Only group owner and administrators can admin group
- if group.has_owner?(user) || user.admin?
- rules.push(*[
- :admin_group,
- :admin_namespace
- ])
- end
-
- rules.flatten
- end
-
- def namespace_abilities(user, namespace)
- rules = []
-
- # Only namespace owner and administrators can admin it
- if namespace.owner == user || user.admin?
- rules.push(*[
- :create_projects,
- :admin_namespace
- ])
- end
-
- rules.flatten
- end
-
- [:issue, :note, :project_snippet, :personal_snippet, :merge_request].each do |name|
- define_method "#{name}_abilities" do |user, subject|
- if subject.author == user || user.is_admin?
- rules = [
- :"read_#{name}",
- :"write_#{name}",
- :"modify_#{name}",
- :"admin_#{name}"
- ]
- rules.push(:change_visibility_level) if subject.is_a?(Snippet)
- rules
- elsif subject.respond_to?(:assignee) && subject.assignee == user
- [
- :"read_#{name}",
- :"write_#{name}",
- :"modify_#{name}",
- ]
- else
- if subject.respond_to?(:project)
- project_abilities(user, subject.project)
- else
- []
- end
- end
- end
- end
-
- def group_member_abilities(user, subject)
- rules = []
- target_user = subject.user
- group = subject.group
- can_manage = group_abilities(user, group).include?(:admin_group)
- if can_manage && (user != target_user)
- rules << :modify_group_member
- rules << :destroy_group_member
- end
- if !group.last_owner?(user) && (can_manage || (user == target_user))
- rules << :destroy_group_member
- end
- rules
- end
-
- def abilities
- @abilities ||= begin
- abilities = Six.new
- abilities << self
- abilities
- end
- end
- end
-end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
deleted file mode 100644
index 0d8365c4ff2..00000000000
--- a/app/models/application_setting.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# == Schema Information
-#
-# Table name: application_settings
-#
-# id :integer not null, primary key
-# default_projects_limit :integer
-# default_branch_protection :integer
-# signup_enabled :boolean
-# signin_enabled :boolean
-# gravatar_enabled :boolean
-# twitter_sharing_enabled :boolean
-# sign_in_text :text
-# created_at :datetime
-# updated_at :datetime
-# home_page_url :string(255)
-# default_branch_protection :integer default(2)
-# twitter_sharing_enabled :boolean default(TRUE)
-# restricted_visibility_levels :text
-# max_attachment_size :integer default(10)
-#
-
-class ApplicationSetting < ActiveRecord::Base
- serialize :restricted_visibility_levels
-
- validates :home_page_url,
- allow_blank: true,
- format: { with: /\A#{URI.regexp(%w(http https))}\z/, message: "should be a valid url" },
- if: :home_page_url_column_exist
-
- validates_each :restricted_visibility_levels do |record, attr, value|
- unless value.nil?
- value.each do |level|
- unless Gitlab::VisibilityLevel.options.has_value?(level)
- record.errors.add(attr, "'#{level}' is not a valid visibility level")
- end
- end
- end
- end
-
- def self.current
- ApplicationSetting.last
- end
-
- def self.create_from_defaults
- create(
- default_projects_limit: Settings.gitlab['default_projects_limit'],
- default_branch_protection: Settings.gitlab['default_branch_protection'],
- signup_enabled: Settings.gitlab['signup_enabled'],
- signin_enabled: Settings.gitlab['signin_enabled'],
- twitter_sharing_enabled: Settings.gitlab['twitter_sharing_enabled'],
- gravatar_enabled: Settings.gravatar['enabled'],
- sign_in_text: Settings.extra['sign_in_text'],
- restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
- max_attachment_size: Settings.gitlab['max_attachment_size']
- )
- end
-
- def home_page_url_column_exist
- ActiveRecord::Base.connection.column_exists?(:application_settings, :home_page_url)
- end
-end
diff --git a/app/models/broadcast_message.rb b/app/models/broadcast_message.rb
deleted file mode 100644
index 05f5e979695..00000000000
--- a/app/models/broadcast_message.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# == Schema Information
-#
-# Table name: broadcast_messages
-#
-# id :integer not null, primary key
-# message :text not null
-# starts_at :datetime
-# ends_at :datetime
-# alert_type :integer
-# created_at :datetime
-# updated_at :datetime
-# color :string(255)
-# font :string(255)
-#
-
-class BroadcastMessage < ActiveRecord::Base
- include Sortable
-
- validates :message, presence: true
- validates :starts_at, presence: true
- validates :ends_at, presence: true
-
- validates :color, format: { with: /\A\#[0-9A-Fa-f]{3}{1,2}+\Z/ }, allow_blank: true
- validates :font, format: { with: /\A\#[0-9A-Fa-f]{3}{1,2}+\Z/ }, allow_blank: true
-
- def self.current
- where("ends_at > :now AND starts_at < :now", now: Time.zone.now).last
- end
-end
diff --git a/app/models/commit.rb b/app/models/commit.rb
deleted file mode 100644
index 006fa62c8f9..00000000000
--- a/app/models/commit.rb
+++ /dev/null
@@ -1,155 +0,0 @@
-class Commit
- include ActiveModel::Conversion
- include StaticModel
- extend ActiveModel::Naming
- include Mentionable
-
- attr_mentionable :safe_message
-
- # Safe amount of changes (files and lines) in one commit to render
- # Used to prevent 500 error on huge commits by suppressing diff
- #
- # User can force display of diff above this size
- DIFF_SAFE_FILES = 100 unless defined?(DIFF_SAFE_FILES)
- DIFF_SAFE_LINES = 5000 unless defined?(DIFF_SAFE_LINES)
-
- # Commits above this size will not be rendered in HTML
- DIFF_HARD_LIMIT_FILES = 1000 unless defined?(DIFF_HARD_LIMIT_FILES)
- DIFF_HARD_LIMIT_LINES = 50000 unless defined?(DIFF_HARD_LIMIT_LINES)
-
- class << self
- def decorate(commits)
- commits.map do |commit|
- if commit.kind_of?(Commit)
- commit
- else
- self.new(commit)
- end
- end
- end
-
- # Calculate number of lines to render for diffs
- def diff_line_count(diffs)
- diffs.reduce(0) { |sum, d| sum + d.diff.lines.count }
- end
-
- # Truncate sha to 8 characters
- def truncate_sha(sha)
- sha[0..7]
- end
- end
-
- attr_accessor :raw
-
- def initialize(raw_commit)
- raise "Nil as raw commit passed" unless raw_commit
-
- @raw = raw_commit
- end
-
- def id
- @raw.id
- end
-
- def diff_line_count
- @diff_line_count ||= Commit::diff_line_count(self.diffs)
- @diff_line_count
- end
-
- # Returns a string describing the commit for use in a link title
- #
- # Example
- #
- # "Commit: Alex Denisov - Project git clone panel"
- def link_title
- "Commit: #{author_name} - #{title}"
- end
-
- # Returns the commits title.
- #
- # Usually, the commit title is the first line of the commit message.
- # In case this first line is longer than 100 characters, it is cut off
- # after 80 characters and ellipses (`&hellp;`) are appended.
- def title
- title = safe_message
-
- return no_commit_message if title.blank?
-
- title_end = title.index("\n")
- if (!title_end && title.length > 100) || (title_end && title_end > 100)
- title[0..79] << "…"
- else
- title.split("\n", 2).first
- end
- end
-
- # Returns the commits description
- #
- # cut off, ellipses (`&hellp;`) are prepended to the commit message.
- def description
- title_end = safe_message.index("\n")
- @description ||=
- if (!title_end && safe_message.length > 100) || (title_end && title_end > 100)
- "…" << safe_message[80..-1]
- else
- safe_message.split("\n", 2)[1].try(:chomp)
- end
- end
-
- def description?
- description.present?
- end
-
- def hook_attrs(project)
- path_with_namespace = project.path_with_namespace
-
- {
- id: id,
- message: safe_message,
- timestamp: committed_date.xmlschema,
- url: "#{Gitlab.config.gitlab.url}/#{path_with_namespace}/commit/#{id}",
- author: {
- name: author_name,
- email: author_email
- }
- }
- end
-
- # Discover issues should be closed when this commit is pushed to a project's
- # default branch.
- def closes_issues(project, current_user = self.committer)
- Gitlab::ClosingIssueExtractor.new(project, current_user).closed_by_message(safe_message)
- end
-
- # Mentionable override.
- def gfm_reference
- "commit #{id}"
- end
-
- def author
- User.find_for_commit(author_email, author_name)
- end
-
- def committer
- User.find_for_commit(committer_email, committer_name)
- end
-
- def method_missing(m, *args, &block)
- @raw.send(m, *args, &block)
- end
-
- def respond_to?(method)
- return true if @raw.respond_to?(method)
-
- super
- end
-
- # Truncate sha to 8 characters
- def short_id
- @raw.short_id(7)
- end
-
- def parents
- @parents ||= Commit.decorate(super)
- end
-end
diff --git a/app/models/concerns/internal_id.rb b/app/models/concerns/internal_id.rb
deleted file mode 100644
index 821ed54fb98..00000000000
--- a/app/models/concerns/internal_id.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-module InternalId
- extend ActiveSupport::Concern
-
- included do
- validate :set_iid, on: :create
- validates :iid, presence: true, numericality: true
- end
-
- def set_iid
- max_iid = project.send(self.class.name.tableize).maximum(:iid)
- self.iid = max_iid.to_i + 1
- end
-
- def to_param
- iid.to_s
- end
-end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
deleted file mode 100644
index 478134dff68..00000000000
--- a/app/models/concerns/issuable.rb
+++ /dev/null
@@ -1,189 +0,0 @@
-# == Issuable concern
-#
-# Contains common functionality shared between Issues and MergeRequests
-#
-# Used by Issue, MergeRequest
-#
-module Issuable
- extend ActiveSupport::Concern
- include Mentionable
-
- included do
- belongs_to :author, class_name: "User"
- belongs_to :assignee, class_name: "User"
- belongs_to :milestone
- has_many :notes, as: :noteable, dependent: :destroy
- has_many :label_links, as: :target, dependent: :destroy
- has_many :labels, through: :label_links
- has_many :subscriptions, dependent: :destroy, as: :subscribable
-
- validates :author, presence: true
- validates :title, presence: true, length: { within: 0..255 }
-
- scope :authored, ->(user) { where(author_id: user) }
- scope :assigned_to, ->(u) { where(assignee_id: u.id)}
- scope :recent, -> { order("created_at DESC") }
- scope :assigned, -> { where("assignee_id IS NOT NULL") }
- scope :unassigned, -> { where("assignee_id IS NULL") }
- scope :of_projects, ->(ids) { where(project_id: ids) }
- scope :opened, -> { with_state(:opened, :reopened) }
- scope :only_opened, -> { with_state(:opened) }
- scope :only_reopened, -> { with_state(:reopened) }
- scope :closed, -> { with_state(:closed) }
- scope :order_milestone_due_desc, -> { joins(:milestone).reorder('milestones.due_date DESC, milestones.id DESC') }
- scope :order_milestone_due_asc, -> { joins(:milestone).reorder('milestones.due_date ASC, milestones.id ASC') }
-
- delegate :name,
- :email,
- to: :author,
- prefix: true
-
- delegate :name,
- :email,
- to: :assignee,
- allow_nil: true,
- prefix: true
-
- attr_mentionable :title, :description
- end
-
- module ClassMethods
- def search(query)
- where("LOWER(title) like :query", query: "%#{query.downcase}%")
- end
-
- def full_search(query)
- where("LOWER(title) like :query OR LOWER(description) like :query", query: "%#{query.downcase}%")
- end
-
- def sort(method)
- case method.to_s
- when 'milestone_due_asc' then order_milestone_due_asc
- when 'milestone_due_desc' then order_milestone_due_desc
- else
- order_by(method)
- end
- end
- end
-
- def today?
- Date.today == created_at.to_date
- end
-
- def new?
- today? && created_at == updated_at
- end
-
- def is_assigned?
- !!assignee_id
- end
-
- def is_being_reassigned?
- assignee_id_changed?
- end
-
- #
- # Votes
- #
-
- # Return the number of -1 comments (downvotes)
- def downvotes
- filter_superceded_votes(notes.select(&:downvote?), notes).size
- end
-
- def downvotes_in_percent
- if votes_count.zero?
- 0
- else
- 100.0 - upvotes_in_percent
- end
- end
-
- # Return the number of +1 comments (upvotes)
- def upvotes
- filter_superceded_votes(notes.select(&:upvote?), notes).size
- end
-
- def upvotes_in_percent
- if votes_count.zero?
- 0
- else
- 100.0 / votes_count * upvotes
- end
- end
-
- # Return the total number of votes
- def votes_count
- upvotes + downvotes
- end
-
- # Return all users participating on the discussion
- def participants(current_user = self.author)
- users = []
- users << author
- users << assignee if is_assigned?
- mentions = []
- mentions << self.mentioned_users(current_user)
-
- notes.each do |note|
- users << note.author
- mentions << note.mentioned_users(current_user)
- end
-
- users.concat(mentions.reduce([], :|)).uniq
- end
-
- def subscribed?(user)
- subscription = subscriptions.find_by_user_id(user.id)
-
- if subscription
- return subscription.subscribed
- end
-
- participants(user).include?(user)
- end
-
- def toggle_subscription(user)
- subscriptions.
- find_or_initialize_by(user_id: user.id).
- update(subscribed: !subscribed?(user))
- end
-
- def to_hook_data(user)
- {
- object_kind: self.class.name.underscore,
- user: user.hook_attrs,
- object_attributes: hook_attrs
- }
- end
-
- def label_names
- labels.order('title ASC').pluck(:title)
- end
-
- def remove_labels
- labels.delete_all
- end
-
- def add_labels_by_names(label_names)
- label_names.each do |label_name|
- label = project.labels.create_with(color: Label::DEFAULT_COLOR).
- find_or_create_by(title: label_name.strip)
- self.labels << label
- end
- end
-
- private
-
- def filter_superceded_votes(votes, notes)
- filteredvotes = [] + votes
-
- votes.each do |vote|
- if vote.superceded?(notes)
- filteredvotes.delete(vote)
- end
- end
-
- filteredvotes
- end
-end
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
deleted file mode 100644
index b7882a2bb16..00000000000
--- a/app/models/concerns/mentionable.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-# == Mentionable concern
-#
-# Contains functionality related to objects that can mention Users, Issues, MergeRequests, or Commits by
-# GFM references.
-#
-# Used by Issue, Note, MergeRequest, and Commit.
-#
-module Mentionable
- extend ActiveSupport::Concern
-
- module ClassMethods
- # Indicate which attributes of the Mentionable to search for GFM references.
- def attr_mentionable(*attrs)
- mentionable_attrs.concat(attrs.map(&:to_s))
- end
-
- # Accessor for attributes marked mentionable.
- def mentionable_attrs
- @mentionable_attrs ||= []
- end
- end
-
- # Generate a GFM back-reference that will construct a link back to this Mentionable when rendered. Must
- # be overridden if this model object can be referenced directly by GFM notation.
- def gfm_reference
- raise NotImplementedError.new("#{self.class} does not implement #gfm_reference")
- end
-
- # Construct a String that contains possible GFM references.
- def mentionable_text
- self.class.mentionable_attrs.map { |attr| send(attr) || '' }.join
- end
-
- # The GFM reference to this Mentionable, which shouldn't be included in its #references.
- def local_reference
- self
- end
-
- # Determine whether or not a cross-reference Note has already been created between this Mentionable and
- # the specified target.
- def has_mentioned?(target)
- Note.cross_reference_exists?(target, local_reference)
- end
-
- def mentioned_users(current_user = nil)
- return [] if mentionable_text.blank?
-
- ext = Gitlab::ReferenceExtractor.new(self.project, current_user)
- ext.analyze(mentionable_text)
- ext.users.uniq
- end
-
- # Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.
- def references(p = project, current_user = self.author, text = mentionable_text)
- return [] if text.blank?
-
- ext = Gitlab::ReferenceExtractor.new(p, current_user)
- ext.analyze(text)
-
- (ext.issues + ext.merge_requests + ext.commits).uniq - [local_reference]
- end
-
- # Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+.
- def create_cross_references!(p = project, a = author, without = [])
- refs = references(p) - without
- refs.each do |ref|
- Note.create_cross_reference_note(ref, local_reference, a, p)
- end
- end
-
- # If the mentionable_text field is about to change, locate any *added* references and create cross references for
- # them. Invoke from an observer's #before_save implementation.
- def notice_added_references(p = project, a = author)
- ch = changed_attributes
- original, mentionable_changed = "", false
- self.class.mentionable_attrs.each do |attr|
- if ch[attr]
- original << ch[attr]
- mentionable_changed = true
- end
- end
-
- # Only proceed if the saved changes actually include a chance to an attr_mentionable field.
- return unless mentionable_changed
-
- preexisting = references(p, self.author, original)
- create_cross_references!(p, a, preexisting)
- end
-end
diff --git a/app/models/concerns/notifiable.rb b/app/models/concerns/notifiable.rb
deleted file mode 100644
index d7dcd97911d..00000000000
--- a/app/models/concerns/notifiable.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# == Notifiable concern
-#
-# Contains notification functionality
-#
-module Notifiable
- extend ActiveSupport::Concern
-
- included do
- validates :notification_level, inclusion: { in: Notification.project_notification_levels }, presence: true
- end
-
- def notification
- @notification ||= Notification.new(self)
- end
-end
diff --git a/app/models/concerns/sortable.rb b/app/models/concerns/sortable.rb
deleted file mode 100644
index 0ad2654867d..00000000000
--- a/app/models/concerns/sortable.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# == Sortable concern
-#
-# Set default scope for ordering objects
-#
-module Sortable
- extend ActiveSupport::Concern
-
- included do
- # By default all models should be ordered
- # by created_at field starting from newest
- default_scope { order(created_at: :desc, id: :desc) }
-
- scope :order_created_desc, -> { reorder(created_at: :desc, id: :desc) }
- scope :order_created_asc, -> { reorder(created_at: :asc, id: :asc) }
- scope :order_updated_desc, -> { reorder(updated_at: :desc, id: :desc) }
- scope :order_updated_asc, -> { reorder(updated_at: :asc, id: :asc) }
- scope :order_name_asc, -> { reorder(name: :asc) }
- scope :order_name_desc, -> { reorder(name: :desc) }
- end
-
- module ClassMethods
- def order_by(method)
- case method.to_s
- when 'name_asc' then order_name_asc
- when 'name_desc' then order_name_desc
- when 'updated_asc' then order_updated_asc
- when 'updated_desc' then order_updated_desc
- when 'created_asc' then order_created_asc
- when 'created_desc' then order_created_desc
- else
- all
- end
- end
- end
-end
diff --git a/app/models/concerns/taskable.rb b/app/models/concerns/taskable.rb
deleted file mode 100644
index bbb3b301a9f..00000000000
--- a/app/models/concerns/taskable.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# Contains functionality for objects that can have task lists in their
-# descriptions. Task list items can be added with Markdown like "* [x] Fix
-# bugs".
-#
-# Used by MergeRequest and Issue
-module Taskable
- TASK_PATTERN_MD = /^(?<bullet> *[*-] *)\[(?<checked>[ xX])\]/.freeze
- TASK_PATTERN_HTML = /^<li>(?<p_tag>\s*<p>)?\[(?<checked>[ xX])\]/.freeze
-
- # Change the state of a task list item for this Taskable. Edit the object's
- # description by finding the nth task item and changing its checkbox
- # placeholder to "[x]" if +checked+ is true, or "[ ]" if it's false.
- # Note: task numbering starts with 1
- def update_nth_task(n, checked)
- index = 0
- check_char = checked ? 'x' : ' '
-
- # Do this instead of using #gsub! so that ActiveRecord detects that a field
- # has changed.
- self.description = self.description.gsub(TASK_PATTERN_MD) do |match|
- index += 1
- case index
- when n then "#{$LAST_MATCH_INFO[:bullet]}[#{check_char}]"
- else match
- end
- end
-
- save
- end
-
- # Return true if this object's description has any task list items.
- def tasks?
- description && description.match(TASK_PATTERN_MD)
- end
-
- # Return a string that describes the current state of this Taskable's task
- # list items, e.g. "20 tasks (12 done, 8 unfinished)"
- def task_status
- return nil unless description
-
- num_tasks = 0
- num_done = 0
-
- description.scan(TASK_PATTERN_MD) do
- num_tasks += 1
- num_done += 1 unless $LAST_MATCH_INFO[:checked] == ' '
- end
-
- "#{num_tasks} tasks (#{num_done} done, #{num_tasks - num_done} unfinished)"
- end
-end
diff --git a/app/models/concerns/token_authenticatable.rb b/app/models/concerns/token_authenticatable.rb
deleted file mode 100644
index 9b88ec1cc38..00000000000
--- a/app/models/concerns/token_authenticatable.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-module TokenAuthenticatable
- extend ActiveSupport::Concern
-
- module ClassMethods
- def find_by_authentication_token(authentication_token = nil)
- if authentication_token
- where(authentication_token: authentication_token).first
- end
- end
- end
-
- def ensure_authentication_token
- if authentication_token.blank?
- self.authentication_token = generate_authentication_token
- end
- end
-
- def reset_authentication_token!
- self.authentication_token = generate_authentication_token
- save
- end
-
- private
-
- def generate_authentication_token
- loop do
- token = Devise.friendly_token
- break token unless self.class.unscoped.where(authentication_token: token).first
- end
- end
-end
diff --git a/app/models/deploy_key.rb b/app/models/deploy_key.rb
deleted file mode 100644
index 85d52d558cd..00000000000
--- a/app/models/deploy_key.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# == Schema Information
-#
-# Table name: keys
-#
-# id :integer not null, primary key
-# user_id :integer
-# created_at :datetime
-# updated_at :datetime
-# key :text
-# public :boolean default(FALSE)
-# title :string(255)
-# type :string(255)
-# fingerprint :string(255)
-#
-
-class DeployKey < Key
- has_many :deploy_keys_projects, dependent: :destroy
- has_many :projects, through: :deploy_keys_projects
-
- scope :in_projects, ->(projects) { joins(:deploy_keys_projects).where('deploy_keys_projects.project_id in (?)', projects) }
- scope :are_public, -> { where(public: true) }
-
- def private?
- !public?
- end
-
- def orphaned?
- self.deploy_keys_projects.length == 0
- end
-
- def almost_orphaned?
- self.deploy_keys_projects.length == 1
- end
-
- def destroyed_when_orphaned?
- self.private?
- end
-end
diff --git a/app/models/deploy_keys_project.rb b/app/models/deploy_keys_project.rb
deleted file mode 100644
index 18db521741f..00000000000
--- a/app/models/deploy_keys_project.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# == Schema Information
-#
-# Table name: deploy_keys_projects
-#
-# id :integer not null, primary key
-# deploy_key_id :integer not null
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-#
-
-class DeployKeysProject < ActiveRecord::Base
- belongs_to :project
- belongs_to :deploy_key
-
- validates :deploy_key_id, presence: true
- validates :deploy_key_id, uniqueness: { scope: [:project_id], message: "already exists in project" }
- validates :project_id, presence: true
-
- after_destroy :destroy_orphaned_deploy_key
-
- private
-
- def destroy_orphaned_deploy_key
- return unless self.deploy_key.destroyed_when_orphaned? && self.deploy_key.orphaned?
-
- self.deploy_key.destroy
- end
-end
diff --git a/app/models/diff_line.rb b/app/models/diff_line.rb
deleted file mode 100644
index ad37945874a..00000000000
--- a/app/models/diff_line.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-class DiffLine
- attr_accessor :type, :content, :num, :code
-end
diff --git a/app/models/email.rb b/app/models/email.rb
deleted file mode 100644
index 556b0e9586e..00000000000
--- a/app/models/email.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# == Schema Information
-#
-# Table name: emails
-#
-# id :integer not null, primary key
-# user_id :integer not null
-# email :string(255) not null
-# created_at :datetime
-# updated_at :datetime
-#
-
-class Email < ActiveRecord::Base
- include Sortable
-
- belongs_to :user
-
- validates :user_id, presence: true
- validates :email, presence: true, email: { strict_mode: true }, uniqueness: true
- validate :unique_email, if: ->(email) { email.email_changed? }
-
- after_create :notify
- before_validation :cleanup_email
-
- def cleanup_email
- self.email = self.email.downcase.strip
- end
-
- def unique_email
- self.errors.add(:email, 'has already been taken') if User.exists?(email: self.email)
- end
-
- def notify
- NotificationService.new.new_email(self)
- end
-end
diff --git a/app/models/event.rb b/app/models/event.rb
deleted file mode 100644
index c9a88ffa8e0..00000000000
--- a/app/models/event.rb
+++ /dev/null
@@ -1,330 +0,0 @@
-# == Schema Information
-#
-# Table name: events
-#
-# id :integer not null, primary key
-# target_type :string(255)
-# target_id :integer
-# title :string(255)
-# data :text
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# action :integer
-# author_id :integer
-#
-
-class Event < ActiveRecord::Base
- include Sortable
- default_scope { where.not(author_id: nil) }
-
- CREATED = 1
- UPDATED = 2
- CLOSED = 3
- REOPENED = 4
- PUSHED = 5
- COMMENTED = 6
- MERGED = 7
- JOINED = 8 # User joined project
- LEFT = 9 # User left project
-
- delegate :name, :email, to: :author, prefix: true, allow_nil: true
- 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
- belongs_to :target, polymorphic: true
-
- # For Hash only
- serialize :data
-
- # Callbacks
- after_create :reset_project_activity
-
- # Scopes
- scope :recent, -> { order("created_at DESC") }
- scope :code_push, -> { where(action: PUSHED) }
- scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent }
- scope :with_associations, -> { includes(project: :namespace) }
-
- class << self
- def reset_event_cache_for(target)
- Event.where(target_id: target.id, target_type: target.class.to_s).
- order('id DESC').limit(100).
- update_all(updated_at: Time.now)
- end
-
- def contributions
- where("action = ? OR (target_type in (?) AND action in (?))",
- Event::PUSHED, ["MergeRequest", "Issue"],
- [Event::CREATED, Event::CLOSED, Event::MERGED])
- end
- end
-
- def proper?
- if push?
- true
- elsif membership_changed?
- true
- elsif created_project?
- true
- else
- (issue? || merge_request? || note? || milestone?) && target
- end
- end
-
- def project_name
- if project
- project.name_with_namespace
- else
- "(deleted project)"
- end
- end
-
- def target_title
- target.title if target && target.respond_to?(:title)
- end
-
- def created?
- action == CREATED
- end
-
- def push?
- action == PUSHED && valid_push?
- end
-
- def merged?
- action == MERGED
- end
-
- def closed?
- action == CLOSED
- end
-
- def reopened?
- action == REOPENED
- end
-
- def joined?
- action == JOINED
- end
-
- def left?
- action == LEFT
- end
-
- def commented?
- action == COMMENTED
- end
-
- def membership_changed?
- joined? || left?
- end
-
- def created_project?
- created? && !target
- end
-
- def created_target?
- created? && target
- end
-
- def milestone?
- target_type == "Milestone"
- end
-
- def note?
- target_type == "Note"
- end
-
- def issue?
- target_type == "Issue"
- end
-
- def merge_request?
- target_type == "MergeRequest"
- end
-
- def milestone
- target if milestone?
- end
-
- def issue
- target if issue?
- end
-
- def merge_request
- target if merge_request?
- end
-
- def note
- target if note?
- end
-
- def action_name
- if push?
- if new_ref?
- "pushed new"
- elsif rm_ref?
- "deleted"
- else
- "pushed to"
- end
- elsif closed?
- "closed"
- elsif merged?
- "accepted"
- elsif joined?
- 'joined'
- elsif left?
- 'left'
- elsif commented?
- "commented on"
- elsif created_project?
- if project.import?
- "imported"
- else
- "created"
- end
- else
- "opened"
- end
- end
-
- def valid_push?
- data[:ref] && ref_name.present?
- rescue
- false
- end
-
- def tag?
- Gitlab::Git.tag_ref?(data[:ref])
- end
-
- def branch?
- Gitlab::Git.branch_ref?(data[:ref])
- end
-
- def new_ref?
- Gitlab::Git.blank_ref?(commit_from)
- end
-
- def rm_ref?
- Gitlab::Git.blank_ref?(commit_to)
- 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
- @branch_name ||= Gitlab::Git.ref_name(data[:ref])
- end
-
- def tag_name
- @tag_name ||= Gitlab::Git.ref_name(data[:ref])
- end
-
- # Max 20 commits from push DESC
- def commits
- @commits ||= (data[:commits] || []).reverse
- end
-
- def commits_count
- data[:total_commits_count] || commits.count || 0
- end
-
- def ref_type
- tag? ? "tag" : "branch"
- end
-
- def push_with_commits?
- !commits.empty? && commit_from && commit_to
- end
-
- def last_push_to_non_root?
- branch? && project.default_branch != branch_name
- end
-
- def note_commit_id
- target.commit_id
- end
-
- def target_iid
- target.respond_to?(:iid) ? target.iid : target_id
- end
-
- def note_short_commit_id
- Commit.truncate_sha(note_commit_id)
- end
-
- def note_commit?
- target.noteable_type == "Commit"
- end
-
- def note_project_snippet?
- target.noteable_type == "Snippet"
- end
-
- def note_target
- target.noteable
- end
-
- def note_target_id
- if note_commit?
- target.commit_id
- else
- target.noteable_id.to_s
- end
- end
-
- def note_target_iid
- if note_target.respond_to?(:iid)
- note_target.iid
- else
- note_target_id
- end.to_s
- end
-
- def note_target_type
- if target.noteable_type.present?
- target.noteable_type.titleize
- else
- "Wall"
- end.downcase
- end
-
- def body?
- if push?
- push_with_commits?
- elsif note?
- true
- else
- target.respond_to? :title
- end
- end
-
- def reset_project_activity
- if project
- project.update_column(:last_activity_at, self.created_at)
- end
- end
-end
diff --git a/app/models/external_issue.rb b/app/models/external_issue.rb
deleted file mode 100644
index 50efcb32f1b..00000000000
--- a/app/models/external_issue.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-class ExternalIssue
- def initialize(issue_identifier, project)
- @issue_identifier, @project = issue_identifier, project
- end
-
- def to_s
- @issue_identifier.to_s
- end
-
- def id
- @issue_identifier.to_s
- end
-
- def iid
- @issue_identifier.to_s
- end
-
- def ==(other)
- other.is_a?(self.class) && (to_s == other.to_s)
- end
-
- def project
- @project
- end
-end
diff --git a/app/models/forked_project_link.rb b/app/models/forked_project_link.rb
deleted file mode 100644
index 9b0c6263a96..00000000000
--- a/app/models/forked_project_link.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# == Schema Information
-#
-# Table name: forked_project_links
-#
-# id :integer not null, primary key
-# forked_to_project_id :integer not null
-# forked_from_project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-#
-
-class ForkedProjectLink < ActiveRecord::Base
- belongs_to :forked_to_project, class_name: Project
- belongs_to :forked_from_project, class_name: Project
-end
diff --git a/app/models/group.rb b/app/models/group.rb
deleted file mode 100644
index 1386a9eccc9..00000000000
--- a/app/models/group.rb
+++ /dev/null
@@ -1,100 +0,0 @@
-# == Schema Information
-#
-# Table name: namespaces
-#
-# id :integer not null, primary key
-# name :string(255) not null
-# path :string(255) not null
-# owner_id :integer
-# created_at :datetime
-# updated_at :datetime
-# type :string(255)
-# description :string(255) default(""), not null
-# avatar :string(255)
-#
-
-require 'carrierwave/orm/activerecord'
-require 'file_size_validator'
-
-class Group < Namespace
- has_many :group_members, dependent: :destroy, as: :source, class_name: 'GroupMember'
- has_many :users, through: :group_members
-
- validate :avatar_type, if: ->(user) { user.avatar_changed? }
- validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
-
- mount_uploader :avatar, AvatarUploader
-
- after_create :post_create_hook
- after_destroy :post_destroy_hook
-
- class << self
- def search(query)
- where("LOWER(namespaces.name) LIKE :query or LOWER(namespaces.path) LIKE :query", query: "%#{query.downcase}%")
- end
-
- def sort(method)
- order_by(method)
- end
- end
-
- def human_name
- name
- end
-
- def owners
- @owners ||= group_members.owners.map(&:user)
- end
-
- def add_users(user_ids, access_level, current_user = nil)
- user_ids.each do |user_id|
- Member.add_user(self.group_members, user_id, access_level, current_user)
- end
- end
-
- def add_user(user, access_level, current_user = nil)
- add_users([user], access_level, current_user)
- end
-
- def add_owner(user, current_user = nil)
- self.add_user(user, Gitlab::Access::OWNER, current_user)
- end
-
- def has_owner?(user)
- owners.include?(user)
- end
-
- def has_master?(user)
- members.masters.where(user_id: user).any?
- end
-
- def last_owner?(user)
- has_owner?(user) && owners.size == 1
- end
-
- def members
- group_members
- end
-
- def avatar_type
- unless self.avatar.image?
- self.errors.add :avatar, "only images allowed"
- end
- end
-
- def public_profile?
- projects.public_only.any?
- end
-
- def post_create_hook
- system_hook_service.execute_hooks_for(self, :create)
- end
-
- def post_destroy_hook
- system_hook_service.execute_hooks_for(self, :destroy)
- end
-
- def system_hook_service
- SystemHooksService.new
- end
-end
diff --git a/app/models/group_milestone.rb b/app/models/group_milestone.rb
deleted file mode 100644
index 7e4f16ebf16..00000000000
--- a/app/models/group_milestone.rb
+++ /dev/null
@@ -1,95 +0,0 @@
-class GroupMilestone
-
- def initialize(title, milestones)
- @title = title
- @milestones = milestones
- end
-
- def title
- @title
- end
-
- def safe_title
- @title.parameterize
- end
-
- def milestones
- @milestones
- end
-
- def projects
- milestones.map { |milestone| milestone.project }
- end
-
- def issue_count
- milestones.map { |milestone| milestone.issues.count }.sum
- end
-
- def merge_requests_count
- milestones.map { |milestone| milestone.merge_requests.count }.sum
- end
-
- def open_items_count
- milestones.map { |milestone| milestone.open_items_count }.sum
- end
-
- def closed_items_count
- milestones.map { |milestone| milestone.closed_items_count }.sum
- end
-
- def total_items_count
- milestones.map { |milestone| milestone.total_items_count }.sum
- end
-
- def percent_complete
- ((closed_items_count * 100) / total_items_count).abs
- rescue ZeroDivisionError
- 100
- end
-
- def state
- state = milestones.map { |milestone| milestone.state }
-
- if state.count('closed') == state.size
- 'closed'
- else
- 'active'
- end
- end
-
- def active?
- state == 'active'
- end
-
- def closed?
- state == 'closed'
- end
-
- def issues
- @group_issues ||= milestones.map(&:issues).flatten.group_by(&:state)
- end
-
- def merge_requests
- @group_merge_requests ||= milestones.map(&:merge_requests).flatten.group_by(&:state)
- end
-
- def participants
- @group_participants ||= milestones.map(&:participants).flatten.compact.uniq
- end
-
- def opened_issues
- issues.values_at("opened", "reopened").compact.flatten
- end
-
- def closed_issues
- issues['closed']
- end
-
- def opened_merge_requests
- merge_requests.values_at("opened", "reopened").compact.flatten
- end
-
- def closed_merge_requests
- merge_requests.values_at("closed", "merged", "locked").compact.flatten
- end
-end
diff --git a/app/models/hooks/project_hook.rb b/app/models/hooks/project_hook.rb
deleted file mode 100644
index 21867a9316c..00000000000
--- a/app/models/hooks/project_hook.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# == Schema Information
-#
-# Table name: web_hooks
-#
-# id :integer not null, primary key
-# url :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# type :string(255) default("ProjectHook")
-# service_id :integer
-# push_events :boolean default(TRUE), not null
-# issues_events :boolean default(FALSE), not null
-# merge_requests_events :boolean default(FALSE), not null
-# tag_push_events :boolean default(FALSE)
-#
-
-class ProjectHook < WebHook
- belongs_to :project
-
- 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/hooks/service_hook.rb b/app/models/hooks/service_hook.rb
deleted file mode 100644
index 2e11239c40b..00000000000
--- a/app/models/hooks/service_hook.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# == Schema Information
-#
-# Table name: web_hooks
-#
-# id :integer not null, primary key
-# url :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# type :string(255) default("ProjectHook")
-# service_id :integer
-# push_events :boolean default(TRUE), not null
-# issues_events :boolean default(FALSE), not null
-# merge_requests_events :boolean default(FALSE), not null
-# tag_push_events :boolean default(FALSE)
-#
-
-class ServiceHook < WebHook
- belongs_to :service
-end
diff --git a/app/models/hooks/system_hook.rb b/app/models/hooks/system_hook.rb
deleted file mode 100644
index ee32b49bc66..00000000000
--- a/app/models/hooks/system_hook.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# == Schema Information
-#
-# Table name: web_hooks
-#
-# id :integer not null, primary key
-# url :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# type :string(255) default("ProjectHook")
-# service_id :integer
-# push_events :boolean default(TRUE), not null
-# issues_events :boolean default(FALSE), not null
-# merge_requests_events :boolean default(FALSE), not null
-# tag_push_events :boolean default(FALSE)
-#
-
-class SystemHook < WebHook
-end
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
deleted file mode 100644
index 315d96af1b9..00000000000
--- a/app/models/hooks/web_hook.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# == Schema Information
-#
-# Table name: web_hooks
-#
-# id :integer not null, primary key
-# url :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# type :string(255) default("ProjectHook")
-# service_id :integer
-# push_events :boolean default(TRUE), not null
-# issues_events :boolean default(FALSE), not null
-# merge_requests_events :boolean default(FALSE), not null
-# tag_push_events :boolean default(FALSE)
-#
-
-class WebHook < ActiveRecord::Base
- include Sortable
- include HTTParty
-
- default_value_for :push_events, true
- default_value_for :issues_events, false
- default_value_for :merge_requests_events, false
- default_value_for :tag_push_events, false
-
- # HTTParty timeout
- default_timeout Gitlab.config.gitlab.webhook_timeout
-
- validates :url, presence: true,
- format: { with: /\A#{URI.regexp(%w(http https))}\z/, message: "should be a valid url" }
-
- def execute(data)
- parsed_url = URI.parse(url)
- if parsed_url.userinfo.blank?
- WebHook.post(url,
- body: data.to_json,
- headers: { "Content-Type" => "application/json" },
- verify: false)
- else
- post_url = url.gsub("#{parsed_url.userinfo}@", "")
- auth = {
- username: URI.decode(parsed_url.user),
- password: URI.decode(parsed_url.password),
- }
- WebHook.post(post_url,
- body: data.to_json,
- headers: { "Content-Type" => "application/json" },
- verify: false,
- basic_auth: auth)
- end
- rescue SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout => e
- logger.error("WebHook Error => #{e}")
- false
- end
-
- def async_execute(data)
- Sidekiq::Client.enqueue(ProjectWebHookWorker, id, data)
- end
-end
diff --git a/app/models/identity.rb b/app/models/identity.rb
deleted file mode 100644
index 756d19adec7..00000000000
--- a/app/models/identity.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# == Schema Information
-#
-# Table name: identities
-#
-# id :integer not null, primary key
-# extern_uid :string(255)
-# provider :string(255)
-# user_id :integer
-# created_at :datetime
-# updated_at :datetime
-#
-
-class Identity < ActiveRecord::Base
- include Sortable
- belongs_to :user
-
- validates :extern_uid, allow_blank: true, uniqueness: { scope: :provider }
- validates :user_id, uniqueness: { scope: :provider }
-end
diff --git a/app/models/issue.rb b/app/models/issue.rb
deleted file mode 100644
index 6e102051387..00000000000
--- a/app/models/issue.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-# == Schema Information
-#
-# Table name: issues
-#
-# id :integer not null, primary key
-# title :string(255)
-# assignee_id :integer
-# author_id :integer
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# position :integer default(0)
-# branch_name :string(255)
-# description :text
-# milestone_id :integer
-# state :string(255)
-# iid :integer
-#
-
-require 'carrierwave/orm/activerecord'
-require 'file_size_validator'
-
-class Issue < ActiveRecord::Base
- include Issuable
- include InternalId
- include Taskable
- include Sortable
-
- ActsAsTaggableOn.strict_case_match = true
-
- belongs_to :project
- validates :project, presence: true
-
- scope :of_group, ->(group) { where(project_id: group.project_ids) }
- scope :cared, ->(user) { where(assignee_id: user) }
- scope :open_for, ->(user) { opened.assigned_to(user) }
-
- state_machine :state, initial: :opened do
- event :close do
- transition [:reopened, :opened] => :closed
- end
-
- event :reopen do
- transition closed: :reopened
- end
-
- state :opened
- state :reopened
- state :closed
- end
-
- def hook_attrs
- attributes
- end
-
- # Mentionable overrides.
-
- def gfm_reference
- "issue ##{iid}"
- end
-
- # Reset issue events cache
- #
- # Since we do cache @event we need to reset cache in special cases:
- # * when an issue is updated
- # Events cache stored like events/23-20130109142513.
- # The cache key includes updated_at timestamp.
- # Thus it will automatically generate a new fragment
- # when the event is updated because the key changes.
- def reset_events_cache
- Event.reset_event_cache_for(self)
- end
-
- # To allow polymorphism with MergeRequest.
- def source_project
- project
- end
-end
diff --git a/app/models/key.rb b/app/models/key.rb
deleted file mode 100644
index 016eee86992..00000000000
--- a/app/models/key.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-# == Schema Information
-#
-# Table name: keys
-#
-# id :integer not null, primary key
-# user_id :integer
-# created_at :datetime
-# updated_at :datetime
-# key :text
-# title :string(255)
-# type :string(255)
-# fingerprint :string(255)
-#
-
-require 'digest/md5'
-
-class Key < ActiveRecord::Base
- include Sortable
-
- belongs_to :user
-
- before_validation :strip_white_space, :generate_fingerprint
-
- validates :title, presence: true, length: { within: 0..255 }
- validates :key, presence: true, length: { within: 0..5000 }, format: { with: /\A(ssh|ecdsa)-.*\Z/ }, uniqueness: true
- validates :fingerprint, uniqueness: true, presence: { message: 'cannot be generated' }
-
- delegate :name, :email, to: :user, prefix: true
-
- after_create :add_to_shell
- after_create :notify_user
- after_create :post_create_hook
- after_destroy :remove_from_shell
- after_destroy :post_destroy_hook
-
- def strip_white_space
- self.key = key.strip unless key.blank?
- end
-
- # projects that has this key
- def projects
- user.authorized_projects
- end
-
- def shell_id
- "key-#{id}"
- end
-
- def add_to_shell
- GitlabShellWorker.perform_async(
- :add_key,
- shell_id,
- key
- )
- end
-
- def notify_user
- NotificationService.new.new_key(self)
- end
-
- def post_create_hook
- SystemHooksService.new.execute_hooks_for(self, :create)
- end
-
- def remove_from_shell
- GitlabShellWorker.perform_async(
- :remove_key,
- shell_id,
- key,
- )
- end
-
- def post_destroy_hook
- SystemHooksService.new.execute_hooks_for(self, :destroy)
- end
-
- private
-
- def generate_fingerprint
- self.fingerprint = nil
-
- return unless self.key.present?
-
- self.fingerprint = Gitlab::KeyFingerprint.new(self.key).fingerprint
- end
-end
diff --git a/app/models/label_link.rb b/app/models/label_link.rb
deleted file mode 100644
index b94c9c777af..00000000000
--- a/app/models/label_link.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# == Schema Information
-#
-# Table name: label_links
-#
-# id :integer not null, primary key
-# label_id :integer
-# target_id :integer
-# target_type :string(255)
-# created_at :datetime
-# updated_at :datetime
-#
-
-class LabelLink < ActiveRecord::Base
- belongs_to :target, polymorphic: true
- belongs_to :label
-
- validates :target, presence: true
- validates :label, presence: true
-end
diff --git a/app/models/member.rb b/app/models/member.rb
deleted file mode 100644
index d151c7b2390..00000000000
--- a/app/models/member.rb
+++ /dev/null
@@ -1,172 +0,0 @@
-# == Schema Information
-#
-# Table name: members
-#
-# id :integer not null, primary key
-# access_level :integer not null
-# source_id :integer not null
-# source_type :string(255) not null
-# user_id :integer not null
-# notification_level :integer not null
-# type :string(255)
-# created_at :datetime
-# updated_at :datetime
-# created_by_id :integer
-# invite_email :string
-# invite_token :string
-# invite_accepted_at :datetime
-#
-
-class Member < ActiveRecord::Base
- include Sortable
- include Notifiable
- include Gitlab::Access
-
- attr_accessor :raw_invite_token
-
- belongs_to :created_by, class_name: "User"
- belongs_to :user
- belongs_to :source, polymorphic: true
-
- validates :user, presence: true, unless: :invite?
- validates :source, presence: true
- validates :user_id, uniqueness: { scope: [:source_type, :source_id],
- message: "already exists in source",
- allow_nil: true }
- validates :access_level, inclusion: { in: Gitlab::Access.all_values }, presence: true
- validates :invite_email, presence: { if: :invite? },
- email: { strict_mode: true, allow_nil: true },
- uniqueness: { scope: [:source_type, :source_id], allow_nil: true }
-
- scope :invite, -> { where(user_id: nil) }
- scope :non_invite, -> { where("user_id IS NOT NULL") }
- scope :guests, -> { where(access_level: GUEST) }
- scope :reporters, -> { where(access_level: REPORTER) }
- scope :developers, -> { where(access_level: DEVELOPER) }
- scope :masters, -> { where(access_level: MASTER) }
- scope :owners, -> { where(access_level: OWNER) }
-
- before_validation :generate_invite_token, on: :create, if: -> (member) { member.invite_email.present? }
- after_create :send_invite, if: :invite?
- after_create :post_create_hook, unless: :invite?
- after_update :post_update_hook, unless: :invite?
- after_destroy :post_destroy_hook, unless: :invite?
-
- delegate :name, :username, :email, to: :user, prefix: true
-
- class << self
- def find_by_invite_token(invite_token)
- invite_token = Devise.token_generator.digest(self, :invite_token, invite_token)
- find_by(invite_token: invite_token)
- end
-
- # This method is used to find users that have been entered into the "Add members" field.
- # These can be the User objects directly, their IDs, their emails, or new emails to be invited.
- def user_for_id(user_id)
- return user_id if user_id.is_a?(User)
-
- user = User.find_by(id: user_id)
- user ||= User.find_by(email: user_id)
- user ||= user_id
- user
- end
-
- def add_user(members, user_id, access_level, current_user = nil)
- user = user_for_id(user_id)
-
- # `user` can be either a User object or an email to be invited
- if user.is_a?(User)
- member = members.find_or_initialize_by(user_id: user.id)
- else
- member = members.build
- member.invite_email = user
- end
-
- member.created_by ||= current_user
- member.access_level = access_level
-
- member.save
- end
- end
-
- def invite?
- self.invite_token.present?
- end
-
- def accept_invite!(new_user)
- return false unless invite?
-
- self.invite_token = nil
- self.invite_accepted_at = Time.now.utc
-
- self.user = new_user
-
- saved = self.save
-
- after_accept_invite if saved
-
- saved
- end
-
- def decline_invite!
- return false unless invite?
-
- destroyed = self.destroy
-
- after_decline_invite if destroyed
-
- destroyed
- end
-
- def generate_invite_token
- raw, enc = Devise.token_generator.generate(self.class, :invite_token)
- @raw_invite_token = raw
- self.invite_token = enc
- end
-
- def generate_invite_token!
- generate_invite_token && save(validate: false)
- end
-
- def resend_invite
- return unless invite?
-
- generate_invite_token! unless @raw_invite_token
-
- send_invite
- end
-
- private
-
- def send_invite
- # override in subclass
- end
-
- def post_create_hook
- system_hook_service.execute_hooks_for(self, :create)
- end
-
- def post_update_hook
- # override in subclass
- end
-
- def post_destroy_hook
- system_hook_service.execute_hooks_for(self, :destroy)
- end
-
- def after_accept_invite
- post_create_hook
- end
-
- def after_decline_invite
- # override in subclass
- end
-
- def system_hook_service
- SystemHooksService.new
- end
-
- def notification_service
- NotificationService.new
- end
-end
diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb
deleted file mode 100644
index 84c91372b3f..00000000000
--- a/app/models/members/group_member.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-# == Schema Information
-#
-# Table name: members
-#
-# id :integer not null, primary key
-# access_level :integer not null
-# source_id :integer not null
-# source_type :string(255) not null
-# user_id :integer not null
-# notification_level :integer not null
-# type :string(255)
-# created_at :datetime
-# updated_at :datetime
-#
-
-class GroupMember < Member
- SOURCE_TYPE = 'Namespace'
-
- belongs_to :group, class_name: 'Group', foreign_key: 'source_id'
-
- # Make sure group member points only to group as it source
- default_value_for :source_type, SOURCE_TYPE
- default_value_for :notification_level, Notification::N_GLOBAL
- validates_format_of :source_type, with: /\ANamespace\z/
- default_scope { where(source_type: SOURCE_TYPE) }
-
- scope :with_group, ->(group) { where(source_id: group.id) }
- scope :with_user, ->(user) { where(user_id: user.id) }
-
- def self.access_level_roles
- Gitlab::Access.options_with_owner
- end
-
- def group
- source
- end
-
- def access_field
- access_level
- end
-
- private
-
- def send_invite
- notification_service.invite_group_member(self, @raw_invite_token)
-
- super
- end
-
- def post_create_hook
- notification_service.new_group_member(self)
-
- super
- end
-
- def post_update_hook
- if access_level_changed?
- notification_service.update_group_member(self)
- end
-
- super
- end
-
- def after_accept_invite
- notification_service.accept_group_invite(self)
-
- super
- end
-
- def after_decline_invite
- notification_service.decline_group_invite(self)
-
- super
- end
-end
diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb
deleted file mode 100644
index 0a3b4d2182b..00000000000
--- a/app/models/members/project_member.rb
+++ /dev/null
@@ -1,165 +0,0 @@
-# == Schema Information
-#
-# Table name: members
-#
-# id :integer not null, primary key
-# access_level :integer not null
-# source_id :integer not null
-# source_type :string(255) not null
-# user_id :integer not null
-# notification_level :integer not null
-# type :string(255)
-# created_at :datetime
-# updated_at :datetime
-#
-
-class ProjectMember < Member
- SOURCE_TYPE = 'Project'
-
- include Gitlab::ShellAdapter
-
- belongs_to :project, class_name: 'Project', foreign_key: 'source_id'
-
-
- # Make sure project member points only to project as it source
- default_value_for :source_type, SOURCE_TYPE
- default_value_for :notification_level, Notification::N_GLOBAL
- validates_format_of :source_type, with: /\AProject\z/
- default_scope { where(source_type: SOURCE_TYPE) }
-
- scope :in_project, ->(project) { where(source_id: project.id) }
- scope :in_projects, ->(projects) { where(source_id: projects.pluck(:id)) }
- scope :with_user, ->(user) { where(user_id: user.id) }
-
- class << self
-
- # Add users to project teams with passed access option
- #
- # access can be an integer representing a access code
- # or symbol like :master representing role
- #
- # Ex.
- # add_users_into_projects(
- # project_ids,
- # user_ids,
- # ProjectMember::MASTER
- # )
- #
- # add_users_into_projects(
- # project_ids,
- # user_ids,
- # :master
- # )
- #
- def add_users_into_projects(project_ids, user_ids, access, current_user = nil)
- access_level = if roles_hash.has_key?(access)
- roles_hash[access]
- elsif roles_hash.values.include?(access.to_i)
- access
- else
- raise "Non valid access"
- end
-
- users = user_ids.map { |user_id| Member.user_for_id(user_id) }
-
- ProjectMember.transaction do
- project_ids.each do |project_id|
- project = Project.find(project_id)
-
- users.each do |user|
- Member.add_user(project.project_members, user, access_level, current_user)
- end
- end
- end
-
- true
- rescue
- false
- end
-
- def truncate_teams(project_ids)
- ProjectMember.transaction do
- members = ProjectMember.where(source_id: project_ids)
-
- members.each do |member|
- member.destroy
- end
- end
-
- true
- rescue
- false
- end
-
- def truncate_team(project)
- truncate_teams [project.id]
- end
-
- def roles_hash
- Gitlab::Access.sym_options
- end
-
- def access_roles
- Gitlab::Access.options
- end
- end
-
- def access_field
- access_level
- end
-
- def project
- source
- end
-
- def owner?
- project.owner == user
- end
-
- private
-
- def send_invite
- notification_service.invite_project_member(self, @raw_invite_token)
-
- super
- end
-
- def post_create_hook
- unless owner?
- event_service.join_project(self.project, self.user)
- notification_service.new_project_member(self)
- end
-
- super
- end
-
- def post_update_hook
- if access_level_changed?
- notification_service.update_project_member(self)
- end
-
- super
- end
-
- def post_destroy_hook
- event_service.leave_project(self.project, self.user)
-
- super
- end
-
- def after_accept_invite
- notification_service.accept_project_invite(self)
-
- super
- end
-
- def after_decline_invite
- notification_service.decline_project_invite(self)
-
- super
- end
-
- def event_service
- EventCreateService.new
- end
-end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
deleted file mode 100644
index 9c9e2762507..00000000000
--- a/app/models/merge_request.rb
+++ /dev/null
@@ -1,368 +0,0 @@
-# == Schema Information
-#
-# Table name: merge_requests
-#
-# id :integer not null, primary key
-# target_branch :string(255) not null
-# source_branch :string(255) not null
-# source_project_id :integer not null
-# author_id :integer
-# assignee_id :integer
-# title :string(255)
-# created_at :datetime
-# updated_at :datetime
-# milestone_id :integer
-# state :string(255)
-# merge_status :string(255)
-# target_project_id :integer not null
-# iid :integer
-# description :text
-# position :integer default(0)
-# locked_at :datetime
-#
-
-require Rails.root.join("app/models/commit")
-require Rails.root.join("lib/static_model")
-
-class MergeRequest < ActiveRecord::Base
- include Issuable
- include Taskable
- include InternalId
- include Sortable
-
- belongs_to :target_project, foreign_key: :target_project_id, class_name: "Project"
- belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project"
-
- has_one :merge_request_diff, dependent: :destroy
-
- after_create :create_merge_request_diff
- after_update :update_merge_request_diff
-
- delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil
-
- attr_accessor :should_remove_source_branch
-
- # When this attribute is true some MR validation is ignored
- # It allows us to close or modify broken merge requests
- attr_accessor :allow_broken
-
- # Temporary fields to store compare vars
- # when creating new merge request
- attr_accessor :can_be_created, :compare_failed,
- :compare_commits, :compare_diffs
-
- state_machine :state, initial: :opened do
- event :close do
- transition [:reopened, :opened] => :closed
- end
-
- event :merge do
- transition [:reopened, :opened, :locked] => :merged
- end
-
- event :reopen do
- transition closed: :reopened
- end
-
- event :lock_mr do
- transition [:reopened, :opened] => :locked
- end
-
- event :unlock_mr do
- transition locked: :reopened
- end
-
- after_transition any => :locked do |merge_request, transition|
- merge_request.locked_at = Time.now
- merge_request.save
- end
-
- after_transition locked: (any - :locked) do |merge_request, transition|
- merge_request.locked_at = nil
- merge_request.save
- end
-
- state :opened
- state :reopened
- state :closed
- state :merged
- state :locked
- end
-
- state_machine :merge_status, initial: :unchecked do
- event :mark_as_unchecked do
- transition [:can_be_merged, :cannot_be_merged] => :unchecked
- end
-
- event :mark_as_mergeable do
- transition [:unchecked, :cannot_be_merged] => :can_be_merged
- end
-
- event :mark_as_unmergeable do
- transition [:unchecked, :can_be_merged] => :cannot_be_merged
- end
-
- state :unchecked
- state :can_be_merged
- state :cannot_be_merged
-
- around_transition do |merge_request, transition, block|
- merge_request.record_timestamps = false
- begin
- block.call
- ensure
- merge_request.record_timestamps = true
- end
- end
- end
-
- validates :source_project, presence: true, unless: :allow_broken
- validates :source_branch, presence: true
- validates :target_project, presence: true
- validates :target_branch, presence: true
- validate :validate_branches
- validate :validate_fork
-
- scope :of_group, ->(group) { where("source_project_id in (:group_project_ids) OR target_project_id in (:group_project_ids)", group_project_ids: group.project_ids) }
- scope :merged, -> { with_state(:merged) }
- scope :by_branch, ->(branch_name) { where("(source_branch LIKE :branch) OR (target_branch LIKE :branch)", branch: branch_name) }
- scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) }
- scope :by_milestone, ->(milestone) { where(milestone_id: milestone) }
- scope :in_projects, ->(project_ids) { where("source_project_id in (:project_ids) OR target_project_id in (:project_ids)", project_ids: project_ids) }
- scope :of_projects, ->(ids) { where(target_project_id: ids) }
- # Closed scope for merge request should return
- # both merged and closed mr's
- scope :closed, -> { with_states(:closed, :merged) }
- scope :declined, -> { with_states(:closed) }
-
- def validate_branches
- if target_project == source_project && target_branch == source_branch
- errors.add :branch_conflict, "You can not use same project/branch for source and target"
- end
-
- if opened? || reopened?
- similar_mrs = self.target_project.merge_requests.where(source_branch: source_branch, target_branch: target_branch, source_project_id: source_project.id).opened
- similar_mrs = similar_mrs.where('id not in (?)', self.id) if self.id
- if similar_mrs.any?
- errors.add :validate_branches,
- "Cannot Create: This merge request already exists: #{
- similar_mrs.pluck(:title)
- }"
- end
- end
- end
-
- def validate_fork
- return true unless target_project && source_project
-
- if target_project == source_project
- true
- else
- # If source and target projects are different
- # we should check if source project is actually a fork of target project
- if source_project.forked_from?(target_project)
- true
- else
- errors.add :validate_fork,
- 'Source project is not a fork of target project'
- end
- end
- end
-
- def update_merge_request_diff
- if source_branch_changed? || target_branch_changed?
- reload_code
- mark_as_unchecked
- end
- end
-
- def reload_code
- if merge_request_diff && open?
- merge_request_diff.reload_content
- end
- end
-
- def check_if_can_be_merged
- if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged?
- mark_as_mergeable
- else
- mark_as_unmergeable
- end
- end
-
- def merge_event
- self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::MERGED).last
- end
-
- def closed_event
- self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::CLOSED).last
- end
-
- def automerge!(current_user, commit_message = nil)
- MergeRequests::AutoMergeService.
- new(target_project, current_user).
- execute(self, commit_message)
- end
-
- def open?
- opened? || reopened?
- end
-
- def mr_and_commit_notes
- # Fetch comments only from last 100 commits
- commits_for_notes_limit = 100
- commit_ids = commits.last(commits_for_notes_limit).map(&:id)
-
- project.notes.where(
- "(noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR (noteable_type = 'Commit' AND commit_id IN (:commit_ids))",
- mr_id: id,
- commit_ids: commit_ids
- )
- end
-
- # Returns the raw diff for this merge request
- #
- # see "git diff"
- def to_diff(current_user)
- Gitlab::Satellite::MergeAction.new(current_user, self).diff_in_satellite
- end
-
- # Returns the commit as a series of email patches.
- #
- # see "git format-patch"
- def to_patch(current_user)
- Gitlab::Satellite::MergeAction.new(current_user, self).format_patch
- end
-
- def hook_attrs
- attrs = {
- source: source_project.hook_attrs,
- target: target_project.hook_attrs,
- last_commit: nil
- }
-
- unless last_commit.nil?
- attrs.merge!(last_commit: last_commit.hook_attrs(source_project))
- end
-
- attributes.merge!(attrs)
- end
-
- def for_fork?
- target_project != source_project
- end
-
- def project
- target_project
- end
-
- # Return the set of issues that will be closed if this merge request is accepted.
- def closes_issues(current_user = self.author)
- if target_branch == project.default_branch
- issues = commits.flat_map { |c| c.closes_issues(project, current_user) }
- issues.push(*Gitlab::ClosingIssueExtractor.new(project, current_user).
- closed_by_message(description))
- issues.uniq.sort_by(&:id)
- else
- []
- end
- end
-
- # Mentionable override.
- def gfm_reference
- "merge request !#{iid}"
- end
-
- def target_project_path
- if target_project
- target_project.path_with_namespace
- else
- "(removed)"
- end
- end
-
- def source_project_path
- if source_project
- source_project.path_with_namespace
- else
- "(removed)"
- end
- end
-
- def source_project_namespace
- if source_project && source_project.namespace
- source_project.namespace.path
- else
- "(removed)"
- end
- end
-
- def target_project_namespace
- if target_project && target_project.namespace
- target_project.namespace.path
- else
- "(removed)"
- end
- end
-
- def source_branch_exists?
- return false unless self.source_project
-
- self.source_project.repository.branch_names.include?(self.source_branch)
- end
-
- def target_branch_exists?
- return false unless self.target_project
-
- self.target_project.repository.branch_names.include?(self.target_branch)
- end
-
- # Reset merge request events cache
- #
- # Since we do cache @event we need to reset cache in special cases:
- # * when a merge request is updated
- # Events cache stored like events/23-20130109142513.
- # The cache key includes updated_at timestamp.
- # Thus it will automatically generate a new fragment
- # when the event is updated because the key changes.
- def reset_events_cache
- Event.reset_event_cache_for(self)
- end
-
- def merge_commit_message
- message = "Merge branch '#{source_branch}' into '#{target_branch}'"
- message << "\n\n"
- message << title.to_s
- message << "\n\n"
- message << description.to_s
- message << "\n\n"
- message << "See merge request !#{iid}"
- message
- end
-
- # Return array of possible target branches
- # depends on target project of MR
- def target_branches
- if target_project.nil?
- []
- else
- target_project.repository.branch_names
- end
- end
-
- # Return array of possible source branches
- # depends on source project of MR
- def source_branches
- if source_project.nil?
- []
- else
- source_project.repository.branch_names
- end
- end
-
- def locked_long_ago?
- return false unless locked?
-
- locked_at.nil? || locked_at < (Time.now - 1.day)
- end
-end
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
deleted file mode 100644
index acac1ca4cf7..00000000000
--- a/app/models/merge_request_diff.rb
+++ /dev/null
@@ -1,171 +0,0 @@
-# == Schema Information
-#
-# Table name: merge_request_diffs
-#
-# id :integer not null, primary key
-# state :string(255)
-# st_commits :text
-# st_diffs :text
-# merge_request_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-#
-
-require Rails.root.join("app/models/commit")
-
-class MergeRequestDiff < ActiveRecord::Base
- include Sortable
-
- # Prevent store of diff
- # if commits amount more then 200
- COMMITS_SAFE_SIZE = 200
-
- attr_reader :commits, :diffs
-
- belongs_to :merge_request
-
- delegate :target_branch, :source_branch, to: :merge_request, prefix: nil
-
- state_machine :state, initial: :empty do
- state :collected
- state :timeout
- state :overflow_commits_safe_size
- state :overflow_diff_files_limit
- state :overflow_diff_lines_limit
- end
-
- serialize :st_commits
- serialize :st_diffs
-
- after_create :reload_content
-
- def reload_content
- reload_commits
- reload_diffs
- end
-
- def diffs
- @diffs ||= (load_diffs(st_diffs) || [])
- end
-
- def commits
- @commits ||= load_commits(st_commits || [])
- end
-
- def last_commit
- commits.first
- end
-
- def last_commit_short_sha
- @last_commit_short_sha ||= last_commit.short_id
- end
-
- private
-
- def dump_commits(commits)
- commits.map(&:to_hash)
- end
-
- def load_commits(array)
- array.map { |hash| Commit.new(Gitlab::Git::Commit.new(hash)) }
- end
-
- def dump_diffs(diffs)
- if diffs.respond_to?(:map)
- diffs.map(&:to_hash)
- end
- end
-
- def load_diffs(raw)
- if raw.respond_to?(:map)
- raw.map { |hash| Gitlab::Git::Diff.new(hash) }
- end
- end
-
- # Collect array of Git::Commit objects
- # between target and source branches
- def unmerged_commits
- commits = compare_result.commits
-
- if commits.present?
- commits = Commit.decorate(commits).
- sort_by(&:created_at).
- reverse
- end
-
- commits
- end
-
- # Reload all commits related to current merge request from repo
- # and save it as array of hashes in st_commits db field
- def reload_commits
- commit_objects = unmerged_commits
-
- if commit_objects.present?
- self.st_commits = dump_commits(commit_objects)
- end
-
- save
- end
-
- # Reload diffs between branches related to current merge request from repo
- # and save it as array of hashes in st_diffs db field
- def reload_diffs
- new_diffs = []
-
- if commits.size.zero?
- self.state = :empty
- elsif commits.size > COMMITS_SAFE_SIZE
- self.state = :overflow_commits_safe_size
- else
- new_diffs = unmerged_diffs
- end
-
- if new_diffs.any?
- if new_diffs.size > Commit::DIFF_HARD_LIMIT_FILES
- self.state = :overflow_diff_files_limit
- new_diffs = []
- end
-
- if new_diffs.sum { |diff| diff.diff.lines.count } > Commit::DIFF_HARD_LIMIT_LINES
- self.state = :overflow_diff_lines_limit
- new_diffs = []
- end
- end
-
- if new_diffs.present?
- new_diffs = dump_commits(new_diffs)
- self.state = :collected
- end
-
- self.st_diffs = new_diffs
- self.save
- end
-
- # Collect array of Git::Diff objects
- # between target and source branches
- def unmerged_diffs
- diffs = compare_result.diffs
- diffs ||= []
- diffs
- rescue Gitlab::Git::Diff::TimeoutError => ex
- self.state = :timeout
- diffs = []
- end
-
- def repository
- merge_request.target_project.repository
- end
-
- private
-
- def compare_result
- @compare_result ||= CompareService.new.execute(
- merge_request.author,
- merge_request.source_project,
- merge_request.source_branch,
- merge_request.target_project,
- merge_request.target_branch,
- )
- end
-end
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
deleted file mode 100644
index 9bbb2bafb98..00000000000
--- a/app/models/milestone.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-# == Schema Information
-#
-# Table name: milestones
-#
-# id :integer not null, primary key
-# title :string(255) not null
-# project_id :integer not null
-# description :text
-# due_date :date
-# created_at :datetime
-# updated_at :datetime
-# state :string(255)
-# iid :integer
-#
-
-class Milestone < ActiveRecord::Base
- include InternalId
- include Sortable
-
- belongs_to :project
- has_many :issues
- has_many :merge_requests
- has_many :participants, through: :issues, source: :assignee
-
- scope :active, -> { with_state(:active) }
- scope :closed, -> { with_state(:closed) }
- scope :of_projects, ->(ids) { where(project_id: ids) }
-
- validates :title, presence: true
- validates :project, presence: true
-
- state_machine :state, initial: :active do
- event :close do
- transition active: :closed
- end
-
- event :activate do
- transition closed: :active
- end
-
- state :closed
-
- state :active
- end
-
- def expired?
- if due_date
- due_date.past?
- else
- false
- end
- end
-
- def open_items_count
- self.issues.opened.count + self.merge_requests.opened.count
- end
-
- def closed_items_count
- self.issues.closed.count + self.merge_requests.closed.count
- end
-
- def total_items_count
- self.issues.count + self.merge_requests.count
- end
-
- def percent_complete
- ((closed_items_count * 100) / total_items_count).abs
- rescue ZeroDivisionError
- 100
- end
-
- def expires_at
- if due_date
- if due_date.past?
- "expired at #{due_date.stamp("Aug 21, 2011")}"
- else
- "expires at #{due_date.stamp("Aug 21, 2011")}"
- end
- end
- end
-
- def can_be_closed?
- active? && issues.opened.count.zero?
- end
-
- def is_empty?
- total_items_count.zero?
- end
-
- def author_id
- nil
- end
-end
diff --git a/app/models/network/commit.rb b/app/models/network/commit.rb
deleted file mode 100644
index 8417f200e36..00000000000
--- a/app/models/network/commit.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-module Network
- class Commit
- include ActionView::Helpers::TagHelper
-
- attr_accessor :time, :spaces, :parent_spaces
-
- def initialize(raw_commit)
- @commit = raw_commit
- @time = -1
- @spaces = []
- @parent_spaces = []
- end
-
- def method_missing(m, *args, &block)
- @commit.send(m, *args, &block)
- end
-
- def space
- if @spaces.size > 0
- @spaces.first
- else
- 0
- end
- end
-
- def parents(map)
- @commit.parents.map do |p|
- if map.include?(p.id)
- map[p.id]
- end
- end
- .compact
- end
- end
-end
diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb
deleted file mode 100644
index f4e90125373..00000000000
--- a/app/models/network/graph.rb
+++ /dev/null
@@ -1,267 +0,0 @@
-module Network
- class Graph
- attr_reader :days, :commits, :map, :notes, :repo
-
- def self.max_count
- @max_count ||= 650
- end
-
- def initialize(project, ref, commit, filter_ref)
- @project = project
- @ref = ref
- @commit = commit
- @filter_ref = filter_ref
- @repo = project.repository
-
- @commits = collect_commits
- @days = index_commits
- @notes = collect_notes
- end
-
- protected
-
- def collect_notes
- h = Hash.new(0)
- @project.notes.where('noteable_type = ?' ,"Commit").group('notes.commit_id').select('notes.commit_id, count(notes.id) as note_count').each do |item|
- h[item.commit_id] = item.note_count.to_i
- end
- h
- end
-
- # Get commits from repository
- #
- def collect_commits
- find_commits(count_to_display_commit_in_center).map do |commit|
- # Decorate with app/model/network/commit.rb
- Network::Commit.new(commit)
- end
- end
-
- # Method is adding time and space on the
- # list of commits. As well as returns date list
- # correlated with time set on commits.
- #
- # @return [Array<TimeDate>] list of commit dates correlated with time on commits
- def index_commits
- days = []
- @map = {}
- @reserved = {}
-
- @commits.each_with_index do |c,i|
- c.time = i
- days[i] = c.committed_date
- @map[c.id] = c
- @reserved[i] = []
- end
-
- commits_sort_by_ref.each do |commit|
- place_chain(commit)
- end
-
- # find parent spaces for not overlap lines
- @commits.each do |c|
- c.parent_spaces.concat(find_free_parent_spaces(c))
- end
-
- days
- end
-
- # Skip count that the target commit is displayed in center.
- def count_to_display_commit_in_center
- offset = -1
- skip = 0
- while offset == -1
- tmp_commits = find_commits(skip)
- if tmp_commits.size > 0
- index = tmp_commits.index do |c|
- c.id == @commit.id
- end
-
- if index
- # Find the target commit
- offset = index + skip
- else
- skip += self.class.max_count
- end
- else
- # Can't find the target commit in the repo.
- offset = 0
- end
- end
-
- if self.class.max_count / 2 < offset then
- # get max index that commit is displayed in the center.
- offset - self.class.max_count / 2
- else
- 0
- end
- end
-
- def find_commits(skip = 0)
- opts = {
- max_count: self.class.max_count,
- skip: skip
- }
-
- opts[:ref] = @commit.id if @filter_ref
-
- @repo.find_commits(opts)
- end
-
- def commits_sort_by_ref
- @commits.sort do |a,b|
- if include_ref?(a)
- -1
- elsif include_ref?(b)
- 1
- else
- b.committed_date <=> a.committed_date
- end
- end
- end
-
- def include_ref?(commit)
- commit.ref_names(@repo).include?(@ref)
- end
-
- def find_free_parent_spaces(commit)
- spaces = []
-
- commit.parents(@map).each do |parent|
- range = commit.time..parent.time
-
- space = if commit.space >= parent.space then
- find_free_parent_space(range, parent.space, -1, commit.space)
- else
- find_free_parent_space(range, commit.space, -1, parent.space)
- end
-
- mark_reserved(range, space)
- spaces << space
- end
-
- spaces
- end
-
- def find_free_parent_space(range, space_base, space_step, space_default)
- if is_overlap?(range, space_default) then
- find_free_space(range, space_step, space_base, space_default)
- else
- space_default
- end
- end
-
- def is_overlap?(range, overlap_space)
- range.each do |i|
- if i != range.first &&
- i != range.last &&
- @commits[i].spaces.include?(overlap_space) then
-
- return true;
- end
- end
-
- false
- end
-
- # Add space mark on commit and its parents
- #
- # @param [::Commit] the commit object.
- def place_chain(commit, parent_time = nil)
- leaves = take_left_leaves(commit)
- if leaves.empty?
- return
- end
-
- time_range = leaves.first.time..leaves.last.time
- space_base = get_space_base(leaves)
- space = find_free_space(time_range, 2, space_base)
- leaves.each do |l|
- l.spaces << space
- end
-
- # and mark it as reserved
- if parent_time.nil?
- min_time = leaves.first.time
- else
- min_time = parent_time + 1
- end
-
- max_time = leaves.last.time
- leaves.last.parents(@map).each do |parent|
- if max_time < parent.time
- max_time = parent.time
- end
- end
- mark_reserved(min_time..max_time, space)
-
- # Visit branching chains
- leaves.each do |l|
- parents = l.parents(@map).select{|p| p.space.zero?}
- for p in parents
- place_chain(p, l.time)
- end
- end
- end
-
- def get_space_base(leaves)
- space_base = 1
- parents = leaves.last.parents(@map)
- if parents.size > 0
- if parents.first.space > 0
- space_base = parents.first.space
- end
- end
- space_base
- end
-
- def mark_reserved(time_range, space)
- for day in time_range
- @reserved[day].push(space)
- end
- end
-
- def find_free_space(time_range, space_step, space_base = 1, space_default = nil)
- space_default ||= space_base
-
- reserved = []
- for day in time_range
- reserved.push(*@reserved[day])
- end
- reserved.uniq!
-
- space = space_default
- while reserved.include?(space) do
- space += space_step
- if space < space_base then
- space_step *= -1
- space = space_base + space_step
- end
- end
-
- space
- end
-
- # Takes most left subtree branch of commits
- # which don't have space mark yet.
- #
- # @param [::Commit] the commit object.
- #
- # @return [Array<Network::Commit>] list of branch commits
- def take_left_leaves(raw_commit)
- commit = @map[raw_commit.id]
- leaves = []
- leaves.push(commit) if commit.space.zero?
-
- while true
- return leaves if commit.parents(@map).count.zero?
-
- commit = commit.parents(@map).first
-
- return leaves unless commit.space.zero?
-
- leaves.push(commit)
- end
- end
- end
-end
diff --git a/app/models/note.rb b/app/models/note.rb
deleted file mode 100644
index 2cf3fac2def..00000000000
--- a/app/models/note.rb
+++ /dev/null
@@ -1,609 +0,0 @@
-# == Schema Information
-#
-# Table name: notes
-#
-# id :integer not null, primary key
-# note :text
-# noteable_type :string(255)
-# author_id :integer
-# created_at :datetime
-# updated_at :datetime
-# project_id :integer
-# attachment :string(255)
-# line_code :string(255)
-# commit_id :string(255)
-# noteable_id :integer
-# system :boolean default(FALSE), not null
-# st_diff :text
-#
-
-require 'carrierwave/orm/activerecord'
-require 'file_size_validator'
-
-class Note < ActiveRecord::Base
- include Mentionable
- include Gitlab::CurrentSettings
-
- default_value_for :system, false
-
- attr_mentionable :note
-
- belongs_to :project
- belongs_to :noteable, polymorphic: true
- belongs_to :author, class_name: "User"
-
- delegate :name, to: :project, prefix: true
- delegate :name, :email, to: :author, prefix: true
-
- validates :note, :project, presence: true
- validates :line_code, format: { with: /\A[a-z0-9]+_\d+_\d+\Z/ }, allow_blank: true
- # Attachments are deprecated and are handled by Markdown uploader
- validates :attachment, file_size: { maximum: :max_attachment_size }
-
- validates :noteable_id, presence: true, if: ->(n) { n.noteable_type.present? && n.noteable_type != 'Commit' }
- validates :commit_id, presence: true, if: ->(n) { n.noteable_type == 'Commit' }
-
- mount_uploader :attachment, AttachmentUploader
-
- # Scopes
- scope :for_commit_id, ->(commit_id) { where(noteable_type: "Commit", commit_id: commit_id) }
- scope :inline, ->{ where("line_code IS NOT NULL") }
- scope :not_inline, ->{ where(line_code: [nil, '']) }
- scope :system, ->{ where(system: true) }
- scope :user, ->{ where(system: false) }
- scope :common, ->{ where(noteable_type: ["", nil]) }
- scope :fresh, ->{ order(created_at: :asc, id: :asc) }
- scope :inc_author_project, ->{ includes(:project, :author) }
- scope :inc_author, ->{ includes(:author) }
-
- serialize :st_diff
- before_create :set_diff, if: ->(n) { n.line_code.present? }
- after_update :set_references
-
- class << self
- def create_status_change_note(noteable, project, author, status, source)
- body = "Status changed to #{status}#{' by ' + source.gfm_reference if source}"
-
- create(
- noteable: noteable,
- project: project,
- author: author,
- note: body,
- system: true
- )
- end
-
- # +noteable+ was referenced from +mentioner+, by including GFM in either
- # +mentioner+'s description or an associated Note.
- # Create a system Note associated with +noteable+ with a GFM back-reference
- # to +mentioner+.
- def create_cross_reference_note(noteable, mentioner, author, project)
- gfm_reference = mentioner_gfm_ref(noteable, mentioner, project)
-
- note_options = {
- project: project,
- author: author,
- note: cross_reference_note_content(gfm_reference),
- system: true
- }
-
- if noteable.kind_of?(Commit)
- note_options.merge!(noteable_type: 'Commit', commit_id: noteable.id)
- else
- note_options.merge!(noteable: noteable)
- end
-
- create(note_options) unless cross_reference_disallowed?(noteable, mentioner)
- end
-
- def create_milestone_change_note(noteable, project, author, milestone)
- body = if milestone.nil?
- 'Milestone removed'
- else
- "Milestone changed to #{milestone.title}"
- end
-
- create(
- noteable: noteable,
- project: project,
- author: author,
- note: body,
- system: true
- )
- end
-
- def create_assignee_change_note(noteable, project, author, assignee)
- body = assignee.nil? ? 'Assignee removed' : "Reassigned to @#{assignee.username}"
-
- create({
- noteable: noteable,
- project: project,
- author: author,
- note: body,
- system: true
- })
- end
-
- def create_labels_change_note(noteable, project, author, added_labels, removed_labels)
- labels_count = added_labels.count + removed_labels.count
- added_labels = added_labels.map{ |label| "~#{label.id}" }.join(' ')
- removed_labels = removed_labels.map{ |label| "~#{label.id}" }.join(' ')
- message = ''
-
- if added_labels.present?
- message << "added #{added_labels}"
- end
-
- if added_labels.present? && removed_labels.present?
- message << ' and '
- end
-
- if removed_labels.present?
- message << "removed #{removed_labels}"
- end
-
- message << ' ' << 'label'.pluralize(labels_count)
- body = "#{message.capitalize}"
-
- create(
- noteable: noteable,
- project: project,
- author: author,
- note: body,
- system: true
- )
- end
-
- def create_new_commits_note(merge_request, project, author, new_commits, existing_commits = [], oldrev = nil)
- total_count = new_commits.length + existing_commits.length
- commits_text = ActionController::Base.helpers.pluralize(total_count, 'commit')
- body = "Added #{commits_text}:\n\n"
-
- if existing_commits.length > 0
- commit_ids =
- if existing_commits.length == 1
- existing_commits.first.short_id
- else
- if oldrev
- "#{Commit.truncate_sha(oldrev)}...#{existing_commits.last.short_id}"
- else
- "#{existing_commits.first.short_id}..#{existing_commits.last.short_id}"
- end
- end
-
- commits_text = ActionController::Base.helpers.pluralize(existing_commits.length, 'commit')
-
- branch =
- if merge_request.for_fork?
- "#{merge_request.target_project_namespace}:#{merge_request.target_branch}"
- else
- merge_request.target_branch
- end
-
- message = "* #{commit_ids} - #{commits_text} from branch `#{branch}`"
- body << message
- body << "\n"
- end
-
- new_commits.each do |commit|
- message = "* #{commit.short_id} - #{commit.title}"
- body << message
- body << "\n"
- end
-
- create(
- noteable: merge_request,
- project: project,
- author: author,
- note: body,
- system: true
- )
- end
-
- def discussions_from_notes(notes)
- discussion_ids = []
- discussions = []
-
- notes.each do |note|
- next if discussion_ids.include?(note.discussion_id)
-
- # don't group notes for the main target
- if !note.for_diff_line? && note.noteable_type == "MergeRequest"
- discussions << [note]
- else
- discussions << notes.select do |other_note|
- note.discussion_id == other_note.discussion_id
- end
- discussion_ids << note.discussion_id
- end
- end
-
- discussions
- end
-
- def build_discussion_id(type, id, line_code)
- [:discussion, type.try(:underscore), id, line_code].join("-").to_sym
- end
-
- # Determine if cross reference note should be created.
- # eg. mentioning a commit in MR comments which exists inside a MR
- # should not create "mentioned in" note.
- def cross_reference_disallowed?(noteable, mentioner)
- if mentioner.kind_of?(MergeRequest)
- mentioner.commits.map(&:id).include? noteable.id
- end
- end
-
- # Determine whether or not a cross-reference note already exists.
- def cross_reference_exists?(noteable, mentioner)
- gfm_reference = mentioner_gfm_ref(noteable, mentioner)
- notes = if noteable.is_a?(Commit)
- where(commit_id: noteable.id)
- else
- where(noteable_id: noteable.id)
- end
-
- notes.where('note like ?', cross_reference_note_pattern(gfm_reference)).
- system.any?
- end
-
- def search(query)
- where("note like :query", query: "%#{query}%")
- end
-
- def cross_reference_note_prefix
- 'mentioned in '
- end
-
- private
-
- def cross_reference_note_content(gfm_reference)
- cross_reference_note_prefix + "#{gfm_reference}"
- end
-
- def cross_reference_note_pattern(gfm_reference)
- # Older cross reference notes contained underscores for emphasis
- "%" + cross_reference_note_content(gfm_reference) + "%"
- end
-
- # Prepend the mentioner's namespaced project path to the GFM reference for
- # cross-project references. For same-project references, return the
- # unmodified GFM reference.
- def mentioner_gfm_ref(noteable, mentioner, project = nil)
- if mentioner.is_a?(Commit)
- if project.nil?
- return mentioner.gfm_reference.sub('commit ', 'commit %')
- else
- mentioning_project = project
- end
- else
- mentioning_project = mentioner.project
- end
-
- noteable_project_id = noteable_project_id(noteable, mentioning_project)
-
- full_gfm_reference(mentioning_project, noteable_project_id, mentioner)
- end
-
- # Return the ID of the project that +noteable+ belongs to, or nil if
- # +noteable+ is a commit and is not part of the project that owns
- # +mentioner+.
- def noteable_project_id(noteable, mentioning_project)
- if noteable.is_a?(Commit)
- if mentioning_project.repository.commit(noteable.id)
- # The noteable commit belongs to the mentioner's project
- mentioning_project.id
- else
- nil
- end
- else
- noteable.project.id
- end
- end
-
- # Return the +mentioner+ GFM reference. If the mentioner and noteable
- # projects are not the same, add the mentioning project's path to the
- # returned value.
- def full_gfm_reference(mentioning_project, noteable_project_id, mentioner)
- if mentioning_project.id == noteable_project_id
- mentioner.gfm_reference
- else
- if mentioner.is_a?(Commit)
- mentioner.gfm_reference.sub(
- /(commit )/,
- "\\1#{mentioning_project.path_with_namespace}@"
- )
- else
- mentioner.gfm_reference.sub(
- /(issue |merge request )/,
- "\\1#{mentioning_project.path_with_namespace}"
- )
- end
- end
- end
- end
-
- def max_attachment_size
- current_application_settings.max_attachment_size.megabytes.to_i
- end
-
- def commit_author
- @commit_author ||=
- project.team.users.find_by(email: noteable.author_email) ||
- project.team.users.find_by(name: noteable.author_name)
- rescue
- nil
- end
-
- def cross_reference?
- note.start_with?(self.class.cross_reference_note_prefix)
- end
-
- def find_diff
- return nil unless noteable && noteable.diffs.present?
-
- @diff ||= noteable.diffs.find do |d|
- Digest::SHA1.hexdigest(d.new_path) == diff_file_index if d.new_path
- end
- end
-
- def hook_attrs
- attributes
- end
-
- def set_diff
- # First lets find notes with same diff
- # before iterating over all mr diffs
- diff = diff_for_line_code unless for_merge_request?
- diff ||= find_diff
-
- self.st_diff = diff.to_hash if diff
- end
-
- def diff
- @diff ||= Gitlab::Git::Diff.new(st_diff) if st_diff.respond_to?(:map)
- end
-
- def diff_for_line_code
- Note.where(noteable_id: noteable_id, noteable_type: noteable_type, line_code: line_code).last.try(:diff)
- end
-
- # Check if such line of code exists in merge request diff
- # If exists - its active discussion
- # If not - its outdated diff
- def active?
- return true unless self.diff
- return false unless noteable
-
- noteable.diffs.each do |mr_diff|
- next unless mr_diff.new_path == self.diff.new_path
-
- lines = Gitlab::Diff::Parser.new.parse(mr_diff.diff.lines.to_a)
-
- lines.each do |line|
- if line.text == diff_line
- return true
- end
- end
- end
-
- false
- end
-
- def outdated?
- !active?
- end
-
- def diff_file_index
- line_code.split('_')[0] if line_code
- end
-
- def diff_file_name
- diff.new_path if diff
- end
-
- def file_path
- if diff.new_path.present?
- diff.new_path
- elsif diff.old_path.present?
- diff.old_path
- end
- end
-
- def diff_old_line
- line_code.split('_')[1].to_i if line_code
- end
-
- def diff_new_line
- line_code.split('_')[2].to_i if line_code
- end
-
- def generate_line_code(line)
- Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos)
- end
-
- def diff_line
- return @diff_line if @diff_line
-
- if diff
- diff_lines.each do |line|
- if generate_line_code(line) == self.line_code
- @diff_line = line.text
- end
- end
- end
-
- @diff_line
- end
-
- def diff_line_type
- return @diff_line_type if @diff_line_type
-
- if diff
- diff_lines.each do |line|
- if generate_line_code(line) == self.line_code
- @diff_line_type = line.type
- end
- end
- end
-
- @diff_line_type
- end
-
- def truncated_diff_lines
- max_number_of_lines = 16
- prev_match_line = nil
- prev_lines = []
-
- diff_lines.each do |line|
- if line.type == "match"
- prev_lines.clear
- prev_match_line = line
- else
- prev_lines << line
-
- break if generate_line_code(line) == self.line_code
-
- prev_lines.shift if prev_lines.length >= max_number_of_lines
- end
- end
-
- prev_lines
- end
-
- def diff_lines
- @diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.lines.to_a)
- end
-
- def discussion_id
- @discussion_id ||= Note.build_discussion_id(noteable_type, noteable_id || commit_id, line_code)
- end
-
- # Returns true if this is a downvote note,
- # otherwise false is returned
- def downvote?
- votable? && (note.start_with?('-1') ||
- note.start_with?(':-1:') ||
- note.start_with?(':thumbsdown:') ||
- note.start_with?(':thumbs_down_sign:')
- )
- end
-
- def for_commit?
- noteable_type == "Commit"
- end
-
- def for_commit_diff_line?
- for_commit? && for_diff_line?
- end
-
- def for_diff_line?
- line_code.present?
- end
-
- def for_issue?
- noteable_type == "Issue"
- end
-
- def for_merge_request?
- noteable_type == "MergeRequest"
- end
-
- def for_merge_request_diff_line?
- for_merge_request? && for_diff_line?
- end
-
- def for_project_snippet?
- noteable_type == "Snippet"
- end
-
- # override to return commits, which are not active record
- def noteable
- if for_commit?
- project.repository.commit(commit_id)
- else
- super
- end
- # Temp fix to prevent app crash
- # if note commit id doesn't exist
- rescue
- nil
- end
-
- # Returns true if this is an upvote note,
- # otherwise false is returned
- def upvote?
- votable? && (note.start_with?('+1') ||
- note.start_with?(':+1:') ||
- note.start_with?(':thumbsup:') ||
- note.start_with?(':thumbs_up_sign:')
- )
- end
-
- def superceded?(notes)
- return false unless vote?
-
- notes.each do |note|
- next if note == self
-
- if note.vote? &&
- self[:author_id] == note[:author_id] &&
- self[:created_at] <= note[:created_at]
- return true
- end
- end
-
- false
- end
-
- def vote?
- upvote? || downvote?
- end
-
- def votable?
- for_issue? || (for_merge_request? && !for_diff_line?)
- end
-
- # Mentionable override.
- def gfm_reference
- noteable.gfm_reference
- end
-
- # Mentionable override.
- def local_reference
- noteable
- end
-
- def noteable_type_name
- if noteable_type.present?
- noteable_type.downcase
- end
- end
-
- # FIXME: Hack for polymorphic associations with STI
- # For more information visit http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Polymorphic+Associations
- def noteable_type=(sType)
- super(sType.to_s.classify.constantize.base_class.to_s)
- end
-
- # Reset notes events cache
- #
- # Since we do cache @event we need to reset cache in special cases:
- # * when a note is updated
- # * when a note is removed
- # Events cache stored like events/23-20130109142513.
- # The cache key includes updated_at timestamp.
- # Thus it will automatically generate a new fragment
- # when the event is updated because the key changes.
- def reset_events_cache
- Event.reset_event_cache_for(self)
- end
-
- def set_references
- notice_added_references(project, author)
- end
-
- def editable?
- !read_attribute(:system)
- end
-end
diff --git a/app/models/notification.rb b/app/models/notification.rb
deleted file mode 100644
index 1395274173d..00000000000
--- a/app/models/notification.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-class Notification
- #
- # Notification levels
- #
- N_DISABLED = 0
- N_PARTICIPATING = 1
- N_WATCH = 2
- N_GLOBAL = 3
- N_MENTION = 4
-
- attr_accessor :target
-
- class << self
- def notification_levels
- [N_DISABLED, N_PARTICIPATING, N_WATCH, N_MENTION]
- end
-
- def options_with_labels
- {
- disabled: N_DISABLED,
- participating: N_PARTICIPATING,
- watch: N_WATCH,
- mention: N_MENTION,
- global: N_GLOBAL
- }
- end
-
- def project_notification_levels
- [N_DISABLED, N_PARTICIPATING, N_WATCH, N_GLOBAL, N_MENTION]
- end
- end
-
- def initialize(target)
- @target = target
- end
-
- def disabled?
- target.notification_level == N_DISABLED
- end
-
- def participating?
- target.notification_level == N_PARTICIPATING
- end
-
- def watch?
- target.notification_level == N_WATCH
- end
-
- def global?
- target.notification_level == N_GLOBAL
- end
-
- def mention?
- target.notification_level == N_MENTION
- end
-
- def level
- target.notification_level
- end
-end
diff --git a/app/models/personal_snippet.rb b/app/models/personal_snippet.rb
deleted file mode 100644
index 9cee3b70cb3..00000000000
--- a/app/models/personal_snippet.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# == Schema Information
-#
-# Table name: snippets
-#
-# id :integer not null, primary key
-# title :string(255)
-# content :text
-# author_id :integer not null
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# file_name :string(255)
-# expires_at :datetime
-# type :string(255)
-# visibility_level :integer default(0), not null
-#
-
-class PersonalSnippet < Snippet
-end
diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb
deleted file mode 100644
index e6e16058d41..00000000000
--- a/app/models/project_services/asana_service.rb
+++ /dev/null
@@ -1,127 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-# note_events :boolean default(TRUE), not null
-#
-require 'asana'
-
-class AsanaService < Service
- prop_accessor :api_key, :restrict_to_branch
- validates :api_key, presence: true, if: :activated?
-
- def title
- 'Asana'
- end
-
- def description
- 'Asana - Teamwork without email'
- end
-
- def help
- 'This service adds commit messages as comments to Asana tasks.
-Once enabled, commit messages are checked for Asana task URLs
-(for example, `https://app.asana.com/0/123456/987654`) or task IDs
-starting with # (for example, `#987654`). Every task ID found will
-get the commit comment added to it.
-
-You can also close a task with a message containing: `fix #123456`.
-
-You can find your Api Keys here:
-http://developer.asana.com/documentation/#api_keys'
- end
-
- def to_param
- 'asana'
- end
-
- def fields
- [
- {
- type: 'text',
- name: 'api_key',
- placeholder: 'User API token. User must have access to task,
-all comments will be attributed to this user.'
- },
- {
- type: 'text',
- name: 'restrict_to_branch',
- placeholder: 'Comma-separated list of branches which will be
-automatically inspected. Leave blank to include all branches.'
- }
- ]
- end
-
- def supported_events
- %w(push)
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- Asana.configure do |client|
- client.api_key = api_key
- end
-
- user = data[:user_name]
- branch = Gitlab::Git.ref_name(data[:ref])
-
- branch_restriction = restrict_to_branch.to_s
-
- # check the branch restriction is poplulated and branch is not included
- if branch_restriction.length > 0 && branch_restriction.index(branch).nil?
- return
- end
-
- project_name = project.name_with_namespace
- push_msg = user + ' pushed to branch ' + branch + ' of ' + project_name
-
- data[:commits].each do |commit|
- check_commit(' ( ' + commit[:url] + ' ): ' + commit[:message], push_msg)
- end
- end
-
- def check_commit(message, push_msg)
- task_list = []
- close_list = []
-
- message.split("\n").each do |line|
- # look for a task ID or a full Asana url
- task_list.concat(line.scan(/#(\d+)/))
- task_list.concat(line.scan(/https:\/\/app\.asana\.com\/\d+\/\d+\/(\d+)/))
- # look for a word starting with 'fix' followed by a task ID
- close_list.concat(line.scan(/(fix\w*)\W*#(\d+)/i))
- end
-
- # post commit to every taskid found
- task_list.each do |taskid|
- task = Asana::Task.find(taskid[0])
-
- if task
- task.create_story(text: push_msg + ' ' + message)
- end
- end
-
- # close all tasks that had 'fix(ed/es/ing) #:id' in them
- close_list.each do |taskid|
- task = Asana::Task.find(taskid.last)
-
- if task
- task.modify(completed: true)
- end
- end
- end
-end
diff --git a/app/models/project_services/assembla_service.rb b/app/models/project_services/assembla_service.rb
deleted file mode 100644
index fb7e0c0fb0d..00000000000
--- a/app/models/project_services/assembla_service.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-# note_events :boolean default(TRUE), not null
-#
-
-class AssemblaService < Service
- include HTTParty
-
- prop_accessor :token, :subdomain
- validates :token, presence: true, if: :activated?
-
- def title
- 'Assembla'
- end
-
- def description
- 'Project Management Software (Source Commits Endpoint)'
- end
-
- def to_param
- 'assembla'
- end
-
- def fields
- [
- { type: 'text', name: 'token', placeholder: '' },
- { type: 'text', name: 'subdomain', placeholder: '' }
- ]
- end
-
- def supported_events
- %w(push)
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- url = "https://atlas.assembla.com/spaces/#{subdomain}/github_tool?secret_key=#{token}"
- AssemblaService.post(url, body: { payload: data }.to_json, headers: { 'Content-Type' => 'application/json' })
- end
-end
diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb
deleted file mode 100644
index d8aedbd2ab4..00000000000
--- a/app/models/project_services/bamboo_service.rb
+++ /dev/null
@@ -1,137 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-# note_events :boolean default(TRUE), not null
-#
-
-class BambooService < CiService
- include HTTParty
-
- prop_accessor :bamboo_url, :build_key, :username, :password
-
- validates :bamboo_url,
- presence: true,
- format: { with: /\A#{URI.regexp}\z/ },
- if: :activated?
- validates :build_key, presence: true, if: :activated?
- validates :username,
- presence: true,
- if: ->(service) { service.password? },
- if: :activated?
- validates :password,
- presence: true,
- if: ->(service) { service.username? },
- if: :activated?
-
- attr_accessor :response
-
- after_save :compose_service_hook, if: :activated?
-
- def compose_service_hook
- hook = service_hook || build_service_hook
- hook.save
- end
-
- def title
- 'Atlassian Bamboo CI'
- end
-
- def description
- 'A continuous integration and build server'
- end
-
- def help
- 'You must set up automatic revision labeling and a repository trigger in Bamboo.'
- end
-
- def to_param
- 'bamboo'
- end
-
- def fields
- [
- { type: 'text', name: 'bamboo_url',
- placeholder: 'Bamboo root URL like https://bamboo.example.com' },
- { type: 'text', name: 'build_key',
- placeholder: 'Bamboo build plan key like KEY' },
- { type: 'text', name: 'username',
- placeholder: 'A user with API access, if applicable' },
- { type: 'password', name: 'password' },
- ]
- end
-
- def supported_events
- %w(push)
- end
-
- def build_info(sha)
- url = URI.parse("#{bamboo_url}/rest/api/latest/result?label=#{sha}")
-
- if username.blank? && password.blank?
- @response = HTTParty.get(parsed_url.to_s, verify: false)
- else
- get_url = "#{url}&os_authType=basic"
- auth = {
- username: username,
- password: password,
- }
- @response = HTTParty.get(get_url, verify: false, basic_auth: auth)
- end
- end
-
- def build_page(sha, ref)
- build_info(sha) if @response.nil? || !@response.code
-
- if @response.code != 200 || @response['results']['results']['size'] == '0'
- # If actual build link can't be determined, send user to build summary page.
- "#{bamboo_url}/browse/#{build_key}"
- else
- # If actual build link is available, go to build result page.
- result_key = @response['results']['results']['result']['planResultKey']['key']
- "#{bamboo_url}/browse/#{result_key}"
- end
- end
-
- def commit_status(sha, ref)
- build_info(sha) if @response.nil? || !@response.code
- return :error unless @response.code == 200 || @response.code == 404
-
- status = if @response.code == 404 || @response['results']['results']['size'] == '0'
- 'Pending'
- else
- @response['results']['results']['result']['buildState']
- end
-
- if status.include?('Success')
- 'success'
- elsif status.include?('Failed')
- 'failed'
- elsif status.include?('Pending')
- 'pending'
- else
- :error
- end
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- # Bamboo requires a GET and does not take any data.
- self.class.get("#{bamboo_url}/updateAndBuild.action?buildKey=#{build_key}",
- verify: false)
- end
-end
diff --git a/app/models/project_services/buildkite_service.rb b/app/models/project_services/buildkite_service.rb
deleted file mode 100644
index a714bc82246..00000000000
--- a/app/models/project_services/buildkite_service.rb
+++ /dev/null
@@ -1,135 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-# note_events :boolean default(TRUE), not null
-#
-
-require "addressable/uri"
-
-class BuildkiteService < CiService
- ENDPOINT = "https://buildkite.com"
-
- prop_accessor :project_url, :token
-
- validates :project_url, presence: true, if: :activated?
- validates :token, presence: true, if: :activated?
-
- after_save :compose_service_hook, if: :activated?
-
- def webhook_url
- "#{buildkite_endpoint('webhook')}/deliver/#{webhook_token}"
- end
-
- def compose_service_hook
- hook = service_hook || build_service_hook
- hook.url = webhook_url
- hook.save
- end
-
- def supported_events
- %w(push)
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- service_hook.execute(data)
- end
-
- def commit_status(sha, ref)
- response = HTTParty.get(commit_status_path(sha), verify: false)
-
- if response.code == 200 && response['status']
- response['status']
- else
- :error
- end
- end
-
- def commit_status_path(sha)
- "#{buildkite_endpoint('gitlab')}/status/#{status_token}.json?commit=#{sha}"
- end
-
- def build_page(sha, ref)
- "#{project_url}/builds?commit=#{sha}"
- end
-
- def builds_path
- "#{project_url}/builds?branch=#{project.default_branch}"
- end
-
- def status_img_path
- "#{buildkite_endpoint('badge')}/#{status_token}.svg"
- end
-
- def title
- 'Buildkite'
- end
-
- def description
- 'Continuous integration and deployments'
- end
-
- def to_param
- 'buildkite'
- end
-
- def fields
- [
- { type: 'text',
- name: 'token',
- placeholder: 'Buildkite project GitLab token' },
-
- { type: 'text',
- name: 'project_url',
- placeholder: "#{ENDPOINT}/example/project" }
- ]
- end
-
- private
-
- def webhook_token
- token_parts.first
- end
-
- def status_token
- token_parts.second
- end
-
- def token_parts
- if token.present?
- token.split(':')
- else
- []
- end
- end
-
- def buildkite_endpoint(subdomain = nil)
- if subdomain.present?
- uri = Addressable::URI.parse(ENDPOINT)
- new_endpoint = "#{uri.scheme || 'http'}://#{subdomain}.#{uri.host}"
-
- if uri.port.present?
- "#{new_endpoint}:#{uri.port}"
- else
- new_endpoint
- end
- else
- ENDPOINT
- end
- end
-end
diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb
deleted file mode 100644
index e591afdda64..00000000000
--- a/app/models/project_services/campfire_service.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-# note_events :boolean default(TRUE), not null
-#
-
-class CampfireService < Service
- prop_accessor :token, :subdomain, :room
- validates :token, presence: true, if: :activated?
-
- def title
- 'Campfire'
- end
-
- def description
- 'Simple web-based real-time group chat'
- end
-
- def to_param
- 'campfire'
- end
-
- def fields
- [
- { type: 'text', name: 'token', placeholder: '' },
- { type: 'text', name: 'subdomain', placeholder: '' },
- { type: 'text', name: 'room', placeholder: '' }
- ]
- end
-
- def supported_events
- %w(push)
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- room = gate.find_room_by_name(self.room)
- return true unless room
-
- message = build_message(data)
-
- room.speak(message)
- end
-
- private
-
- def gate
- @gate ||= Tinder::Campfire.new(subdomain, token: token)
- end
-
- def build_message(push)
- ref = Gitlab::Git.ref_name(push[:ref])
- before = push[:before]
- after = push[:after]
-
- message = ""
- message << "[#{project.name_with_namespace}] "
- message << "#{push[:user_name]} "
-
- if Gitlab::Git.blank_ref?(before)
- message << "pushed new branch #{ref} \n"
- elsif Gitlab::Git.blank_ref?(after)
- message << "removed branch #{ref} \n"
- else
- message << "pushed #{push[:total_commits_count]} commits to #{ref}. "
- message << "#{project.web_url}/compare/#{before}...#{after}"
- end
-
- message
- end
-end
diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb
deleted file mode 100644
index 1a36e439245..00000000000
--- a/app/models/project_services/ci_service.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-#
-
-# Base class for CI services
-# List methods you need to implement to get your CI service
-# working with GitLab Merge Requests
-class CiService < Service
- def category
- :ci
- end
-
- def supported_events
- %w(push)
- end
-
- # Return complete url to build page
- #
- # Ex.
- # http://jenkins.example.com:8888/job/test1/scm/bySHA1/12d65c
- #
- def build_page(sha, ref)
- # implement inside child
- end
-
- # Return string with build status or :error symbol
- #
- # Allowed states: 'success', 'failed', 'running', 'pending'
- #
- #
- # Ex.
- # @service.commit_status('13be4ac')
- # # => 'success'
- #
- # @service.commit_status('2abe4ac')
- # # => 'running'
- #
- #
- def commit_status(sha, ref)
- # implement inside child
- end
-end
diff --git a/app/models/project_services/custom_issue_tracker_service.rb b/app/models/project_services/custom_issue_tracker_service.rb
deleted file mode 100644
index 8d25f627870..00000000000
--- a/app/models/project_services/custom_issue_tracker_service.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-#
-
-class CustomIssueTrackerService < IssueTrackerService
-
- prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
-
- def title
- if self.properties && self.properties['title'].present?
- self.properties['title']
- else
- 'Custom Issue Tracker'
- end
- end
-
- def description
- if self.properties && self.properties['description'].present?
- self.properties['description']
- else
- 'Custom issue tracker'
- end
- end
-
- def to_param
- 'custom_issue_tracker'
- end
-
- def fields
- [
- { type: 'text', name: 'title', placeholder: title },
- { type: 'text', name: 'description', placeholder: description },
- { type: 'text', name: 'project_url', placeholder: 'Project url' },
- { type: 'text', name: 'issues_url', placeholder: 'Issue url' },
- { type: 'text', name: 'new_issue_url', placeholder: 'New Issue url' }
- ]
- end
-
- def initialize_properties
- self.properties = {} if properties.nil?
- end
-end
diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb
deleted file mode 100644
index 6f6e5950aab..00000000000
--- a/app/models/project_services/emails_on_push_service.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-#
-
-class EmailsOnPushService < Service
- prop_accessor :send_from_committer_email
- prop_accessor :disable_diffs
- prop_accessor :recipients
- validates :recipients, presence: true, if: :activated?
-
- def title
- 'Emails on push'
- end
-
- def description
- 'Email the commits and diff of each push to a list of recipients.'
- end
-
- def to_param
- 'emails_on_push'
- end
-
- def supported_events
- %w(push tag_push)
- end
-
- def execute(push_data)
- return unless supported_events.include?(push_data[:object_kind])
-
- EmailsOnPushWorker.perform_async(
- project_id,
- recipients,
- push_data,
- send_from_committer_email: send_from_committer_email?,
- disable_diffs: disable_diffs?
- )
- end
-
- def send_from_committer_email?
- self.send_from_committer_email == "1"
- end
-
- def disable_diffs?
- self.disable_diffs == "1"
- end
-
- def fields
- domains = Notify.allowed_email_domains.map { |domain| "user@#{domain}" }.join(", ")
- [
- { type: 'checkbox', name: 'send_from_committer_email', title: "Send from committer",
- help: "Send notifications from the committer's email address if the domain is part of the domain GitLab is running on (e.g. #{domains})." },
- { type: 'checkbox', name: 'disable_diffs', title: "Disable code diffs",
- help: "Don't include possibly sensitive code diffs in notification body." },
- { type: 'textarea', name: 'recipients', placeholder: 'Emails separated by whitespace' },
- ]
- end
-end
diff --git a/app/models/project_services/external_wiki_service.rb b/app/models/project_services/external_wiki_service.rb
deleted file mode 100644
index a199d0e86f2..00000000000
--- a/app/models/project_services/external_wiki_service.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-#
-
-class ExternalWikiService < Service
- include HTTParty
-
- prop_accessor :external_wiki_url
- validates :external_wiki_url,
- presence: true,
- format: { with: /\A#{URI.regexp}\z/ },
- if: :activated?
-
- def title
- 'External Wiki'
- end
-
- def description
- 'Replaces the link to the internal wiki with a link to an external wiki.'
- end
-
- def to_param
- 'external_wiki'
- end
-
- def fields
- [
- { type: 'text', name: 'external_wiki_url', placeholder: 'The URL of the external Wiki' },
- ]
- end
-
- def execute(_data)
- @response = HTTParty.get(properties['external_wiki_url'], verify: true) rescue nil
- if @response !=200
- nil
- end
- end
-end
diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb
deleted file mode 100644
index 99e361dd6ed..00000000000
--- a/app/models/project_services/flowdock_service.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-#
-
-require "flowdock-git-hook"
-
-class FlowdockService < Service
- prop_accessor :token
- validates :token, presence: true, if: :activated?
-
- def title
- 'Flowdock'
- end
-
- def description
- 'Flowdock is a collaboration web app for technical teams.'
- end
-
- def to_param
- 'flowdock'
- end
-
- def fields
- [
- { type: 'text', name: 'token', placeholder: '' }
- ]
- end
-
- def supported_events
- %w(push)
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- Flowdock::Git.post(
- data[:ref],
- data[:before],
- data[:after],
- token: token,
- repo: project.repository.path_to_repo,
- repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}",
- commit_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/%s",
- diff_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/compare/%s...%s",
- )
- end
-end
diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb
deleted file mode 100644
index 4e75bdfc953..00000000000
--- a/app/models/project_services/gemnasium_service.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-#
-
-require "gemnasium/gitlab_service"
-
-class GemnasiumService < Service
- prop_accessor :token, :api_key
- validates :token, :api_key, presence: true, if: :activated?
-
- def title
- 'Gemnasium'
- end
-
- def description
- 'Gemnasium monitors your project dependencies and alerts you about updates and security vulnerabilities.'
- end
-
- def to_param
- 'gemnasium'
- end
-
- def fields
- [
- { type: 'text', name: 'api_key', placeholder: 'Your personal API KEY on gemnasium.com ' },
- { type: 'text', name: 'token', placeholder: 'The project\'s slug on gemnasium.com' }
- ]
- end
-
- def supported_events
- %w(push)
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- Gemnasium::GitlabService.execute(
- ref: data[:ref],
- before: data[:before],
- after: data[:after],
- token: token,
- api_key: api_key,
- repo: project.repository.path_to_repo
- )
- end
-end
diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb
deleted file mode 100644
index 0f9838a575d..00000000000
--- a/app/models/project_services/gitlab_ci_service.rb
+++ /dev/null
@@ -1,128 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-#
-
-class GitlabCiService < CiService
- API_PREFIX = "api/v1"
-
- prop_accessor :project_url, :token
- validates :project_url, presence: true, if: :activated?
- validates :token, presence: true, if: :activated?
-
- after_save :compose_service_hook, if: :activated?
-
- def compose_service_hook
- hook = service_hook || build_service_hook
- hook.url = [project_url, "/build", "?token=#{token}"].join("")
- hook.save
- end
-
- def supported_events
- %w(push tag_push)
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- service_hook.execute(data)
- end
-
- def commit_status_path(sha, ref)
- project_url + "/refs/#{ref}/commits/#{sha}/status.json?token=#{token}"
- end
-
- def get_ci_build(sha, ref)
- @ci_builds ||= {}
- @ci_builds[sha] ||= HTTParty.get(commit_status_path(sha, ref), verify: false)
- end
-
- def commit_status(sha, ref)
- response = get_ci_build(sha, ref)
-
- if response.code == 200 and response["status"]
- response["status"]
- else
- :error
- end
- end
-
- def fork_registration(new_project, private_token)
- params = {
- id: new_project.id,
- name_with_namespace: new_project.name_with_namespace,
- web_url: new_project.web_url,
- default_branch: new_project.default_branch,
- ssh_url_to_repo: new_project.ssh_url_to_repo
- }
-
- HTTParty.post(
- fork_registration_path,
- body: {
- project_id: project.id,
- project_token: token,
- private_token: private_token,
- data: params },
- verify: false
- )
- end
-
- def commit_coverage(sha, ref)
- response = get_ci_build(sha, ref)
-
- if response.code == 200 and response["coverage"]
- response["coverage"]
- end
- end
-
- def build_page(sha, ref)
- project_url + "/refs/#{ref}/commits/#{sha}"
- end
-
- def builds_path
- project_url + "?ref=" + project.default_branch
- end
-
- def status_img_path
- project_url + "/status.png?ref=" + project.default_branch
- end
-
- def title
- 'GitLab CI'
- end
-
- def description
- 'Continuous integration server from GitLab'
- end
-
- def to_param
- 'gitlab_ci'
- end
-
- def fields
- [
- { type: 'text', name: 'token', placeholder: 'GitLab CI project specific token' },
- { type: 'text', name: 'project_url', placeholder: 'http://ci.gitlabhq.com/projects/3' }
- ]
- end
-
- private
-
- def fork_registration_path
- project_url.sub(/projects\/\d*/, "#{API_PREFIX}/forks")
- end
-end
diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb
deleted file mode 100644
index 5f0553f3b0b..00000000000
--- a/app/models/project_services/gitlab_issue_tracker_service.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-# note_events :boolean default(TRUE), not null
-#
-
-class GitlabIssueTrackerService < IssueTrackerService
- include Rails.application.routes.url_helpers
-
- default_url_options[:host] = Gitlab.config.gitlab.host
- default_url_options[:protocol] = Gitlab.config.gitlab.protocol
- default_url_options[:port] = Gitlab.config.gitlab.port unless Gitlab.config.gitlab_on_standard_port?
- default_url_options[:script_name] = Gitlab.config.gitlab.relative_url_root
-
- prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
-
- def default?
- true
- end
-
- def to_param
- 'gitlab'
- end
-
- def project_url
- namespace_project_issues_url(project.namespace, project)
- end
-
- def new_issue_url
- new_namespace_project_issue_url(namespace_id: project.namespace, project_id: project)
- end
-
- def issue_url(iid)
- namespace_project_issue_url(namespace_id: project.namespace, project_id: project, id: iid)
- end
-
- def project_path
- namespace_project_issues_path(project.namespace, project)
- end
-
- def new_issue_path
- new_namespace_project_issue_path(namespace_id: project.namespace, project_id: project)
- end
-
- def issue_path(iid)
- namespace_project_issue_path(namespace_id: project.namespace, project_id: project, id: iid)
- end
-end
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
deleted file mode 100644
index d264a56ebdf..00000000000
--- a/app/models/project_services/hipchat_service.rb
+++ /dev/null
@@ -1,238 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-#
-
-class HipchatService < Service
- MAX_COMMITS = 3
-
- prop_accessor :token, :room, :server
- validates :token, presence: true, if: :activated?
-
- def title
- 'HipChat'
- end
-
- def description
- 'Private group chat and IM'
- end
-
- def to_param
- 'hipchat'
- end
-
- def fields
- [
- { type: 'text', name: 'token', placeholder: 'Room token' },
- { type: 'text', name: 'room', placeholder: 'Room name or ID' },
- { type: 'text', name: 'server',
- placeholder: 'Leave blank for default. https://hipchat.example.com' }
- ]
- end
-
- def supported_events
- %w(push issue merge_request note tag_push)
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- gate[room].send('GitLab', create_message(data))
- end
-
- private
-
- def gate
- options = { api_version: 'v2' }
- options[:server_url] = server unless server.blank?
- @gate ||= HipChat::Client.new(token, options)
- end
-
- def create_message(data)
- object_kind = data[:object_kind]
-
- message = \
- case object_kind
- when "push", "tag_push"
- create_push_message(data)
- when "issue"
- create_issue_message(data) unless is_update?(data)
- when "merge_request"
- create_merge_request_message(data) unless is_update?(data)
- when "note"
- create_note_message(data)
- end
- end
-
- def create_push_message(push)
- ref_type = Gitlab::Git.tag_ref?(push[:ref]) ? 'tag' : 'branch'
- ref = Gitlab::Git.ref_name(push[:ref])
-
- before = push[:before]
- after = push[:after]
-
- message = ""
- message << "#{push[:user_name]} "
- if Gitlab::Git.blank_ref?(before)
- message << "pushed new #{ref_type} <a href=\""\
- "#{project_url}/commits/#{URI.escape(ref)}\">#{ref}</a>"\
- " to #{project_link}\n"
- elsif Gitlab::Git.blank_ref?(after)
- message << "removed #{ref_type} <b>#{ref}</b> from <a href=\"#{project.web_url}\">#{project_name}</a> \n"
- else
- message << "pushed to #{ref_type} <a href=\""\
- "#{project.web_url}/commits/#{URI.escape(ref)}\">#{ref}</a> "
- message << "of <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/,'')}</a> "
- message << "(<a href=\"#{project.web_url}/compare/#{before}...#{after}\">Compare changes</a>)"
-
- push[:commits].take(MAX_COMMITS).each do |commit|
- message << "<br /> - #{commit[:message].lines.first} (<a href=\"#{commit[:url]}\">#{commit[:id][0..5]}</a>)"
- end
-
- if push[:commits].count > MAX_COMMITS
- message << "<br />... #{push[:commits].count - MAX_COMMITS} more commits"
- end
- end
-
- message
- end
-
- def format_body(body)
- if body
- body = body.truncate(200, separator: ' ', omission: '...')
- end
-
- "<pre>#{body}</pre>"
- end
-
- def create_issue_message(data)
- user_name = data[:user][:name]
-
- obj_attr = data[:object_attributes]
- obj_attr = HashWithIndifferentAccess.new(obj_attr)
- title = obj_attr[:title]
- state = obj_attr[:state]
- issue_iid = obj_attr[:iid]
- issue_url = obj_attr[:url]
- description = obj_attr[:description]
-
- issue_link = "<a href=\"#{issue_url}\">issue ##{issue_iid}</a>"
- message = "#{user_name} #{state} #{issue_link} in #{project_link}: <b>#{title}</b>"
-
- if description
- description = format_body(description)
- message << description
- end
-
- message
- end
-
- def create_merge_request_message(data)
- user_name = data[:user][:name]
-
- obj_attr = data[:object_attributes]
- obj_attr = HashWithIndifferentAccess.new(obj_attr)
- merge_request_id = obj_attr[:iid]
- source_branch = obj_attr[:source_branch]
- target_branch = obj_attr[:target_branch]
- state = obj_attr[:state]
- description = obj_attr[:description]
- title = obj_attr[:title]
-
- merge_request_url = "#{project_url}/merge_requests/#{merge_request_id}"
- merge_request_link = "<a href=\"#{merge_request_url}\">merge request ##{merge_request_id}</a>"
- message = "#{user_name} #{state} #{merge_request_link} in " \
- "#{project_link}: <b>#{title}</b>"
-
- if description
- description = format_body(description)
- message << description
- end
-
- message
- end
-
- def format_title(title)
- "<b>" + title.lines.first.chomp + "</b>"
- end
-
- def create_note_message(data)
- data = HashWithIndifferentAccess.new(data)
- user_name = data[:user][:name]
-
- repo_attr = HashWithIndifferentAccess.new(data[:repository])
-
- obj_attr = HashWithIndifferentAccess.new(data[:object_attributes])
- note = obj_attr[:note]
- note_url = obj_attr[:url]
- noteable_type = obj_attr[:noteable_type]
-
- case noteable_type
- when "Commit"
- commit_attr = HashWithIndifferentAccess.new(data[:commit])
- subject_desc = commit_attr[:id]
- subject_desc = Commit.truncate_sha(subject_desc)
- subject_type = "commit"
- title = format_title(commit_attr[:message])
- when "Issue"
- subj_attr = HashWithIndifferentAccess.new(data[:issue])
- subject_id = subj_attr[:iid]
- subject_desc = "##{subject_id}"
- subject_type = "issue"
- title = format_title(subj_attr[:title])
- when "MergeRequest"
- subj_attr = HashWithIndifferentAccess.new(data[:merge_request])
- subject_id = subj_attr[:iid]
- subject_desc = "##{subject_id}"
- subject_type = "merge request"
- title = format_title(subj_attr[:title])
- when "Snippet"
- subj_attr = HashWithIndifferentAccess.new(data[:snippet])
- subject_id = subj_attr[:id]
- subject_desc = "##{subject_id}"
- subject_type = "snippet"
- title = format_title(subj_attr[:title])
- end
-
- subject_html = "<a href=\"#{note_url}\">#{subject_type} #{subject_desc}</a>"
- message = "#{user_name} commented on #{subject_html} in #{project_link}: "
- message << title
-
- if note
- note = format_body(note)
- message << note
- end
-
- message
- end
-
- def project_name
- project.name_with_namespace.gsub(/\s/, '')
- end
-
- def project_url
- project.web_url
- end
-
- def project_link
- "<a href=\"#{project_url}\">#{project_name}</a>"
- end
-
- def is_update?(data)
- data[:object_attributes][:action] == 'update'
- end
-end
diff --git a/app/models/project_services/irker_service.rb b/app/models/project_services/irker_service.rb
deleted file mode 100644
index e9e1e276e7d..00000000000
--- a/app/models/project_services/irker_service.rb
+++ /dev/null
@@ -1,163 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-#
-
-require 'uri'
-
-class IrkerService < Service
- prop_accessor :colorize_messages, :recipients, :channels
- validates :recipients, presence: true, if: :activated?
- validate :check_recipients_count, if: :activated?
-
- before_validation :get_channels
- after_initialize :initialize_settings
-
- # Writer for RSpec tests
- attr_writer :settings
-
- def initialize_settings
- # See the documentation (doc/project_services/irker.md) for possible values
- # here
- @settings ||= {
- server_ip: 'localhost',
- server_port: 6659,
- max_channels: 3,
- default_irc_uri: nil
- }
- end
-
- def title
- 'Irker (IRC gateway)'
- end
-
- def description
- 'Send IRC messages, on update, to a list of recipients through an Irker '\
- 'gateway.'
- end
-
- def help
- msg = 'Recipients have to be specified with a full URI: '\
- 'irc[s]://irc.network.net[:port]/#channel. Special cases: if you want '\
- 'the channel to be a nickname instead, append ",isnick" to the channel '\
- 'name; if the channel is protected by a secret password, append '\
- '"?key=secretpassword" to the URI.'
-
- unless @settings[:default_irc].nil?
- msg += ' Note that a default IRC URI is provided by this service\'s '\
- "administrator: #{default_irc}. You can thus just give a channel name."
- end
- msg
- end
-
- def to_param
- 'irker'
- end
-
- def supported_events
- %w(push)
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- IrkerWorker.perform_async(project_id, channels,
- colorize_messages, data, @settings)
- end
-
- def fields
- [
- { type: 'textarea', name: 'recipients',
- placeholder: 'Recipients/channels separated by whitespaces' },
- { type: 'checkbox', name: 'colorize_messages' },
- ]
- end
-
- private
-
- def check_recipients_count
- return true if recipients.nil? || recipients.empty?
-
- if recipients.split(/\s+/).count > max_chans
- errors.add(:recipients, "are limited to #{max_chans}")
- end
- end
-
- def max_chans
- @settings[:max_channels]
- end
-
- def get_channels
- return true unless :activated?
- return true if recipients.nil? || recipients.empty?
-
- map_recipients
-
- errors.add(:recipients, 'are all invalid') if channels.empty?
- true
- end
-
- def map_recipients
- self.channels = recipients.split(/\s+/).map do |recipient|
- format_channel default_irc_uri, recipient
- end
- channels.reject! &:nil?
- end
-
- def default_irc_uri
- default_irc = @settings[:default_irc_uri]
- if !(default_irc.nil? || default_irc[-1] == '/')
- default_irc += '/'
- end
- default_irc
- end
-
- def format_channel(default_irc, recipient)
- cnt = 0
- url = nil
-
- # Try to parse the chan as a full URI
- begin
- uri = URI.parse(recipient)
- raise URI::InvalidURIError if uri.scheme.nil? && cnt == 0
- rescue URI::InvalidURIError
- unless default_irc.nil?
- cnt += 1
- recipient = "#{default_irc}#{recipient}"
- retry if cnt == 1
- end
- else
- url = consider_uri uri
- end
- url
- end
-
- def consider_uri(uri)
- # Authorize both irc://domain.com/#chan and irc://domain.com/chan
- if uri.is_a?(URI) && uri.scheme[/^ircs?\z/] && !uri.path.nil?
- # Do not authorize irc://domain.com/
- if uri.fragment.nil? && uri.path.length > 1
- uri.to_s
- else
- # Authorize irc://domain.com/smthg#chan
- # The irker daemon will deal with it by concatenating smthg and
- # chan, thus sending messages on #smthgchan
- uri.to_s
- end
- end
- end
-end
diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
deleted file mode 100644
index c8ab9d63b74..00000000000
--- a/app/models/project_services/issue_tracker_service.rb
+++ /dev/null
@@ -1,125 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-# note_events :boolean default(TRUE), not null
-#
-
-class IssueTrackerService < Service
-
- validates :project_url, :issues_url, :new_issue_url, presence: true, if: :activated?
-
- def category
- :issue_tracker
- end
-
- def default?
- false
- end
-
- def issue_url(iid)
- self.issues_url.gsub(':id', iid.to_s)
- end
-
- def project_path
- project_url
- end
-
- def new_issue_path
- new_issue_url
- end
-
- def issue_path(iid)
- issue_url(iid)
- end
-
- def fields
- [
- { type: 'text', name: 'description', placeholder: description },
- { type: 'text', name: 'project_url', placeholder: 'Project url' },
- { type: 'text', name: 'issues_url', placeholder: 'Issue url' },
- { type: 'text', name: 'new_issue_url', placeholder: 'New Issue url' }
- ]
- end
-
- def initialize_properties
- if properties.nil?
- if enabled_in_gitlab_config
- self.properties = {
- title: issues_tracker['title'],
- project_url: add_issues_tracker_id(issues_tracker['project_url']),
- issues_url: add_issues_tracker_id(issues_tracker['issues_url']),
- new_issue_url: add_issues_tracker_id(issues_tracker['new_issue_url'])
- }
- else
- self.properties = {}
- end
- end
- end
-
- def supported_events
- %w(push)
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- message = "#{self.type} was unable to reach #{self.project_url}. Check the url and try again."
- result = false
-
- begin
- url = URI.parse(self.project_url)
-
- if url.host && url.port
- http = Net::HTTP.start(url.host, url.port, { open_timeout: 5, read_timeout: 5 })
- response = http.head("/")
-
- if response
- message = "#{self.type} received response #{response.code} when attempting to connect to #{self.project_url}"
- result = true
- end
- end
- rescue Timeout::Error, SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED => error
- message = "#{self.type} had an error when trying to connect to #{self.project_url}: #{error.message}"
- end
- Rails.logger.info(message)
- result
- end
-
- private
-
- def enabled_in_gitlab_config
- Gitlab.config.issues_tracker &&
- Gitlab.config.issues_tracker.values.any? &&
- issues_tracker
- end
-
- def issues_tracker
- Gitlab.config.issues_tracker[to_param]
- end
-
- def add_issues_tracker_id(url)
- if self.project
- id = self.project.issues_tracker_id
-
- if id
- url = url.gsub(":issues_tracker_id", id)
- end
- end
-
- url
- end
-end
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
deleted file mode 100644
index fcd9dc2f336..00000000000
--- a/app/models/project_services/jira_service.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-# note_events :boolean default(TRUE), not null
-#
-
-class JiraService < IssueTrackerService
- include Rails.application.routes.url_helpers
-
- prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
-
- def help
- issue_tracker_link = help_page_path("integration", "external-issue-tracker")
-
- line1 = "Setting `project_url`, `issues_url` and `new_issue_url` will "\
- "allow a user to easily navigate to the Jira issue tracker. "\
- "See the [integration doc](#{issue_tracker_link}) for details."
-
- line2 = 'Support for referencing commits and automatic closing of Jira issues directly ' \
- 'from GitLab is [available in GitLab EE.](http://doc.gitlab.com/ee/integration/jira.html)'
-
- [line1, line2].join("\n\n")
- end
-
- def title
- if self.properties && self.properties['title'].present?
- self.properties['title']
- else
- 'JIRA'
- end
- end
-
- def description
- if self.properties && self.properties['description'].present?
- self.properties['description']
- else
- 'Jira issue tracker'
- end
- end
-
- def to_param
- 'jira'
- end
-end
diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb
deleted file mode 100644
index ade9ee97873..00000000000
--- a/app/models/project_services/pivotaltracker_service.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-# note_events :boolean default(TRUE), not null
-#
-
-class PivotaltrackerService < Service
- include HTTParty
-
- prop_accessor :token
- validates :token, presence: true, if: :activated?
-
- def title
- 'PivotalTracker'
- end
-
- def description
- 'Project Management Software (Source Commits Endpoint)'
- end
-
- def to_param
- 'pivotaltracker'
- end
-
- def fields
- [
- { type: 'text', name: 'token', placeholder: '' }
- ]
- end
-
- def supported_events
- %w(push)
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- url = 'https://www.pivotaltracker.com/services/v5/source_commits'
- data[:commits].each do |commit|
- message = {
- 'source_commit' => {
- 'commit_id' => commit[:id],
- 'author' => commit[:author][:name],
- 'url' => commit[:url],
- 'message' => commit[:message]
- }
- }
- PivotaltrackerService.post(
- url,
- body: message.to_json,
- headers: {
- 'Content-Type' => 'application/json',
- 'X-TrackerToken' => token
- }
- )
- end
- end
-end
diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb
deleted file mode 100644
index 53edf522e9a..00000000000
--- a/app/models/project_services/pushover_service.rb
+++ /dev/null
@@ -1,125 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-# note_events :boolean default(TRUE), not null
-#
-
-class PushoverService < Service
- include HTTParty
- base_uri 'https://api.pushover.net/1'
-
- prop_accessor :api_key, :user_key, :device, :priority, :sound
- validates :api_key, :user_key, :priority, presence: true, if: :activated?
-
- def title
- 'Pushover'
- end
-
- def description
- 'Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop.'
- end
-
- def to_param
- 'pushover'
- end
-
- def fields
- [
- { type: 'text', name: 'api_key', placeholder: 'Your application key' },
- { type: 'text', name: 'user_key', placeholder: 'Your user key' },
- { type: 'text', name: 'device', placeholder: 'Leave blank for all active devices' },
- { type: 'select', name: 'priority', choices:
- [
- ['Lowest Priority', -2],
- ['Low Priority', -1],
- ['Normal Priority', 0],
- ['High Priority', 1]
- ],
- default_choice: 0
- },
- { type: 'select', name: 'sound', choices:
- [
- ['Device default sound', nil],
- ['Pushover (default)', 'pushover'],
- ['Bike', 'bike'],
- ['Bugle', 'bugle'],
- ['Cash Register', 'cashregister'],
- ['Classical', 'classical'],
- ['Cosmic', 'cosmic'],
- ['Falling', 'falling'],
- ['Gamelan', 'gamelan'],
- ['Incoming', 'incoming'],
- ['Intermission', 'intermission'],
- ['Magic', 'magic'],
- ['Mechanical', 'mechanical'],
- ['Piano Bar', 'pianobar'],
- ['Siren', 'siren'],
- ['Space Alarm', 'spacealarm'],
- ['Tug Boat', 'tugboat'],
- ['Alien Alarm (long)', 'alien'],
- ['Climb (long)', 'climb'],
- ['Persistent (long)', 'persistent'],
- ['Pushover Echo (long)', 'echo'],
- ['Up Down (long)', 'updown'],
- ['None (silent)', 'none']
- ]
- },
- ]
- end
-
- def supported_events
- %w(push)
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- ref = Gitlab::Git.ref_name(data[:ref])
- before = data[:before]
- after = data[:after]
-
- if Gitlab::Git.blank_ref?(before)
- message = "#{data[:user_name]} pushed new branch \"#{ref}\"."
- elsif Gitlab::Git.blank_ref?(after)
- message = "#{data[:user_name]} deleted branch \"#{ref}\"."
- else
- message = "#{data[:user_name]} push to branch \"#{ref}\"."
- end
-
- if data[:total_commits_count] > 0
- message << "\nTotal commits count: #{data[:total_commits_count]}"
- end
-
- pushover_data = {
- token: api_key,
- user: user_key,
- device: device,
- priority: priority,
- title: "#{project.name_with_namespace}",
- message: message,
- url: data[:repository][:homepage],
- url_title: "See project #{project.name_with_namespace}"
- }
-
- # Sound parameter MUST NOT be sent to API if not selected
- if sound
- pushover_data.merge!(sound: sound)
- end
-
- PushoverService.post('/messages.json', body: pushover_data)
- end
-end
diff --git a/app/models/project_services/redmine_service.rb b/app/models/project_services/redmine_service.rb
deleted file mode 100644
index dd9ba97ee1f..00000000000
--- a/app/models/project_services/redmine_service.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-# note_events :boolean default(TRUE), not null
-#
-
-class RedmineService < IssueTrackerService
-
- prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
-
- def title
- if self.properties && self.properties['title'].present?
- self.properties['title']
- else
- 'Redmine'
- end
- end
-
- def description
- if self.properties && self.properties['description'].present?
- self.properties['description']
- else
- 'Redmine issue tracker'
- end
- end
-
- def to_param
- 'redmine'
- end
-end
diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb
deleted file mode 100644
index 36d9874edd3..00000000000
--- a/app/models/project_services/slack_service.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-# note_events :boolean default(TRUE), not null
-#
-
-class SlackService < Service
- prop_accessor :webhook, :username, :channel
- validates :webhook, 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: 'webhook',
- placeholder: 'https://hooks.slack.com/services/...' },
- { type: 'text', name: 'username', placeholder: 'username' },
- { type: 'text', name: 'channel', placeholder: '#channel' }
- ]
- end
-
- def supported_events
- %w(push issue merge_request note tag_push)
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
- return unless webhook.present?
-
- object_kind = data[:object_kind]
-
- data = data.merge(
- project_url: project_url,
- project_name: project_name
- )
-
- # WebHook events often have an 'update' event that follows a 'open' or
- # 'close' action. Ignore update events for now to prevent duplicate
- # messages from arriving.
-
- message = \
- case object_kind
- when "push", "tag_push"
- PushMessage.new(data)
- when "issue"
- IssueMessage.new(data) unless is_update?(data)
- when "merge_request"
- MergeMessage.new(data) unless is_update?(data)
- when "note"
- NoteMessage.new(data)
- end
-
- opt = {}
- opt[:channel] = channel if channel
- opt[:username] = username if username
-
- if message
- notifier = Slack::Notifier.new(webhook, opt)
- notifier.ping(message.pretext, attachments: message.attachments)
- end
- end
-
- private
-
- def project_name
- project.name_with_namespace.gsub(/\s/, '')
- end
-
- def project_url
- project.web_url
- end
-
- def is_update?(data)
- data[:object_attributes][:action] == 'update'
- end
-end
-
-require "slack_service/issue_message"
-require "slack_service/push_message"
-require "slack_service/merge_message"
-require "slack_service/note_message"
diff --git a/app/models/project_services/slack_service/base_message.rb b/app/models/project_services/slack_service/base_message.rb
deleted file mode 100644
index aa00d6061a1..00000000000
--- a/app/models/project_services/slack_service/base_message.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-require 'slack-notifier'
-
-class SlackService
- class BaseMessage
- def initialize(params)
- raise NotImplementedError
- end
-
- def pretext
- format(message)
- end
-
- def attachments
- raise NotImplementedError
- end
-
- private
-
- def message
- raise NotImplementedError
- end
-
- def format(string)
- Slack::Notifier::LinkFormatter.format(string)
- end
-
- def attachment_color
- '#345'
- end
- end
-end
diff --git a/app/models/project_services/slack_service/issue_message.rb b/app/models/project_services/slack_service/issue_message.rb
deleted file mode 100644
index 5af24a80609..00000000000
--- a/app/models/project_services/slack_service/issue_message.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-class SlackService
- class IssueMessage < BaseMessage
- attr_reader :user_name
- attr_reader :title
- attr_reader :project_name
- attr_reader :project_url
- attr_reader :issue_iid
- attr_reader :issue_url
- attr_reader :action
- attr_reader :state
- attr_reader :description
-
- def initialize(params)
- @user_name = params[:user][:name]
- @project_name = params[:project_name]
- @project_url = params[:project_url]
-
- obj_attr = params[:object_attributes]
- obj_attr = HashWithIndifferentAccess.new(obj_attr)
- @title = obj_attr[:title]
- @issue_iid = obj_attr[:iid]
- @issue_url = obj_attr[:url]
- @action = obj_attr[:action]
- @state = obj_attr[:state]
- @description = obj_attr[:description]
- end
-
- def attachments
- return [] unless opened_issue?
-
- description_message
- end
-
- private
-
- def message
- "#{user_name} #{state} #{issue_link} in #{project_link}: *#{title}*"
- end
-
- def opened_issue?
- action == "open"
- end
-
- def description_message
- [{ text: format(description), color: attachment_color }]
- end
-
- def project_link
- "[#{project_name}](#{project_url})"
- end
-
- def issue_link
- "[issue ##{issue_iid}](#{issue_url})"
- end
- end
-end
diff --git a/app/models/project_services/slack_service/merge_message.rb b/app/models/project_services/slack_service/merge_message.rb
deleted file mode 100644
index e792c258f73..00000000000
--- a/app/models/project_services/slack_service/merge_message.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-class SlackService
- class MergeMessage < BaseMessage
- attr_reader :user_name
- attr_reader :project_name
- attr_reader :project_url
- attr_reader :merge_request_id
- attr_reader :source_branch
- attr_reader :target_branch
- attr_reader :state
- attr_reader :title
-
- def initialize(params)
- @user_name = params[:user][:name]
- @project_name = params[:project_name]
- @project_url = params[:project_url]
-
- obj_attr = params[:object_attributes]
- obj_attr = HashWithIndifferentAccess.new(obj_attr)
- @merge_request_id = obj_attr[:iid]
- @source_branch = obj_attr[:source_branch]
- @target_branch = obj_attr[:target_branch]
- @state = obj_attr[:state]
- @title = format_title(obj_attr[:title])
- end
-
- def pretext
- format(message)
- end
-
- def attachments
- []
- end
-
- private
-
- def format_title(title)
- '*' + title.lines.first.chomp + '*'
- end
-
- def message
- merge_request_message
- end
-
- def project_link
- "[#{project_name}](#{project_url})"
- end
-
- def merge_request_message
- "#{user_name} #{state} #{merge_request_link} in #{project_link}: #{title}"
- end
-
- def merge_request_link
- "[merge request ##{merge_request_id}](#{merge_request_url})"
- end
-
- def merge_request_url
- "#{project_url}/merge_requests/#{merge_request_id}"
- end
- end
-end
diff --git a/app/models/project_services/slack_service/note_message.rb b/app/models/project_services/slack_service/note_message.rb
deleted file mode 100644
index 074478b292d..00000000000
--- a/app/models/project_services/slack_service/note_message.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-class SlackService
- class NoteMessage < BaseMessage
- attr_reader :message
- attr_reader :user_name
- attr_reader :project_name
- attr_reader :project_link
- attr_reader :note
- attr_reader :note_url
- attr_reader :title
-
- def initialize(params)
- params = HashWithIndifferentAccess.new(params)
- @user_name = params[:user][:name]
- @project_name = params[:project_name]
- @project_url = params[:project_url]
-
- obj_attr = params[:object_attributes]
- obj_attr = HashWithIndifferentAccess.new(obj_attr)
- @note = obj_attr[:note]
- @note_url = obj_attr[:url]
- noteable_type = obj_attr[:noteable_type]
-
- case noteable_type
- when "Commit"
- create_commit_note(HashWithIndifferentAccess.new(params[:commit]))
- when "Issue"
- create_issue_note(HashWithIndifferentAccess.new(params[:issue]))
- when "MergeRequest"
- create_merge_note(HashWithIndifferentAccess.new(params[:merge_request]))
- when "Snippet"
- create_snippet_note(HashWithIndifferentAccess.new(params[:snippet]))
- end
- end
-
- def attachments
- description_message
- end
-
- private
-
- def format_title(title)
- title.lines.first.chomp
- end
-
- def create_commit_note(commit)
- commit_sha = commit[:id]
- commit_sha = Commit.truncate_sha(commit_sha)
- commit_link = "[commit #{commit_sha}](#{@note_url})"
- title = format_title(commit[:message])
- @message = "#{@user_name} commented on #{commit_link} in #{project_link}: *#{title}*"
- end
-
- def create_issue_note(issue)
- issue_iid = issue[:iid]
- note_link = "[issue ##{issue_iid}](#{@note_url})"
- title = format_title(issue[:title])
- @message = "#{@user_name} commented on #{note_link} in #{project_link}: *#{title}*"
- end
-
- def create_merge_note(merge_request)
- merge_request_id = merge_request[:iid]
- merge_request_link = "[merge request ##{merge_request_id}](#{@note_url})"
- title = format_title(merge_request[:title])
- @message = "#{@user_name} commented on #{merge_request_link} in #{project_link}: *#{title}*"
- end
-
- def create_snippet_note(snippet)
- snippet_id = snippet[:id]
- snippet_link = "[snippet ##{snippet_id}](#{@note_url})"
- title = format_title(snippet[:title])
- @message = "#{@user_name} commented on #{snippet_link} in #{project_link}: *#{title}*"
- end
-
- def description_message
- [{ text: format(@note), color: attachment_color }]
- end
-
- def project_link
- "[#{@project_name}](#{@project_url})"
- end
- end
-end
diff --git a/app/models/project_services/slack_service/push_message.rb b/app/models/project_services/slack_service/push_message.rb
deleted file mode 100644
index b26f3e9ddce..00000000000
--- a/app/models/project_services/slack_service/push_message.rb
+++ /dev/null
@@ -1,110 +0,0 @@
-class SlackService
- class PushMessage < BaseMessage
- attr_reader :after
- attr_reader :before
- attr_reader :commits
- attr_reader :project_name
- attr_reader :project_url
- attr_reader :ref
- attr_reader :ref_type
- attr_reader :user_name
-
- def initialize(params)
- @after = params[:after]
- @before = params[:before]
- @commits = params.fetch(:commits, [])
- @project_name = params[:project_name]
- @project_url = params[:project_url]
- @ref_type = Gitlab::Git.tag_ref?(params[:ref]) ? 'tag' : 'branch'
- @ref = Gitlab::Git.ref_name(params[:ref])
- @user_name = params[:user_name]
- end
-
- def pretext
- format(message)
- end
-
- def attachments
- return [] if new_branch? || removed_branch?
-
- commit_message_attachments
- end
-
- private
-
- def message
- if new_branch?
- new_branch_message
- elsif removed_branch?
- removed_branch_message
- else
- push_message
- end
- end
-
- def format(string)
- Slack::Notifier::LinkFormatter.format(string)
- end
-
- def new_branch_message
- "#{user_name} pushed new #{ref_type} #{branch_link} to #{project_link}"
- end
-
- def removed_branch_message
- "#{user_name} removed #{ref_type} #{ref} from #{project_link}"
- end
-
- def push_message
- "#{user_name} pushed to #{ref_type} #{branch_link} of #{project_link} (#{compare_link})"
- end
-
- def commit_messages
- commits.map { |commit| compose_commit_message(commit) }.join("\n")
- end
-
- def commit_message_attachments
- [{ text: format(commit_messages), color: attachment_color }]
- end
-
- def compose_commit_message(commit)
- author = commit[:author][:name]
- id = Commit.truncate_sha(commit[:id])
- message = commit[:message]
- url = commit[:url]
-
- "[#{id}](#{url}): #{message} - #{author}"
- end
-
- def new_branch?
- Gitlab::Git.blank_ref?(before)
- end
-
- def removed_branch?
- Gitlab::Git.blank_ref?(after)
- 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
-
- def attachment_color
- '#345'
- end
- end
-end
diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb
deleted file mode 100644
index 3c002a1634b..00000000000
--- a/app/models/project_services/teamcity_service.rb
+++ /dev/null
@@ -1,145 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-# note_events :boolean default(TRUE), not null
-#
-
-class TeamcityService < CiService
- include HTTParty
-
- prop_accessor :teamcity_url, :build_type, :username, :password
-
- validates :teamcity_url,
- presence: true,
- format: { with: /\A#{URI.regexp}\z/ }, if: :activated?
- validates :build_type, presence: true, if: :activated?
- validates :username,
- presence: true,
- if: ->(service) { service.password? }, if: :activated?
- validates :password,
- presence: true,
- if: ->(service) { service.username? }, if: :activated?
-
- attr_accessor :response
-
- after_save :compose_service_hook, if: :activated?
-
- def compose_service_hook
- hook = service_hook || build_service_hook
- hook.save
- end
-
- def title
- 'JetBrains TeamCity CI'
- end
-
- def description
- 'A continuous integration and build server'
- end
-
- def help
- 'The build configuration in Teamcity must use the build format '\
- 'number %build.vcs.number% '\
- 'you will also want to configure monitoring of all branches so merge '\
- 'requests build, that setting is in the vsc root advanced settings.'
- end
-
- def to_param
- 'teamcity'
- end
-
- def supported_events
- %w(push)
- end
-
- def fields
- [
- { type: 'text', name: 'teamcity_url',
- placeholder: 'TeamCity root URL like https://teamcity.example.com' },
- { type: 'text', name: 'build_type',
- placeholder: 'Build configuration ID' },
- { type: 'text', name: 'username',
- placeholder: 'A user with permissions to trigger a manual build' },
- { type: 'password', name: 'password' },
- ]
- end
-
- def build_info(sha)
- url = URI.parse("#{teamcity_url}/httpAuth/app/rest/builds/"\
- "branch:unspecified:any,number:#{sha}")
- auth = {
- username: username,
- password: password,
- }
- @response = HTTParty.get("#{url}", verify: false, basic_auth: auth)
- end
-
- def build_page(sha, ref)
- build_info(sha) if @response.nil? || !@response.code
-
- if @response.code != 200
- # If actual build link can't be determined,
- # send user to build summary page.
- "#{teamcity_url}/viewLog.html?buildTypeId=#{build_type}"
- else
- # If actual build link is available, go to build result page.
- built_id = @response['build']['id']
- "#{teamcity_url}/viewLog.html?buildId=#{built_id}"\
- "&buildTypeId=#{build_type}"
- end
- end
-
- def commit_status(sha, ref)
- build_info(sha) if @response.nil? || !@response.code
- return :error unless @response.code == 200 || @response.code == 404
-
- status = if @response.code == 404
- 'Pending'
- else
- @response['build']['status']
- end
-
- if status.include?('SUCCESS')
- 'success'
- elsif status.include?('FAILURE')
- 'failed'
- elsif status.include?('Pending')
- 'pending'
- else
- :error
- end
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- auth = {
- username: username,
- password: password,
- }
-
- branch = Gitlab::Git.ref_name(data[:ref])
-
- self.class.post("#{teamcity_url}/httpAuth/app/rest/buildQueue",
- body: "<build branchName=\"#{branch}\">"\
- "<buildType id=\"#{build_type}\"/>"\
- '</build>',
- headers: { 'Content-type' => 'application/xml' },
- basic_auth: auth
- )
- end
-end
diff --git a/app/models/project_snippet.rb b/app/models/project_snippet.rb
deleted file mode 100644
index 9e2c1b0e18e..00000000000
--- a/app/models/project_snippet.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# == Schema Information
-#
-# Table name: snippets
-#
-# id :integer not null, primary key
-# title :string(255)
-# content :text
-# author_id :integer not null
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# file_name :string(255)
-# expires_at :datetime
-# type :string(255)
-# visibility_level :integer default(0), not null
-#
-
-class ProjectSnippet < Snippet
- belongs_to :project
- belongs_to :author, class_name: "User"
-
- validates :project, presence: true
-
- # Scopes
- scope :fresh, -> { order("created_at DESC") }
- scope :non_expired, -> { where(["expires_at IS NULL OR expires_at > ?", Time.current]) }
- scope :expired, -> { where(["expires_at IS NOT NULL AND expires_at < ?", Time.current]) }
-end
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
deleted file mode 100644
index 56e49af2324..00000000000
--- a/app/models/project_team.rb
+++ /dev/null
@@ -1,169 +0,0 @@
-class ProjectTeam
- attr_accessor :project
-
- def initialize(project)
- @project = project
- end
-
- # Shortcut to add users
- #
- # Use:
- # @team << [@user, :master]
- # @team << [@users, :master]
- #
- def <<(args)
- users, access, current_user = *args
-
- if users.respond_to?(:each)
- add_users(users, access, current_user)
- else
- add_user(users, access, current_user)
- end
- end
-
- def find(user_id)
- user = project.users.find_by(id: user_id)
-
- if group
- user ||= group.users.find_by(id: user_id)
- end
-
- user
- end
-
- def find_member(user_id)
- member = project.project_members.find_by(user_id: user_id)
-
- # If user is not in project members
- # we should check for group membership
- if group && !member
- member = group.group_members.find_by(user_id: user_id)
- end
-
- member
- end
-
- def add_users(users, access, current_user = nil)
- ProjectMember.add_users_into_projects(
- [project.id],
- users,
- access,
- current_user
- )
- end
-
- def add_user(user, access, current_user = nil)
- add_users([user], access, current_user)
- end
-
- # Remove all users from project team
- def truncate
- ProjectMember.truncate_team(project)
- end
-
- def users
- members
- end
-
- def members
- @members ||= fetch_members
- end
-
- def guests
- @guests ||= fetch_members(:guests)
- end
-
- def reporters
- @reporters ||= fetch_members(:reporters)
- end
-
- def developers
- @developers ||= fetch_members(:developers)
- end
-
- def masters
- @masters ||= fetch_members(:masters)
- end
-
- def import(source_project, current_user = nil)
- target_project = project
-
- source_members = source_project.project_members.to_a
- target_user_ids = target_project.project_members.pluck(:user_id)
-
- source_members.reject! do |member|
- # Skip if user already present in team
- !member.invite? && target_user_ids.include?(member.user_id)
- end
-
- source_members.map! do |member|
- new_member = member.dup
- new_member.id = nil
- new_member.source = target_project
- new_member.created_by = current_user
- new_member
- end
-
- ProjectMember.transaction do
- source_members.each do |member|
- member.save
- end
- end
-
- true
- rescue
- false
- end
-
- def guest?(user)
- max_member_access(user.id) == Gitlab::Access::GUEST
- end
-
- def reporter?(user)
- max_member_access(user.id) == Gitlab::Access::REPORTER
- end
-
- def developer?(user)
- max_member_access(user.id) == Gitlab::Access::DEVELOPER
- end
-
- def master?(user)
- max_member_access(user.id) == Gitlab::Access::MASTER
- end
-
- def member?(user_id)
- !!find_member(user_id)
- end
-
- def max_member_access(user_id)
- access = []
- access << project.project_members.find_by(user_id: user_id).try(:access_field)
-
- if group
- access << group.group_members.find_by(user_id: user_id).try(:access_field)
- end
-
- access.compact.max
- end
-
- private
-
- def fetch_members(level = nil)
- project_members = project.project_members
- group_members = group ? group.group_members : []
-
- if level
- project_members = project_members.send(level)
- group_members = group_members.send(level) if group
- end
-
- user_ids = project_members.pluck(:user_id)
- user_ids.push(*group_members.pluck(:user_id)) if group
-
- User.where(id: user_ids)
- end
-
- def group
- project.group
- end
-end
diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb
deleted file mode 100644
index 772c868d9cd..00000000000
--- a/app/models/project_wiki.rb
+++ /dev/null
@@ -1,149 +0,0 @@
-class ProjectWiki
- include Gitlab::ShellAdapter
-
- MARKUPS = {
- 'Markdown' => :markdown,
- 'RDoc' => :rdoc,
- 'AsciiDoc' => :asciidoc
- } unless defined?(MARKUPS)
-
- class CouldNotCreateWikiError < StandardError; end
-
- # Returns a string describing what went wrong after
- # an operation fails.
- attr_reader :error_message
-
- def initialize(project, user = nil)
- @project = project
- @user = user
- end
-
- def path
- @project.path + '.wiki'
- end
-
- def path_with_namespace
- @project.path_with_namespace + ".wiki"
- end
-
- def url_to_repo
- gitlab_shell.url_to_repo(path_with_namespace)
- end
-
- def ssh_url_to_repo
- url_to_repo
- end
-
- def http_url_to_repo
- [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
- end
-
- # Returns the Gollum::Wiki object.
- def wiki
- @wiki ||= begin
- Gollum::Wiki.new(path_to_repo)
- rescue Gollum::NoSuchPathError
- create_repo!
- end
- end
-
- def empty?
- pages.empty?
- end
-
- # Returns an Array of Gitlab WikiPage instances or an
- # empty Array if this Wiki has no pages.
- def pages
- wiki.pages.map { |page| WikiPage.new(self, page, true) }
- end
-
- # Finds a page within the repository based on a tile
- # or slug.
- #
- # title - The human readable or parameterized title of
- # the page.
- #
- # Returns an initialized WikiPage instance or nil
- def find_page(title, version = nil)
- page_title, page_dir = page_title_and_dir(title)
- if page = wiki.page(page_title, version, page_dir)
- WikiPage.new(self, page, true)
- else
- nil
- end
- end
-
- def find_file(name, version = nil, try_on_disk = true)
- version = wiki.ref if version.nil? # Gollum::Wiki#file ?
- if wiki_file = wiki.file(name, version, try_on_disk)
- wiki_file
- else
- nil
- end
- end
-
- def create_page(title, content, format = :markdown, message = nil)
- commit = commit_details(:created, message, title)
-
- wiki.write_page(title, format, content, commit)
- rescue Gollum::DuplicatePageError => e
- @error_message = "Duplicate page: #{e.message}"
- return false
- end
-
- def update_page(page, content, format = :markdown, message = nil)
- commit = commit_details(:updated, message, page.title)
-
- wiki.update_page(page, page.name, format, content, commit)
- end
-
- def delete_page(page, message = nil)
- wiki.delete_page(page, commit_details(:deleted, message, page.title))
- end
-
- def page_title_and_dir(title)
- title_array = title.split("/")
- title = title_array.pop
- [title, title_array.join("/")]
- end
-
- def search_files(query)
- repository.search_files(query, default_branch)
- end
-
- def repository
- Repository.new(path_with_namespace, default_branch)
- end
-
- def default_branch
- wiki.class.default_ref
- end
-
- private
-
- def create_repo!
- if init_repo(path_with_namespace)
- Gollum::Wiki.new(path_to_repo)
- else
- raise CouldNotCreateWikiError
- end
- end
-
- def init_repo(path_with_namespace)
- gitlab_shell.add_repository(path_with_namespace)
- end
-
- def commit_details(action, message = nil, title = nil)
- commit_message = message || default_message(action, title)
-
- { email: @user.email, name: @user.name, message: commit_message }
- end
-
- def default_message(action, title)
- "#{@user.username} #{action} page: #{title}"
- end
-
- def path_to_repo
- @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git")
- end
-end
diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb
deleted file mode 100644
index 97207ba1272..00000000000
--- a/app/models/protected_branch.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# == Schema Information
-#
-# Table name: protected_branches
-#
-# id :integer not null, primary key
-# project_id :integer not null
-# name :string(255) not null
-# created_at :datetime
-# updated_at :datetime
-# developers_can_push :boolean default(FALSE), not null
-#
-
-class ProtectedBranch < ActiveRecord::Base
- include Gitlab::ShellAdapter
-
- belongs_to :project
- validates :name, presence: true
- validates :project, presence: true
-
- def commit
- project.repository.commit(self.name)
- end
-end
diff --git a/app/models/repository.rb b/app/models/repository.rb
deleted file mode 100644
index 263a436d521..00000000000
--- a/app/models/repository.rb
+++ /dev/null
@@ -1,377 +0,0 @@
-class Repository
- include Gitlab::ShellAdapter
-
- attr_accessor :raw_repository, :path_with_namespace
-
- def initialize(path_with_namespace, default_branch = nil)
- @path_with_namespace = path_with_namespace
- @raw_repository = Gitlab::Git::Repository.new(path_to_repo) if path_with_namespace
- rescue Gitlab::Git::Repository::NoRepository
- nil
- end
-
- # Return absolute path to repository
- def path_to_repo
- @path_to_repo ||= File.expand_path(
- File.join(Gitlab.config.gitlab_shell.repos_path, path_with_namespace + ".git")
- )
- end
-
- def exists?
- raw_repository
- end
-
- def empty?
- raw_repository.empty?
- end
-
- def commit(id = 'HEAD')
- return nil unless raw_repository
- commit = Gitlab::Git::Commit.find(raw_repository, id)
- commit = Commit.new(commit) if commit
- commit
- rescue Rugged::OdbError
- nil
- end
-
- def commits(ref, path = nil, limit = nil, offset = nil, skip_merges = false)
- commits = Gitlab::Git::Commit.where(
- repo: raw_repository,
- ref: ref,
- path: path,
- limit: limit,
- offset: offset,
- )
- commits = Commit.decorate(commits) if commits.present?
- commits
- end
-
- def commits_between(from, to)
- commits = Gitlab::Git::Commit.between(raw_repository, from, to)
- commits = Commit.decorate(commits) if commits.present?
- commits
- end
-
- def find_branch(name)
- branches.find { |branch| branch.name == name }
- end
-
- def find_tag(name)
- tags.find { |tag| tag.name == name }
- end
-
- def add_branch(branch_name, ref)
- cache.expire(:branch_names)
- @branches = nil
-
- gitlab_shell.add_branch(path_with_namespace, branch_name, ref)
- end
-
- def add_tag(tag_name, ref, message = nil)
- cache.expire(:tag_names)
- @tags = nil
-
- gitlab_shell.add_tag(path_with_namespace, tag_name, ref, message)
- end
-
- def rm_branch(branch_name)
- cache.expire(:branch_names)
- @branches = nil
-
- gitlab_shell.rm_branch(path_with_namespace, branch_name)
- end
-
- def rm_tag(tag_name)
- cache.expire(:tag_names)
- @tags = nil
-
- gitlab_shell.rm_tag(path_with_namespace, tag_name)
- end
-
- def round_commit_count
- if commit_count > 10000
- '10000+'
- elsif commit_count > 5000
- '5000+'
- elsif commit_count > 1000
- '1000+'
- else
- commit_count
- end
- end
-
- def branch_names
- cache.fetch(:branch_names) { raw_repository.branch_names }
- end
-
- def tag_names
- cache.fetch(:tag_names) { raw_repository.tag_names }
- end
-
- def commit_count
- cache.fetch(:commit_count) do
- begin
- raw_repository.commit_count(self.root_ref)
- rescue
- 0
- end
- end
- end
-
- # Return repo size in megabytes
- # Cached in redis
- def size
- cache.fetch(:size) { raw_repository.size }
- end
-
- def expire_cache
- %i(size branch_names tag_names commit_count graph_log
- readme version contribution_guide changelog license).each do |key|
- cache.expire(key)
- end
- end
-
- def graph_log
- cache.fetch(:graph_log) do
- commits = raw_repository.log(limit: 6000, skip_merges: true,
- ref: root_ref)
-
- commits.map do |rugged_commit|
- commit = Gitlab::Git::Commit.new(rugged_commit)
-
- {
- author_name: commit.author_name,
- author_email: commit.author_email,
- additions: commit.stats.additions,
- deletions: commit.stats.deletions,
- }
- end
- end
- end
-
- def lookup_cache
- @lookup_cache ||= {}
- end
-
- def method_missing(m, *args, &block)
- if m == :lookup && !block_given?
- lookup_cache[m] ||= {}
- lookup_cache[m][args.join(":")] ||= raw_repository.send(m, *args, &block)
- else
- raw_repository.send(m, *args, &block)
- end
- end
-
- def respond_to?(method)
- return true if raw_repository.respond_to?(method)
-
- super
- end
-
- def blob_at(sha, path)
- Gitlab::Git::Blob.find(self, sha, path)
- end
-
- def blob_by_oid(oid)
- Gitlab::Git::Blob.raw(self, oid)
- end
-
- def readme
- cache.fetch(:readme) { tree(:head).readme }
- end
-
- def version
- cache.fetch(:version) do
- tree(:head).blobs.find do |file|
- file.name.downcase == 'version'
- end
- end
- end
-
- def contribution_guide
- cache.fetch(:contribution_guide) do
- tree(:head).blobs.find do |file|
- file.contributing?
- end
- end
- end
-
- def changelog
- cache.fetch(:changelog) do
- tree(:head).blobs.find do |file|
- file.name =~ /\A(changelog|history)/i
- end
- end
- end
-
- def license
- cache.fetch(:license) do
- tree(:head).blobs.find do |file|
- file.name =~ /\Alicense/i
- end
- end
- end
-
- def head_commit
- @head_commit ||= commit(self.root_ref)
- end
-
- def head_tree
- @head_tree ||= Tree.new(self, head_commit.sha, nil)
- end
-
- def tree(sha = :head, path = nil)
- if sha == :head
- if path.nil?
- return head_tree
- else
- sha = head_commit.sha
- end
- end
-
- Tree.new(self, sha, path)
- end
-
- def blob_at_branch(branch_name, path)
- last_commit = commit(branch_name)
-
- if last_commit
- blob_at(last_commit.sha, path)
- else
- nil
- end
- end
-
- # Returns url for submodule
- #
- # Ex.
- # @repository.submodule_url_for('master', 'rack')
- # # => git@localhost:rack.git
- #
- def submodule_url_for(ref, path)
- if submodules(ref).any?
- submodule = submodules(ref)[path]
-
- if submodule
- submodule['url']
- end
- end
- end
-
- def last_commit_for_path(sha, path)
- args = %W(git rev-list --max-count=1 #{sha} -- #{path})
- sha = Gitlab::Popen.popen(args, path_to_repo).first.strip
- commit(sha)
- end
-
- # Remove archives older than 2 hours
- def clean_old_archives
- repository_downloads_path = Gitlab.config.gitlab.repository_downloads_path
-
- return unless File.directory?(repository_downloads_path)
-
- Gitlab::Popen.popen(%W(find #{repository_downloads_path} -not -path #{repository_downloads_path} -mmin +120 -delete))
- end
-
- def branches_sorted_by(value)
- case value
- when 'recently_updated'
- branches.sort do |a, b|
- commit(b.target).committed_date <=> commit(a.target).committed_date
- end
- when 'last_updated'
- branches.sort do |a, b|
- commit(a.target).committed_date <=> commit(b.target).committed_date
- end
- else
- branches
- end
- end
-
- def contributors
- commits = self.commits(nil, nil, 2000, 0, true)
-
- commits.group_by(&:author_email).map do |email, commits|
- contributor = Gitlab::Contributor.new
- contributor.email = email
-
- commits.each do |commit|
- if contributor.name.blank?
- contributor.name = commit.author_name
- end
-
- contributor.commits += 1
- end
-
- contributor
- end
- end
-
- def blob_for_diff(commit, diff)
- file = blob_at(commit.id, diff.new_path)
-
- unless file
- file = prev_blob_for_diff(commit, diff)
- end
-
- file
- end
-
- def prev_blob_for_diff(commit, diff)
- if commit.parent_id
- blob_at(commit.parent_id, diff.old_path)
- end
- end
-
- def branch_names_contains(sha)
- args = %W(git branch --contains #{sha})
- names = Gitlab::Popen.popen(args, path_to_repo).first
-
- if names.respond_to?(:split)
- names = names.split("\n").map(&:strip)
-
- names.each do |name|
- name.slice! '* '
- end
-
- names
- else
- []
- end
- end
-
- def tag_names_contains(sha)
- args = %W(git tag --contains #{sha})
- names = Gitlab::Popen.popen(args, path_to_repo).first
-
- if names.respond_to?(:split)
- names = names.split("\n").map(&:strip)
-
- names.each do |name|
- name.slice! '* '
- end
-
- names
- else
- []
- end
- end
-
- def branches
- @branches ||= raw_repository.branches
- end
-
- def tags
- @tags ||= raw_repository.tags
- end
-
- def root_ref
- @root_ref ||= raw_repository.root_ref
- end
-
- private
-
- def cache
- @cache ||= RepositoryCache.new(path_with_namespace)
- end
-end
diff --git a/app/models/service.rb b/app/models/service.rb
deleted file mode 100644
index 393cf55a69f..00000000000
--- a/app/models/service.rb
+++ /dev/null
@@ -1,153 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-#
-
-# To add new service you should build a class inherited from Service
-# and implement a set of methods
-class Service < ActiveRecord::Base
- include Sortable
- serialize :properties, JSON
-
- default_value_for :active, false
- default_value_for :push_events, true
- default_value_for :issues_events, true
- default_value_for :merge_requests_events, true
- default_value_for :tag_push_events, true
- default_value_for :note_events, true
-
- after_initialize :initialize_properties
-
- belongs_to :project
- has_one :service_hook
-
- validates :project_id, presence: true, unless: Proc.new { |service| service.template? }
-
- scope :visible, -> { where.not(type: 'GitlabIssueTrackerService') }
-
- scope :push_hooks, -> { where(push_events: true, active: true) }
- scope :tag_push_hooks, -> { where(tag_push_events: true, active: true) }
- scope :issue_hooks, -> { where(issues_events: true, active: true) }
- scope :merge_request_hooks, -> { where(merge_requests_events: true, active: true) }
- scope :note_hooks, -> { where(note_events: true, active: true) }
-
- def activated?
- active
- end
-
- def template?
- template
- end
-
- def category
- :common
- end
-
- def initialize_properties
- self.properties = {} if properties.nil?
- end
-
- def title
- # implement inside child
- end
-
- def description
- # implement inside child
- end
-
- def help
- # implement inside child
- end
-
- def to_param
- # implement inside child
- end
-
- def fields
- # implement inside child
- []
- end
-
- def supported_events
- %w(push tag_push issue merge_request)
- end
-
- def execute
- # implement inside child
- end
-
- def can_test?
- !project.empty_repo?
- end
-
- # Provide convenient accessor methods
- # for each serialized property.
- def self.prop_accessor(*args)
- args.each do |arg|
- class_eval %{
- def #{arg}
- properties['#{arg}']
- end
-
- def #{arg}=(value)
- self.properties['#{arg}'] = value
- end
- }
- end
- end
-
- def async_execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- Sidekiq::Client.enqueue(ProjectServiceWorker, id, data)
- end
-
- def issue_tracker?
- self.category == :issue_tracker
- end
-
- def self.available_services_names
- %w(
- asana
- assembla
- bamboo
- buildkite
- campfire
- custom_issue_tracker
- emails_on_push
- external_wiki
- flowdock
- gemnasium
- gitlab_ci
- hipchat
- irker
- jira
- pivotaltracker
- pushover
- redmine
- slack
- teamcity
- )
- end
-
- def self.create_from_template(project_id, template)
- service = template.dup
- service.template = false
- service.project_id = project_id
- service if service.save
- end
-end
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
deleted file mode 100644
index b35e72c4bdb..00000000000
--- a/app/models/snippet.rb
+++ /dev/null
@@ -1,103 +0,0 @@
-# == Schema Information
-#
-# Table name: snippets
-#
-# id :integer not null, primary key
-# title :string(255)
-# content :text
-# author_id :integer not null
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# file_name :string(255)
-# expires_at :datetime
-# type :string(255)
-# visibility_level :integer default(0), not null
-#
-
-class Snippet < ActiveRecord::Base
- include Sortable
- include Linguist::BlobHelper
- include Gitlab::VisibilityLevel
-
- default_value_for :visibility_level, Snippet::PRIVATE
-
- belongs_to :author, class_name: "User"
-
- has_many :notes, as: :noteable, dependent: :destroy
-
- delegate :name, :email, to: :author, prefix: true, allow_nil: true
-
- validates :author, presence: true
- validates :title, presence: true, length: { within: 0..255 }
- validates :file_name,
- presence: true,
- length: { within: 0..255 },
- format: { with: Gitlab::Regex.file_name_regex,
- message: Gitlab::Regex.file_name_regex_message }
- validates :content, presence: true
- validates :visibility_level, inclusion: { in: Gitlab::VisibilityLevel.values }
-
- # Scopes
- scope :are_internal, -> { where(visibility_level: Snippet::INTERNAL) }
- scope :are_private, -> { where(visibility_level: Snippet::PRIVATE) }
- scope :are_public, -> { where(visibility_level: Snippet::PUBLIC) }
- scope :public_and_internal, -> { where(visibility_level: [Snippet::PUBLIC, Snippet::INTERNAL]) }
- scope :fresh, -> { order("created_at DESC") }
- 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]) }
-
- def self.content_types
- [
- ".rb", ".py", ".pl", ".scala", ".c", ".cpp", ".java",
- ".haml", ".html", ".sass", ".scss", ".xml", ".php", ".erb",
- ".js", ".sh", ".coffee", ".yml", ".md"
- ]
- end
-
- def data
- content
- end
-
- def hook_attrs
- attributes
- end
-
- def size
- 0
- end
-
- def name
- file_name
- end
-
- def sanitized_file_name
- file_name.gsub(/[^a-zA-Z0-9_\-\.]+/, '')
- end
-
- def mode
- nil
- end
-
- def expired?
- expires_at && expires_at < Time.current
- end
-
- def visibility_level_field
- visibility_level
- end
-
- class << self
- def search(query)
- where('(title LIKE :query OR file_name LIKE :query)', query: "%#{query}%")
- end
-
- def search_code(query)
- where('(content LIKE :query)', query: "%#{query}%")
- end
-
- def accessible_to(user)
- where('visibility_level IN (?) OR author_id = ?', [Snippet::INTERNAL, Snippet::PUBLIC], user)
- end
- end
-end
diff --git a/app/models/subscription.rb b/app/models/subscription.rb
deleted file mode 100644
index dd75d3ab8ba..00000000000
--- a/app/models/subscription.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# == Schema Information
-#
-# Table name: subscriptions
-#
-# id :integer not null, primary key
-# user_id :integer
-# subscribable_id :integer
-# subscribable_type :string(255)
-# subscribed :boolean
-# created_at :datetime
-# updated_at :datetime
-#
-
-class Subscription < ActiveRecord::Base
- belongs_to :user
- belongs_to :subscribable, polymorphic: true
-
- validates :user_id,
- uniqueness: { scope: [:subscribable_id, :subscribable_type] },
- presence: true
-end
diff --git a/app/models/tree.rb b/app/models/tree.rb
deleted file mode 100644
index f279e896cda..00000000000
--- a/app/models/tree.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-class Tree
- include Gitlab::MarkdownHelper
-
- attr_accessor :repository, :sha, :path, :entries
-
- def initialize(repository, sha, path = '/')
- path = '/' if path.blank?
-
- @repository = repository
- @sha = sha
- @path = path
-
- git_repo = @repository.raw_repository
- @entries = Gitlab::Git::Tree.where(git_repo, @sha, @path)
- end
-
- def readme
- return @readme if defined?(@readme)
-
- available_readmes = blobs.select(&:readme?)
-
- if available_readmes.count == 0
- return @readme = nil
- end
-
- # Take the first previewable readme, or the first available readme, if we
- # can't preview any of them
- readme_tree = available_readmes.find do |readme|
- previewable?(readme.name)
- end || available_readmes.first
-
- readme_path = path == '/' ? readme_tree.name : File.join(path, readme_tree.name)
-
- git_repo = repository.raw_repository
- @readme = Gitlab::Git::Blob.find(git_repo, sha, readme_path)
- end
-
- def trees
- @entries.select(&:dir?)
- end
-
- def blobs
- @entries.select(&:file?)
- end
-
- def submodules
- @entries.select(&:submodule?)
- end
-
- def sorted_entries
- trees + blobs + submodules
- end
-end
diff --git a/app/models/user.rb b/app/models/user.rb
deleted file mode 100644
index d6b93afe739..00000000000
--- a/app/models/user.rb
+++ /dev/null
@@ -1,614 +0,0 @@
-# == Schema Information
-#
-# Table name: users
-#
-# id :integer not null, primary key
-# email :string(255) default(""), not null
-# encrypted_password :string(255) default(""), not null
-# reset_password_token :string(255)
-# reset_password_sent_at :datetime
-# remember_created_at :datetime
-# sign_in_count :integer default(0)
-# current_sign_in_at :datetime
-# last_sign_in_at :datetime
-# current_sign_in_ip :string(255)
-# last_sign_in_ip :string(255)
-# created_at :datetime
-# updated_at :datetime
-# name :string(255)
-# admin :boolean default(FALSE), not null
-# projects_limit :integer default(10)
-# skype :string(255) default(""), not null
-# linkedin :string(255) default(""), not null
-# twitter :string(255) default(""), not null
-# authentication_token :string(255)
-# theme_id :integer default(1), not null
-# bio :string(255)
-# failed_attempts :integer default(0)
-# locked_at :datetime
-# username :string(255)
-# can_create_group :boolean default(TRUE), not null
-# can_create_team :boolean default(TRUE), not null
-# state :string(255)
-# color_scheme_id :integer default(1), not null
-# notification_level :integer default(1), not null
-# password_expires_at :datetime
-# created_by_id :integer
-# last_credential_check_at :datetime
-# avatar :string(255)
-# confirmation_token :string(255)
-# confirmed_at :datetime
-# confirmation_sent_at :datetime
-# unconfirmed_email :string(255)
-# hide_no_ssh_key :boolean default(FALSE)
-# website_url :string(255) default(""), not null
-# github_access_token :string(255)
-# gitlab_access_token :string(255)
-# notification_email :string(255)
-# hide_no_password :boolean default(FALSE)
-# password_automatically_set :boolean default(FALSE)
-# bitbucket_access_token :string(255)
-# bitbucket_access_token_secret :string(255)
-# public_email :string(255) default(""), not null
-#
-
-require 'carrierwave/orm/activerecord'
-require 'file_size_validator'
-
-class User < ActiveRecord::Base
- include Sortable
- include Gitlab::ConfigHelper
- include TokenAuthenticatable
- extend Gitlab::ConfigHelper
- include Gitlab::CurrentSettings
-
- default_value_for :admin, false
- default_value_for :can_create_group, gitlab_config.default_can_create_group
- default_value_for :can_create_team, false
- default_value_for :hide_no_ssh_key, false
- default_value_for :hide_no_password, false
- default_value_for :theme_id, gitlab_config.default_theme
-
- devise :database_authenticatable, :lockable, :async,
- :recoverable, :rememberable, :trackable, :validatable, :omniauthable, :confirmable, :registerable
-
- attr_accessor :force_random_password
-
- # Virtual attribute for authenticating by either username or email
- attr_accessor :login
-
- #
- # Relations
- #
-
- # Namespace for personal projects
- has_one :namespace, -> { where type: nil }, dependent: :destroy, foreign_key: :owner_id, class_name: "Namespace"
-
- # Profile
- has_many :keys, dependent: :destroy
- has_many :emails, dependent: :destroy
- has_many :identities, dependent: :destroy
-
- # Groups
- has_many :members, dependent: :destroy
- has_many :project_members, source: 'ProjectMember'
- has_many :group_members, source: 'GroupMember'
- has_many :groups, through: :group_members
- has_many :owned_groups, -> { where members: { access_level: Gitlab::Access::OWNER } }, through: :group_members, source: :group
- has_many :masters_groups, -> { where members: { access_level: Gitlab::Access::MASTER } }, through: :group_members, source: :group
-
- # Projects
- has_many :groups_projects, through: :groups, source: :projects
- has_many :personal_projects, through: :namespace, source: :projects
- has_many :projects, through: :project_members
- has_many :created_projects, foreign_key: :creator_id, class_name: 'Project'
- has_many :users_star_projects, dependent: :destroy
- has_many :starred_projects, through: :users_star_projects, source: :project
-
- has_many :snippets, dependent: :destroy, foreign_key: :author_id, class_name: "Snippet"
- has_many :project_members, dependent: :destroy, class_name: 'ProjectMember'
- has_many :issues, dependent: :destroy, foreign_key: :author_id
- has_many :notes, dependent: :destroy, foreign_key: :author_id
- has_many :merge_requests, dependent: :destroy, foreign_key: :author_id
- has_many :events, dependent: :destroy, foreign_key: :author_id, class_name: "Event"
- has_many :subscriptions, dependent: :destroy
- has_many :recent_events, -> { order "id DESC" }, foreign_key: :author_id, class_name: "Event"
- has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue"
- has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest"
- has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy
-
-
- #
- # Validations
- #
- validates :name, presence: true
- validates :email, presence: true, email: { strict_mode: true }, uniqueness: true
- validates :notification_email, presence: true, email: { strict_mode: true }
- validates :public_email, presence: true, email: { strict_mode: true }, allow_blank: true, uniqueness: true
- validates :bio, length: { maximum: 255 }, allow_blank: true
- validates :projects_limit, presence: true, numericality: { greater_than_or_equal_to: 0 }
- validates :username,
- presence: true,
- uniqueness: { case_sensitive: false },
- exclusion: { in: Gitlab::Blacklist.path },
- format: { with: Gitlab::Regex.namespace_regex,
- message: Gitlab::Regex.namespace_regex_message }
-
- validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true
- validate :namespace_uniq, if: ->(user) { user.username_changed? }
- validate :avatar_type, if: ->(user) { user.avatar_changed? }
- validate :unique_email, if: ->(user) { user.email_changed? }
- validate :owns_notification_email, if: ->(user) { user.notification_email_changed? }
- validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
-
- before_validation :generate_password, on: :create
- before_validation :sanitize_attrs
- before_validation :set_notification_email, if: ->(user) { user.email_changed? }
- before_validation :set_public_email, if: ->(user) { user.public_email_changed? }
-
- before_save :ensure_authentication_token
- after_save :ensure_namespace_correct
- after_initialize :set_projects_limit
- after_create :post_create_hook
- after_destroy :post_destroy_hook
-
-
- alias_attribute :private_token, :authentication_token
-
- delegate :path, to: :namespace, allow_nil: true, prefix: true
-
- state_machine :state, initial: :active do
- event :block do
- transition active: :blocked
- end
-
- event :activate do
- transition blocked: :active
- end
- end
-
- mount_uploader :avatar, AvatarUploader
-
- # Scopes
- scope :admins, -> { where(admin: true) }
- scope :blocked, -> { with_state(:blocked) }
- scope :active, -> { with_state(:active) }
- scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all }
- scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM members)') }
-
- #
- # Class methods
- #
- class << self
- # Devise method overridden to allow sign in with email or username
- def find_for_database_authentication(warden_conditions)
- conditions = warden_conditions.dup
- if login = conditions.delete(:login)
- where(conditions).where(["lower(username) = :value OR lower(email) = :value", { value: login.downcase }]).first
- else
- where(conditions).first
- end
- end
-
- def sort(method)
- case method.to_s
- when 'recent_sign_in' then reorder(last_sign_in_at: :desc)
- when 'oldest_sign_in' then reorder(last_sign_in_at: :asc)
- else
- order_by(method)
- end
- end
-
- def find_for_commit(email, name)
- # Prefer email match over name match
- User.where(email: email).first ||
- User.joins(:emails).where(emails: { email: email }).first ||
- User.where(name: name).first
- end
-
- def filter(filter_name)
- case filter_name
- when "admins"; self.admins
- when "blocked"; self.blocked
- when "wop"; self.without_projects
- else
- self.active
- end
- end
-
- def search(query)
- where("lower(name) LIKE :query OR lower(email) LIKE :query OR lower(username) LIKE :query", query: "%#{query.downcase}%")
- end
-
- def by_login(login)
- where('lower(username) = :value OR lower(email) = :value',
- value: login.to_s.downcase).first
- end
-
- def by_username_or_id(name_or_id)
- where('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i).first
- end
-
- def build_user(attrs = {})
- User.new(attrs)
- end
- end
-
- #
- # Instance methods
- #
-
- def to_param
- username
- end
-
- def notification
- @notification ||= Notification.new(self)
- end
-
- def generate_password
- if self.force_random_password
- self.password = self.password_confirmation = Devise.friendly_token.first(8)
- end
- end
-
- def generate_reset_token
- @reset_token, enc = Devise.token_generator.generate(self.class, :reset_password_token)
-
- self.reset_password_token = enc
- self.reset_password_sent_at = Time.now.utc
-
- @reset_token
- end
-
- def namespace_uniq
- namespace_name = self.username
- existing_namespace = Namespace.by_path(namespace_name)
- if existing_namespace && existing_namespace != self.namespace
- self.errors.add :username, "already exists"
- end
- end
-
- def avatar_type
- unless self.avatar.image?
- self.errors.add :avatar, "only images allowed"
- end
- end
-
- def unique_email
- self.errors.add(:email, 'has already been taken') if Email.exists?(email: self.email)
- end
-
- def owns_notification_email
- self.errors.add(:notification_email, "is not an email you own") unless self.all_emails.include?(self.notification_email)
- end
-
- # Groups user has access to
- def authorized_groups
- @authorized_groups ||= begin
- group_ids = (groups.pluck(:id) + authorized_projects.pluck(:namespace_id))
- Group.where(id: group_ids)
- end
- end
-
-
- # Projects user has access to
- def authorized_projects
- @authorized_projects ||= begin
- project_ids = personal_projects.pluck(:id)
- project_ids.push(*groups_projects.pluck(:id))
- project_ids.push(*projects.pluck(:id).uniq)
- Project.where(id: project_ids)
- end
- end
-
- def owned_projects
- @owned_projects ||= begin
- Project.where(namespace_id: owned_groups.pluck(:id).push(namespace.id)).joins(:namespace)
- end
- end
-
- # Team membership in authorized projects
- def tm_in_authorized_projects
- ProjectMember.where(source_id: authorized_projects.map(&:id), user_id: self.id)
- end
-
- def is_admin?
- admin
- end
-
- def require_ssh_key?
- keys.count == 0
- end
-
- def require_password?
- password_automatically_set? && !ldap_user?
- end
-
- def can_change_username?
- gitlab_config.username_changing_enabled
- end
-
- def can_create_project?
- projects_limit_left > 0
- end
-
- def can_create_group?
- can?(:create_group, nil)
- end
-
- def abilities
- Ability.abilities
- end
-
- def can_select_namespace?
- several_namespaces? || admin
- end
-
- def can?(action, subject)
- abilities.allowed?(self, action, subject)
- end
-
- def first_name
- name.split.first unless name.blank?
- end
-
- def cared_merge_requests
- MergeRequest.cared(self)
- end
-
- def projects_limit_left
- projects_limit - personal_projects.count
- end
-
- def projects_limit_percent
- return 100 if projects_limit.zero?
- (personal_projects.count.to_f / projects_limit) * 100
- end
-
- def recent_push(project_id = nil)
- # Get push events not earlier than 2 hours ago
- events = recent_events.code_push.where("created_at > ?", Time.now - 2.hours)
- events = events.where(project_id: project_id) if project_id
-
- # Take only latest one
- events = events.recent.limit(1).first
- end
-
- def projects_sorted_by_activity
- authorized_projects.sorted_by_activity
- end
-
- def several_namespaces?
- owned_groups.any? || masters_groups.any?
- end
-
- def namespace_id
- namespace.try :id
- end
-
- def name_with_username
- "#{name} (#{username})"
- end
-
- def tm_of(project)
- project.project_member_by_id(self.id)
- end
-
- def already_forked?(project)
- !!fork_of(project)
- end
-
- def fork_of(project)
- links = ForkedProjectLink.where(forked_from_project_id: project, forked_to_project_id: personal_projects)
-
- if links.any?
- links.first.forked_to_project
- else
- nil
- end
- end
-
- def ldap_user?
- identities.exists?(["provider LIKE ? AND extern_uid IS NOT NULL", "ldap%"])
- end
-
- def ldap_identity
- @ldap_identity ||= identities.find_by(["provider LIKE ?", "ldap%"])
- end
-
- def project_deploy_keys
- DeployKey.in_projects(self.authorized_projects.pluck(:id))
- end
-
- def accessible_deploy_keys
- @accessible_deploy_keys ||= begin
- key_ids = project_deploy_keys.pluck(:id)
- key_ids.push(*DeployKey.are_public.pluck(:id))
- DeployKey.where(id: key_ids)
- end
- end
-
- def created_by
- User.find_by(id: created_by_id) if created_by_id
- end
-
- def sanitize_attrs
- %w(name username skype linkedin twitter bio).each do |attr|
- value = self.send(attr)
- self.send("#{attr}=", Sanitize.clean(value)) if value.present?
- end
- end
-
- def set_notification_email
- if self.notification_email.blank? || !self.all_emails.include?(self.notification_email)
- self.notification_email = self.email
- end
- end
-
- def set_public_email
- if self.public_email.blank? || !self.all_emails.include?(self.public_email)
- self.public_email = ''
- end
- end
-
- def set_projects_limit
- connection_default_value_defined = new_record? && !projects_limit_changed?
- return unless self.projects_limit.nil? || connection_default_value_defined
-
- self.projects_limit = current_application_settings.default_projects_limit
- end
-
- def requires_ldap_check?
- if !Gitlab.config.ldap.enabled
- false
- elsif 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]
- end
- end
-
- def with_defaults
- User.defaults.each do |k, v|
- self.send("#{k}=", v)
- end
-
- self
- end
-
- def can_leave_project?(project)
- project.namespace != namespace &&
- project.project_member(self)
- end
-
- # Reset project events cache related to this user
- #
- # Since we do cache @event we need to reset cache in special cases:
- # * when the user changes their avatar
- # Events cache stored like events/23-20130109142513.
- # The cache key includes updated_at timestamp.
- # Thus it will automatically generate a new fragment
- # when the event is updated because the key changes.
- def reset_events_cache
- Event.where(author_id: self.id).
- order('id DESC').limit(1000).
- update_all(updated_at: Time.now)
- end
-
- def full_website_url
- return "http://#{website_url}" if website_url !~ /\Ahttps?:\/\//
-
- website_url
- end
-
- def short_website_url
- website_url.sub(/\Ahttps?:\/\//, '')
- end
-
- def all_ssh_keys
- keys.map(&:key)
- end
-
- def temp_oauth_email?
- email.start_with?('temp-email-for-oauth')
- end
-
- def public_profile?
- authorized_projects.public_only.any?
- end
-
- def avatar_url(size = nil)
- if avatar.present?
- [gitlab_config.url, avatar.url].join
- else
- GravatarService.new.execute(email, size)
- end
- end
-
- def all_emails
- [self.email, *self.emails.map(&:email)]
- end
-
- def hook_attrs
- {
- name: name,
- username: username,
- avatar_url: avatar_url
- }
- end
-
- def ensure_namespace_correct
- # Ensure user has namespace
- self.create_namespace!(path: self.username, name: self.username) unless self.namespace
-
- if self.username_changed?
- self.namespace.update_attributes(path: self.username, name: self.username)
- end
- end
-
- def post_create_hook
- log_info("User \"#{self.name}\" (#{self.email}) was created")
- notification_service.new_user(self, @reset_token) if self.created_by_id
- system_hook_service.execute_hooks_for(self, :create)
- end
-
- def post_destroy_hook
- log_info("User \"#{self.name}\" (#{self.email}) was removed")
- system_hook_service.execute_hooks_for(self, :destroy)
- end
-
- def notification_service
- NotificationService.new
- end
-
- def log_info(message)
- Gitlab::AppLogger.info message
- end
-
- def system_hook_service
- SystemHooksService.new
- end
-
- def starred?(project)
- starred_projects.exists?(project)
- end
-
- def toggle_star(project)
- user_star_project = users_star_projects.
- where(project: project, user: self).take
- if user_star_project
- user_star_project.destroy
- else
- UsersStarProject.create!(project: project, user: self)
- end
- end
-
- def manageable_namespaces
- @manageable_namespaces ||=
- begin
- namespaces = []
- namespaces << namespace
- namespaces += owned_groups
- namespaces += masters_groups
- end
- end
-
- def oauth_authorized_tokens
- Doorkeeper::AccessToken.where(resource_owner_id: self.id, revoked_at: nil)
- end
-
- def contributed_projects_ids
- Event.contributions.where(author_id: self).
- where("created_at > ?", Time.now - 1.year).
- reorder(project_id: :desc).
- select(:project_id).
- uniq.map(&:project_id)
- end
-end
diff --git a/app/models/users_star_project.rb b/app/models/users_star_project.rb
deleted file mode 100644
index 3d49cb05949..00000000000
--- a/app/models/users_star_project.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# == Schema Information
-#
-# Table name: users_star_projects
-#
-# id :integer not null, primary key
-# project_id :integer not null
-# user_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-#
-
-class UsersStarProject < ActiveRecord::Base
- belongs_to :project, counter_cache: :star_count
- belongs_to :user
-
- validates :user, presence: true
- validates :user_id, uniqueness: { scope: [:project_id] }
- validates :project, presence: true
-end
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
deleted file mode 100644
index e9413c34bae..00000000000
--- a/app/models/wiki_page.rb
+++ /dev/null
@@ -1,201 +0,0 @@
-class WikiPage
- include ActiveModel::Validations
- include ActiveModel::Conversion
- include StaticModel
- extend ActiveModel::Naming
-
- def self.primary_key
- 'slug'
- end
-
- def self.model_name
- ActiveModel::Name.new(self, nil, 'wiki')
- end
-
- def to_key
- [:slug]
- end
-
- validates :title, presence: true
- validates :content, presence: true
-
- # The Gitlab ProjectWiki instance.
- attr_reader :wiki
-
- # The raw Gollum::Page instance.
- attr_reader :page
-
- # The attributes Hash used for storing and validating
- # new Page values before writing to the Gollum repository.
- attr_accessor :attributes
-
- def initialize(wiki, page = nil, persisted = false)
- @wiki = wiki
- @page = page
- @persisted = persisted
- @attributes = {}.with_indifferent_access
-
- set_attributes if persisted?
- end
-
- # The escaped URL path of this page.
- def slug
- @attributes[:slug]
- end
-
- alias_method :to_param, :slug
-
- # The formatted title of this page.
- def title
- if @attributes[:title]
- @attributes[:title].gsub(/-+/, ' ')
- else
- ""
- end
- end
-
- # Sets the title of this page.
- def title=(new_title)
- @attributes[:title] = new_title
- end
-
- # The raw content of this page.
- def content
- @attributes[:content] ||= if @page
- @page.raw_data
- end
- end
-
- # The processed/formatted content of this page.
- def formatted_content
- @attributes[:formatted_content] ||= if @page
- @page.formatted_data
- end
- end
-
- # The markup format for the page.
- def format
- @attributes[:format] || :markdown
- end
-
- # The commit message for this page version.
- def message
- version.try(:message)
- end
-
- # The Gitlab Commit instance for this page.
- def version
- return nil unless persisted?
-
- @version ||= @page.version
- end
-
- # Returns an array of Gitlab Commit instances.
- def versions
- return [] unless persisted?
-
- @page.versions
- end
-
- def commit
- versions.first
- end
-
- # Returns the Date that this latest version was
- # created on.
- def created_at
- @page.version.date
- end
-
- # Returns boolean True or False if this instance
- # is an old version of the page.
- def historical?
- @page.historical?
- end
-
- # Returns boolean True or False if this instance
- # has been fully saved to disk or not.
- def persisted?
- @persisted == true
- end
-
- # Creates a new Wiki Page.
- #
- # attr - Hash of attributes to set on the new page.
- # :title - The title for the new page.
- # :content - The raw markup content.
- # :format - Optional symbol representing the
- # content format. Can be any type
- # listed in the ProjectWiki::MARKUPS
- # Hash.
- # :message - Optional commit message to set on
- # the new page.
- #
- # Returns the String SHA1 of the newly created page
- # or False if the save was unsuccessful.
- def create(attr = {})
- @attributes.merge!(attr)
-
- save :create_page, title, content, format, message
- end
-
- # Updates an existing Wiki Page, creating a new version.
- #
- # new_content - The raw markup content to replace the existing.
- # format - Optional symbol representing the content format.
- # See ProjectWiki::MARKUPS Hash for available formats.
- # message - Optional commit message to set on the new version.
- #
- # Returns the String SHA1 of the newly created page
- # or False if the save was unsuccessful.
- def update(new_content = "", format = :markdown, message = nil)
- @attributes[:content] = new_content
- @attributes[:format] = format
-
- save :update_page, @page, content, format, message
- end
-
- # Destroys the Wiki Page.
- #
- # Returns boolean True or False.
- def delete
- if wiki.delete_page(@page)
- true
- else
- false
- end
- end
-
- private
-
- def set_attributes
- attributes[:slug] = @page.escaped_url_path
- attributes[:title] = @page.title
- attributes[:format] = @page.format
- end
-
- def save(method, *args)
- project_wiki = wiki
- if valid? && project_wiki.send(method, *args)
-
- page_details = if method == :update_page
- # Use url_path instead of path to omit format extension
- @page.url_path
- else
- title
- end
-
- page_title, page_dir = project_wiki.page_title_and_dir(page_details)
- gollum_wiki = project_wiki.wiki
- @page = gollum_wiki.paged(page_title, page_dir)
-
- set_attributes
-
- @persisted = true
- else
- errors.add(:base, project_wiki.error_message) if project_wiki.error_message
- @persisted = false
- end
- @persisted
- end
-end