sufia 6.3.0 → 6.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -2
  3. data/.rubocop.yml +10 -0
  4. data/Gemfile +16 -7
  5. data/History.md +43 -0
  6. data/README.md +26 -19
  7. data/SUFIA_VERSION +1 -1
  8. data/app/assets/javascripts/notifications_check.js.erb +46 -0
  9. data/app/assets/javascripts/sufia.js +1 -2
  10. data/app/assets/javascripts/sufia/uploader.js +3 -3
  11. data/app/assets/stylesheets/sufia/_collections.scss +5 -0
  12. data/app/assets/stylesheets/sufia/_dashboard.scss +6 -1
  13. data/app/assets/stylesheets/sufia/_file-listing.scss +44 -6
  14. data/app/assets/stylesheets/sufia/_file-show.scss +4 -0
  15. data/app/assets/stylesheets/sufia/_settings.scss +3 -0
  16. data/app/controllers/api/items_controller.rb +7 -3
  17. data/app/controllers/concerns/sufia/admin/depositor_stats.rb +1 -1
  18. data/app/controllers/concerns/sufia/admin/stats_behavior.rb +6 -76
  19. data/app/controllers/concerns/sufia/batch_controller_behavior.rb +10 -2
  20. data/app/controllers/concerns/sufia/contact_form_controller_behavior.rb +1 -0
  21. data/app/controllers/concerns/sufia/files_controller_behavior.rb +11 -1
  22. data/app/controllers/concerns/sufia/homepage_controller.rb +1 -1
  23. data/app/controllers/concerns/sufia/my_controller_behavior.rb +2 -0
  24. data/app/controllers/concerns/sufia/users_controller_behavior.rb +2 -2
  25. data/app/helpers/generic_file_helper.rb +8 -5
  26. data/app/jobs/content_delete_event_job.rb +16 -11
  27. data/app/jobs/content_deposit_event_job.rb +4 -16
  28. data/app/jobs/content_depositor_change_event_job.rb +32 -20
  29. data/app/jobs/content_event_job.rb +39 -0
  30. data/app/jobs/content_new_version_event_job.rb +4 -16
  31. data/app/jobs/content_restored_version_event_job.rb +6 -19
  32. data/app/jobs/content_update_event_job.rb +4 -16
  33. data/app/jobs/event_job.rb +48 -4
  34. data/app/jobs/user_edit_profile_event_job.rb +4 -17
  35. data/app/jobs/user_follow_event_job.rb +10 -12
  36. data/app/jobs/user_unfollow_event_job.rb +10 -15
  37. data/app/models/concerns/sufia/solr_document_behavior.rb +11 -1
  38. data/app/models/system_stats.rb +108 -0
  39. data/app/presenters/sufia/admin_stats_presenter.rb +49 -0
  40. data/app/views/_controls.html.erb +1 -1
  41. data/app/views/_footer.html.erb +1 -1
  42. data/app/views/_logo.html.erb +1 -3
  43. data/app/views/admin/stats/_date_form.html.erb +8 -0
  44. data/app/views/admin/stats/_deposits.html.erb +2 -10
  45. data/app/views/admin/stats/_files.html.erb +6 -14
  46. data/app/views/admin/stats/_new_users.html.erb +7 -14
  47. data/app/views/admin/stats/_stats_by_date.html.erb +8 -0
  48. data/app/views/admin/stats/_top_data.html.erb +24 -0
  49. data/app/views/admin/stats/index.html.erb +5 -31
  50. data/app/views/collections/_form_for_select_collection.html.erb +5 -4
  51. data/app/views/collections/_show_actions.html.erb +7 -2
  52. data/app/views/collections/_show_document_list_row.html.erb +1 -9
  53. data/app/views/generic_files/_browse_everything.html.erb +3 -0
  54. data/app/views/generic_files/_descriptions.html.erb +1 -1
  55. data/app/views/generic_files/_generic_file.html.erb +1 -1
  56. data/app/views/generic_files/_local_file_import.html.erb +3 -0
  57. data/app/views/generic_files/_show_actions.html.erb +4 -0
  58. data/app/views/generic_files/upload/_form.html.erb +3 -0
  59. data/app/views/generic_files/upload/_to_collection.html.erb +5 -0
  60. data/app/views/homepage/_recent_document.html.erb +1 -7
  61. data/app/views/my/_index_partials/_default_group.html.erb +1 -1
  62. data/app/views/my/_index_partials/_list_collections.html.erb +3 -10
  63. data/app/views/my/_index_partials/_list_files.html.erb +13 -22
  64. data/app/views/my/_sort_and_per_page.html.erb +3 -3
  65. data/app/views/records/edit_fields/_rights.html.erb +2 -1
  66. data/app/views/static/terms.html.erb +1 -1
  67. data/config/locales/sufia.en.yml +13 -0
  68. data/lib/generators/sufia/templates/catalog_controller.rb +2 -2
  69. data/lib/sufia/version.rb +1 -1
  70. data/spec/actors/generic_file/actor_spec.rb +35 -0
  71. data/spec/controllers/admin_stats_controller_spec.rb +53 -23
  72. data/spec/controllers/api/items_controller_spec.rb +47 -41
  73. data/spec/controllers/batch_controller_spec.rb +1 -0
  74. data/spec/controllers/generic_files_controller_spec.rb +35 -1
  75. data/spec/controllers/my/files_controller_spec.rb +5 -0
  76. data/spec/factories/generic_files.rb +3 -0
  77. data/spec/features/collection_spec.rb +91 -0
  78. data/spec/features/contact_form_spec.rb +1 -0
  79. data/spec/forms/collection_edit_form_spec.rb +3 -3
  80. data/spec/forms/generic_file_edit_form_spec.rb +1 -1
  81. data/spec/jobs/create_derivatives_job_spec.rb +6 -0
  82. data/spec/models/file_content_datastream_spec.rb +1 -1
  83. data/spec/models/file_download_stat_spec.rb +4 -4
  84. data/spec/models/file_usage_spec.rb +2 -2
  85. data/spec/models/file_view_stat_spec.rb +4 -4
  86. data/spec/models/generic_file_spec.rb +15 -3
  87. data/spec/models/geo_names_resource_spec.rb +10 -0
  88. data/spec/models/solr_document_spec.rb +28 -0
  89. data/spec/models/system_stats_spec.rb +184 -0
  90. data/spec/models/user_spec.rb +1 -1
  91. data/spec/models/user_usage_stats_spec.rb +1 -1
  92. data/spec/services/generic_file_csv_service_spec.rb +66 -0
  93. data/spec/services/generic_file_indexing_service_spec.rb +35 -0
  94. data/spec/services/lock_manager_spec.rb +12 -0
  95. data/spec/spec_helper.rb +2 -1
  96. data/spec/views/admin/stats/index.html.erb_spec.rb +11 -10
  97. data/spec/views/catalog/sort_and_per_page.html.erb_spec.rb +1 -1
  98. data/spec/views/collections/_form_for_select_collection.html.erb_spec.rb +51 -0
  99. data/spec/views/generic_file/_browse_everything.html.erb_spec.rb +4 -0
  100. data/spec/views/generic_file/edit.html.erb_spec.rb +31 -24
  101. data/spec/views/generic_file/new.html.erb_spec.rb +70 -0
  102. data/spec/views/generic_file/show.html.erb_spec.rb +23 -0
  103. data/sufia.gemspec +3 -2
  104. data/tasks/sufia-dev.rake +2 -0
  105. metadata +42 -9
  106. data/lib/sufia/role_mapper.rb +0 -7
