diff --git a/.gitignore b/.gitignore
index 940069dd..4b6c5bed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ capybara-*.html
.idea
.rspec
+.rspec-local
/log
/tmp
/db/*.sqlite3
diff --git a/Gemfile b/Gemfile
index 2a4a4d68..9d37dd71 100644
--- a/Gemfile
+++ b/Gemfile
@@ -40,5 +40,5 @@ end
group :test do
gem 'simplecov', '~> 0.13.0', require: false
gem "codeclimate-test-reporter", '~> 1.0.8', require: nil
- gem 'fuubar', '~> 2.2'
+ gem 'shoulda', '~> 4.0'
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 9a1d8730..b70f57ed 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -129,9 +129,6 @@ GEM
faraday (0.13.1)
multipart-post (>= 1.2, < 3)
ffi (1.12.2)
- fuubar (2.5.0)
- rspec-core (~> 3.0)
- ruby-progressbar (~> 1.4)
globalid (0.4.2)
activesupport (>= 4.2.0)
grape (1.3.2)
@@ -256,6 +253,12 @@ GEM
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.10.1)
ruby2_keywords (0.0.2)
+ shoulda (4.0.0)
+ shoulda-context (~> 2.0)
+ shoulda-matchers (~> 4.0)
+ shoulda-context (2.0.0)
+ shoulda-matchers (4.4.1)
+ activesupport (>= 4.2.0)
simplecov (0.13.0)
docile (~> 1.1.0)
json (>= 1.8, < 3)
@@ -301,7 +304,6 @@ DEPENDENCIES
elasticsearch-model (~> 5.0.2)
elasticsearch-persistence (= 5.0.2)
faker (~> 1.7)
- fuubar (~> 2.2)
grape (~> 1.3.2)
jbuilder (~> 2.7)
listen
@@ -315,6 +317,7 @@ DEPENDENCIES
rails (~> 5.2.0)
rspec-rails (~> 3.7)
rubocop (= 0.52.1)
+ shoulda (~> 4.0)
simplecov (~> 0.13.0)
BUNDLED WITH
diff --git a/app/classes/document_query.rb b/app/classes/document_query.rb
index a87ccd36..13b02aee 100644
--- a/app/classes/document_query.rb
+++ b/app/classes/document_query.rb
@@ -105,7 +105,7 @@ def functions
extension: %w(doc docx pdf ppt pptx xls xlsx)
}
},
- weight: -3
+ weight: '.75'
},
# Prefer documents that have been clicked more often
diff --git a/app/templates/collections.rb b/app/templates/collections.rb
index 6ea8ff6b..5956c0da 100644
--- a/app/templates/collections.rb
+++ b/app/templates/collections.rb
@@ -1,13 +1,14 @@
+# frozen_string_literal: true
+
class Collections
include Templatable
def body
Jbuilder.encode do |json|
- json.template "*-#{I14y::APP_NAME}-collections-*"
+ json.index_patterns "*-#{I14y::APP_NAME}-collections-*"
json.mappings do
json.collection do
dynamic_templates(json)
- json._all { json.enabled false }
end
end
end
@@ -18,4 +19,4 @@ def dynamic_templates(json)
string_fields_template(json, "keyword")
end
end
-end
\ No newline at end of file
+end
diff --git a/app/templates/documents.rb b/app/templates/documents.rb
index ce5d93b0..2a0b8af5 100644
--- a/app/templates/documents.rb
+++ b/app/templates/documents.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Documents
include Templatable
LIGHT_STEMMERS = { fr: "french", de: "german", es: "spanish", it: "italian", pt: "portuguese" }
@@ -10,7 +12,7 @@ def initialize
def body
Jbuilder.encode do |json|
- json.template "*-#{I14y::APP_NAME}-documents-*"
+ json.index_patterns "*-#{I14y::APP_NAME}-documents-*"
json.settings do
json.analysis do
char_filter(json)
@@ -23,7 +25,6 @@ def body
json.document do
dynamic_templates(json)
properties(json)
- json._all { json.enabled false }
end
end
end
diff --git a/spec/lib/serde_spec.rb b/spec/lib/serde_spec.rb
index 58922834..eac6c4d5 100644
--- a/spec/lib/serde_spec.rb
+++ b/spec/lib/serde_spec.rb
@@ -37,6 +37,31 @@
}
)
end
+
+ context 'when language fields contain HTML/CSS' do
+ let(:html) do
+ <<~HTML
+
+ hello & goodbye!
+ HTML
+ end
+
+ let(:original_hash) do
+ ActiveSupport::HashWithIndifferentAccess.new(
+ title: 'foo
',
+ description: html,
+ content: "this is html"
+ )
+ end
+
+ it 'sanitizes the language fields' do
+ expect(serialize_hash).to match(hash_including(
+ title_en: 'foo',
+ description_en: 'hello & goodbye!',
+ content_en: 'this is html'
+ ))
+ end
+ end
end
describe '.deserialize_hash' do
diff --git a/spec/models/collection_spec.rb b/spec/models/collection_spec.rb
new file mode 100644
index 00000000..3dfa1903
--- /dev/null
+++ b/spec/models/collection_spec.rb
@@ -0,0 +1,29 @@
+require 'rails_helper'
+
+describe Collection do
+ subject(:collection) { described_class.new(collection_params) }
+
+ let(:id) { 'agency_blogs' }
+ let(:token) { 'secret' }
+ let(:collection_params) do
+ {
+ _id: id,
+ token: token
+ }
+ end
+
+ it { is_expected.to be_valid }
+
+ describe 'attributes' do
+ it do
+ is_expected.to have_attributes(
+ token: 'secret',
+ id: 'agency_blogs'
+ )
+ end
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:token) }
+ end
+end
diff --git a/spec/models/document_spec.rb b/spec/models/document_spec.rb
index 1419e2d3..cddf88ae 100644
--- a/spec/models/document_spec.rb
+++ b/spec/models/document_spec.rb
@@ -7,72 +7,37 @@
language: 'en',
path: 'http://www.agency.gov/page1.html',
title: 'My Title',
- created: DateTime.now,
- changed: DateTime.now,
+ created: DateTime.new(2020, 1, 1),
+ changed: DateTime.new(2020, 1, 2),
description: 'My Description',
content: 'some content',
promote: true,
- tags: 'this,that'
+ tags: 'this,that',
+ click_count: 5
}
end
- before(:all) do
- handle = 'test_index'
- Elasticsearch::Persistence.client.indices.delete(
- index: [Document.index_namespace(handle), '*'].join('-')
- )
- es_documents_index_name = [Document.index_namespace(handle), 'v1'].join('-')
- Document.create_index!(index: es_documents_index_name)
- Elasticsearch::Persistence.client.indices.put_alias index: es_documents_index_name,
- name: Document.index_namespace(handle)
- Document.index_name = Document.index_namespace(handle)
- end
-
- after(:all) do
- Elasticsearch::Persistence.client.indices.delete(
- index: [Document.index_namespace('test_index'), '*'].join('-')
- )
- end
-
- describe '.create' do
- context 'when language fields contain HTML/CSS and HTML entities' do
- let(:html) do
- <<~HTML
-
- hello & goodbye!
- HTML
- end
-
- before do
- Document.create(_id: 'a123',
- language: 'en',
- title: 'foo
',
- description: html,
- created: DateTime.now,
- path: 'http://www.agency.gov/page1.html',
- content: "this is html")
- end
-
- it 'sanitizes the language fields' do
- document = Document.find 'a123'
- expect(document.title).to eq('foo')
- expect(document.description).to eq('hello & goodbye!')
- expect(document.content).to eq('this is html')
- end
+ describe 'attributes' do
+ subject(:document) { described_class.new(valid_params) }
+
+ it do
+ is_expected.to have_attributes(
+ language: 'en',
+ path: 'http://www.agency.gov/page1.html',
+ title: 'My Title',
+ created: DateTime.new(2020, 1, 1),
+ changed: DateTime.new(2020, 1, 2),
+ description: 'My Description',
+ content: 'some content',
+ promote: true,
+ tags: 'this,that',
+ click_count: 5
+ )
end
+ end
- context 'when a created value is provided but not changed' do
- let(:params_without_changed) do
- valid_params.merge(created: DateTime.now, changed: '')
- end
-
- before { Document.create(params_without_changed) }
-
- it 'sets "changed" to be the same as "created"' do
- Document.create(params_without_changed)
- document = Document.find('a123')
- expect(document.changed).to eq document.created
- end
- end
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:path) }
+ it { is_expected.to validate_presence_of(:language) }
end
end
diff --git a/spec/requests/api/v1/collections_spec.rb b/spec/requests/api/v1/collections_spec.rb
index edf66f30..5b8892df 100644
--- a/spec/requests/api/v1/collections_spec.rb
+++ b/spec/requests/api/v1/collections_spec.rb
@@ -50,6 +50,8 @@
it 'stores the appropriate fields in the Elasticsearch collection' do
collection = Collection.find('agency_blogs')
expect(collection.token).to eq('secret')
+ expect(collection.created_at).to be_an_instance_of(Time)
+ expect(collection.updated_at).to be_an_instance_of(Time)
end
it_behaves_like 'a data modifying request made during read-only mode'
diff --git a/spec/requests/api/v1/documents_spec.rb b/spec/requests/api/v1/documents_spec.rb
index b667c3d9..487a501d 100644
--- a/spec/requests/api/v1/documents_spec.rb
+++ b/spec/requests/api/v1/documents_spec.rb
@@ -66,6 +66,25 @@
expect(document.description).to eq('my desc')
expect(document.content).to eq('my content')
expect(document.tags).to match_array(['bar blat', 'foo'])
+ expect(document.created_at).to be_an_instance_of(Time)
+ expect(document.updated_at).to be_an_instance_of(Time)
+ end
+
+ context 'when a "created" value is provided but not "changed"' do
+ let(:valid_params) do
+ { document_id: id,
+ title: 'my title',
+ path: 'http://www.gov.gov/goo.html',
+ description: 'my desc',
+ language: 'hy',
+ content: 'my content',
+ created: '2020-01-01T10:00:00Z' }
+ end
+
+ it 'sets "changed" to be the same as "created"' do
+ document = Document.find(id)
+ expect(document.changed).to eq '2020-01-01T10:00:00Z'
+ end
end
it_behaves_like 'a data modifying request made during read-only mode'
@@ -260,6 +279,13 @@
end
describe 'PUT /api/v1/documents/{document_id}' do
+ subject(:put_document) do
+ put "/api/v1/documents/#{URI.encode(id)}",
+ params: update_params,
+ headers: valid_session
+ Document.refresh_index!
+ end
+
let(:update_params) do
{
title: 'new title',
@@ -285,7 +311,7 @@
promote: true,
path: 'http://www.gov.gov/url4.html')
- api_put "/api/v1/documents/#{URI.encode(id)}", update_params, valid_session
+ put_document
end
it 'returns success message as JSON' do
@@ -310,6 +336,39 @@
it_behaves_like 'a data modifying request made during read-only mode'
end
+
+ context 'when time has passed since the document was created' do
+ before do
+ document_create(_id: id,
+ language: 'en',
+ title: 'hi there 4',
+ description: 'bigger desc 4',
+ content: 'huge content 4',
+ path: 'http://www.gov.gov/url4.html')
+ # Force-update the timestamps to avoid fooling the specs with any
+ # automagic trickery
+ Elasticsearch::Persistence.client.update(
+ index: Document.index_name,
+ id: id,
+ body: {
+ doc: {
+ updated_at: 1.year.ago,
+ created_at: 1.year.ago
+ }
+ },
+ type: 'document'
+ )
+ Document.refresh_index!
+ end
+
+ it 'updates the updated_at timestamp' do
+ expect { put_document }.to change { Document.find(id).updated_at }
+ end
+
+ it 'does not update the created_at timestamp' do
+ expect { put_document }.not_to change { Document.find(id).created_at }
+ end
+ end
end
describe 'DELETE /api/v1/documents/{document_id}' do
diff --git a/spec/support/document_crud.rb b/spec/support/document_crud.rb
index eac1e3b9..6a46bcf3 100644
--- a/spec/support/document_crud.rb
+++ b/spec/support/document_crud.rb
@@ -10,13 +10,8 @@ def api_post(params,session)
Document.refresh_index!
end
- def api_put(path,params, session)
- put path, params: params, headers: session
- Document.refresh_index!
- end
-
def api_delete(path,session)
delete path, headers: session
end
-end
\ No newline at end of file
+end
diff --git a/spec/support/shoulda.rb b/spec/support/shoulda.rb
new file mode 100644
index 00000000..7d045f35
--- /dev/null
+++ b/spec/support/shoulda.rb
@@ -0,0 +1,6 @@
+Shoulda::Matchers.configure do |config|
+ config.integrate do |with|
+ with.test_framework :rspec
+ with.library :rails
+ end
+end