summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Barbosa Alexandre <dbalexandre@gmail.com>2016-02-17 17:45:32 -0200
committerDouglas Barbosa Alexandre <dbalexandre@gmail.com>2016-02-20 12:12:05 -0200
commit1d476b0656b3ec24e264d7a7c30bdca83704b3bd (patch)
treed1cdb1b22c0f1365efd80a0485e25b1ecfaf7735
parent14fc05ebfdfb6654859ee6f57aa462420a6bcb56 (diff)
downloadgitlab-ce-1d476b0656b3ec24e264d7a7c30bdca83704b3bd.tar.gz
Create a pending task when a user is mentioned on a note
-rw-r--r--app/assets/stylesheets/pages/tasks.scss24
-rw-r--r--app/helpers/tasks_helper.rb16
-rw-r--r--app/models/note.rb2
-rw-r--r--app/models/task.rb6
-rw-r--r--app/services/task_service.rb17
-rw-r--r--app/views/dashboard/tasks/_common.html.haml17
-rw-r--r--app/views/dashboard/tasks/_note.html.haml26
-rw-r--r--app/views/dashboard/tasks/_task.html.haml21
-rw-r--r--db/migrate/20160217174422_add_note_to_tasks.rb5
-rw-r--r--db/schema.rb4
-rw-r--r--spec/models/note_spec.rb2
-rw-r--r--spec/models/task_spec.rb16
-rw-r--r--spec/services/task_service_spec.rb11
13 files changed, 146 insertions, 21 deletions
diff --git a/app/assets/stylesheets/pages/tasks.scss b/app/assets/stylesheets/pages/tasks.scss
index f0e13f4d786..a3dffeed4ab 100644
--- a/app/assets/stylesheets/pages/tasks.scss
+++ b/app/assets/stylesheets/pages/tasks.scss
@@ -59,6 +59,15 @@
.task-note {
word-wrap: break-word;
+ .md {
+ color: #7f8fa4;
+ font-size: $gl-font-size;
+
+ p {
+ color: #5c5d5e;
+ }
+ }
+
pre {
border: none;
background: #f9f9f9;
@@ -68,10 +77,25 @@
overflow: hidden;
}
+ .note-image-attach {
+ margin-top: 4px;
+ margin-left: 0px;
+ max-width: 200px;
+ float: none;
+ }
+
p:last-child {
margin-bottom: 0;
}
}
+
+ .task-note-icon {
+ color: #777;
+ float: left;
+ font-size: $gl-font-size;
+ line-height: 16px;
+ margin-right: 5px;
+ }
}
&:last-child { border:none }
diff --git a/app/helpers/tasks_helper.rb b/app/helpers/tasks_helper.rb
index cf4eab0ef94..6975c1d1604 100644
--- a/app/helpers/tasks_helper.rb
+++ b/app/helpers/tasks_helper.rb
@@ -22,4 +22,20 @@ module TasksHelper
[task.action_name, target].join(" ")
end
+
+ def task_note_link_html(task)
+ link_to task_note_target_path(task) do
+ "##{task.target_iid}"
+ end
+ end
+
+ def task_note_target_path(task)
+ polymorphic_path([task.project.namespace.becomes(Namespace),
+ task.project, task.target], anchor: dom_id(task.note))
+ end
+
+ def task_note(text, options = {})
+ text = first_line_in_markdown(text, 150, options)
+ sanitize(text, tags: %w(a img b pre code p span))
+ end
end
diff --git a/app/models/note.rb b/app/models/note.rb
index b3809ad81e0..73412024f4e 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -37,6 +37,8 @@ class Note < ActiveRecord::Base
belongs_to :author, class_name: "User"
belongs_to :updated_by, class_name: "User"
+ has_many :tasks, dependent: :delete_all
+
delegate :name, to: :project, prefix: true
delegate :name, :email, to: :author, prefix: true
diff --git a/app/models/task.rb b/app/models/task.rb
index c9881991e38..38c6637e456 100644
--- a/app/models/task.rb
+++ b/app/models/task.rb
@@ -8,6 +8,7 @@
# target_id :integer not null
# target_type :string not null
# author_id :integer
+# note_id :integer
# action :integer
# state :string not null
# created_at :datetime
@@ -19,6 +20,7 @@ class Task < ActiveRecord::Base
MENTIONED = 2
belongs_to :author, class_name: "User"
+ belongs_to :note
belongs_to :project
belongs_to :target, polymorphic: true, touch: true
belongs_to :user
@@ -52,6 +54,10 @@ class Task < ActiveRecord::Base
target.respond_to? :title
end
+ def note_text
+ note.try(:note)
+ end
+
def target_iid
target.respond_to?(:iid) ? target.iid : target_id
end
diff --git a/app/services/task_service.rb b/app/services/task_service.rb
index fa615f4cfcf..d97fa146f5c 100644
--- a/app/services/task_service.rb
+++ b/app/services/task_service.rb
@@ -77,7 +77,17 @@ class TaskService
def new_note(note)
# Skip system notes, like status changes and cross-references
unless note.system
- mark_pending_tasks_as_done(note.noteable, note.author)
+ project = note.project
+ target = note.noteable
+ author = note.author
+
+ mark_pending_tasks_as_done(target, author)
+
+ mentioned_users = build_mentioned_users(project, note, author)
+
+ mentioned_users.each do |user|
+ create_task(project, target, author, user, Task::MENTIONED, note)
+ end
end
end
@@ -94,14 +104,15 @@ class TaskService
private
- def create_task(project, target, author, user, action)
+ def create_task(project, target, author, user, action, note = nil)
attributes = {
project: project,
user_id: user.id,
author_id: author.id,
target_id: target.id,
target_type: target.class.name,
- action: action
+ action: action,
+ note: note
}
Task.create(attributes)
diff --git a/app/views/dashboard/tasks/_common.html.haml b/app/views/dashboard/tasks/_common.html.haml
new file mode 100644
index 00000000000..b6d0c3c03ac
--- /dev/null
+++ b/app/views/dashboard/tasks/_common.html.haml
@@ -0,0 +1,17 @@
+.task-title
+ %span.author_name= link_to_author task
+ %span.task_label{class: task.action_name}
+ = task_action_name(task)
+
+ %strong= link_to "##{task.target_iid}", [task.project.namespace.becomes(Namespace), task.project, task.target]
+
+ &middot; #{time_ago_with_tooltip(task.created_at)}
+
+- if task.pending?
+ .task-actions.pull-right
+ = link_to 'Done', [:dashboard, task], method: :delete, class: 'btn'
+
+- if task.body?
+ .task-body
+ .task-note
+ = task.target.title
diff --git a/app/views/dashboard/tasks/_note.html.haml b/app/views/dashboard/tasks/_note.html.haml
new file mode 100644
index 00000000000..2cfd55afccb
--- /dev/null
+++ b/app/views/dashboard/tasks/_note.html.haml
@@ -0,0 +1,26 @@
+.task-title
+ %span.author_name
+ = link_to_author task
+ %span.task_label{class: task.action_name}
+ = task_action_name(task)
+ = task_note_link_html(task)
+
+ &middot; #{time_ago_with_tooltip(task.created_at)}
+
+- if task.pending?
+ .task-actions.pull-right
+ = link_to 'Done', [:dashboard, task], method: :delete, class: 'btn'
+
+.task-body
+ .task-note
+ .md
+ = task_note(task.note_text, project: task.project)
+ - note = task.note
+ - if note.attachment.url
+ - if note.attachment.image?
+ = link_to note.attachment.url, target: '_blank' do
+ = image_tag note.attachment.url, class: 'note-image-attach'
+ - else
+ = link_to note.attachment.url, target: "_blank", class: 'note-file-attach' do
+ %i.fa.fa-paperclip
+ = note.attachment_identifier
diff --git a/app/views/dashboard/tasks/_task.html.haml b/app/views/dashboard/tasks/_task.html.haml
index b33f3894fd3..2ca8f0dad63 100644
--- a/app/views/dashboard/tasks/_task.html.haml
+++ b/app/views/dashboard/tasks/_task.html.haml
@@ -2,20 +2,7 @@
.task-item{class: "#{task.body? ? 'task-block' : 'task-inline' }"}
= image_tag avatar_icon(task.author_email, 40), class: "avatar s40", alt:''
- .task-title
- %span.author_name= link_to_author task
- %span.task_label{class: task.action_name}
- = task_action_name(task)
-
- %strong= link_to "##{task.target_iid}", [task.project.namespace.becomes(Namespace), task.project, task.target]
-
- &middot; #{time_ago_with_tooltip(task.created_at)}
-
- - if task.pending?
- .task-actions.pull-right
- = link_to 'Done', [:dashboard, task], method: :delete, class: 'btn'
-
- - if task.body?
- .task-body
- .task-note
- = task.target.title
+ - if task.note.present?
+ = render 'note', task: task
+ - else
+ = render 'common', task: task
diff --git a/db/migrate/20160217174422_add_note_to_tasks.rb b/db/migrate/20160217174422_add_note_to_tasks.rb
new file mode 100644
index 00000000000..da5cb2e05db
--- /dev/null
+++ b/db/migrate/20160217174422_add_note_to_tasks.rb
@@ -0,0 +1,5 @@
+class AddNoteToTasks < ActiveRecord::Migration
+ def change
+ add_reference :tasks, :note, index: true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 183227a91ca..2b726d17682 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20160217100506) do
+ActiveRecord::Schema.define(version: 20160217174422) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -834,9 +834,11 @@ ActiveRecord::Schema.define(version: 20160217100506) do
t.string "state", null: false
t.datetime "created_at"
t.datetime "updated_at"
+ t.integer "note_id"
end
add_index "tasks", ["author_id"], name: "index_tasks_on_author_id", using: :btree
+ add_index "tasks", ["note_id"], name: "index_tasks_on_note_id", using: :btree
add_index "tasks", ["project_id"], name: "index_tasks_on_project_id", using: :btree
add_index "tasks", ["state"], name: "index_tasks_on_state", using: :btree
add_index "tasks", ["target_type", "target_id"], name: "index_tasks_on_target_type_and_target_id", using: :btree
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index e6da3724d33..e146f53c3f7 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -26,6 +26,8 @@ describe Note, models: true do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:noteable) }
it { is_expected.to belong_to(:author).class_name('User') }
+
+ it { is_expected.to have_many(:tasks).dependent(:delete_all) }
end
describe 'validation' do
diff --git a/spec/models/task_spec.rb b/spec/models/task_spec.rb
index 86317626cc3..2f0b51ffc61 100644
--- a/spec/models/task_spec.rb
+++ b/spec/models/task_spec.rb
@@ -8,6 +8,7 @@
# target_id :integer not null
# target_type :string not null
# author_id :integer
+# note_id :integer
# action :integer
# state :string not null
# created_at :datetime
@@ -19,6 +20,7 @@ require 'spec_helper'
describe Task, models: true do
describe 'relationships' do
it { is_expected.to belong_to(:author).class_name("User") }
+ it { is_expected.to belong_to(:note) }
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:target).touch(true) }
it { is_expected.to belong_to(:user) }
@@ -48,6 +50,20 @@ describe Task, models: true do
it 'returns false when target does not respond to title'
end
+ describe '#note_text' do
+ it 'returns nil when note is blank' do
+ subject.note = nil
+
+ expect(subject.note_text).to be_nil
+ end
+
+ it 'returns note when note is present' do
+ subject.note = build(:note, note: 'quick fix')
+
+ expect(subject.note_text).to eq 'quick fix'
+ end
+ end
+
describe '#target_iid' do
it 'returns target.iid when target respond to iid'
it 'returns target_id when target does not respond to iid'
diff --git a/spec/services/task_service_spec.rb b/spec/services/task_service_spec.rb
index b35715c8b7a..e373d3a4931 100644
--- a/spec/services/task_service_spec.rb
+++ b/spec/services/task_service_spec.rb
@@ -128,6 +128,17 @@ describe TaskService, services: true do
expect(first_pending_task.reload).to be_pending
expect(second_pending_task.reload).to be_pending
end
+
+ it 'creates a task for each valid mentioned user' do
+ note.update_attribute(:note, mentions)
+
+ service.new_note(note)
+
+ should_create_task(user: michael, target: issue, author: john_doe, action: Task::MENTIONED, note: note)
+ should_create_task(user: author, target: issue, author: john_doe, action: Task::MENTIONED, note: note)
+ should_not_create_task(user: john_doe, target: issue, author: john_doe, action: Task::MENTIONED, note: note)
+ should_not_create_task(user: stranger, target: issue, author: john_doe, action: Task::MENTIONED, note: note)
+ end
end
end