@@ -17,6 +17,7 @@ describe BatchController do
17
17
  it "is successful" do
18
18
  expect(Sufia.queue).to receive(:push).with(batch_update_message).once
19
19
  post :update, id: batch.id, title: { '1' => 'foo' }, visibility: 'open', generic_file: { tag: [""] }
20
+ expect(assigns(:batch_update_job)).to eq(batch_update_message)
20
21
  expect(response).to redirect_to routes.url_helpers.dashboard_files_path
21
22
  expect(flash[:notice]).to include("Your files are being processed")
22
23
  end
@@ -15,6 +15,14 @@ describe GenericFilesController do
15
15
  let(:mock) { GenericFile.new(id: 'test123') }
16
16
  let(:batch) { Batch.create }
17
17
  let(:batch_id) { batch.id }
18
+ let(:collection) {
19
+ Collection.create(title: 'test collection') do |c|
20
+ c.apply_depositor_metadata(user.user_key)
21
+ end
22
+ }
23
+ let(:collection_id) { collection.id }
24
+ let(:collection_noedit) { Collection.create(title: 'test collection - NO EDIT') }
25
+ let(:collection_noedit_id) { collection_noedit.id }
18
26
  let(:file) { fixture_file_upload('/world.png', 'image/png') }
19
27
 
20
28
  before do
@@ -39,10 +47,22 @@ describe GenericFilesController do
39
47
  end
40
48
  end
41
49
 
50
+ context "when user tries to upload to a collection they can't edit" do
51
+ # This shouldn't happen via the UI which will only present to the user collections they can edit.
52
+ it "adds new file but does not put the file in the collection" do
53
+ xhr :post, :create, files: [file], Filename: "The world", batch_id: batch_id, permission: { "group" => { "public" => "read" } }, terms_of_service: "1", collection: collection_noedit_id
54
+ expect(response).to be_success
55
+
56
+ updated_collection = Collection.find(collection_id)
57
+ # This is confirming that the file was NOT added to the collection the user cannot edit
58
+ expect(updated_collection.member_ids).to eq []
59
+ end
60
+ end
61
+
42
62
  context "when everything is perfect" do
