From 61a306aa58f7fffd652a31b85719b19d08f0fd7f Mon Sep 17 00:00:00 2001
From: Mehmet Beydogan <mehmet.beydogan@gmail.com>
Date: Fri, 18 Mar 2016 19:17:01 +0200
Subject: [PATCH] Fix functionality of due this week. Add due this month and
 overdue, remove due tomorrow to issues. Fix typos on sorting dropdown related
 to due date Remove constant array and add Structs on Issue to keep due date
 data to fill options

---
 app/finders/issuable_finder.rb               | 26 +++++++++++++----
 app/helpers/issues_helper.rb                 | 12 ++++----
 app/helpers/sorting_helper.rb                |  4 +--
 app/models/concerns/issuable.rb              |  6 ++--
 app/models/concerns/sortable.rb              |  8 +++---
 app/models/issue.rb                          |  8 ++++--
 app/views/shared/_sort_dropdown.html.haml    |  4 +--
 app/views/shared/issuable/_filter.html.haml  |  2 +-
 app/views/shared/issuable/_sidebar.html.haml |  1 -
 spec/features/issues_spec.rb                 | 30 +++++++++++++++-----
 10 files changed, 69 insertions(+), 32 deletions(-)

diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 5e08193b5cf..7613283443a 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -118,7 +118,19 @@ class IssuableFinder
   end
 
   def filter_by_no_due_date?
-    due_date? && params[:due_date] == Issue::NO_DUE_DATE[1]
+    due_date? && params[:due_date] == Issue::NoDueDate.name
+  end
+
+  def filter_by_overdue?
+    due_date? && params[:due_date] == Issue::OverDue.name
+  end
+
+  def filter_by_due_this_week?
+    due_date? && params[:due_date] == Issue::DueThisWeek.name
+  end
+
+  def filter_by_due_this_month?
+    due_date? && params[:due_date] == Issue::DueThisMonth.name
   end
 
   def labels?
@@ -295,11 +307,13 @@ class IssuableFinder
   def by_due_date(items)
     if due_date?
       if filter_by_no_due_date?
-        items = items.no_due_date
-      else
-        items = items.has_due_date
-        # Must use issues prefix to avoid ambiguous match with Milestone#due_date
-        items = items.where("issues.due_date > ? AND issues.due_date <= ?", Date.today, params[:due_date])
+        items = items.without_due_date
+      elsif filter_by_overdue?
+        items = items.overdue
+      elsif filter_by_due_this_week?
+        items = items.due_between(Date.today.beginning_of_week, Date.today.end_of_week + 1.day)
+      elsif filter_by_due_this_month?
+        items = items.due_between(Date.today.beginning_of_month, Date.today.end_of_month + 1.day)
       end
     end
     items
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 2a193e12ec9..d3779eda91f 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -174,12 +174,14 @@ module IssuesHelper
 
   def due_date_options
     options = [
-      ["Due to tomorrow", 1.day.from_now.to_date],
-      ["Due in this week", 1.week.from_now.to_date]
+        Issue::AnyDueDate,
+        Issue::NoDueDate,
+        Issue::DueThisWeek,
+        Issue::DueThisMonth,
+        Issue::OverDue
     ]
-    options.unshift(Issue::ANY_DUE_DATE)
-    options.unshift(Issue::NO_DUE_DATE)
-    options_for_select(options, params[:due_date])
+
+    options_from_collection_for_select(options, 'name', 'title', params[:due_date])
   end
 
 
diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb
index 624cb7bb847..630e10ea892 100644
--- a/app/helpers/sorting_helper.rb
+++ b/app/helpers/sorting_helper.rb
@@ -53,11 +53,11 @@ module SortingHelper
   end
 
   def sort_title_due_date_soon
-    'Due date soon'
+    'Due soon'
   end
 
   def sort_title_due_date_later
-    'Due date due later'
+    'Due later'
   end
 
   def sort_title_name
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 691b7e104e4..03d8a573a4d 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -39,8 +39,10 @@ module Issuable
     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 :has_due_date, ->{ where("issues.due_date IS NOT NULL") }
-    scope :no_due_date, ->{ where("issues.due_date IS NULL")}
+    scope :without_due_date, ->{ where("issues.due_date IS NULL")}
+    scope :due_before, ->(date){ where("issues.due_date IS NOT NULL AND issues.due_date < ?", date)}
+    scope :due_between, ->(from_date, to_date){ where("issues.due_date >= ?", from_date).due_before(to_date) }
+    scope :overdue, ->{ where("issues.due_date < ?", Date.today)}
 
     scope :join_project, -> { joins(:project) }
     scope :references_project, -> { references(:project) }
diff --git a/app/models/concerns/sortable.rb b/app/models/concerns/sortable.rb
index 86c7e38adc8..f1f09011c1b 100644
--- a/app/models/concerns/sortable.rb
+++ b/app/models/concerns/sortable.rb
@@ -18,8 +18,8 @@ module Sortable
     scope :order_updated_asc, -> { reorder(updated_at: :asc) }
     scope :order_name_asc, -> { reorder(name: :asc) }
     scope :order_name_desc, -> { reorder(name: :desc) }
-    scope :due_date_asc, -> { reorder("due_date IS NULL, due_date ASC") }
-    scope :due_date_desc, -> { reorder("due_date IS NULL, due_date DESC") }
+    scope :order_due_date_asc, -> { reorder("issues.due_date IS NULL, issues.due_date ASC") }
+    scope :order_due_date_desc, -> { reorder("issues.due_date IS NULL, issues.due_date DESC") }
   end
 
   module ClassMethods
