Commit f34f9a9ef364a5d67abece6dc235b015aa0fb380
Exists in
spb-stable
and in
2 other branches
Merge branch 'notes_finder_updated_at' into 'master'
NotesFinder filters by updated_at
Showing
7 changed files
with
62 additions
and
5 deletions
Show diff stats
app/assets/javascripts/notes.js.coffee
| 1 | 1 | class Notes |
| 2 | 2 | @interval: null |
| 3 | 3 | |
| 4 | - constructor: (notes_url, note_ids) -> | |
| 4 | + constructor: (notes_url, note_ids, last_fetched_at) -> | |
| 5 | 5 | @notes_url = notes_url |
| 6 | 6 | @notes_url = gon.relative_url_root + @notes_url if gon.relative_url_root? |
| 7 | 7 | @note_ids = note_ids |
| 8 | + @last_fetched_at = last_fetched_at | |
| 8 | 9 | @initRefresh() |
| 9 | 10 | @setupMainTargetNoteForm() |
| 10 | 11 | @cleanBinding() |
| ... | ... | @@ -76,9 +77,11 @@ class Notes |
| 76 | 77 | getContent: -> |
| 77 | 78 | $.ajax |
| 78 | 79 | url: @notes_url |
| 80 | + data: "last_fetched_at=" + @last_fetched_at | |
| 79 | 81 | dataType: "json" |
| 80 | 82 | success: (data) => |
| 81 | 83 | notes = data.notes |
| 84 | + @last_fetched_at = data.last_fetched_at | |
| 82 | 85 | $.each notes, (i, note) => |
| 83 | 86 | @renderNote(note) |
| 84 | 87 | ... | ... |
app/controllers/projects/notes_controller.rb
| ... | ... | @@ -5,9 +5,10 @@ class Projects::NotesController < Projects::ApplicationController |
| 5 | 5 | before_filter :authorize_admin_note!, only: [:update, :destroy] |
| 6 | 6 | |
| 7 | 7 | def index |
| 8 | + current_fetched_at = Time.now.to_i | |
| 8 | 9 | @notes = NotesFinder.new.execute(project, current_user, params) |
| 9 | 10 | |
| 10 | - notes_json = { notes: [] } | |
| 11 | + notes_json = { notes: [], last_fetched_at: current_fetched_at } | |
| 11 | 12 | |
| 12 | 13 | @notes.each do |note| |
| 13 | 14 | notes_json[:notes] << { | ... | ... |
app/finders/notes_finder.rb
| 1 | 1 | class NotesFinder |
| 2 | + FETCH_OVERLAP = 5.seconds | |
| 3 | + | |
| 2 | 4 | def execute(project, current_user, params) |
| 3 | 5 | target_type = params[:target_type] |
| 4 | 6 | target_id = params[:target_id] |
| 7 | + # Default to 0 to remain compatible with old clients | |
| 8 | + last_fetched_at = Time.at(params.fetch(:last_fetched_at, 0).to_i) | |
| 5 | 9 | |
| 6 | - case target_type | |
| 10 | + notes = case target_type | |
| 7 | 11 | when "commit" |
| 8 | 12 | project.notes.for_commit_id(target_id).not_inline.fresh |
| 9 | 13 | when "issue" |
| ... | ... | @@ -12,6 +16,11 @@ class NotesFinder |
| 12 | 16 | project.merge_requests.find(target_id).mr_and_commit_notes.inc_author.fresh |
| 13 | 17 | when "snippet" |
| 14 | 18 | project.snippets.find(target_id).notes.fresh |
| 19 | + else | |
| 20 | + raise 'invalid target_type' | |
| 15 | 21 | end |
| 22 | + | |
| 23 | + # Use overlapping intervals to avoid worrying about race conditions | |
| 24 | + notes.where('updated_at > ?', last_fetched_at - FETCH_OVERLAP) | |
| 16 | 25 | end |
| 17 | 26 | end | ... | ... |
app/views/projects/notes/_notes_with_form.html.haml
| ... | ... | @@ -7,4 +7,4 @@ |
| 7 | 7 | = render "projects/notes/form" |
| 8 | 8 | |
| 9 | 9 | :javascript |
| 10 | - new Notes("#{project_notes_path(target_id: @noteable.id, target_type: @noteable.class.name.underscore)}", #{@notes.map(&:id).to_json}) | |
| 10 | + new Notes("#{project_notes_path(target_id: @noteable.id, target_type: @noteable.class.name.underscore)}", #{@notes.map(&:id).to_json}, #{Time.now.to_i}) | ... | ... |
db/schema.rb
| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | # |
| 12 | 12 | # It's strongly recommended that you check this file into your version control system. |
| 13 | 13 | |
| 14 | -ActiveRecord::Schema.define(version: 20140416185734) do | |
| 14 | +ActiveRecord::Schema.define(version: 20140428105831) do | |
| 15 | 15 | |
| 16 | 16 | # These are extensions that must be enabled in order to support this database |
| 17 | 17 | enable_extension "plpgsql" |
| ... | ... | @@ -200,6 +200,7 @@ ActiveRecord::Schema.define(version: 20140416185734) do |
| 200 | 200 | add_index "notes", ["noteable_type"], name: "index_notes_on_noteable_type", using: :btree |
| 201 | 201 | add_index "notes", ["project_id", "noteable_type"], name: "index_notes_on_project_id_and_noteable_type", using: :btree |
| 202 | 202 | add_index "notes", ["project_id"], name: "index_notes_on_project_id", using: :btree |
| 203 | + add_index "notes", ["updated_at"], name: "index_notes_on_updated_at", using: :btree | |
| 203 | 204 | |
| 204 | 205 | create_table "projects", force: true do |t| |
| 205 | 206 | t.string "name" | ... | ... |
| ... | ... | @@ -0,0 +1,38 @@ |
| 1 | +require 'spec_helper' | |
| 2 | + | |
| 3 | +describe NotesFinder do | |
| 4 | + let(:user) { create :user } | |
| 5 | + let(:project) { create :project } | |
| 6 | + let(:note1) { create :note_on_commit, project: project } | |
| 7 | + let(:note2) { create :note_on_commit, project: project } | |
| 8 | + let(:commit) { note1.noteable } | |
| 9 | + | |
| 10 | + before do | |
| 11 | + project.team << [user, :master] | |
| 12 | + end | |
| 13 | + | |
| 14 | + describe :execute do | |
| 15 | + let(:params) { { target_id: commit.id, target_type: 'commit', last_fetched_at: 1.hour.ago.to_i } } | |
| 16 | + | |
| 17 | + before do | |
| 18 | + note1 | |
| 19 | + note2 | |
| 20 | + end | |
| 21 | + | |
| 22 | + it 'should find all notes' do | |
| 23 | + notes = NotesFinder.new.execute(project, user, params) | |
| 24 | + notes.size.should eq(2) | |
| 25 | + end | |
| 26 | + | |
| 27 | + it 'should raise an exception for an invalid target_type' do | |
| 28 | + params.merge!(target_type: 'invalid') | |
| 29 | + expect { NotesFinder.new.execute(project, user, params) }.to raise_error('invalid target_type') | |
| 30 | + end | |
| 31 | + | |
| 32 | + it 'filters out old notes' do | |
| 33 | + note2.update_attribute(:updated_at, 2.hours.ago) | |
| 34 | + notes = NotesFinder.new.execute(project, user, params) | |
| 35 | + notes.should eq([note1]) | |
| 36 | + end | |
| 37 | + end | |
| 38 | +end | ... | ... |