43
63
  render_views
44
64
  it "spawns a content deposit event job" do
45
- expect_any_instance_of(Sufia::GenericFile::Actor).to receive(:create_content).with(file, 'world.png', 'content', 'image/png').and_return(true)
65
+ expect_any_instance_of(Sufia::GenericFile::Actor).to receive(:create_content).with(file, 'world.png', 'content', 'image/png', nil).and_return(true)
46
66
  xhr :post, :create, files: [file], 'Filename' => 'The world', batch_id: batch_id, permission: { group: { public: 'read' } }, terms_of_service: '1'
47
67
  expect(response.body).to eq '[{"name":null,"size":null,"url":"/files/test123","thumbnail_url":"test123","delete_url":"deleteme","delete_type":"DELETE"}]'
48
68
  expect(flash[:error]).to be_nil
@@ -82,6 +102,20 @@ describe GenericFilesController do
82
102
  expect(saved_file.depositor).to eq 'jilluser@example.com'
83
103
  expect(saved_file.to_solr['depositor_tesim']).to eq ['jilluser@example.com']
84
104
  end
105
+
106
+ it "adds new file when collection is instructions id" do
107
+ xhr :post, :create, files: [file], Filename: "The world", batch_id: batch_id, permission: { "group" => { "public" => "read" } }, terms_of_service: "1", collection: '-1'
108
+ expect(response).to be_success
109
+ end
110
+
111
+ it "adds new file to collection" do
112
+ xhr :post, :create, files: [file], Filename: "The world", batch_id: batch_id, permission: { "group" => { "public" => "read" } }, terms_of_service: "1", collection: collection_id
113
+ expect(response).to be_success
114
+
115
+ updated_collection = Collection.find(collection_id)
116
+ # This is confirming that the file was added to the collection
117
+ expect(updated_collection.member_ids).to eq ['test123']
118
+ end
85
119
  end
86
120
 
87
121
  context "when the file has a virus" do
@@ -87,4 +87,9 @@ describe My::FilesController, type: :controller do
87
87
  expect(assigns(:batches)).to include("ss-" + batch_id2)
88
88
  end
89
89
  end
90
+
91
+ it "sets add_files_to_collection when provided in params" do
92
+ get :index, add_files_to_collection: '12345'
93
+ expect(assigns(:add_files_to_collection)).to eql('12345')
94
+ end
90
95
  end
@@ -25,6 +25,7 @@ FactoryGirl.define do
25
25
  resource_type ["Dissertation"]
26
26
  subject %w(lorem ipsum dolor sit amet)
27
27
  title ["fake_document.pdf"]
28
+ mime_type 'application/pdf'
28
29
  before(:create) do |gf|
29
30
  gf.title = ["Fake PDF Title"]
30
31
  end
@@ -36,6 +37,7 @@ FactoryGirl.define do
36
37
  initialize_with { new(id: id) }
37
38
  subject %w(consectetur adipisicing elit)
38
39
  title ["Test Document MP3.mp3"]
40
+ mime_type 'audio/mpeg'
39
41
  read_groups ["public"]
40
42
  end
41
43
  factory :public_wav do
@@ -46,6 +48,7 @@ FactoryGirl.define do
46
48
  resource_type ["Audio", "Dataset"]
47
49
  read_groups ["public"]
48
50
  title ["Fake Wav File.wav"]
51
+ mime_type 'audio/wav'
49
52
  subject %w(sed do eiusmod tempor incididunt ut labore)
50
53
  end
51
54
  end
@@ -25,6 +25,15 @@ describe 'collection', type: :feature do
25
25
  let(:title2) { "Test Collection 2" }
26
26
  let(:description2) { "Description for collection 2 we are testing." }
27
27
 
28
+ let(:collection1) do
29
+ Collection.create(title: title1, description: description1,
30
+ members: []) { |c| c.apply_depositor_metadata(user.user_key) }
31
+ end
32
+ let(:collection2) do
33
+ Collection.create(title: title2, description: description2,
34
+ members: []) { |c| c.apply_depositor_metadata(user.user_key) }
35
+ end
36
+
28
37
  let(:user) { FactoryGirl.create(:user) }
29
38
 
30
39
  let(:gfs) do
@@ -140,6 +149,88 @@ describe 'collection', type: :feature do
140
149
  end
141
150
  end
142
151
 