@@ -33,8 +33,8 @@ module Sortable
       when 'created_desc' then order_created_desc
       when 'id_desc' then order_id_desc
       when 'id_asc' then order_id_asc
-      when 'due_date_asc' then due_date_asc
-      when 'due_date_desc' then due_date_desc
+      when 'due_date_asc' then order_due_date_asc
+      when 'due_date_desc' then order_due_date_desc
       else
         all
       end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index ee5be904330..b9350e191b7 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -28,8 +28,12 @@ class Issue < ActiveRecord::Base
   include Sortable
   include Taskable
 
-  NO_DUE_DATE = ['No Due Date', '0']
-  ANY_DUE_DATE = ['Any Due Date', '']
+  DueDateStruct = Struct.new(:title, :name)
+  NoDueDate = DueDateStruct.new('No Due Date', '0')
+  AnyDueDate = DueDateStruct.new('Any Due Date', '')
+  OverDue = DueDateStruct.new('Overdue', 'overdue')
+  DueThisWeek = DueDateStruct.new('Due This Week', 'week')
+  DueThisMonth = DueDateStruct.new('Due This Month', 'month')
 
   ActsAsTaggableOn.strict_case_match = true
 
diff --git a/app/views/shared/_sort_dropdown.html.haml b/app/views/shared/_sort_dropdown.html.haml
index 80971309da7..922b02f9f3e 100644
--- a/app/views/shared/_sort_dropdown.html.haml
+++ b/app/views/shared/_sort_dropdown.html.haml
@@ -21,9 +21,9 @@
       = link_to page_filter_path(sort: sort_value_milestone_later) do
         = sort_title_milestone_later
       = link_to page_filter_path(sort: sort_value_due_date_soon) do
-        = sort_title_due_date_soon if controller_name == "issues"
+        = sort_title_due_date_soon if @issues
       = link_to page_filter_path(sort: sort_value_due_date_later) do
-        = sort_title_due_date_later if controller_name == "issues"
+        = sort_title_due_date_later if @issues
       = link_to page_filter_path(sort: sort_value_upvotes) do
         = sort_title_upvotes
       = link_to page_filter_path(sort: sort_value_downvotes) do
diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml
index f832f430b2b..7b76e7e368b 100644
--- a/app/views/shared/issuable/_filter.html.haml
+++ b/app/views/shared/issuable/_filter.html.haml
@@ -24,7 +24,7 @@
         .filter-item.inline.labels-filter
           = render "shared/issuable/label_dropdown"
 
-        - if controller.controller_name == 'issues'
+        - if @issues
           .filter-item.inline.due_date-filter
             = select_tag('due_date', due_date_options,
               class: 'select2 trigger-submit', include_blank: true,
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index fb2c727d57a..8923efd2fc2 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -80,7 +80,6 @@
             = icon('calendar')
             %span
               - if issuable.due_date
-                = icon('calendar')
                 = issuable.due_date.to_s(:medium)
               - else
                 .light None
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index ac54a0c2719..32c27d6e97e 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -187,33 +187,49 @@ describe 'Issues', feature: true do
       end
 
       it 'filters by none' do
-        visit namespace_project_issues_path(project.namespace, project, due_date: Issue::NO_DUE_DATE[1])
+        visit namespace_project_issues_path(project.namespace, project, due_date: Issue::NoDueDate.name)
         expect(page).not_to have_content("foo")
         expect(page).not_to have_content("bar")
         expect(page).to have_content("baz")
       end
 
       it 'filters by any' do
-        visit namespace_project_issues_path(project.namespace, project, due_date: Issue::ANY_DUE_DATE[1])
+        visit namespace_project_issues_path(project.namespace, project, due_date: Issue::AnyDueDate.name)
         expect(page).to have_content("foo")
         expect(page).to have_content("bar")
         expect(page).to have_content("baz")
       end
 
-      it 'filters by due to tomorrow' do
-        visit namespace_project_issues_path(project.namespace, project, due_date: Date.tomorrow.to_s)
+      it 'filters by due this week' do
+        foo.update(due_date: Date.today.beginning_of_week + 2.days)
+        bar.update(due_date: Date.today.end_of_week)
+        baz.update(due_date: Date.today - 8.days)
+        visit namespace_project_issues_path(project.namespace, project, due_date: Issue::DueThisWeek.name)
         expect(page).to have_content("foo")
-        expect(page).not_to have_content("bar")
+        expect(page).to have_content("bar")
         expect(page).not_to have_content("baz")
       end
 
-      it 'filters by due in this week' do
-        visit namespace_project_issues_path(project.namespace, project, due_date: 7.days.from_now.to_date.to_s)
+      it 'filters by due this month' do
+        foo.update(due_date: Date.today.beginning_of_month + 2.days)
+        bar.update(due_date: Date.today.end_of_month)
+        baz.update(due_date: Date.today - 50.days)
+        visit namespace_project_issues_path(project.namespace, project, due_date: Issue::DueThisMonth.name)
         expect(page).to have_content("foo")
         expect(page).to have_content("bar")
         expect(page).not_to have_content("baz")
       end
 
+      it 'filters by overdue' do
+        foo.update(due_date: Date.today + 2.days)
+        bar.update(due_date: Date.today + 20.days)
+        baz.update(due_date: Date.yesterday)
+        visit namespace_project_issues_path(project.namespace, project, due_date: Issue::OverDue.name)
+        expect(page).not_to have_content("foo")
+        expect(page).not_to have_content("bar")
+        expect(page).to have_content("baz")
+      end
+
     end
 
     describe 'sorting by milestone' do
-- 
GitLab