summaryrefslogtreecommitdiff
path: root/app/models
diff options
context:
space:
mode:
Diffstat (limited to 'app/models')
-rw-r--r--app/models/concerns/taskable.rb51
-rw-r--r--app/models/issue.rb1
-rw-r--r--app/models/merge_request.rb1
3 files changed, 53 insertions, 0 deletions
diff --git a/app/models/concerns/taskable.rb b/app/models/concerns/taskable.rb
new file mode 100644
index 00000000000..410e8dc820b
--- /dev/null
+++ b/app/models/concerns/taskable.rb
@@ -0,0 +1,51 @@
+# 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>\[(?<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/issue.rb b/app/models/issue.rb
index 13152fdf94e..8a9e969248c 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -23,6 +23,7 @@ require 'file_size_validator'
class Issue < ActiveRecord::Base
include Issuable
include InternalId
+ include Taskable
ActsAsTaggableOn.strict_case_match = true
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index e0358c1889c..7c525b02f48 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -25,6 +25,7 @@ require Rails.root.join("lib/static_model")
class MergeRequest < ActiveRecord::Base
include Issuable
+ include Taskable
include InternalId
belongs_to :target_project, foreign_key: :target_project_id, class_name: "Project"