152
+ describe 'collection sorting' do
153
+ before do
154
+ collection1 # create the collections by referencing them
155
+ sleep(1) # make sure the timestamps aren't equal
156
+ collection2
157
+ sleep(1)
158
+ collection1.title += 'changed'
159
+ collection1.save
160
+ # collection 1 is now earlier when sorting by create date but later
161
+ # when sorting by modified date
162
+
163
+ sign_in user
164
+ visit '/dashboard/collections'
165
+ end
166
+
167
+ it "has creation date for collections" do
168
+ expect(page).to have_content(collection1.create_date.to_date.to_formatted_s(:standard))
169
+ end
170
+
171
+ it "allows changing sort order" do
172
+ find(:xpath, "//select[@id='sort']/option[contains(., 'date modified')][contains(@value, 'asc')]") \
173
+ .select_option
174
+ click_button('Refresh')
175
+ expect(page).to have_css("#document_#{collection1.id}")
176
+ expect(page).to have_css("#document_#{collection2.id}")
177
+ expect(page.body.index("id=\"document_#{collection1.id}")).to be > page.body.index("id=\"document_#{collection2.id}")
178
+
179
+ find(:xpath, "//select[@id='sort']/option[contains(., 'date modified')][contains(@value, 'desc')]") \
180
+ .select_option
181
+ click_button('Refresh')
182
+ expect(page).to have_css("#document_#{collection1.id}")
183
+ expect(page).to have_css("#document_#{collection2.id}")
184
+ expect(page.body.index("id=\"document_#{collection1.id}")).to be < page.body.index("id=\"document_#{collection2.id}")
185
+ end
186
+ end
187
+
188
+ describe 'add files to collection' do
189
+ let!(:gf1) { gfs[0] }
190
+ let!(:gf2) { gfs[1] }
191
+
192
+ before do
193
+ collection1 # create collections by referencing them
194
+ collection2
195
+ sign_in user
196
+ end
197
+
198
+ it "preselects the collection we are adding files to" do
199
+ visit "/collections/#{collection1.id}"
200
+ click_link 'Add files'
201
+ first('input#check_all').click
202
+ click_button "Add to Collection"
203
+ expect(page).to have_css("input#id_#{collection1.id}[checked='checked']")
204
+ expect(page).not_to have_css("input#id_#{collection2.id}[checked='checked']")
205
+
206
+ visit "/collections/#{collection2.id}"
207
+ click_link 'Add files'
208
+ first('input#check_all').click
209
+ click_button "Add to Collection"
210
+ expect(page).not_to have_css("input#id_#{collection1.id}[checked='checked']")
211
+ expect(page).to have_css("input#id_#{collection2.id}[checked='checked']")
212
+ end
213
+ end
214
+
215
+ describe 'upload files to collection' do
216
+ let(:upload_to_collection) { true }
217
+ let!(:gf1) { gfs[0] }
218
+ let!(:gf2) { gfs[1] }
219
+
220
+ before do
221
+ Sufia.config.upload_to_collection = upload_to_collection
222
+ collection1 # create collections by referencing them
223
+ collection2
224
+ sign_in user
225
+ end
226
+
227
+ it "preselects the collection we are uploading files to" do
228
+ visit "/collections/#{collection1.id}"
229
+ click_link 'Upload files'
230
+ expect(page).to have_select('collection', selected: title1)
231
+ end
232
+ end
233
+
143
234
  describe 'edit collection' do
144
235
  let!(:collection) do
145
236
  Collection.create(title: 'collection title', description: 'collection description',
@@ -17,6 +17,7 @@ describe "Sending an email via the contact form", type: :feature do
17
17
  select "Depositing content", from: "contact_form_category"
18
18
  click_button "Send"
19
19
  expect(page).to have_content "Thank you"
20
+ expect(page).not_to have_content "I am contacting you regarding ScholarSphere."
20
21
  # this step allows the delivery to go back to normal
21
22
  allow_any_instance_of(ContactForm).to receive(:deliver).and_call_original
22
23
  end
@@ -11,10 +11,10 @@ describe Sufia::Forms::CollectionEditForm do
11
11
  :identifier, :based_near, :related_url] }
12
12
  end
13
13
 
14
- describe "unique?" do
14
+ describe "multiple?" do
15
15
  context "with :title" do
16
- subject { described_class.unique?(:title) }
17
- it { is_expected.to be true }
16
+ subject { described_class.multiple?(:title) }
17
+ it { is_expected.to be false }
18
18
  end
19
19
  end
20
20
  end
@@ -23,7 +23,7 @@ describe Sufia::Forms::GenericFileEditForm do
23
23
  let(:params) { ActionController::Parameters.new(title: ['foo'], description: [''], "permissions_attributes" => { "2" => { "access" => "edit", "_destroy" => "true", "id" => "a987551e-b87f-427a-8721-3e5942273125" } }) }
24
24
  subject { described_class.model_attributes(params) }
25
25
 
26
- it "onlies change title" do
26
+ it "only changes title" do
27
27
  expect(subject['title']).to eq ["foo"]
28
28
  expect(subject['description']).to be_empty
