From 70623cd423b0c7e26e56422bf25c413d9921ee88 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 2 Mar 2016 12:18:43 +0100 Subject: fix token issue - timing attack --- app/models/project.rb | 4 ++-- app/models/project_services/ci_service.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index 6f5d592755a..6c9377448e2 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -889,13 +889,13 @@ class Project < ActiveRecord::Base end def valid_runners_token? token - self.runners_token && self.runners_token == token + self.runners_token && ActiveSupport::SecurityUtils.secure_compare(token, self.runners_token) end # TODO (ayufan): For now we use runners_token (backward compatibility) # In 8.4 every build will have its own individual token valid for time of build def valid_build_token? token - self.builds_enabled? && self.runners_token && self.runners_token == token + self.builds_enabled? && self.runners_token && ActiveSupport::SecurityUtils.secure_compare(token, self.runners_token) end def build_coverage_enabled? diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb index e10b5529b42..f328deda354 100644 --- a/app/models/project_services/ci_service.rb +++ b/app/models/project_services/ci_service.rb @@ -26,7 +26,7 @@ class CiService < Service default_value_for :category, 'ci' def valid_token?(token) - self.respond_to?(:token) && self.token.present? && self.token == token + self.respond_to?(:token) && self.token.present? && ActiveSupport::SecurityUtils.secure_compare(token, self.token) end def supported_events -- cgit v1.2.1 From fc90d9e5896cdcccedb697fd4536f126d10f3f8e Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 3 Mar 2016 17:59:47 +0100 Subject: Tell clients/proxies to cache raw blob requests --- app/models/project.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index 148eab692ff..aba48f87be3 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -56,6 +56,7 @@ class Project < ActiveRecord::Base extend Gitlab::ConfigHelper UNKNOWN_IMPORT_URL = 'http://unknown.git' + AVATAR_BRANCH = 'master' default_value_for :archived, false default_value_for :visibility_level, gitlab_config_features.visibility_level @@ -544,9 +545,9 @@ class Project < ActiveRecord::Base end def avatar_in_git - @avatar_file ||= 'logo.png' if repository.blob_at_branch('master', 'logo.png') - @avatar_file ||= 'logo.jpg' if repository.blob_at_branch('master', 'logo.jpg') - @avatar_file ||= 'logo.gif' if repository.blob_at_branch('master', 'logo.gif') + @avatar_file ||= 'logo.png' if repository.blob_at_branch(AVATAR_BRANCH, 'logo.png') + @avatar_file ||= 'logo.jpg' if repository.blob_at_branch(AVATAR_BRANCH, 'logo.jpg') + @avatar_file ||= 'logo.gif' if repository.blob_at_branch(AVATAR_BRANCH, 'logo.gif') @avatar_file end -- cgit v1.2.1 From 97093a52984f1f4682b5d3432f7666f3c806c4ca Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 4 Mar 2016 15:17:12 +0100 Subject: Show at most 100 commits in the web UI When rendering 1 commit takes over 5ms (on my laptop: around 9ms), it saves seconds in rendering time to show 100 instead of 500 commits. --- app/models/merge_request_diff.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/models') diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index df08d3a6dfb..33884118595 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -17,7 +17,7 @@ class MergeRequestDiff < ActiveRecord::Base include Sortable # Prevent store of diff if commits amount more then 500 - COMMITS_SAFE_SIZE = 500 + COMMITS_SAFE_SIZE = 100 belongs_to :merge_request -- cgit v1.2.1 From a056dfa9a077def4c3ffb958d3f86f7c9d7c2096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Mon, 22 Feb 2016 19:08:00 -0500 Subject: Refactor GlobalMilestone queries. Make methods return ActiveRecord Relations instead of Arrays. --- app/models/concerns/issuable.rb | 1 + app/models/global_milestone.rb | 26 +++++++++++++------------- app/models/merge_request.rb | 1 - app/models/project.rb | 1 + 4 files changed, 15 insertions(+), 14 deletions(-) (limited to 'app/models') diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 286d6655861..a3c4a3d2776 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -29,6 +29,7 @@ module Issuable scope :assigned, -> { where("assignee_id IS NOT NULL") } scope :unassigned, -> { where("assignee_id IS NULL") } scope :of_projects, ->(ids) { where(project_id: ids) } + scope :of_milestones, ->(ids) { where(milestone_id: ids) } scope :opened, -> { with_state(:opened, :reopened) } scope :only_opened, -> { with_state(:opened) } scope :only_reopened, -> { with_state(:reopened) } diff --git a/app/models/global_milestone.rb b/app/models/global_milestone.rb index 7ee276255a0..e4dd90b631e 100644 --- a/app/models/global_milestone.rb +++ b/app/models/global_milestone.rb @@ -28,27 +28,27 @@ class GlobalMilestone end def projects - milestones.map { |milestone| milestone.project } + @projects ||= Project.for_milestones(milestones.map(&:id)) end - def issue_count - milestones.map { |milestone| milestone.issues.count }.sum + def issues_count + issues.count end def merge_requests_count - milestones.map { |milestone| milestone.merge_requests.count }.sum + merge_requests.count end def open_items_count - milestones.map { |milestone| milestone.open_items_count }.sum + opened_issues.count + opened_merge_requests.count end def closed_items_count - milestones.map { |milestone| milestone.closed_items_count }.sum + closed_issues.count + closed_merge_requests.count end def total_items_count - milestones.map { |milestone| milestone.total_items_count }.sum + issues_count + merge_requests_count end def percent_complete @@ -76,11 +76,11 @@ class GlobalMilestone end def issues - @issues ||= milestones.map(&:issues).flatten.group_by(&:state) + @issues ||= Issue.of_milestones(milestones.map(&:id)) end def merge_requests - @merge_requests ||= milestones.map(&:merge_requests).flatten.group_by(&:state) + @merge_requests ||= MergeRequest.of_milestones(milestones.map(&:id)) end def participants @@ -88,19 +88,19 @@ class GlobalMilestone end def opened_issues - issues.values_at("opened", "reopened").compact.flatten + issues.opened end def closed_issues - issues['closed'] + issues.closed end def opened_merge_requests - merge_requests.values_at("opened", "reopened").compact.flatten + merge_requests.opened end def closed_merge_requests - merge_requests.values_at("closed", "merged", "locked").compact.flatten + merge_requests.with_states(:closed, :merged, :locked) end def complete? diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 025b522cf66..f575494e2bf 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -139,7 +139,6 @@ class MergeRequest < ActiveRecord::Base scope :of_projects, ->(ids) { where(target_project_id: ids) } scope :opened, -> { with_states(:opened, :reopened) } scope :merged, -> { with_state(:merged) } - scope :closed, -> { with_state(:closed) } scope :closed_and_merged, -> { with_states(:closed, :merged) } scope :join_project, -> { joins(:target_project) } diff --git a/app/models/project.rb b/app/models/project.rb index 148eab692ff..3a28d5d7fee 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -215,6 +215,7 @@ class Project < ActiveRecord::Base scope :public_only, -> { where(visibility_level: Project::PUBLIC) } scope :public_and_internal_only, -> { where(visibility_level: Project.public_and_internal_levels) } scope :non_archived, -> { where(archived: false) } + scope :for_milestones, ->(ids) { joins(:milestones).where('milestones.id' => ids) } state_machine :import_status, initial: :none do event :import_start do -- cgit v1.2.1 From e805becfe838b6ac351a15a01d58e355a0b1763b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Tue, 23 Feb 2016 12:15:19 -0500 Subject: Eager load Issues/MRs project for Milestone. With this change we avoid doing N+1 queries when viewing Milestone's Issues/MRs from a Group context. --- app/models/global_milestone.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/models') diff --git a/app/models/global_milestone.rb b/app/models/global_milestone.rb index e4dd90b631e..40193a6f050 100644 --- a/app/models/global_milestone.rb +++ b/app/models/global_milestone.rb @@ -76,11 +76,11 @@ class GlobalMilestone end def issues - @issues ||= Issue.of_milestones(milestones.map(&:id)) + @issues ||= Issue.of_milestones(milestones.map(&:id)).includes(:project) end def merge_requests - @merge_requests ||= MergeRequest.of_milestones(milestones.map(&:id)) + @merge_requests ||= MergeRequest.of_milestones(milestones.map(&:id)).includes(:target_project) end def participants -- cgit v1.2.1 From ed4808555877c668366d98a5408937712ad10d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Tue, 23 Feb 2016 16:22:36 -0500 Subject: Refactor Merge Requests tab into a custom partial * Add Labels tab to Groups * Add decorator for label so it's aware of Milestones. --- app/models/global_milestone.rb | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'app/models') diff --git a/app/models/global_milestone.rb b/app/models/global_milestone.rb index 40193a6f050..e13aaf16732 100644 --- a/app/models/global_milestone.rb +++ b/app/models/global_milestone.rb @@ -87,6 +87,12 @@ class GlobalMilestone @participants ||= milestones.map(&:participants).flatten.compact.uniq end + def labels + @labels ||= milestones.map do |ms| + ms.labels.map { |label| LabelWithMilestone.new(label, ms) } + end.flatten.sort_by!(&:title) + end + def opened_issues issues.opened end -- cgit v1.2.1 From 836d5930332797192094ce4a3c8083e96f7e8c53 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sat, 5 Mar 2016 17:17:49 -0500 Subject: Remove `Snippet#expires_at` This was removed from the interface in https://github.com/gitlabhq/gitlabhq/pull/6027 but its implementation lingered around for two years. --- app/models/personal_snippet.rb | 1 - app/models/project_snippet.rb | 3 --- app/models/snippet.rb | 7 ------- 3 files changed, 11 deletions(-) (limited to 'app/models') diff --git a/app/models/personal_snippet.rb b/app/models/personal_snippet.rb index 9cee3b70cb3..452f3913eef 100644 --- a/app/models/personal_snippet.rb +++ b/app/models/personal_snippet.rb @@ -10,7 +10,6 @@ # created_at :datetime # updated_at :datetime # file_name :string(255) -# expires_at :datetime # type :string(255) # visibility_level :integer default(0), not null # diff --git a/app/models/project_snippet.rb b/app/models/project_snippet.rb index 9e2c1b0e18e..1f7d85a5f3d 100644 --- a/app/models/project_snippet.rb +++ b/app/models/project_snippet.rb @@ -10,7 +10,6 @@ # created_at :datetime # updated_at :datetime # file_name :string(255) -# expires_at :datetime # type :string(255) # visibility_level :integer default(0), not null # @@ -23,6 +22,4 @@ class ProjectSnippet < Snippet # 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/snippet.rb b/app/models/snippet.rb index f876be7a4c8..dd3925c7a7d 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -10,7 +10,6 @@ # created_at :datetime # updated_at :datetime # file_name :string(255) -# expires_at :datetime # type :string(255) # visibility_level :integer default(0), not null # @@ -46,8 +45,6 @@ class Snippet < ActiveRecord::Base 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]) } participant :author, :notes @@ -111,10 +108,6 @@ class Snippet < ActiveRecord::Base nil end - def expired? - expires_at && expires_at < Time.current - end - def visibility_level_field visibility_level end -- cgit v1.2.1 From 95b06a62c0db5f8c285a1d24fa1994e10c70ff27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Sun, 6 Mar 2016 23:07:19 -0500 Subject: Updates from last code review. --- app/models/concerns/issuable.rb | 2 ++ app/models/concerns/milestoneish.rb | 25 +++++++++++++++++ app/models/global_label.rb | 7 +++-- app/models/global_milestone.rb | 53 +++---------------------------------- app/models/merge_request.rb | 1 - app/models/milestone.rb | 27 ++----------------- app/models/project.rb | 2 +- 7 files changed, 39 insertions(+), 78 deletions(-) create mode 100644 app/models/concerns/milestoneish.rb (limited to 'app/models') diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index a3c4a3d2776..27b97944e38 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -36,6 +36,8 @@ module Issuable 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') } + scope :with_label, ->(title) { joins(:labels).where(labels: { title: title }) } + scope :without_label, -> { joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{name}' AND label_links.target_id = #{table_name}.id").where(label_links: { id: nil }) } scope :join_project, -> { joins(:project) } scope :references_project, -> { references(:project) } diff --git a/app/models/concerns/milestoneish.rb b/app/models/concerns/milestoneish.rb new file mode 100644 index 00000000000..d67df7c1d9c --- /dev/null +++ b/app/models/concerns/milestoneish.rb @@ -0,0 +1,25 @@ +module Milestoneish + def closed_items_count + issues.closed.size + merge_requests.closed_and_merged.size + end + + def total_items_count + issues.size + merge_requests.size + end + + def complete? + total_items_count == closed_items_count + end + + def percent_complete + ((closed_items_count * 100) / total_items_count).abs + rescue ZeroDivisionError + 0 + end + + def remaining_days + return 0 if !due_date || expired? + + (due_date - Date.today).to_i + end +end diff --git a/app/models/global_label.rb b/app/models/global_label.rb index 0171f7d54b7..ddd4bad5c21 100644 --- a/app/models/global_label.rb +++ b/app/models/global_label.rb @@ -2,16 +2,19 @@ class GlobalLabel attr_accessor :title, :labels alias_attribute :name, :title + delegate :color, :description, to: :@first_label + def self.build_collection(labels) labels = labels.group_by(&:title) - labels.map do |title, label| - new(title, label) + labels.map do |title, labels| + new(title, labels) end end def initialize(title, labels) @title = title @labels = labels + @first_label = labels.find { |lbl| lbl.description.present? } || labels.first end end diff --git a/app/models/global_milestone.rb b/app/models/global_milestone.rb index e13aaf16732..97bd79af083 100644 --- a/app/models/global_milestone.rb +++ b/app/models/global_milestone.rb @@ -1,4 +1,6 @@ class GlobalMilestone + include Milestoneish + attr_accessor :title, :milestones alias_attribute :name, :title @@ -31,32 +33,6 @@ class GlobalMilestone @projects ||= Project.for_milestones(milestones.map(&:id)) end - def issues_count - issues.count - end - - def merge_requests_count - merge_requests.count - end - - def open_items_count - opened_issues.count + opened_merge_requests.count - end - - def closed_items_count - closed_issues.count + closed_merge_requests.count - end - - def total_items_count - issues_count + merge_requests_count - end - - def percent_complete - ((closed_items_count * 100) / total_items_count).abs - rescue ZeroDivisionError - 0 - end - def state state = milestones.map { |milestone| milestone.state } @@ -88,29 +64,8 @@ class GlobalMilestone end def labels - @labels ||= milestones.map do |ms| - ms.labels.map { |label| LabelWithMilestone.new(label, ms) } - end.flatten.sort_by!(&:title) - end - - def opened_issues - issues.opened - end - - def closed_issues - issues.closed - end - - def opened_merge_requests - merge_requests.opened - end - - def closed_merge_requests - merge_requests.with_states(:closed, :merged, :locked) - end - - def complete? - total_items_count == closed_items_count + @labels ||= GlobalLabel.build_collection(milestones.map(&:labels).flatten) + .sort_by!(&:title) end def due_date diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index f575494e2bf..0c1a47b3f6a 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -137,7 +137,6 @@ class MergeRequest < ActiveRecord::Base 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) } - scope :opened, -> { with_states(:opened, :reopened) } scope :merged, -> { with_state(:merged) } scope :closed_and_merged, -> { with_states(:closed, :merged) } diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 7dc2f909b2f..e3969f32dd6 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -24,12 +24,13 @@ class Milestone < ActiveRecord::Base include Sortable include Referable include StripAttribute + include Milestoneish belongs_to :project has_many :issues has_many :labels, -> { distinct.reorder('labels.title') }, through: :issues has_many :merge_requests - has_many :participants, through: :issues, source: :assignee + has_many :participants, -> { distinct.reorder('users.name') }, through: :issues, source: :assignee scope :active, -> { with_state(:active) } scope :closed, -> { with_state(:closed) } @@ -92,30 +93,6 @@ class Milestone < ActiveRecord::Base 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_and_merged.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 - 0 - end - - def remaining_days - return 0 if !due_date || expired? - - (due_date - Date.today).to_i - end - def expires_at if due_date if due_date.past? diff --git a/app/models/project.rb b/app/models/project.rb index 3a28d5d7fee..3235a1cee50 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -215,7 +215,7 @@ class Project < ActiveRecord::Base scope :public_only, -> { where(visibility_level: Project::PUBLIC) } scope :public_and_internal_only, -> { where(visibility_level: Project.public_and_internal_levels) } scope :non_archived, -> { where(archived: false) } - scope :for_milestones, ->(ids) { joins(:milestones).where('milestones.id' => ids) } + scope :for_milestones, ->(ids) { joins(:milestones).where('milestones.id' => ids).distinct } state_machine :import_status, initial: :none do event :import_start do -- cgit v1.2.1 From a215e2ee8ddaefbfef16669ad0bd8ccd6853e163 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 7 Mar 2016 14:11:38 +0100 Subject: Revert changes in the Project model --- app/models/project.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index aba48f87be3..148eab692ff 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -56,7 +56,6 @@ class Project < ActiveRecord::Base extend Gitlab::ConfigHelper UNKNOWN_IMPORT_URL = 'http://unknown.git' - AVATAR_BRANCH = 'master' default_value_for :archived, false default_value_for :visibility_level, gitlab_config_features.visibility_level @@ -545,9 +544,9 @@ class Project < ActiveRecord::Base end def avatar_in_git - @avatar_file ||= 'logo.png' if repository.blob_at_branch(AVATAR_BRANCH, 'logo.png') - @avatar_file ||= 'logo.jpg' if repository.blob_at_branch(AVATAR_BRANCH, 'logo.jpg') - @avatar_file ||= 'logo.gif' if repository.blob_at_branch(AVATAR_BRANCH, 'logo.gif') + @avatar_file ||= 'logo.png' if repository.blob_at_branch('master', 'logo.png') + @avatar_file ||= 'logo.jpg' if repository.blob_at_branch('master', 'logo.jpg') + @avatar_file ||= 'logo.gif' if repository.blob_at_branch('master', 'logo.gif') @avatar_file end -- cgit v1.2.1 From 41bc9c463c187396e47b4a942965de6ecddca5a1 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 7 Mar 2016 14:27:53 +0100 Subject: Refactor caching code --- app/models/blob.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'app/models') diff --git a/app/models/blob.rb b/app/models/blob.rb index 8ee9f3006b2..72e6c5fa3fd 100644 --- a/app/models/blob.rb +++ b/app/models/blob.rb @@ -1,5 +1,8 @@ # Blob is a Rails-specific wrapper around Gitlab::Git::Blob objects class Blob < SimpleDelegator + CACHE_TIME = 60 # Cache raw blobs referred to by a (mutable) ref for 1 minute + CACHE_TIME_IMMUTABLE = 3600 # Cache blobs referred to by an immutable reference for 1 hour + # Wrap a Gitlab::Git::Blob object, or return nil when given nil # # This method prevents the decorated object from evaluating to "truthy" when -- cgit v1.2.1 From 73535b80b246248e932e6a88c462bc827d510e24 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Sun, 28 Feb 2016 17:27:22 +0000 Subject: adds language names to projects list github style --- app/models/project.rb | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index 3235a1cee50..2fdd4bfbbc1 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -945,4 +945,13 @@ class Project < ActiveRecord::Base def wiki @wiki ||= ProjectWiki.new(self, self.owner) end + + def main_language + if !empty_repo? + languages = Linguist::Repository.new( + @repository.rugged, + @repository.rugged.head.target_id).languages + return languages.key(languages.values.max) + end + end end -- cgit v1.2.1 From fe934a2da2be153d7346c90671103a5423b13833 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Sun, 28 Feb 2016 21:29:27 +0000 Subject: adds cache to languages list --- app/models/project.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index 2fdd4bfbbc1..3a41812f3c9 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -948,10 +948,10 @@ class Project < ActiveRecord::Base def main_language if !empty_repo? - languages = Linguist::Repository.new( - @repository.rugged, - @repository.rugged.head.target_id).languages - return languages.key(languages.values.max) + Rails.cache.fetch([self, "language"]) do + languages = Linguist::Repository.new(@repository.rugged, @repository.rugged.head.target_id).languages + languages.key(languages.values.max) + end end end end -- cgit v1.2.1 From 85de3f69558af88ad0af8716ee6fb7197b2d28df Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Mon, 29 Feb 2016 10:15:53 +0000 Subject: changes if ! to unless and now asks for language instead of languages --- app/models/project.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index 3a41812f3c9..92aef8a60f4 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -947,10 +947,11 @@ class Project < ActiveRecord::Base end def main_language - if !empty_repo? + unless empty_repo? Rails.cache.fetch([self, "language"]) do - languages = Linguist::Repository.new(@repository.rugged, @repository.rugged.head.target_id).languages - languages.key(languages.values.max) + Linguist::Repository.new( + @repository.rugged, + @repository.rugged.head.target_id).language end end end -- cgit v1.2.1 From d9e646a796795de43b23a27b74289f44255810e3 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Mon, 29 Feb 2016 16:50:59 +0000 Subject: moves method to repository model --- app/models/project.rb | 8 +------- app/models/repository.rb | 12 ++++++++++++ 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index 92aef8a60f4..3b565ef809a 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -947,12 +947,6 @@ class Project < ActiveRecord::Base end def main_language - unless empty_repo? - Rails.cache.fetch([self, "language"]) do - Linguist::Repository.new( - @repository.rugged, - @repository.rugged.head.target_id).language - end - end + @main_language = repository.main_language end end diff --git a/app/models/repository.rb b/app/models/repository.rb index c135ab61f6a..f911611acab 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -812,6 +812,18 @@ class Repository raw_repository.ls_files(actual_ref) end + def main_language + return @main_language unless @main_language.nil? + + unless empty? + @main_language = cache.fetch(:main_language) do + Linguist::Repository.new( + rugged, + rugged.head.target_id).language + end + end + end + private def cache -- cgit v1.2.1 From a14b98f858cadf60c67db4cbd23aa10ae0d5213b Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Tue, 1 Mar 2016 01:55:36 +0000 Subject: implements project languages saving them onto the database --- app/models/.project.rb.swo | Bin 0 -> 49152 bytes app/models/project.rb | 12 ++++++++++++ 2 files changed, 12 insertions(+) create mode 100644 app/models/.project.rb.swo (limited to 'app/models') diff --git a/app/models/.project.rb.swo b/app/models/.project.rb.swo new file mode 100644 index 00000000000..5d264ccfaaa Binary files /dev/null and b/app/models/.project.rb.swo differ diff --git a/app/models/project.rb b/app/models/project.rb index 3b565ef809a..4d2ff11cc11 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -86,6 +86,18 @@ class Project < ActiveRecord::Base end end + # checks if the language main language of the project changed + before_save :check_main_language + def check_main_language + if !repository.empty? && self.changed? + language = Linguist::Repository.new( + repository.rugged, + repository.rugged.head.target_id).language + + self.main_language = language + end + end + ActsAsTaggableOn.strict_case_match = true acts_as_taggable_on :tags -- cgit v1.2.1 From dc31aff3da6a2d576e0bd99249911c9373e56d98 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Tue, 1 Mar 2016 01:58:02 +0000 Subject: removes unused methods that I forgot --- app/models/project.rb | 4 ---- app/models/repository.rb | 12 ------------ 2 files changed, 16 deletions(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index 4d2ff11cc11..3d3fd6f76a2 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -957,8 +957,4 @@ class Project < ActiveRecord::Base def wiki @wiki ||= ProjectWiki.new(self, self.owner) end - - def main_language - @main_language = repository.main_language - end end diff --git a/app/models/repository.rb b/app/models/repository.rb index f911611acab..c135ab61f6a 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -812,18 +812,6 @@ class Repository raw_repository.ls_files(actual_ref) end - def main_language - return @main_language unless @main_language.nil? - - unless empty? - @main_language = cache.fetch(:main_language) do - Linguist::Repository.new( - rugged, - rugged.head.target_id).language - end - end - end - private def cache -- cgit v1.2.1 From c2c5572e22d8e03b111859f3cf143181edd8c20f Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Tue, 1 Mar 2016 11:42:47 +0000 Subject: adds swp and swo to gitignore and improves migration for project main_language --- app/models/.project.rb.swo | Bin 49152 -> 0 bytes app/models/project.rb | 18 ++++++++++++------ app/models/repository.rb | 6 ++++++ 3 files changed, 18 insertions(+), 6 deletions(-) delete mode 100644 app/models/.project.rb.swo (limited to 'app/models') diff --git a/app/models/.project.rb.swo b/app/models/.project.rb.swo deleted file mode 100644 index 5d264ccfaaa..00000000000 Binary files a/app/models/.project.rb.swo and /dev/null differ diff --git a/app/models/project.rb b/app/models/project.rb index 3d3fd6f76a2..9400d8a17af 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -89,12 +89,8 @@ class Project < ActiveRecord::Base # checks if the language main language of the project changed before_save :check_main_language def check_main_language - if !repository.empty? && self.changed? - language = Linguist::Repository.new( - repository.rugged, - repository.rugged.head.target_id).language - - self.main_language = language + if commit_count.changed? + self.main_language = repository.main_language end end @@ -957,4 +953,14 @@ class Project < ActiveRecord::Base def wiki @wiki ||= ProjectWiki.new(self, self.owner) end + + def main_language + language = read_attributes(:main_language) + + return language if language + + update_attributes(main_language: repository.main_language) + + read_attributes(:main_language) + end end diff --git a/app/models/repository.rb b/app/models/repository.rb index c135ab61f6a..ff48f993d42 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -812,6 +812,12 @@ class Repository raw_repository.ls_files(actual_ref) end + def main_language + unless empty? + Linguist::Repository.new(rugged, rugged.head.target_id).language + end + end + private def cache -- cgit v1.2.1 From d72e6ad2a176d5d73cbefbb971ed34a75f327923 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Tue, 1 Mar 2016 19:45:55 +0000 Subject: adds tests and fixes some broken code to main language mr --- app/models/project.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index 9400d8a17af..470fa2194de 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -89,7 +89,7 @@ class Project < ActiveRecord::Base # checks if the language main language of the project changed before_save :check_main_language def check_main_language - if commit_count.changed? + if self.commit_count_changed? self.main_language = repository.main_language end end @@ -955,12 +955,12 @@ class Project < ActiveRecord::Base end def main_language - language = read_attributes(:main_language) + language = read_attribute(:main_language) return language if language update_attributes(main_language: repository.main_language) - read_attributes(:main_language) + read_attribute(:main_language) end end -- cgit v1.2.1 From 93fb4ce2c5f9c7db40a0ab698cd4812a5cb7373b Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Wed, 2 Mar 2016 13:01:00 +0000 Subject: removes redundant self --- app/models/project.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index 470fa2194de..a8731514b9f 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -89,7 +89,7 @@ class Project < ActiveRecord::Base # checks if the language main language of the project changed before_save :check_main_language def check_main_language - if self.commit_count_changed? + if commit_count_changed? self.main_language = repository.main_language end end -- cgit v1.2.1 From 68d6f5bce19bac95e63de165f3e9597273ef97b1 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Wed, 2 Mar 2016 13:06:21 +0000 Subject: fixes typo --- app/models/project.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index a8731514b9f..34787f5fa3c 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -90,7 +90,7 @@ class Project < ActiveRecord::Base before_save :check_main_language def check_main_language if commit_count_changed? - self.main_language = repository.main_language + main_language = repository.main_language end end -- cgit v1.2.1 From 337cb45226cfc4955fdd79a15088522a91058b3c Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Wed, 2 Mar 2016 18:21:53 +0000 Subject: removes automatic setting of main_language to project for it to set a main language you have now to make a commit to the project --- app/models/project.rb | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index 34787f5fa3c..137fa42a9b9 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -953,14 +953,4 @@ class Project < ActiveRecord::Base def wiki @wiki ||= ProjectWiki.new(self, self.owner) end - - def main_language - language = read_attribute(:main_language) - - return language if language - - update_attributes(main_language: repository.main_language) - - read_attribute(:main_language) - end end -- cgit v1.2.1 From 96c02551070a5f2d90beea7068fc6fddbf1498e8 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Thu, 3 Mar 2016 10:51:48 +0000 Subject: moves the main_language update logic to git push service --- app/models/project.rb | 8 -------- 1 file changed, 8 deletions(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index 137fa42a9b9..3235a1cee50 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -86,14 +86,6 @@ class Project < ActiveRecord::Base end end - # checks if the language main language of the project changed - before_save :check_main_language - def check_main_language - if commit_count_changed? - main_language = repository.main_language - end - end - ActsAsTaggableOn.strict_case_match = true acts_as_taggable_on :tags -- cgit v1.2.1 From fc610c182e73cdff2534bef91ce0385b06befacf Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 8 Mar 2016 15:57:45 +0100 Subject: add SHA256 to secure_compare --- app/models/project.rb | 4 ++-- app/models/project_services/ci_service.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index c0f2ab91fa4..3451779e18d 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -908,13 +908,13 @@ class Project < ActiveRecord::Base end def valid_runners_token? token - self.runners_token && ActiveSupport::SecurityUtils.secure_compare(token, self.runners_token) + self.runners_token && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.runners_token) end # TODO (ayufan): For now we use runners_token (backward compatibility) # In 8.4 every build will have its own individual token valid for time of build def valid_build_token? token - self.builds_enabled? && self.runners_token && ActiveSupport::SecurityUtils.secure_compare(token, self.runners_token) + self.builds_enabled? && self.runners_token && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.runners_token) end def build_coverage_enabled? diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb index f328deda354..d9f0849d147 100644 --- a/app/models/project_services/ci_service.rb +++ b/app/models/project_services/ci_service.rb @@ -26,7 +26,7 @@ class CiService < Service default_value_for :category, 'ci' def valid_token?(token) - self.respond_to?(:token) && self.token.present? && ActiveSupport::SecurityUtils.secure_compare(token, self.token) + self.respond_to?(:token) && self.token.present? && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.token) end def supported_events -- cgit v1.2.1 From cb5a5ba09588af866aed595d960755bf4ced4483 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 8 Mar 2016 17:38:23 +0100 Subject: Cache & flush tag/branch counts The methods used for this are Repository#tag_count and Repository#branch_count which cache their output in Redis as well as memoizing it in an instance variable. Both methods have a corresponding methods/hooks to flush the caches at the right time. --- app/models/repository.rb | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) (limited to 'app/models') diff --git a/app/models/repository.rb b/app/models/repository.rb index ff48f993d42..d3ca268a659 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -160,7 +160,7 @@ class Repository end def rm_tag(tag_name) - expire_tags_cache + before_remove_tag gitlab_shell.rm_tag(path_with_namespace, tag_name) end @@ -183,6 +183,14 @@ class Repository end end + def branch_count + @branch_count ||= cache.fetch(:branch_count) { raw_repository.branch_count } + end + + def tag_count + @tag_count ||= cache.fetch(:tag_count) { raw_repository.rugged.tags.count } + end + # Return repo size in megabytes # Cached in redis def size @@ -278,6 +286,16 @@ class Repository @has_visible_content = nil end + def expire_branch_count_cache + cache.expire(:branch_count) + @branch_count = nil + end + + def expire_tag_count_cache + cache.expire(:tag_count) + @tag_count = nil + end + def rebuild_cache cache_keys.each do |key| cache.expire(key) @@ -313,9 +331,16 @@ class Repository expire_root_ref_cache end - # Runs code before creating a new tag. - def before_create_tag + # Runs code before pushing (= creating or removing) a tag. + def before_push_tag expire_cache + expire_tag_count_cache + end + + # Runs code before removing a tag. + def before_remove_tag + expire_tags_cache + expire_tag_count_cache end # Runs code after a repository has been forked/imported. @@ -331,11 +356,13 @@ class Repository # Runs code after a new branch has been created. def after_create_branch expire_has_visible_content_cache + expire_branch_count_cache end # Runs code after an existing branch has been removed. def after_remove_branch expire_has_visible_content_cache + expire_branch_count_cache end def method_missing(m, *args, &block) -- cgit v1.2.1 From 177025b5dde5ca34b05744f000a1eee64501863a Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 8 Mar 2016 17:53:00 +0100 Subject: Call the right hooks when removing branches This ensures that Repository#rm_branch calls before_remove_branch/after_remove_branch instead of just 1 random cache expiration method. --- app/models/repository.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'app/models') diff --git a/app/models/repository.rb b/app/models/repository.rb index d3ca268a659..c3ae461a016 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -144,7 +144,7 @@ class Repository end def rm_branch(user, branch_name) - expire_branches_cache + before_remove_branch branch = find_branch(branch_name) oldrev = branch.try(:target) @@ -155,7 +155,7 @@ class Repository rugged.branches.delete(branch_name) end - expire_branches_cache + after_remove_branch true end @@ -359,10 +359,16 @@ class Repository expire_branch_count_cache end + # Runs code before removing an existing branch. + def before_remove_branch + expire_branches_cache + end + # Runs code after an existing branch has been removed. def after_remove_branch expire_has_visible_content_cache expire_branch_count_cache + expire_branches_cache end def method_missing(m, *args, &block) -- cgit v1.2.1 From 4ec035b48869d8364f6ae8cb14c8486075786757 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 8 Mar 2016 18:01:16 +0100 Subject: Call the right hooks in Repository#add_tag This ensures Repository#add_tag calls Repository#before_push_tag instead of just 1 random cache expiration method. --- app/models/repository.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app/models') diff --git a/app/models/repository.rb b/app/models/repository.rb index c3ae461a016..c0730b34316 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -138,7 +138,7 @@ class Repository end def add_tag(tag_name, ref, message = nil) - expire_tags_cache + before_push_tag gitlab_shell.add_tag(path_with_namespace, tag_name, ref, message) end @@ -334,6 +334,7 @@ class Repository # Runs code before pushing (= creating or removing) a tag. def before_push_tag expire_cache + expire_tags_cache expire_tag_count_cache end -- cgit v1.2.1 From 590e1b4b21f2a39bf573800392b04859b563f3e5 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 8 Mar 2016 18:04:00 +0100 Subject: Call after_create_branch in Repository#add_branch This ensures the right caches are flushed when adding a branch via the UI, instead of only flushing this one random cache. --- app/models/repository.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app/models') diff --git a/app/models/repository.rb b/app/models/repository.rb index c0730b34316..6441cd87e87 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -133,7 +133,7 @@ class Repository rugged.branches.create(branch_name, target) end - expire_branches_cache + after_create_branch find_branch(branch_name) end @@ -356,6 +356,7 @@ class Repository # Runs code after a new branch has been created. def after_create_branch + expire_branches_cache expire_has_visible_content_cache expire_branch_count_cache end -- cgit v1.2.1 From 9e342fb00a50cbb483013acd4644bd31c440f99a Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 9 Mar 2016 11:06:58 -0300 Subject: Destroy all related todos when removing a project --- app/models/project.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index 3235a1cee50..426464dee81 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -151,6 +151,7 @@ class Project < ActiveRecord::Base has_many :releases, dependent: :destroy has_many :lfs_objects_projects, dependent: :destroy has_many :lfs_objects, through: :lfs_objects_projects + has_many :todos, dependent: :destroy has_one :import_data, dependent: :destroy, class_name: "ProjectImportData" -- cgit v1.2.1 From 53719ecb80b757a2096e55cd3da995ac9db8d3b8 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 9 Mar 2016 15:38:07 +0100 Subject: Handle permissions for ExternalIssue instances This fixes the remainder of the GitPushService specs. --- app/models/ability.rb | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'app/models') diff --git a/app/models/ability.rb b/app/models/ability.rb index f34554d557c..fe9e0aab717 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -9,6 +9,7 @@ class Ability when CommitStatus then commit_status_abilities(user, subject) when Project then project_abilities(user, subject) when Issue then issue_abilities(user, subject) + when ExternalIssue then external_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) @@ -424,6 +425,10 @@ class Ability end end + def external_issue_abilities(user, subject) + project_abilities(user, subject.project) + end + private def named_abilities(name) -- cgit v1.2.1 From e7df3f51c9cc246279da36c9488b4c591f30b866 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 10 Mar 2016 12:37:14 +0100 Subject: Move method to User --- app/models/user.rb | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'app/models') diff --git a/app/models/user.rb b/app/models/user.rb index 3098d49d58a..505a547d8ec 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -612,6 +612,13 @@ class User < ActiveRecord::Base end end + def try_obtain_ldap_lease + # After obtaining this lease LDAP checks will be blocked for 600 seconds + # (10 minutes) for this user. + lease = Gitlab::ExclusiveLease.new("user_ldap_check:#{id}", timeout: 600) + lease.try_obtain + end + def solo_owned_groups @solo_owned_groups ||= owned_groups.select do |group| group.owners == [self] -- cgit v1.2.1 From f2992cf343c28736efa5b49fc6a4c3e40a9f0a8f Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 10 Mar 2016 15:32:31 +0100 Subject: Optimize Project#ci_service(s) The method Project#ci_services would load all services into memory (including _all_ their columns) and then use Enumerable#select to reduce the list. Project#ci_service in turn would further reduce this list down to just 1 Service instance. Instead of doing all this in Ruby we can just offload the work to the database, reducing the amount of time spent in these methods. These changes reduce the time of the first call to Project#ci_services from around 240 ms to around 10 ms, though the final timings will vary based on database load. Because Project#ci_service is memoized there's no further overhead introduced by using a database query. Fixes gitlab-org/gitlab-ce#14186 --- app/models/project.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index 426464dee81..65829bec77a 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -528,11 +528,11 @@ class Project < ActiveRecord::Base end def ci_services - services.select { |service| service.category == :ci } + services.where(category: :ci) end def ci_service - @ci_service ||= ci_services.find(&:activated?) + @ci_service ||= ci_services.reorder(nil).find_by(active: true) end def jira_tracker? -- cgit v1.2.1 From 135659a75135b47563b349d13a9846b9b017af15 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 1 Mar 2016 12:02:06 +0100 Subject: Use ILIKE/LIKE + UNION in Project.search This chance is broken up in two steps: 1. Use ILIKE on PostgreSQL and LIKE on MySQL, instead of using "WHERE lower(x) LIKE lower(y)" as ILIKE is significantly faster than using lower(). In many cases the use of lower() will force a slow sequence scan. 2. Instead of using 1 query that searches both projects and namespaces using a JOIN we're using 2 separate queries that are UNION'd together. Using a JOIN would force a slow sequence scan, using a UNION avoids this. This method now uses Arel as Arel automatically uses ILIKE on PostgreSQL and LIKE on MySQL, removing the need to handle this manually. --- app/models/project.rb | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index 65829bec77a..2f19ec9ba89 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -266,13 +266,31 @@ class Project < ActiveRecord::Base joins(:issues, :notes, :merge_requests).order('issues.created_at, notes.created_at, merge_requests.created_at DESC') end + # Searches for a list of projects based on the query given in `query`. + # + # On PostgreSQL this method uses "ILIKE" to perform a case-insensitive + # search. On MySQL a regular "LIKE" is used as it's already + # case-insensitive. + # + # query - The search query as a String. def search(query) - joins(:namespace). - where('LOWER(projects.name) LIKE :query OR - LOWER(projects.path) LIKE :query OR - LOWER(namespaces.name) LIKE :query OR - LOWER(projects.description) LIKE :query', - query: "%#{query.try(:downcase)}%") + ptable = Project.arel_table + ntable = Namespace.arel_table + pattern = "%#{query}%" + + projects = select(:id).where( + ptable[:path].matches(pattern). + or(ptable[:name].matches(pattern)). + or(ptable[:description].matches(pattern)) + ) + + namespaces = select(:id). + joins(:namespace). + where(ntable[:name].matches(pattern)) + + union = Gitlab::SQL::Union.new([projects, namespaces]) + + where("projects.id IN (#{union.to_sql})") end def search_by_visibility(level) -- cgit v1.2.1 From db615d0a7992d5118c3e9e8914064eb26970666b Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 1 Mar 2016 12:16:15 +0100 Subject: Use ILIKE in Project.search_by_title Similar to the changes made to Project.search the method Project.search_by_title now also uses Arel so it can automatically use ILIKE/LIKE instead of the lower() function. --- app/models/project.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'app/models') diff --git a/app/models/project.rb b/app/models/project.rb index 2f19ec9ba89..cb236bf41cd 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -298,7 +298,10 @@ class Project < ActiveRecord::Base end def search_by_title(query) - non_archived.where('LOWER(projects.name) LIKE :query', query: "%#{query.downcase}%") + pattern = "%#{query}%" + table = Project.arel_table + + non_archived.where(table[:name].matches(pattern)) end def find_with_namespace(id) -- cgit v1.2.1 From 1f5284e5ddf2ce9b555799f43ca73be32d9bdf67 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 1 Mar 2016 12:51:01 +0100 Subject: Use ILIKE/LIKE for searching snippets Previously this used a regular LIKE which is case-sensitive on PostgreSQL. This ensures that for both PostgreSQL and MySQL the searching is case-insensitive similar to searching for projects. --- app/models/snippet.rb | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'app/models') diff --git a/app/models/snippet.rb b/app/models/snippet.rb index dd3925c7a7d..35d05af38bf 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -113,12 +113,32 @@ class Snippet < ActiveRecord::Base end class << self + # Searches for snippets with a matching title or file name. + # + # This method uses ILIKE on PostgreSQL and LIKE on MySQL. + # + # query - The search query as a String. + # + # Returns an ActiveRecord::Relation. def search(query) - where('(title LIKE :query OR file_name LIKE :query)', query: "%#{query}%") + t = Snippet.arel_table + pattern = "%#{query}%" + + where(t[:title].matches(pattern).or(t[:file_name].matches(pattern))) end + # Searches for snippets with matching content. + # + # This method uses ILIKE on PostgreSQL and LIKE on MySQL. + # + # query - The search query as a String. + # + # Returns an ActiveRecord::Relation. def search_code(query) - where('(content LIKE :query)', query: "%#{query}%") + table = Snippet.arel_table + pattern = "%#{query}%" + + where(table[:content].matches(pattern)) end def accessible_to(user) -- cgit v1.2.1 From 508b6b46fea6b4bae9ce19c0337bafdb694edda8 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 1 Mar 2016 15:43:19 +0100 Subject: Use ILIKE/LIKE for searching notes --- app/models/note.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'app/models') diff --git a/app/models/note.rb b/app/models/note.rb index 3b20d5d22b6..76e86fdbcaa 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -105,8 +105,18 @@ class Note < ActiveRecord::Base [:discussion, type.try(:underscore), id, line_code].join("-").to_sym end + # Searches for notes matching the given query. + # + # This method uses ILIKE on PostgreSQL and LIKE on MySQL. + # + # query - The search query as a String. + # + # Returns an ActiveRecord::Relation. def search(query) - where("LOWER(note) like :query", query: "%#{query.downcase}%") + table = Note.arel_table + pattern = "%#{query}%" + + where(table[:note].matches(pattern)) end def grouped_awards -- cgit v1.2.1 From 800aa296953c4a99e16e0493d9260359ef8c8414 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 1 Mar 2016 16:08:48 +0100 Subject: Use ILIKE/LIKE for searching users --- app/models/user.rb | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'app/models') diff --git a/app/models/user.rb b/app/models/user.rb index 505a547d8ec..fc4cf92be60 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -286,8 +286,22 @@ class User < ActiveRecord::Base end end + # Searches users matching the given query. + # + # This method uses ILIKE on PostgreSQL and LIKE on MySQL. + # + # query - The search query as a String + # + # Returns an ActiveRecord::Relation. def search(query) - where("lower(name) LIKE :query OR lower(email) LIKE :query OR lower(username) LIKE :query", query: "%#{query.downcase}%") + table = User.arel_table + pattern = "%#{query}%" + + where( + table[:name].matches(pattern). + or(table[:email].matches(pattern)). + or(table[:username].matches(pattern)) + ) end def by_login(login) -- cgit v1.2.1 From ce5e831bcfd7daf1a12d488e2857d9424de091dd Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 1 Mar 2016 16:15:42 +0100 Subject: Use ILIKE/LIKE for searching groups --- app/models/group.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'app/models') diff --git a/app/models/group.rb b/app/models/group.rb index 76042b3e3fd..bfeddf8b4d2 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -33,8 +33,18 @@ class Group < Namespace after_destroy :post_destroy_hook class << self + # Searches for groups matching the given query. + # + # This method uses ILIKE on PostgreSQL and LIKE on MySQL. + # + # query - The search query as a String + # + # Returns an ActiveRecord::Relation. def search(query) - where("LOWER(namespaces.name) LIKE :query or LOWER(namespaces.path) LIKE :query", query: "%#{query.downcase}%") + table = Group.arel_table + pattern = "%#{query}%" + + where(table[:name].matches(pattern).or(table[:path].matches(pattern))) end def sort(method) -- cgit v1.2.1 From 2076bdb62e6535cd8b5027c5636610eb06af00a0 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 1 Mar 2016 16:41:18 +0100 Subject: Use ILIKE/LIKE for searching CI runners --- app/models/ci/runner.rb | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'app/models') diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index e725a6d468c..ce2750b071c 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -23,7 +23,7 @@ module Ci LAST_CONTACT_TIME = 5.minutes.ago AVAILABLE_SCOPES = ['specific', 'shared', 'active', 'paused', 'online'] - + has_many :builds, class_name: 'Ci::Build' has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject' has_many :projects, through: :runner_projects, class_name: '::Project', foreign_key: :gl_project_id @@ -46,9 +46,23 @@ module Ci acts_as_taggable + # Searches for runners matching the given query. + # + # This method uses ILIKE on PostgreSQL and LIKE on MySQL. + # + # This method performs a *partial* match on tokens, thus a query for "a" + # will match any runner where the token contains the letter "a". As a result + # you should *not* use this method for non-admin purposes as otherwise users + # might be able to query a list of all runners. + # + # query - The search query as a String + # + # Returns an ActiveRecord::Relation. def self.search(query) - where('LOWER(ci_runners.token) LIKE :query OR LOWER(ci_runners.description) like :query', - query: "%#{query.try(:downcase)}%") + t = Ci::Runner.arel_table + pattern = "%#{query}%" + + where(t[:token].matches(pattern).or(t[:description].matches(pattern))) end def set_default_values -- cgit v1.2.1 From 87e7c3e1321ac5ae26d6a23d7b16e8dadaff98d2 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 1 Mar 2016 16:59:36 +0100 Subject: Use ILIKE/LIKE for Issuable.search and full_search --- app/models/concerns/issuable.rb | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'app/models') diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 27b97944e38..3c42f582937 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -61,12 +61,29 @@ module Issuable end module ClassMethods + # Searches for records with a matching title. + # + # This method uses ILIKE on PostgreSQL and LIKE on MySQL. + # + # query - The search query as a String + # + # Returns an ActiveRecord::Relation. def search(query) - where("LOWER(title) like :query", query: "%#{query.downcase}%") + where(arel_table[:title].matches("%#{query}%")) end + # Searches for records with a matching title or description. + # + # This method uses ILIKE on PostgreSQL and LIKE on MySQL. + # + # query - The search query as a String + # + # Returns an ActiveRecord::Relation. def full_search(query) - where("LOWER(title) like :query OR LOWER(description) like :query", query: "%#{query.downcase}%") + t = arel_table + pattern = "%#{query}%" + + where(t[:title].matches(pattern).or(t[:description].matches(pattern))) end def sort(method) -- cgit v1.2.1 From 2cf7f3f410832560bf049b24fbcaa27c1e3f30c7 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 1 Mar 2016 17:05:26 +0100 Subject: Use ILIKE/LIKE for searching milestones --- app/models/milestone.rb | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'app/models') diff --git a/app/models/milestone.rb b/app/models/milestone.rb index e3969f32dd6..e3b6c552f92 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -58,9 +58,18 @@ class Milestone < ActiveRecord::Base alias_attribute :name, :title class << self + # Searches for milestones matching the given query. + # + # This method uses ILIKE on PostgreSQL and LIKE on MySQL. + # + # query - The search query as a String + # + # Returns an ActiveRecord::Relation. def search(query) - query = "%#{query}%" - where("title like ? or description like ?", query, query) + t = arel_table + pattern = "%#{query}%" + + where(t[:title].matches(pattern).or(t[:description].matches(pattern))) end end -- cgit v1.2.1 From 9e00a237161679b0d6afdefd246e0a7bf209510c Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 4 Mar 2016 11:39:00 +0100 Subject: Clean up ProjectsFinder for getting user projects We don't need the extra layer of nesting of UNION queries here (as User#authorized_projects already returns a UNION'd query). --- app/models/user.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'app/models') diff --git a/app/models/user.rb b/app/models/user.rb index fc4cf92be60..725f748faf0 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -442,6 +442,11 @@ class User < ActiveRecord::Base Project.where("projects.id IN (#{projects_union.to_sql})") end + # Returns all the project relations + def project_relations + [personal_projects, groups_projects, projects] + end + def owned_projects @owned_projects ||= Project.where('namespace_id IN (?) OR namespace_id = ?', @@ -830,9 +835,7 @@ class User < ActiveRecord::Base private def projects_union - Gitlab::SQL::Union.new([personal_projects.select(:id), - groups_projects.select(:id), - projects.select(:id)]) + Gitlab::SQL::Union.new(project_relations.map { |r| r.select(:id) }) end def ci_projects_union -- cgit v1.2.1 From d7d5937531350283f6cbd68dead5750227e6d962 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 4 Mar 2016 12:01:21 +0100 Subject: Removed arel_table receiver from search methods We can just use "arel_table" in these cases instead of "SomeClass.arel_table". --- app/models/ci/runner.rb | 2 +- app/models/group.rb | 2 +- app/models/note.rb | 2 +- app/models/project.rb | 2 +- app/models/snippet.rb | 2 +- app/models/user.rb | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'app/models') diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index ce2750b071c..90349a07594 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -59,7 +59,7 @@ module Ci # # Returns an ActiveRecord::Relation. def self.search(query) - t = Ci::Runner.arel_table + t = arel_table pattern = "%#{query}%" where(t[:token].matches(pattern).or(t[:description].matches(pattern))) diff --git a/app/models/group.rb b/app/models/group.rb index bfeddf8b4d2..afbc2922013 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -41,7 +41,7 @@ class Group < Namespace # # Returns an ActiveRecord::Relation. def search(query) - table = Group.arel_table + table = Namespace.arel_table pattern = "%#{query}%" where(table[:name].matches(pattern).or(table[:path].matches(pattern))) diff --git a/app/models/note.rb b/app/models/note.rb index 76e86fdbcaa..8b0610ff77e 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -113,7 +113,7 @@ class Note < ActiveRecord::Base # # Returns an ActiveRecord::Relation. def search(query) - table = Note.arel_table + table = arel_table pattern = "%#{query}%" where(table[:note].matches(pattern)) diff --git a/app/models/project.rb b/app/models/project.rb index cb236bf41cd..ce103398a9a 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -274,7 +274,7 @@ class Project < ActiveRecord::Base # # query - The search query as a String. def search(query) - ptable = Project.arel_table + ptable = arel_table ntable = Namespace.arel_table pattern = "%#{query}%" diff --git a/app/models/snippet.rb b/app/models/snippet.rb index 35d05af38bf..b9e835a4486 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -121,7 +121,7 @@ class Snippet < ActiveRecord::Base # # Returns an ActiveRecord::Relation. def search(query) - t = Snippet.arel_table + t = arel_table pattern = "%#{query}%" where(t[:title].matches(pattern).or(t[:file_name].matches(pattern))) diff --git a/app/models/user.rb b/app/models/user.rb index 725f748faf0..101303e1f1f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -294,7 +294,7 @@ class User < ActiveRecord::Base # # Returns an ActiveRecord::Relation. def search(query) - table = User.arel_table + table = arel_table pattern = "%#{query}%" where( -- cgit v1.2.1 From ee75c49313127f53fe60a0701f40024b897a15e8 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 4 Mar 2016 12:06:25 +0100 Subject: Make Namespace.search case-insensitive This ensures searching namespaces works exactly the same as searching for any other resource. --- app/models/namespace.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'app/models') diff --git a/app/models/namespace.rb b/app/models/namespace.rb index bdb33f37495..55842df1e2d 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -52,8 +52,18 @@ class Namespace < ActiveRecord::Base find_by("lower(path) = :path OR lower(name) = :path", path: path.downcase) end + # Searches for namespaces matching the given query. + # + # This method uses ILIKE on PostgreSQL and LIKE on MySQL. + # + # query - The search query as a String + # + # Returns an ActiveRecord::Relation def search(query) - where("name LIKE :query OR path LIKE :query", query: "%#{query}%") + t = arel_table + pattern = "%#{query}%" + + where(t[:name].matches(pattern).or(t[:path].matches(pattern))) end def clean_path(path) -- cgit v1.2.1 From 4f3fa519c627b7caf45273226ae438181dfbc392 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 7 Mar 2016 12:56:46 +0100 Subject: Use a UNION in MergeRequest.in_projects The OR condition for source_project_id/target_project_id leads to a query plan that performs rather poorly on PostgreSQL due to the use of sub-queries. Because Rails offers no easy alternative for this particular problem we're forced to using a UNION for both conditions. The resulting query performs much faster than just using an OR. --- app/models/merge_request.rb | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'app/models') diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index c1e18bb3cc5..188325045e2 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -135,7 +135,6 @@ class MergeRequest < ActiveRecord::Base 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) } scope :merged, -> { with_state(:merged) } scope :closed_and_merged, -> { with_states(:closed, :merged) } @@ -161,6 +160,24 @@ class MergeRequest < ActiveRecord::Base super("merge_requests", /(?\d+)/) end + # Returns all the merge requests from an ActiveRecord:Relation. + # + # This method uses a UNION as it usually operates on the result of + # ProjectsFinder#execute. PostgreSQL in particular doesn't always like queries + # using multiple sub-queries especially when combined with an OR statement. + # UNIONs on the other hand perform much better in these cases. + # + # relation - An ActiveRecord::Relation that returns a list of Projects. + # + # Returns an ActiveRecord::Relation. + def self.in_projects(relation) + source = where(source_project_id: relation).select(:id) + target = where(target_project_id: relation).select(:id) + union = Gitlab::SQL::Union.new([source, target]) + + where("merge_requests.id IN (#{union.to_sql})") + end + def to_reference(from_project = nil) reference = "#{self.class.reference_prefix}#{iid}" -- cgit v1.2.1 From 01f6db4f643380d143772958b22d3f318b1db3a7 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 11 Mar 2016 17:46:50 -0500 Subject: Disallow blank (non-null) values for a Note's `line_code` attribute It's unclear how these blank values got added, but GitLab.com had a few: ``` irb(main):002:0> Note.where("line_code IS NOT NULL AND line_code = ''").count => 439 ``` We've added a migration to convert any existing records to use a NULL value when blank, and updated Note to set blank values to nil before validation. --- app/models/note.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'app/models') diff --git a/app/models/note.rb b/app/models/note.rb index 8b0610ff77e..2e084b5c80c 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -44,6 +44,7 @@ class Note < ActiveRecord::Base delegate :name, :email, to: :author, prefix: true before_validation :set_award! + before_validation :clear_blank_line_code! validates :note, :project, presence: true validates :note, uniqueness: { scope: [:author, :noteable_type, :noteable_id] }, if: ->(n) { n.is_award } @@ -63,7 +64,7 @@ class Note < ActiveRecord::Base scope :nonawards, ->{ where(is_award: false) } 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 :not_inline, ->{ where(line_code: nil) } scope :system, ->{ where(system: true) } scope :user, ->{ where(system: false) } scope :common, ->{ where(noteable_type: ["", nil]) } @@ -375,6 +376,10 @@ class Note < ActiveRecord::Base private + def clear_blank_line_code! + self.line_code = nil if self.line_code.blank? + end + def awards_supported? (for_issue? || for_merge_request?) && !for_diff_line? end -- cgit v1.2.1 From 3b76b73ab178f0504e2a9be934fb13f239c81857 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Sat, 12 Mar 2016 15:44:48 +0100 Subject: Removed User#project_relations GitLab EE adds an extra relation that selects a "project_id" column instead of an "id" column, making it very hard for this method to be re-used in EE. Since using User#authorized_groups in ProjectsFinder#all_groups apparently has no performance impact we can just use it and keep everything compatible with EE. --- app/models/user.rb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'app/models') diff --git a/app/models/user.rb b/app/models/user.rb index 101303e1f1f..043bc825ade 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -442,11 +442,6 @@ class User < ActiveRecord::Base Project.where("projects.id IN (#{projects_union.to_sql})") end - # Returns all the project relations - def project_relations - [personal_projects, groups_projects, projects] - end - def owned_projects @owned_projects ||= Project.where('namespace_id IN (?) OR namespace_id = ?', @@ -835,7 +830,9 @@ class User < ActiveRecord::Base private def projects_union - Gitlab::SQL::Union.new(project_relations.map { |r| r.select(:id) }) + Gitlab::SQL::Union.new([personal_projects.select(:id), + groups_projects.select(:id), + projects.select(:id)]) end def ci_projects_union -- cgit v1.2.1 From b9d13c11dee8f555b0d80fd5b9b6a42be7721461 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Thu, 10 Mar 2016 01:49:13 +0000 Subject: implements upcoming filter in milstones --- app/models/milestone.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'app/models') diff --git a/app/models/milestone.rb b/app/models/milestone.rb index e3b6c552f92..85f7d8a7754 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -19,6 +19,7 @@ class Milestone < ActiveRecord::Base MilestoneStruct = Struct.new(:title, :name, :id) None = MilestoneStruct.new('No Milestone', 'No Milestone', 0) Any = MilestoneStruct.new('Any Milestone', '', -1) + Upcoming = MilestoneStruct.new('Upcoming', '', -2) include InternalId include Sortable -- cgit v1.2.1 From 7530827ecae0596616623d1c4f7775b08d5ada3c Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Fri, 11 Mar 2016 17:46:14 +0000 Subject: fixes issues for mr acceptance --- app/models/milestone.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'app/models') diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 85f7d8a7754..7697072d231 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -19,7 +19,7 @@ class Milestone < ActiveRecord::Base MilestoneStruct = Struct.new(:title, :name, :id) None = MilestoneStruct.new('No Milestone', 'No Milestone', 0) Any = MilestoneStruct.new('Any Milestone', '', -1) - Upcoming = MilestoneStruct.new('Upcoming', '', -2) + Upcoming = MilestoneStruct.new('Upcoming', '#upcoming', -2) include InternalId include Sortable @@ -82,6 +82,11 @@ class Milestone < ActiveRecord::Base super("milestones", /(?\d+)/) end + def self.upcoming(projects) + self.where(project_id: projects) + .where('due_date > ?', Time.now). order(due_date: :asc).first + end + def to_reference(from_project = nil) escaped_title = self.title.gsub("]", "\\]") -- cgit v1.2.1 From 0291473b98b457e85657aac29520b5f2b5b631ec Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Sat, 12 Mar 2016 16:54:05 +0000 Subject: fixes issues --- app/models/milestone.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'app/models') diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 7697072d231..374590ba0c5 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -82,9 +82,8 @@ class Milestone < ActiveRecord::Base super("milestones", /(?\d+)/) end - def self.upcoming(projects) - self.where(project_id: projects) - .where('due_date > ?', Time.now). order(due_date: :asc).first + def self.upcoming + self.where('due_date > ?', Time.now).order(due_date: :asc).first end def to_reference(from_project = nil) -- cgit v1.2.1