diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 01e74400a..b9d072f5a 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -49,8 +49,9 @@ //= require markdown-it //= require markdown_editor //= require cocoon -//= require allegations //= require legislation +//= require legislation_allegations +//= require legislation_annotatable //= require custom var initialize_modules = function() { @@ -74,8 +75,9 @@ var initialize_modules = function() { App.Banners.initialize(); App.SocialShare.initialize(); App.MarkdownEditor.initialize(); - App.Allegations.initialize(); + App.LegislationAllegations.initialize(); App.Legislation.initialize(); + App.LegislationAnnotatable.initialize(); }; $(function(){ diff --git a/app/assets/javascripts/allegations.js.coffee b/app/assets/javascripts/legislation_allegations.js.coffee similarity index 74% rename from app/assets/javascripts/allegations.js.coffee rename to app/assets/javascripts/legislation_allegations.js.coffee index d57fa30ed..e01a8b5d4 100644 --- a/app/assets/javascripts/allegations.js.coffee +++ b/app/assets/javascripts/legislation_allegations.js.coffee @@ -1,4 +1,4 @@ -App.Allegations = +App.LegislationAllegations = toggle_comments: -> $('.draft-allegation').toggleClass('comments-on'); @@ -8,10 +8,10 @@ App.Allegations = click: (e) -> e.preventDefault(); e.stopPropagation(); - App.Allegations.toggle_comments() + App.LegislationAllegations.toggle_comments() $('.js-toggle-allegations').on click: (e) -> # Toggle comments when the section title is visible if $(this).find('.draft-panel .panel-title:visible').length == 0 - App.Allegations.toggle_comments() + App.LegislationAllegations.toggle_comments() diff --git a/app/assets/javascripts/legislation_annotatable.js.coffee b/app/assets/javascripts/legislation_annotatable.js.coffee new file mode 100644 index 000000000..fa5df598a --- /dev/null +++ b/app/assets/javascripts/legislation_annotatable.js.coffee @@ -0,0 +1,38 @@ +_t = (key) -> new Gettext().gettext(key) + +App.LegislationAnnotatable = + initialize: -> + current_user_id = $('html').data('current-user-id') + if current_user_id == "" + annotator.ui.editor.Editor.template = [ + '
', + '
', + ' ' + _t('Unregistered'), + '
', + ' ' + _t('Cancel') + '', + '
', + '
', + '
' + ].join('\n') + + $(".legislation-annotatable").each -> + $this = $(this) + ann_type = "legislation_draft_version" + ann_id = $this.data("legislation-draft-version-id") + base_url = $this.data("legislation-annotatable-base-url") + + app = new annotator.App() + .include -> + beforeAnnotationCreated: (ann) -> + ann["legislation_draft_version_id"] = ann_id + ann.permissions = ann.permissions || {} + ann.permissions.admin = [] + .include(annotator.ui.main, { element: this }) + .include(annotator.storage.http, { prefix: base_url, urls: { search: "/annotations/search" } }) + + app.start().then -> + app.ident.identity = current_user_id + + options = {} + options["legislation_draft_version_id"] = ann_id + app.annotations.load(options) diff --git a/app/controllers/legislation/annotations_controller.rb b/app/controllers/legislation/annotations_controller.rb new file mode 100644 index 000000000..7e053f510 --- /dev/null +++ b/app/controllers/legislation/annotations_controller.rb @@ -0,0 +1,32 @@ +class Legislation::AnnotationsController < ApplicationController + skip_before_action :verify_authenticity_token + + before_action :authenticate_user!, only: [:create] + + load_and_authorize_resource :process + load_and_authorize_resource :draft_version, through: :process + load_and_authorize_resource + + def create + @annotation = Legislation::Annotation.new(annotation_params) + @annotation.user = current_user + if @annotation.save + render json: @annotation.to_json + end + end + + def search + @annotations = Legislation::Annotation.where(legislation_draft_version_id: params[:legislation_draft_version_id]) + annotations_hash = { total: @annotations.size, rows: @annotations } + render json: annotations_hash.to_json + end + + private + + def annotation_params + params + .require(:annotation) + .permit(:quote, :text, ranges: [:start, :startOffset, :end, :endOffset]) + .merge(legislation_draft_version_id: params[:legislation_draft_version_id]) + end +end diff --git a/app/models/abilities/everyone.rb b/app/models/abilities/everyone.rb index b71e1f7d5..e29880e95 100644 --- a/app/models/abilities/everyone.rb +++ b/app/models/abilities/everyone.rb @@ -15,6 +15,7 @@ module Abilities can [:read, :changes, :go_to_version], Legislation::DraftVersion can [:read], Legislation::Question can [:create], Legislation::Answer + can [:search, :read, :create], Legislation::Annotation end end end diff --git a/app/models/legislation/annotation.rb b/app/models/legislation/annotation.rb new file mode 100644 index 000000000..365f84ad0 --- /dev/null +++ b/app/models/legislation/annotation.rb @@ -0,0 +1,6 @@ +class Legislation::Annotation < ActiveRecord::Base + serialize :ranges, Array + + belongs_to :draft_version, class_name: 'Legislation::DraftVersion', foreign_key: 'legislation_draft_version_id' + belongs_to :user +end diff --git a/app/views/legislation/draft_versions/show.html.erb b/app/views/legislation/draft_versions/show.html.erb index 5ff3a76ba..8ab20eea9 100644 --- a/app/views/legislation/draft_versions/show.html.erb +++ b/app/views/legislation/draft_versions/show.html.erb @@ -44,7 +44,12 @@
<%= t('.text_body') %>
- <%= @draft_version.body_html.html_safe %> +
+ <%= @draft_version.body_html.html_safe %> +
diff --git a/config/routes.rb b/config/routes.rb index 0ef0187f6..956b68f32 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -101,7 +101,9 @@ Rails.application.routes.draw do resources :draft_versions, only: [:show] do get :go_to_version, on: :collection get :changes - resources :annotations + resources :annotations do + get :search, on: :collection + end end end end diff --git a/db/migrate/20170103125835_create_legislation_annotations.rb b/db/migrate/20170103125835_create_legislation_annotations.rb new file mode 100644 index 000000000..723bf3813 --- /dev/null +++ b/db/migrate/20170103125835_create_legislation_annotations.rb @@ -0,0 +1,16 @@ +class CreateLegislationAnnotations < ActiveRecord::Migration + def change + create_table :legislation_annotations do |t| + t.string :quote + t.text :ranges + t.text :text + + t.references :legislation_draft_version, index: true + t.references :user, index: true + + t.datetime :hidden_at, index: true + + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index d949dbb3a..39e3ec56c 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: 20161229213217) do +ActiveRecord::Schema.define(version: 20170103125835) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -228,6 +228,21 @@ ActiveRecord::Schema.define(version: 20161229213217) do t.datetime "updated_at", null: false end + create_table "legislation_annotations", force: :cascade do |t| + t.string "quote" + t.text "ranges" + t.text "text" + t.integer "legislation_draft_version_id" + t.integer "user_id" + t.datetime "hidden_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "legislation_annotations", ["hidden_at"], name: "index_legislation_annotations_on_hidden_at", using: :btree + add_index "legislation_annotations", ["legislation_draft_version_id"], name: "index_legislation_annotations_on_legislation_draft_version_id", using: :btree + add_index "legislation_annotations", ["user_id"], name: "index_legislation_annotations_on_user_id", using: :btree + create_table "legislation_answers", force: :cascade do |t| t.integer "legislation_question_id" t.integer "legislation_question_option_id" diff --git a/spec/factories.rb b/spec/factories.rb index 731e1fef1..fe0750756 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -399,6 +399,18 @@ FactoryGirl.define do status "draft" final_version false body "Body of the legislation text" + + trait :published do + status "published" + end + end + + factory :legislation_annotation, class: 'Legislation::Annotation' do + draft_version factory: :legislation_draft_version + user + quote "ipsum" + text "Loremp ipsum dolor" + ranges [{"start"=>"/div[1]", "startOffset"=>5, "end"=>"/div[1]", "endOffset"=>10}] end factory :legislation_question, class: 'Legislation::Question' do diff --git a/spec/features/legislation/draft_versions_spec.rb b/spec/features/legislation/draft_versions_spec.rb index 594cb8cdc..7df1939be 100644 --- a/spec/features/legislation/draft_versions_spec.rb +++ b/spec/features/legislation/draft_versions_spec.rb @@ -119,4 +119,45 @@ feature 'Legislation Draft Versions' do end end + context 'Annotations', :js do + let(:user) { create(:user) } + background { login_as user } + + scenario 'Create' do + draft_version = create(:legislation_draft_version, :published, body: Faker::Lorem.paragraph) + + visit legislation_process_draft_version_path(draft_version.process, draft_version) + + page.find(:css, ".legislation-annotatable").double_click + page.find(:css, ".annotator-adder button").click + fill_in 'annotator-field-0', with: 'this is my annotation' + page.find(:css, ".annotator-controls a[href='#save']").click + + expect(page).to have_css ".annotator-hl" + first(:css, ".annotator-hl").click + expect(page).to have_content "this is my annotation" + + visit legislation_process_draft_version_path(draft_version.process, draft_version) + + expect(page).to have_css ".annotator-hl" + first(:css, ".annotator-hl").click + expect(page).to have_content "this is my annotation" + end + + scenario 'Search' do + draft_version = create(:legislation_draft_version, :published, body: Faker::Lorem.paragraph) + annotation1 = create(:legislation_annotation, draft_version: draft_version, text: "my annotation", ranges: [{"start"=>"/p[1]", "startOffset"=>5, "end"=>"/p[1]", "endOffset"=>10}]) + annotation2 = create(:legislation_annotation, draft_version: draft_version, text: "my other annotation", ranges: [{"start"=>"/p[1]", "startOffset"=>12, "end"=>"/p[1]", "endOffset"=>19}]) + + visit legislation_process_draft_version_path(draft_version.process, draft_version) + + expect(page).to have_css ".annotator-hl" + first(:css, ".annotator-hl").click + expect(page).to have_content "my annotation" + + all(".annotator-hl")[1].click + expect(page).to have_content "my other annotation" + end + end + end