29
29
  expect(subject['permissions_attributes']).to eq("2" => { "access" => "edit", "id" => "a987551e-b87f-427a-8721-3e5942273125", "_destroy" => "true" })
@@ -171,4 +171,10 @@ describe CreateDerivativesJob do
171
171
  end
172
172
  end
173
173
  end
174
+
175
+ describe 'minimagick setup' do
176
+ it 'uses posix-spawn' do
177
+ expect(MiniMagick.shell_api).to eq('posix-spawn')
178
+ end
179
+ end
174
180
  end
@@ -45,7 +45,7 @@ describe FileContentDatastream, type: :model do
45
45
  @generic_file.apply_depositor_metadata('mjg36')
46
46
  end
47
47
 
48
- it "onlies return true when the datastream has actually changed" do
48
+ it "only returns true when the datastream has actually changed" do
49
49
  @generic_file.add_file(File.open(fixture_path + '/world.png', 'rb'), path: 'content', original_name: 'world.png')
50
50
  expect(@generic_file.content).to be_changed
51
51
  @generic_file.save!
@@ -46,7 +46,7 @@ RSpec.describe FileDownloadStat, type: :model do
46
46
  describe "cache empty" do
47
47
  let(:stats) do
48
48
  expect(described_class).to receive(:ga_statistics).and_return(sample_download_statistics)
49
- described_class.statistics(file_id, Date.today - 4.day)
49
+ described_class.statistics(file_id, Date.today - 4.days)
50
50
  end
51
51
 
52
52
  it "includes cached ga data" do
@@ -59,17 +59,17 @@ RSpec.describe FileDownloadStat, type: :model do
59
59
  # at this point all data should be cached
60
60
  allow(described_class).to receive(:ga_statistics).with(Date.today, file_id).and_raise("We should not call Google Analytics All data should be cached!")
61
61
 
62
- stats2 = described_class.statistics(file_id, Date.today - 4.day)
62
+ stats2 = described_class.statistics(file_id, Date.today - 4.days)
63
63
  expect(described_class.to_flots stats2).to include(*download_output)
64
64
  end
65
65
  end
66
66
 
67
67
  describe "cache loaded" do
68
- let!(:file_download_stat) { described_class.create(date: (Date.today - 5.day).to_datetime, file_id: file_id, downloads: "25") }
68
+ let!(:file_download_stat) { described_class.create(date: (Date.today - 5.days).to_datetime, file_id: file_id, downloads: "25") }
69
69
 
70
70
  let(:stats) do
71
71
  expect(described_class).to receive(:ga_statistics).and_return(sample_download_statistics)
72
- described_class.statistics(file_id, Date.today - 5.day)
72
+ described_class.statistics(file_id, Date.today - 5.days)
73
73
  end
74
74
 
75
75
  it "includes cached data" do
@@ -55,7 +55,7 @@ describe FileUsage, type: :model do
55
55
  end
56
56
 
57
57
  let(:usage) do
58
- allow_any_instance_of(GenericFile).to receive(:create_date).and_return((Date.today - 4.day).to_s)
58
+ allow_any_instance_of(GenericFile).to receive(:create_date).and_return((Date.today - 4.days).to_s)
59
59
  expect(FileDownloadStat).to receive(:ga_statistics).and_return(sample_download_statistics)
60
60
  expect(FileViewStat).to receive(:ga_statistics).and_return(sample_pageview_statistics)
61
61
  described_class.new(file.id)
@@ -123,7 +123,7 @@ describe FileUsage, type: :model do
123
123
 
124
124
  describe "create date after earliest" do
125
125
  let(:usage) do
126
- allow_any_instance_of(GenericFile).to receive(:create_date).and_return((Date.today - 4.day).to_s)
126
+ allow_any_instance_of(GenericFile).to receive(:create_date).and_return((Date.today - 4.days).to_s)
127
127
  expect(FileDownloadStat).to receive(:ga_statistics).and_return(sample_download_statistics)
128
128
  expect(FileViewStat).to receive(:ga_statistics).and_return(sample_pageview_statistics)
129
129
  Sufia.config.analytic_start_date = earliest
@@ -47,7 +47,7 @@ RSpec.describe FileViewStat, type: :model do
47
47
  describe "cache empty" do
48
48
  let(:stats) do
49
49
  expect(described_class).to receive(:ga_statistics).and_return(sample_pageview_statistics)
50
- described_class.statistics(file_id, Date.today - 4.day, user_id)
50
+ described_class.statistics(file_id, Date.today - 4.days, user_id)
51
51
  end
52
52
 
53
53
  it "includes cached ga data" do
@@ -61,17 +61,17 @@ RSpec.describe FileViewStat, type: :model do
61
61
  # at this point all data should be cached
62
62
  allow(described_class).to receive(:ga_statistics).with(Date.today, file_id).and_raise("We should not call Google Analytics All data should be cached!")
63
63
 
64
- stats2 = described_class.statistics(file_id, Date.today - 5.day)
64
+ stats2 = described_class.statistics(file_id, Date.today - 5.days)
65
65
  expect(described_class.to_flots stats2).to include(*view_output)
66
66
  end
67
67
  end
68
68
 
69
69
  describe "cache loaded" do
70
- let!(:file_view_stat) { described_class.create(date: (Date.today - 5.day).to_datetime, file_id: file_id, views: "25") }
70
+ let!(:file_view_stat) { described_class.create(date: (Date.today - 5.days).to_datetime, file_id: file_id, views: "25") }
71
71
 
72
72
  let(:stats) do
73
73
  expect(described_class).to receive(:ga_statistics).and_return(sample_pageview_statistics)
74
- described_class.statistics(file_id, Date.today - 5.day)
74
+ described_class.statistics(file_id, Date.today - 5.days)
75
75
  end
76
76
 
77
77
  it "includes cached data" do
@@ -491,7 +491,7 @@ describe GenericFile, type: :model do
491
491
  expect(subject.edit_users).to eq ['jcoyne']
492
492
  end
493
493
 
494
- it "onlies revoke eligible groups" do
494
+ it "only revokes eligible groups" do
495
495
  subject.set_read_groups(['group-2', 'group-3'], ['group-6'])
496
496
  # 'group-7' is not eligible to be revoked
497
497
  expect(subject.read_groups).to match_array ['group-2', 'group-3', 'group-7']
@@ -643,7 +643,7 @@ describe GenericFile, type: :model do
643
643
  end
644
644
 
645
645
  context "with no end date" do
646
- let(:start_date) { 1.days.ago }
646
+ let(:start_date) { 1.day.ago }
647
647
  let(:end_date) { nil }
648
648
  before do
649
649
  @file.save
@@ -652,7 +652,7 @@ describe GenericFile, type: :model do
652
652
  end
653
653
 
654
654
  context "with an end date" do
655
- let(:start_date) { 1.days.ago }
655
+ let(:start_date) { 1.day.ago }
656
656
  let(:end_date) { DateTime.now }
657
657
  before do
658
658
  @file.save
@@ -661,6 +661,18 @@ describe GenericFile, type: :model do
661
661
  end
662
662
  end
663
663
 
664
+ describe '#where_digest_is' do
665
+ subject { described_class.where_digest_is digest_string }
666
+ let(:digest_string) { 'f794b23c0c6fe1083d0ca8b58261a078cd968967' }
667
+ before do
668
+ @file.add_file(File.open(fixture_path + '/world.png'), path: 'content', original_name: 'world.png')
669
+ @file.save
670
+ end
671
+ it 'returns a list of files' do
672
+ expect(subject).to eq [@file]
673
+ end
674
+ end
675
+
664
676
  describe "where_access_is" do
665
677
  subject { described_class.where_access_is access_level }
666
678
  before do
@@ -1,6 +1,16 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe GeoNamesResource, type: :model do
4
+ before do
5
+ state = {
6
+ "totalResultsCount" => 1, "geonames" => [{
7
+ "countryId" => "1327865", "adminCode1" => "11", "countryName" => "Myanmar [Burma]", "fclName" => "country, state, region,...", "countryCode" => "MM", "lng" => "98", "fcodeName" => "first-order administrative division", "toponymName" => "Shan State", "fcl" => "A", "name" => "Shan State", "fcode" => "ADM1", "geonameId" => 1_297_099, "lat" => "22", "adminName1" => "Shan", "population" => 5_815_384
8
+ }]
9
+ }
10
+ ActiveResource::HttpMock.respond_to do |mock|
11
+ mock.get "/searchJSON?maxRows=10&q=State&username=", {}, state.to_json
12
+ end
13
+ end
4
14
  it "finds locations" do
5
15
  hits = described_class.find_location("State")
6
16
  expect(hits).not_to be_nil
@@ -8,6 +8,34 @@ describe SolrDocument, type: :model do
8
8
  it "is a date" do
9
9
  expect(subject.date_uploaded).to eq '03/14/2013'
10
10
  end
11
+ it "logs parse errors" do
12
+ expect(ActiveFedora::Base.logger).to receive(:info).with(/Unable to parse date.*/)
13
+ subject['date_uploaded_dtsi'] = 'Test'
14
+ subject.date_uploaded
15
+ end
16
+ end
17
+
18
+ describe "create_date" do
19
+ before do
20
+ subject['system_create_dtsi'] = '2013-03-14T00:00:00Z'
21
+ end
22
+ it "is a date" do
23
+ expect(subject.create_date).to eq '03/14/2013'
24
+ end
25
+ it "logs parse errors" do
26
+ expect(ActiveFedora::Base.logger).to receive(:info).with(/Unable to parse date.*/)
27
+ subject['system_create_dtsi'] = 'Test'
28
+ subject.create_date
29
+ end
30
+ end
31
+
32
+ describe "resource_type" do
33
+ before do
34
+ subject['resource_type_tesim'] = ['Image']
35
+ end
36
+ it "returns the resource type" do
37
+ expect(subject.resource_type).to eq ['Image']
38
+ end
11
39
  end
12
40
 
13
41
  describe '#to_param' do
@@ -0,0 +1,184 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::SystemStats, type: :model do
4
+ let(:user1) { FactoryGirl.find_or_create(:user) }
5
+ let(:morning_two_days_ago) { 2.days.ago.to_date.to_datetime.to_s }
6
+ let(:yesterday) { 1.day.ago.to_datetime.to_s }
7
+ let(:this_morning) { 0.days.ago.to_date.to_datetime.to_s }
8
+
9
+ let(:stats) { described_class.new(depositor_count, user_stats[:start_date], user_stats[:end_date]) }
10
+
11
+ describe "#top_depositors" do
12
+ let(:user_stats) { {} }
13
+
14
+ context "when requested count is withing bounds" do
15
+ let!(:user2) { FactoryGirl.find_or_create(:archivist) }
16
+ let(:depositor_count) { 15 }
17
+
18
+ # I am specifically creating objects in this test
19
+ # I am doing this for one test to make sure that the full loop works
20
+ before do
21
+ GenericFile.new(id: "abc123") do |gf|
22
+ gf.apply_depositor_metadata(user1)
23
+ gf.update_index
24
+ end
25
+ GenericFile.new(id: "def123") do |gf|
26
+ gf.apply_depositor_metadata(user2)
27
+ gf.update_index
28
+ end
29
+ GenericFile.new(id: "zzz123") do |gf|
30
+ gf.create_date = [2.days.ago]
31
+ gf.apply_depositor_metadata(user1)
32
+ gf.update_index
33
+ end
34
+ Collection.new(id: "ccc123") do |c|
35
+ c.apply_depositor_metadata(user1)
36
+ c.update_index
37
+ end
38
+ end
39
+
40
+ it "queries for the data" do
41
+ expect(stats.top_depositors).to include(display_name(user1) => 3, display_name(user2) => 1)
42
+ end
43
+ end
44
+
45
+ context "when requested count is too small" do
46
+ let(:depositor_count) { 3 }
47
+ let(:actual_count) { 5 }
48
+ it "queries for 5 items" do
49
+ expect(stats).to receive(:open).with("http://127.0.0.1:8983/solr/test/terms?terms.fl=depositor_tesim&terms.sort=count&terms.limit=#{actual_count}&wt=json&omitHeader=true").and_return(StringIO.new('{"terms":{"depositor_tesim":["example.com",4,"user2",3,"archivist1",1]}}'))
50
+ stats.top_depositors
51
+ end
52
+ end
53
+
54
+ context "when requested count is too big" do
55
+ let(:depositor_count) { 99 }
56
+ let(:actual_count) { 20 }
57
+ it "queries for 20 items" do
58
+ expect(stats).to receive(:open).with("http://127.0.0.1:8983/solr/test/terms?terms.fl=depositor_tesim&terms.sort=count&terms.limit=#{actual_count}&wt=json&omitHeader=true").and_return(StringIO.new('{"terms":{"depositor_tesim":["example.com",4,"user2",3,"archivist1",1]}}'))
59
+ stats.top_depositors
60
+ end
61
+ end
62
+ end
63
+
64
+ def display_name(user)
65
+ user.user_key.split('@')[0]
66
+ end
67
+
68
+ describe "#document_by_permission" do
69
+ let(:user_stats) { {} }
70
+ let(:depositor_count) { nil }
71
+
72
+ before do
73
+ FactoryGirl.build(:public_pdf, depositor: user1, id: "pdf1223").update_index
74
+ FactoryGirl.build(:public_wav, depositor: user1, id: "wav1223").update_index
75
+ FactoryGirl.build(:public_mp3, depositor: user1, id: "mp31223", create_date: [2.days.ago]).update_index
76
+ FactoryGirl.build(:registered_file, depositor: user1, id: "reg1223").update_index
77
+ FactoryGirl.build(:generic_file, depositor: user1, id: "private1223").update_index
78
+ Collection.new(id: "ccc123") do |c|
79
+ c.apply_depositor_metadata(user1)
80
+ c.update_index
81
+ end
82
+ end
83
+ it "get all documents by permissions" do
84
+ expect(stats.document_by_permission).to include(public: 3, private: 1, registered: 1, total: 5)
85
+ end
86
+
87
+ context "when passing a start date" do
88
+ let(:user_stats) { { start_date: yesterday } }
89
+ it "get documents after date by permissions" do
90
+ expect(stats.document_by_permission).to include(public: 2, private: 1, registered: 1, total: 4)
91
+ end
92
+
93
+ context "when passing an end date" do
94
+ let(:user_stats) { { start_date: morning_two_days_ago, end_date: yesterday } }
95
+ it "get documents between dates by permissions" do
96
+ expect(stats.document_by_permission).to include(public: 1, private: 0, registered: 0, total: 1)
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ describe "#top_formats" do
103
+ let(:user_stats) { {} }
104
+ let(:depositor_count) { nil }
105
+
106
+ before do
107
+ FactoryGirl.build(:public_pdf, depositor: user1, id: "pdf1111").update_index
108
+ FactoryGirl.build(:public_wav, depositor: user1, id: "wav1111").update_index
109
+ FactoryGirl.build(:public_mp3, depositor: user1, id: "mp31111", create_date: [2.days.ago]).update_index
110
+ FactoryGirl.build(:registered_file, depositor: user1, id: "word1111", mime_type: "application/vnd.ms-word.document").update_index
111
+ end
112
+
113
+ subject { stats.top_formats }
114
+
115
+ it { is_expected.to include("mpeg" => 1, "pdf" => 1, "wav" => 1, "vnd.ms-word.document" => 1) }
116
+
117
+ context "when more than 5 formats available" do
118
+ before do
119
+ FactoryGirl.build(:public_pdf, depositor: user1, id: "pdf2222").update_index
120
+ FactoryGirl.build(:public_wav, depositor: user1, id: "wav2222").update_index
121
+ FactoryGirl.build(:public_mp3, depositor: user1, id: "mp32222", create_date: [2.days.ago]).update_index
122
+ FactoryGirl.build(:registered_file, depositor: user1, id: "reg2222", mime_type: "application/vnd.ms-word.document").update_index
123
+ FactoryGirl.build(:generic_file, depositor: user1, id: "png1111", mime_type: "image/png").update_index
124
+ FactoryGirl.build(:generic_file, depositor: user1, id: "png2222", mime_type: "image/png").update_index
125
+ FactoryGirl.build(:generic_file, depositor: user1, id: "jpeg2222", mime_type: "image/jpeg").update_index
126
+ end
127
+
128
+ it do
129
+ is_expected.to include("mpeg" => 2, "pdf" => 2, "wav" => 2, "vnd.ms-word.document" => 2, "png" => 2)
130
+ is_expected.not_to include("jpeg" => 1)
131
+ end
132
+ end
133
+ end
134
+
135
+ describe "#recent_users" do
136
+ let!(:user2) { FactoryGirl.find_or_create(:archivist) }
137
+
138
+ let(:one_day_ago_date) { 1.day.ago.to_datetime }
139
+ let(:two_days_ago_date) { 2.days.ago.to_datetime.end_of_day }
140
+ let(:one_day_ago) { one_day_ago_date.strftime("%Y-%m-%d") }
141
+ let(:two_days_ago) { two_days_ago_date.strftime("%Y-%m-%d") }
142
+ let(:depositor_count) { nil }
143
+
144
+ subject { stats.recent_users }
145
+
146
+ context "without dates" do
147
+ let(:user_stats) { {} }
148
+ let(:mock_order) { double }
149
+ let(:mock_limit) { double }
150
+ it "defaults to latest 5 users" do
151
+ expect(mock_order).to receive(:limit).with(5).and_return(mock_limit)
152
+ expect(User).to receive(:order).with('created_at DESC').and_return(mock_order)
153
+ is_expected.to eq mock_limit
154
+ end
155
+ end
156
+
157
+ context "with start date" do
158
+ let(:user_stats) { { start_date: one_day_ago } }
159
+
160
+ it "allows queries against user_stats without an end date " do
161
+ expect(User).to receive(:recent_users).with(one_day_ago_date, nil).and_return([user2])
162
+ is_expected.to eq([user2])
163
+ end
164
+ end
165
+ context "with start date and end date" do
166
+ let(:user_stats) { { start_date: two_days_ago, end_date: one_day_ago } }
167
+ it "queries" do
168
+ expect(User).to receive(:recent_users).with(two_days_ago_date, one_day_ago_date).and_return([user2])
169
+ is_expected.to eq([user2])
170
+ end
171
+ end
172
+ end
173
+
174
+ describe "#users_count" do
175
+ let(:user_stats) { {} }
176
+ let(:depositor_count) { nil }
177
+ let!(:user1) { FactoryGirl.find_or_create(:user) }
178
+ let!(:user2) { FactoryGirl.find_or_create(:archivist) }
179
+
180
+ subject { stats.users_count }
181
+
182
+ it { is_expected.to eq 2 }
183
+ end
184
+ end