sufia 4.1.0 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +14 -3
- data/SUFIA_VERSION +1 -1
- data/app/assets/javascripts/sufia/batch_edit.js +50 -39
- data/app/jobs/content_depositor_change_event_job.rb +7 -14
- data/app/views/_head_tag_extras.html.erb +1 -0
- data/app/views/homepage/_featured.html.erb +1 -1
- data/app/views/homepage/_featured_fields.html.erb +1 -1
- data/app/views/homepage/_recent_document.html.erb +1 -1
- data/app/views/homepage/_tagcloud.html.erb +1 -2
- data/app/views/layouts/_head_tag_content.html.erb +11 -3
- data/lib/sufia/version.rb +1 -1
- data/spec/controllers/generic_files_controller_spec.rb +1 -1
- data/spec/jobs/event_jobs_spec.rb +16 -1
- data/spec/models/file_download_stat_spec.rb +86 -0
- data/spec/models/file_usage_spec.rb +41 -21
- data/spec/models/file_view_stat_spec.rb +84 -0
- data/spec/support/features.rb +1 -0
- data/spec/support/statistic_helper.rb +9 -0
- data/sufia-models/app/models/concerns/sufia/file_stat_utils.rb +35 -0
- data/sufia-models/app/models/file_download_stat.rb +18 -0
- data/sufia-models/app/models/file_usage.rb +6 -35
- data/sufia-models/app/models/file_view_stat.rb +18 -0
- data/sufia-models/lib/generators/sufia/models/cached_stats_generator.rb +53 -0
- data/sufia-models/lib/generators/sufia/models/install_generator.rb +8 -4
- data/sufia-models/lib/generators/sufia/models/templates/migrations/create_file_download_stats.rb +12 -0
- data/sufia-models/lib/generators/sufia/models/templates/migrations/create_file_view_stats.rb +12 -0
- data/sufia-models/lib/sufia/models/version.rb +1 -1
- data/sufia-models/sufia-models.gemspec +5 -0
- metadata +18 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0becb3e785f413597d7424ec1ed417c1712a740
|
4
|
+
data.tar.gz: a7c8c1607bb853f638cf2be54eaf105feeb80cea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afe990f4ee1a1b7cef86f77919fcf79808399553de7627057f34bae0f54f3782f89d4a5b9f07267d57222269f5451918493063b43bbc299a39e8d8b929c29739
|
7
|
+
data.tar.gz: b708364b4863882be9f7376c83a99d7202d1d9b9784844e550ebac24db019f9228b24fbaf4492e7fd884813ea07fac81b975118940a8b733f5d0da6905798a5b
|
data/History.md
CHANGED
@@ -1,10 +1,21 @@
|
|
1
1
|
# History of Sufia releases
|
2
2
|
|
3
|
+
## 4.2.0
|
4
|
+
|
5
|
+
* Caches google analytics data in the database so we do not have to retrieve them each time the page is loaded [Carolyn Cole]
|
6
|
+
* Allows adopters to inject content into the layout's head block, needed by ScholarSphere to add a favicon [Mike Giarlo]
|
7
|
+
* Removes redundant title attributes for featured and recent works, fixes orphaned labels [Michael Tribone]
|
8
|
+
* Pins mini_magick for rubies < 2.1 [Carolyn Cole]
|
9
|
+
* Changes the way we log depositor change events [Mike Giarlo]
|
10
|
+
* Breaks cached stats migrations into dedicated generator [Mike Giarlo]
|
11
|
+
* Fixes bug with proxy setup in the install generator [Mike Giarlo]
|
12
|
+
* Fixes bug in batch editing javascript [Carolyn Cole]
|
13
|
+
|
3
14
|
## 4.1.0
|
4
15
|
|
5
|
-
* Adds proxy deposit, "sticky" proxies, and transfers of ownership (from ScholarSphere) [
|
6
|
-
* Fixes bug with form fields attached to single-valued terms [
|
7
|
-
* Converts specs to use RSpec 3 style [
|
16
|
+
* Adds proxy deposit, "sticky" proxies, and transfers of ownership (from ScholarSphere) [Mike Giarlo]
|
17
|
+
* Fixes bug with form fields attached to single-valued terms [Carolyn Cole]
|
18
|
+
* Converts specs to use RSpec 3 style [Mike Giarlo]
|
8
19
|
|
9
20
|
## 4.0.1
|
10
21
|
|
data/SUFIA_VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
4.
|
1
|
+
4.2.0
|
@@ -20,9 +20,13 @@ function batch_edit_init () {
|
|
20
20
|
var Result = {};
|
21
21
|
while (i--) {
|
22
22
|
var Pair = decodeURIComponent(Data[i]).split("=");
|
23
|
-
var
|
24
|
-
var
|
25
|
-
Result[
|
23
|
+
var key = Pair[0];
|
24
|
+
var val = Pair[1];
|
25
|
+
if (Result[key] != null) {
|
26
|
+
if(!$.isArray(Result[key])) Result[key] = [Result[key]];
|
27
|
+
Result[key].push(val);
|
28
|
+
} else
|
29
|
+
Result[key] = val;
|
26
30
|
}
|
27
31
|
return Result;
|
28
32
|
}
|
@@ -46,54 +50,65 @@ function batch_edit_init () {
|
|
46
50
|
},
|
47
51
|
run: function () {
|
48
52
|
running = true;
|
49
|
-
var self = this
|
50
|
-
orgSuc;
|
53
|
+
var self = this;
|
51
54
|
|
52
55
|
if (requests.length) {
|
53
|
-
oriSuc = requests[0].complete;
|
54
56
|
|
55
57
|
// combine data from multiple requests
|
56
58
|
if (requests.length > 1) {
|
57
|
-
|
58
|
-
form = [requests[0].form]
|
59
|
-
for (var i = requests.length - 1; i > 0; i--) {
|
60
|
-
req = requests.pop();
|
61
|
-
adata = deserialize(req.data.replace(/\+/g, " "));
|
62
|
-
for (key in Object.keys(adata)) {
|
63
|
-
curKey = Object.keys(adata)[key];
|
64
|
-
if (curKey.slice(0, 12) == "generic_file") {
|
65
|
-
data[curKey] = adata[curKey];
|
66
|
-
form.push(req.form);
|
67
|
-
}
|
68
|
-
}
|
69
|
-
}
|
70
|
-
requests[0].data = $.param(data);
|
71
|
-
requests[0].form = form;
|
59
|
+
requests = this.combine_requests(requests);
|
72
60
|
}
|
73
61
|
|
74
|
-
requests
|
75
|
-
if (typeof oriSuc === 'function') oriSuc();
|
76
|
-
if (typeof requests[0].form === 'object') {
|
77
|
-
for (f in form) {
|
78
|
-
form_id = form[f];
|
79
|
-
after_ajax(form_id);
|
80
|
-
}
|
81
|
-
}
|
82
|
-
requests.shift();
|
83
|
-
self.run.apply(self, []);
|
84
|
-
};
|
85
|
-
|
62
|
+
requests = this.setup_request_complete(requests);
|
86
63
|
$.ajax(requests[0]);
|
87
64
|
} else {
|
88
65
|
self.tid = setTimeout(function () {
|
89
66
|
self.run.apply(self, []);
|
90
67
|
}, 500);
|
68
|
+
running = false;
|
91
69
|
}
|
92
|
-
running = false;
|
93
70
|
},
|
94
71
|
stop: function () {
|
95
72
|
requests = [];
|
96
73
|
clearTimeout(this.tid);
|
74
|
+
},
|
75
|
+
setup_request_complete: function (requests) {
|
76
|
+
oriComp = requests[0].complete;
|
77
|
+
|
78
|
+
requests[0].complete = [ function (e) {
|
79
|
+
req = requests.shift();
|
80
|
+
if (typeof req.form === 'object') {
|
81
|
+
for (f in req.form) {
|
82
|
+
form_id = form[f];
|
83
|
+
after_ajax(form_id);
|
84
|
+
}
|
85
|
+
}
|
86
|
+
this.tid = setTimeout(function () {
|
87
|
+
ajaxManager.run.apply(ajaxManager, []);
|
88
|
+
}, 50);
|
89
|
+
return true;
|
90
|
+
}];
|
91
|
+
if (typeof oriComp === 'function') requests[0].complete.push(oriComp);
|
92
|
+
return requests;
|
93
|
+
},
|
94
|
+
combine_requests: function (requests) {
|
95
|
+
var data = deserialize(requests[0].data.replace(/\+/g, " "));
|
96
|
+
form = [requests[0].form]
|
97
|
+
for (var i = requests.length - 1; i > 0; i--) {
|
98
|
+
req = requests.pop();
|
99
|
+
adata = deserialize(req.data.replace(/\+/g, " "));
|
100
|
+
|
101
|
+
for (key in Object.keys(adata)) {
|
102
|
+
curKey = Object.keys(adata)[key];
|
103
|
+
if (curKey.slice(0, 12) == "generic_file") {
|
104
|
+
data[curKey] = adata[curKey];
|
105
|
+
form.push(req.form);
|
106
|
+
}
|
107
|
+
}
|
108
|
+
}
|
109
|
+
requests[0].data = $.param(data);
|
110
|
+
requests[0].form = form;
|
111
|
+
return requests;
|
97
112
|
}
|
98
113
|
};
|
99
114
|
}());
|
@@ -135,11 +150,7 @@ function batch_edit_init () {
|
|
135
150
|
dataType: "json",
|
136
151
|
type: form.attr("method").toUpperCase(),
|
137
152
|
data: form.serialize(),
|
138
|
-
|
139
|
-
eval(e.responseText);
|
140
|
-
after_ajax(form_id);
|
141
|
-
},
|
142
|
-
error: function (e) {
|
153
|
+
complete: function (e) {
|
143
154
|
after_ajax(form_id);
|
144
155
|
if (e.status == 200) {
|
145
156
|
eval(e.responseText);
|
@@ -23,7 +23,7 @@ class ContentDepositorChangeEventJob < EventJob
|
|
23
23
|
file.apply_depositor_metadata(login)
|
24
24
|
file.save!
|
25
25
|
|
26
|
-
action = "User #{link_to_profile file.proxy_depositor} has transferred #{link_to file.title.first, Sufia::Engine.routes.url_helpers.generic_file_path(file.noid)} to
|
26
|
+
action = "User #{link_to_profile file.proxy_depositor} has transferred #{link_to file.title.first, Sufia::Engine.routes.url_helpers.generic_file_path(file.noid)} to user #{link_to_profile login}"
|
27
27
|
timestamp = Time.now.to_i
|
28
28
|
depositor = ::User.find_by_user_key(file.depositor)
|
29
29
|
proxy_depositor = ::User.find_by_user_key(file.proxy_depositor)
|
@@ -31,19 +31,12 @@ class ContentDepositorChangeEventJob < EventJob
|
|
31
31
|
event = proxy_depositor.create_event(action, timestamp)
|
32
32
|
# Log the event to the GF's stream
|
33
33
|
file.log_event(event)
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
#
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
|
-
def log_depositor_event(event, depositor, gf)
|
43
|
-
# Log the event to the depositor's profile stream
|
44
|
-
depositor.log_profile_event(event)
|
45
|
-
# Fan out the event to all followers who have access
|
46
|
-
depositor.followers.select { |user| user.can? :read, gf }.each do |follower|
|
34
|
+
# log the event to the proxy depositor's profile
|
35
|
+
proxy_depositor.log_profile_event(event)
|
36
|
+
# log the event to the depositor's dashboard
|
37
|
+
depositor.log_event(event)
|
38
|
+
# Fan out the event to the depositor's followers who have access
|
39
|
+
depositor.followers.select { |user| user.can? :read, file }.each do |follower|
|
47
40
|
follower.log_event(event)
|
48
41
|
end
|
49
42
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%# Override this partial in your application to insert extra HEAD content into every page %>
|
@@ -2,7 +2,7 @@
|
|
2
2
|
<li class="featured-item" data-id="<%= solr_document.noid %>">
|
3
3
|
<div class="main row">
|
4
4
|
<div class="col-sm-3">
|
5
|
-
<%= link_to sufia.generic_file_path(solr_document) do %>
|
5
|
+
<%= link_to sufia.generic_file_path(solr_document), "aria-hidden" => true do %>
|
6
6
|
<%= render_thumbnail_tag solr_document, {width: 90} %>
|
7
7
|
<% end %>
|
8
8
|
</div>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<h3>
|
2
2
|
<span class="sr-only">Title</span>
|
3
|
-
<%= link_to truncate(featured.title_or_label, length: 28, separator: ' '), sufia.generic_file_path(featured)
|
3
|
+
<%= link_to truncate(featured.title_or_label, length: 28, separator: ' '), sufia.generic_file_path(featured) %>
|
4
4
|
</h3>
|
5
5
|
<div>
|
6
6
|
<span class="sr-only">Depositor</span>
|
@@ -9,7 +9,7 @@
|
|
9
9
|
<% end %>
|
10
10
|
<td>
|
11
11
|
<h3>
|
12
|
-
<span class="sr-only">Title</span><%= link_to truncate(recent_document.title_or_label, length: 28, separator: ' '), sufia.generic_file_path(recent_document.noid)
|
12
|
+
<span class="sr-only">Title</span><%= link_to truncate(recent_document.title_or_label, length: 28, separator: ' '), sufia.generic_file_path(recent_document.noid) %>
|
13
13
|
<% if display_access %>
|
14
14
|
<% if recent_document.registered? %>
|
15
15
|
<span class="label label-info" title="<%=t('sufia.institution_name') %>"><%=t('sufia.institution_name') %></span>
|
@@ -1,6 +1,5 @@
|
|
1
1
|
<a role="button" aria-hidden="true" class="btn btn-default tag-toggle-list">List</a>
|
2
|
-
<
|
3
|
-
<div id="tag-cloud" class="btn-group btn-group-justified tag-sort">
|
2
|
+
<div id="tag-cloud" class="btn-group btn-group-justified tag-sort" aria-label="Sort By">
|
4
3
|
<a role="button" class="btn btn-default tag-sort-za">Z-A</a>
|
5
4
|
<a role="button" class="btn btn-default tag-sort-az">A-Z</a>
|
6
5
|
<a role="button" class="btn btn-default tag-sort-numerical">Rank</a>
|
@@ -2,18 +2,26 @@
|
|
2
2
|
<link href='https://fonts.googleapis.com/css?family=Lato:300,400' rel='stylesheet' type='text/css'>
|
3
3
|
<meta charset="utf-8" />
|
4
4
|
|
5
|
-
<!-- added for use on small devices like phones
|
5
|
+
<!-- added for use on small devices like phones -->
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
7
7
|
|
8
|
-
|
9
|
-
<%= yield :
|
8
|
+
<!-- Twitter card metadata -->
|
9
|
+
<%= yield :twitter_meta %>
|
10
|
+
<!-- Google Scholar metadata -->
|
11
|
+
<%= yield :gscholar_meta %>
|
10
12
|
|
11
13
|
<title><%= h(@page_title || application_name) %></title>
|
14
|
+
|
12
15
|
<!-- application css -->
|
13
16
|
<%= stylesheet_link_tag 'application' %>
|
14
17
|
<%= yield(:css_head) %>
|
15
18
|
|
16
19
|
<!-- application js -->
|
17
20
|
<%= javascript_include_tag 'application' %>
|
21
|
+
<%= yield(:js_head) %>
|
18
22
|
|
23
|
+
<!-- Google Analytics -->
|
19
24
|
<%= render partial: '/ga', formats: [:html] %>
|
25
|
+
|
26
|
+
<!-- for extras, e.g., a favicon -->
|
27
|
+
<%= render partial: '/head_tag_extras', formats: [:html] %>
|
data/lib/sufia/version.rb
CHANGED
@@ -304,7 +304,7 @@ describe GenericFilesController, :type => :controller do
|
|
304
304
|
|
305
305
|
download_query = double('query')
|
306
306
|
allow(download_query).to receive(:for_file).and_return([
|
307
|
-
OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:123456789", totalEvents: "3")
|
307
|
+
OpenStruct.new(date: Date.today.strftime("%Y%m%d"), eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:123456789", totalEvents: "3")
|
308
308
|
])
|
309
309
|
allow(download_query).to receive(:map).and_return(download_query.for_file.map(&:marshal_dump))
|
310
310
|
allow(profile).to receive(:sufia__download).and_return(download_query)
|
@@ -86,6 +86,22 @@ describe 'event jobs' do
|
|
86
86
|
expect(@gf.events.length).to eq(1)
|
87
87
|
expect(@gf.events.first).to eq(event)
|
88
88
|
end
|
89
|
+
it "logs content depositor change events" do
|
90
|
+
# ContentDepositorChange should log the event to the proxy depositor's profile, the depositor's dashboard, followers' dashboards, and the GF
|
91
|
+
@third_user.follow(@another_user)
|
92
|
+
allow_any_instance_of(User).to receive(:can?).and_return(true)
|
93
|
+
allow(Time).to receive(:now).at_least(:once).and_return(1)
|
94
|
+
event = {action: 'User <a href="/users/jilluser@example-dot-com">jilluser@example.com</a> has transferred <a href="/files/123">Hamlet</a> to user <a href="/users/archivist1@example-dot-com">archivist1@example.com</a>', timestamp: '1' }
|
95
|
+
ContentDepositorChangeEventJob.new('test:123', @another_user.user_key).run
|
96
|
+
expect(@user.profile_events.length).to eq(1)
|
97
|
+
expect(@user.profile_events.first).to eq(event)
|
98
|
+
expect(@another_user.events.length).to eq(1)
|
99
|
+
expect(@another_user.events.first).to eq(event)
|
100
|
+
expect(@third_user.events.length).to eq(1)
|
101
|
+
expect(@third_user.events.first).to eq(event)
|
102
|
+
expect(@gf.events.length).to eq(1)
|
103
|
+
expect(@gf.events.first).to eq(event)
|
104
|
+
end
|
89
105
|
it "should log content update events" do
|
90
106
|
# ContentUpdate should log the event to the depositor's profile, followers' dashboards, and the GF
|
91
107
|
@another_user.follow(@user)
|
@@ -188,4 +204,3 @@ describe 'event jobs' do
|
|
188
204
|
expect(@gf.events.first).to eq(event)
|
189
205
|
end
|
190
206
|
end
|
191
|
-
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe FileDownloadStat, :type => :model do
|
4
|
+
let (:file_id) {"99"}
|
5
|
+
let (:date) {DateTime.new}
|
6
|
+
let (:file_stat) {FileDownloadStat.create(downloads:"2", date: date, file_id: file_id)}
|
7
|
+
|
8
|
+
it "has attributes" do
|
9
|
+
expect(file_stat).to respond_to(:downloads)
|
10
|
+
expect(file_stat).to respond_to(:date)
|
11
|
+
expect(file_stat).to respond_to(:file_id)
|
12
|
+
expect(file_stat.file_id).to eq("99")
|
13
|
+
expect(file_stat.date).to eq(date)
|
14
|
+
expect(file_stat.downloads).to eq(2)
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
describe "#get_float_statistics" do
|
19
|
+
|
20
|
+
let(:dates) {
|
21
|
+
ldates = []
|
22
|
+
4.downto(0) {|idx| ldates << (Date.today-idx.day) }
|
23
|
+
ldates
|
24
|
+
}
|
25
|
+
let(:date_strs) {
|
26
|
+
dates.map {|date| date.strftime("%Y%m%d") }
|
27
|
+
}
|
28
|
+
|
29
|
+
let(:download_output) {
|
30
|
+
[[statistic_date(dates[0]), 1], [statistic_date(dates[1]), 1], [statistic_date(dates[2]), 2], [statistic_date(dates[3]), 3]]
|
31
|
+
}
|
32
|
+
|
33
|
+
# This is what the data looks like that's returned from Google Analytics (GA) via the Legato gem
|
34
|
+
# Due to the nature of querying GA, testing this data in an automated fashion is problematc.
|
35
|
+
# Sample data structures were created by sending real events to GA from a test instance of
|
36
|
+
# Scholarsphere. The data below are essentially a "cut and paste" from the output of query
|
37
|
+
# results from the Legato gem.
|
38
|
+
let(:sample_download_statistics) {
|
39
|
+
[
|
40
|
+
OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:x920fw85p", date: date_strs[0], totalEvents: "1"),
|
41
|
+
OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:x920fw85p", date: date_strs[1], totalEvents: "1"),
|
42
|
+
OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:x920fw85p", date: date_strs[2], totalEvents: "2"),
|
43
|
+
OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:x920fw85p", date: date_strs[3], totalEvents: "3"),
|
44
|
+
#OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:x920fw85p", date: date_strs[4], totalEvents: "5"),
|
45
|
+
]
|
46
|
+
}
|
47
|
+
|
48
|
+
describe "cache empty" do
|
49
|
+
let (:stats) {
|
50
|
+
expect(FileDownloadStat).to receive(:ga_statistics).and_return(sample_download_statistics)
|
51
|
+
FileDownloadStat.statistics(file_id,Date.today-4.day)
|
52
|
+
}
|
53
|
+
|
54
|
+
it "includes cached ga data" do
|
55
|
+
expect(FileDownloadStat.to_flots stats).to include(*download_output)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "caches data" do
|
59
|
+
expect(FileDownloadStat.to_flots stats).to include(*download_output)
|
60
|
+
|
61
|
+
# at this point all data should be cached
|
62
|
+
allow(FileDownloadStat).to receive(:ga_statistics).with(Date.today, file_id).and_raise("We should not call Google Analytics All data should be cached!")
|
63
|
+
|
64
|
+
stats2 = FileDownloadStat.statistics(file_id,Date.today-4.day)
|
65
|
+
expect(FileDownloadStat.to_flots stats2).to include(*download_output)
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "cache loaded" do
|
71
|
+
|
72
|
+
let!(:file_download_stat) { FileDownloadStat.create(date: (Date.today-5.day).to_datetime, file_id: file_id, downloads:"25")}
|
73
|
+
|
74
|
+
let (:stats) {
|
75
|
+
expect(FileDownloadStat).to receive(:ga_statistics).and_return(sample_download_statistics)
|
76
|
+
FileDownloadStat.statistics(file_id,Date.today-5.day)
|
77
|
+
}
|
78
|
+
|
79
|
+
it "includes cached data" do
|
80
|
+
expect(FileDownloadStat.to_flots stats).to include([file_download_stat.date.to_i*1000,file_download_stat.downloads],*download_output)
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -12,6 +12,25 @@ describe FileUsage, :type => :model do
|
|
12
12
|
@file.delete
|
13
13
|
end
|
14
14
|
|
15
|
+
let(:dates) {
|
16
|
+
ldates = []
|
17
|
+
4.downto(0) {|idx| ldates << (Date.today-idx.day) }
|
18
|
+
ldates
|
19
|
+
}
|
20
|
+
let(:date_strs) {
|
21
|
+
ldate_strs = []
|
22
|
+
dates.each {|date| ldate_strs << date.strftime("%Y%m%d") }
|
23
|
+
ldate_strs
|
24
|
+
}
|
25
|
+
|
26
|
+
let(:view_output) {
|
27
|
+
[[statistic_date(dates[0]), 4], [statistic_date(dates[1]), 8], [statistic_date(dates[2]), 6], [statistic_date(dates[3]), 10], [statistic_date(dates[4]), 2]]
|
28
|
+
}
|
29
|
+
|
30
|
+
let(:download_output) {
|
31
|
+
[[statistic_date(dates[0]), 1], [statistic_date(dates[1]), 1], [statistic_date(dates[2]), 2], [statistic_date(dates[3]), 3], [statistic_date(dates[4]), 5]]
|
32
|
+
}
|
33
|
+
|
15
34
|
# This is what the data looks like that's returned from Google Analytics (GA) via the Legato gem
|
16
35
|
# Due to the nature of querying GA, testing this data in an automated fashion is problematc.
|
17
36
|
# Sample data structures were created by sending real events to GA from a test instance of
|
@@ -20,27 +39,28 @@ describe FileUsage, :type => :model do
|
|
20
39
|
|
21
40
|
let(:sample_download_statistics) {
|
22
41
|
[
|
23
|
-
OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:x920fw85p", date:
|
24
|
-
OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:x920fw85p", date:
|
25
|
-
OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:x920fw85p", date:
|
26
|
-
OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:x920fw85p", date:
|
27
|
-
OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:x920fw85p", date:
|
42
|
+
OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:x920fw85p", date: date_strs[0], totalEvents: "1"),
|
43
|
+
OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:x920fw85p", date: date_strs[1], totalEvents: "1"),
|
44
|
+
OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:x920fw85p", date: date_strs[2], totalEvents: "2"),
|
45
|
+
OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:x920fw85p", date: date_strs[3], totalEvents: "3"),
|
46
|
+
OpenStruct.new(eventCategory: "Files", eventAction: "Downloaded", eventLabel: "sufia:x920fw85p", date: date_strs[4], totalEvents: "5"),
|
28
47
|
]
|
29
48
|
}
|
30
49
|
|
31
50
|
let(:sample_pageview_statistics) {
|
32
51
|
[
|
33
|
-
OpenStruct.new(date:
|
34
|
-
OpenStruct.new(date:
|
35
|
-
OpenStruct.new(date:
|
36
|
-
OpenStruct.new(date:
|
37
|
-
OpenStruct.new(date:
|
52
|
+
OpenStruct.new(date: date_strs[0], pageviews: 4),
|
53
|
+
OpenStruct.new(date: date_strs[1], pageviews: 8),
|
54
|
+
OpenStruct.new(date: date_strs[2], pageviews: 6),
|
55
|
+
OpenStruct.new(date: date_strs[3], pageviews: 10),
|
56
|
+
OpenStruct.new(date: date_strs[4], pageviews: 2)
|
38
57
|
]
|
39
58
|
}
|
40
59
|
|
41
60
|
let(:usage) {
|
42
|
-
allow_any_instance_of(
|
43
|
-
|
61
|
+
allow_any_instance_of(GenericFile).to receive(:create_date).and_return((Date.today-4.day).to_s)
|
62
|
+
expect(FileDownloadStat).to receive(:ga_statistics).and_return(sample_download_statistics)
|
63
|
+
expect(FileViewStat).to receive(:ga_statistics).and_return(sample_pageview_statistics)
|
44
64
|
FileUsage.new(@file.id)
|
45
65
|
}
|
46
66
|
|
@@ -82,8 +102,8 @@ describe FileUsage, :type => :model do
|
|
82
102
|
it "should return an array of hashes for use with JQuery Flot" do
|
83
103
|
expect(usage.to_flot[0][:label]).to eq("Pageviews")
|
84
104
|
expect(usage.to_flot[1][:label]).to eq("Downloads")
|
85
|
-
expect(usage.to_flot[0][:data]).to include(
|
86
|
-
expect(usage.to_flot[1][:data]).to include(
|
105
|
+
expect(usage.to_flot[0][:data]).to include(*view_output)
|
106
|
+
expect(usage.to_flot[1][:data]).to include(*download_output)
|
87
107
|
end
|
88
108
|
|
89
109
|
let(:create_date) {DateTime.new(2014, 01, 01)}
|
@@ -100,8 +120,8 @@ describe FileUsage, :type => :model do
|
|
100
120
|
describe "create date before earliest date set" do
|
101
121
|
let(:usage) {
|
102
122
|
allow_any_instance_of(GenericFile).to receive(:create_date).and_return(create_date.to_s)
|
103
|
-
|
104
|
-
|
123
|
+
expect(FileDownloadStat).to receive(:ga_statistics).and_return(sample_download_statistics)
|
124
|
+
expect(FileViewStat).to receive(:ga_statistics).and_return(sample_pageview_statistics)
|
105
125
|
FileUsage.new(@file.id)
|
106
126
|
}
|
107
127
|
it "should set the created date to the earliest date not the created date" do
|
@@ -112,8 +132,9 @@ describe FileUsage, :type => :model do
|
|
112
132
|
|
113
133
|
describe "create date after earliest" do
|
114
134
|
let(:usage) {
|
115
|
-
allow_any_instance_of(
|
116
|
-
|
135
|
+
allow_any_instance_of(GenericFile).to receive(:create_date).and_return((Date.today-4.day).to_s)
|
136
|
+
expect(FileDownloadStat).to receive(:ga_statistics).and_return(sample_download_statistics)
|
137
|
+
expect(FileViewStat).to receive(:ga_statistics).and_return(sample_pageview_statistics)
|
117
138
|
Sufia.config.analytic_start_date = earliest
|
118
139
|
FileUsage.new(@file.id)
|
119
140
|
}
|
@@ -129,8 +150,8 @@ describe FileUsage, :type => :model do
|
|
129
150
|
|
130
151
|
let(:usage) {
|
131
152
|
allow_any_instance_of(GenericFile).to receive(:create_date).and_return(create_date.to_s)
|
132
|
-
|
133
|
-
|
153
|
+
expect(FileDownloadStat).to receive(:ga_statistics).and_return(sample_download_statistics)
|
154
|
+
expect(FileViewStat).to receive(:ga_statistics).and_return(sample_pageview_statistics)
|
134
155
|
FileUsage.new(@file.id)
|
135
156
|
}
|
136
157
|
it "should set the created date to the earliest date not the created date" do
|
@@ -139,5 +160,4 @@ describe FileUsage, :type => :model do
|
|
139
160
|
|
140
161
|
end
|
141
162
|
end
|
142
|
-
|
143
163
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe FileViewStat, :type => :model do
|
4
|
+
let (:file_id) {"99"}
|
5
|
+
let (:date) {DateTime.new}
|
6
|
+
let (:file_stat) {FileViewStat.create(views:"25", date: date, file_id: file_id)}
|
7
|
+
|
8
|
+
it "has attributes" do
|
9
|
+
expect(file_stat).to respond_to(:views)
|
10
|
+
expect(file_stat).to respond_to(:date)
|
11
|
+
expect(file_stat).to respond_to(:file_id)
|
12
|
+
expect(file_stat.file_id).to eq("99")
|
13
|
+
expect(file_stat.date).to eq(date)
|
14
|
+
expect(file_stat.views).to eq(25)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#get_float_statistics" do
|
18
|
+
|
19
|
+
let(:dates) {
|
20
|
+
ldates = []
|
21
|
+
4.downto(0) {|idx| ldates << (Date.today-idx.day) }
|
22
|
+
ldates
|
23
|
+
}
|
24
|
+
let(:date_strs) {
|
25
|
+
dates.map {|date| date.strftime("%Y%m%d") }
|
26
|
+
}
|
27
|
+
|
28
|
+
let(:view_output) {
|
29
|
+
[[statistic_date(dates[0]), 4], [statistic_date(dates[1]), 8], [statistic_date(dates[2]), 6], [statistic_date(dates[3]), 10]]
|
30
|
+
}
|
31
|
+
|
32
|
+
# This is what the data looks like that's returned from Google Analytics (GA) via the Legato gem
|
33
|
+
# Due to the nature of querying GA, testing this data in an automated fashion is problematc.
|
34
|
+
# Sample data structures were created by sending real events to GA from a test instance of
|
35
|
+
# Scholarsphere. The data below are essentially a "cut and paste" from the output of query
|
36
|
+
# results from the Legato gem.
|
37
|
+
let(:sample_pageview_statistics) {
|
38
|
+
[
|
39
|
+
OpenStruct.new(date: date_strs[0], pageviews: 4),
|
40
|
+
OpenStruct.new(date: date_strs[1], pageviews: 8),
|
41
|
+
OpenStruct.new(date: date_strs[2], pageviews: 6),
|
42
|
+
OpenStruct.new(date: date_strs[3], pageviews: 10),
|
43
|
+
#OpenStruct.new(date: date_strs[4], pageviews: 2)
|
44
|
+
]
|
45
|
+
}
|
46
|
+
describe "cache empty" do
|
47
|
+
let (:stats) {
|
48
|
+
expect(FileViewStat).to receive(:ga_statistics).and_return(sample_pageview_statistics)
|
49
|
+
FileViewStat.statistics(file_id,Date.today-4.day)
|
50
|
+
}
|
51
|
+
|
52
|
+
it "includes cached ga data" do
|
53
|
+
expect(FileViewStat.to_flots stats).to include(*view_output)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "caches data" do
|
57
|
+
expect(FileViewStat.to_flots stats).to include(*view_output)
|
58
|
+
|
59
|
+
# at this point all data should be cached
|
60
|
+
allow(FileViewStat).to receive(:ga_statistics).with(Date.today, file_id).and_raise("We should not call Google Analytics All data should be cached!")
|
61
|
+
|
62
|
+
stats2 = FileViewStat.statistics(file_id,Date.today-5.day)
|
63
|
+
expect(FileViewStat.to_flots stats2).to include(*view_output)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "cache loaded" do
|
69
|
+
|
70
|
+
let!(:file_view_stat) { FileViewStat.create(date: (Date.today-5.day).to_datetime, file_id: file_id, views:"25")}
|
71
|
+
|
72
|
+
let (:stats) {
|
73
|
+
expect(FileViewStat).to receive(:ga_statistics).and_return(sample_pageview_statistics)
|
74
|
+
FileViewStat.statistics(file_id,Date.today-5.day)
|
75
|
+
}
|
76
|
+
|
77
|
+
it "includes cached data" do
|
78
|
+
expect(FileViewStat.to_flots stats).to include([file_view_stat.date.to_i*1000,file_view_stat.views],*view_output)
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
data/spec/support/features.rb
CHANGED
@@ -6,6 +6,7 @@ require File.expand_path('../proxies', __FILE__)
|
|
6
6
|
require File.expand_path('../locations', __FILE__)
|
7
7
|
require File.expand_path('../poltergeist', __FILE__)
|
8
8
|
require File.expand_path('../cleaner', __FILE__)
|
9
|
+
require File.expand_path('../statistic_helper', __FILE__)
|
9
10
|
|
10
11
|
RSpec.configure do |config|
|
11
12
|
config.include Features::SessionHelpers, type: :feature
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Sufia
|
2
|
+
module FileStatUtils
|
3
|
+
|
4
|
+
def to_flots stats
|
5
|
+
stats.map {|stat| stat.to_flot}
|
6
|
+
end
|
7
|
+
|
8
|
+
def convert_date date_time
|
9
|
+
date_time.to_datetime.to_i * 1000
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def cached_stats(file_id, start_date, method)
|
15
|
+
stats = self.where(file_id:file_id).order(date: :asc)
|
16
|
+
ga_start_date = stats.size > 0 ? stats[stats.size-1].date + 1.day : start_date.to_date
|
17
|
+
{ga_start_date: ga_start_date, cached_stats: stats.to_a }
|
18
|
+
end
|
19
|
+
|
20
|
+
def combined_stats file_id, start_date, object_method, ga_key
|
21
|
+
stat_cache_info = cached_stats( file_id, start_date, object_method)
|
22
|
+
stats = stat_cache_info[:cached_stats]
|
23
|
+
if stat_cache_info[:ga_start_date] < Date.today
|
24
|
+
ga_stats = ga_statistics(stat_cache_info[:ga_start_date], file_id)
|
25
|
+
ga_stats.each do |stat|
|
26
|
+
lstat = self.new file_id:file_id, date: stat[:date], object_method => stat[ga_key]
|
27
|
+
lstat.save unless Date.parse(stat[:date]) == Date.today
|
28
|
+
stats << lstat
|
29
|
+
end
|
30
|
+
end
|
31
|
+
stats
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class FileDownloadStat < ActiveRecord::Base
|
2
|
+
extend Sufia::FileStatUtils
|
3
|
+
|
4
|
+
def to_flot
|
5
|
+
[ self.class.convert_date(date), downloads ]
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.statistics file_id, start_date
|
9
|
+
combined_stats file_id, start_date, :downloads, :totalEvents
|
10
|
+
end
|
11
|
+
|
12
|
+
# Sufia::Download is sent to Sufia::Analytics.profile as #sufia__download
|
13
|
+
# see Legato::ProfileMethods.method_name_from_klass
|
14
|
+
def self.ga_statistics start_date, file_id
|
15
|
+
Sufia::Analytics.profile.sufia__download(sort: 'date', start_date: start_date, end_date: Date.yesterday).for_file(file_id)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -8,52 +8,23 @@ class FileUsage
|
|
8
8
|
earliest = Sufia.config.analytic_start_date
|
9
9
|
self.created = DateTime.parse(::GenericFile.find(id).create_date)
|
10
10
|
self.created = earliest > created ? earliest : created unless earliest.blank?
|
11
|
-
self.downloads =
|
12
|
-
self.pageviews =
|
11
|
+
self.downloads = FileDownloadStat.to_flots FileDownloadStat.statistics(id, created)
|
12
|
+
self.pageviews = FileViewStat.to_flots FileViewStat.statistics(id, created)
|
13
13
|
end
|
14
14
|
|
15
15
|
def total_downloads
|
16
|
-
self.downloads.
|
16
|
+
self.downloads.reduce(0) { |total, result| total + result[1].to_i }
|
17
17
|
end
|
18
18
|
|
19
19
|
def total_pageviews
|
20
|
-
self.pageviews.
|
20
|
+
self.pageviews.reduce(0) { |total, result| total + result[1].to_i }
|
21
21
|
end
|
22
22
|
|
23
23
|
# Package data for visualization using JQuery Flot
|
24
24
|
def to_flot
|
25
25
|
[
|
26
|
-
{ label: "Pageviews", data:
|
27
|
-
{ label: "Downloads", data:
|
26
|
+
{ label: "Pageviews", data: pageviews },
|
27
|
+
{ label: "Downloads", data: downloads }
|
28
28
|
]
|
29
29
|
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
# Sufia::Download is sent to Sufia::Analytics.profile as #sufia__download
|
34
|
-
# see Legato::ProfileMethods.method_name_from_klass
|
35
|
-
def download_statistics
|
36
|
-
Sufia::Analytics.profile.sufia__download(sort: 'date', start_date: created).for_file(self.id)
|
37
|
-
end
|
38
|
-
|
39
|
-
# Sufia::Pageview is sent to Sufia::Analytics.profile as #sufia__pageview
|
40
|
-
# see Legato::ProfileMethods.method_name_from_klass
|
41
|
-
def pageview_statistics
|
42
|
-
Sufia::Analytics.profile.sufia__pageview(sort: 'date', start_date: created).for_path(self.path)
|
43
|
-
end
|
44
|
-
|
45
|
-
def pageviews_to_flot values = Array.new
|
46
|
-
self.pageviews.map(&:marshal_dump).map do |result_hash|
|
47
|
-
values << [ (Date.parse(result_hash[:date]).to_time.to_i * 1000), result_hash[:pageviews].to_i ]
|
48
|
-
end
|
49
|
-
return values
|
50
|
-
end
|
51
|
-
|
52
|
-
def downloads_to_flot values = Array.new
|
53
|
-
self.downloads.map(&:marshal_dump).map do |result_hash|
|
54
|
-
values << [ (Date.parse(result_hash[:date]).to_time.to_i * 1000), result_hash[:totalEvents].to_i ]
|
55
|
-
end
|
56
|
-
return values
|
57
|
-
end
|
58
|
-
|
59
30
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class FileViewStat < ActiveRecord::Base
|
2
|
+
extend Sufia::FileStatUtils
|
3
|
+
|
4
|
+
def to_flot
|
5
|
+
[ self.class.convert_date(date), views ]
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.statistics file_id, start_date
|
9
|
+
combined_stats file_id, start_date, :views, :pageviews
|
10
|
+
end
|
11
|
+
|
12
|
+
# Sufia::Download is sent to Sufia::Analytics.profile as #sufia__download
|
13
|
+
# see Legato::ProfileMethods.method_name_from_klass
|
14
|
+
def self.ga_statistics start_date, file_id
|
15
|
+
path = Sufia::Engine.routes.url_helpers.generic_file_path(Sufia::Noid.noidify(file_id))
|
16
|
+
Sufia::Analytics.profile.sufia__pageview(sort: 'date', start_date: start_date).for_path(path)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'rails/generators'
|
3
|
+
require 'rails/generators/migration'
|
4
|
+
|
5
|
+
class Sufia::Models::CachedStatsGenerator < Rails::Generators::Base
|
6
|
+
include Rails::Generators::Migration
|
7
|
+
|
8
|
+
source_root File.expand_path('../templates', __FILE__)
|
9
|
+
|
10
|
+
desc """
|
11
|
+
This generator adds the ability to cache usage stats to your application:
|
12
|
+
1. Creates several database migrations if they do not exist in /db/migrate
|
13
|
+
"""
|
14
|
+
# Implement the required interface for Rails::Generators::Migration.
|
15
|
+
# taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
|
16
|
+
def self.next_migration_number(path)
|
17
|
+
if @prev_migration_nr
|
18
|
+
@prev_migration_nr += 1
|
19
|
+
else
|
20
|
+
if last_migration = Dir[File.join(path, '*.rb')].sort.last
|
21
|
+
@prev_migration_nr = last_migration.sub(File.join(path, '/'), '').to_i + 1
|
22
|
+
else
|
23
|
+
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
24
|
+
end
|
25
|
+
end
|
26
|
+
@prev_migration_nr.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
def banner
|
30
|
+
say_status("warning", "ADDING STATS CACHING-RELATED SUFIA MODELS", :yellow)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Setup the database migrations
|
34
|
+
def copy_migrations
|
35
|
+
# Can't get this any more DRY, because we need this order.
|
36
|
+
[
|
37
|
+
'create_file_view_stats.rb',
|
38
|
+
'create_file_download_stats.rb'
|
39
|
+
].each do |file|
|
40
|
+
better_migration_template file
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def better_migration_template(file)
|
47
|
+
begin
|
48
|
+
migration_template "migrations/#{file}", "db/migrate/#{file}"
|
49
|
+
rescue Rails::Generators::Error => e
|
50
|
+
say_status("warning", e.message, :yellow)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -18,6 +18,7 @@ This generator makes the following changes to your application:
|
|
18
18
|
6. Installs Blacklight gallery
|
19
19
|
7. Runs full-text generator
|
20
20
|
8. Runs proxies generator
|
21
|
+
9. Runs cached stats generator
|
21
22
|
"""
|
22
23
|
|
23
24
|
# Implement the required interface for Rails::Generators::Migration.
|
@@ -56,9 +57,7 @@ This generator makes the following changes to your application:
|
|
56
57
|
'add_linkedin_to_users.rb',
|
57
58
|
'create_tinymce_assets.rb',
|
58
59
|
'create_content_blocks.rb',
|
59
|
-
'create_featured_works.rb'
|
60
|
-
'create_proxy_deposit_requests.rb',
|
61
|
-
'create_proxy_deposit_rights.rb'
|
60
|
+
'create_featured_works.rb'
|
62
61
|
].each do |file|
|
63
62
|
better_migration_template file
|
64
63
|
end
|
@@ -106,10 +105,15 @@ This generator makes the following changes to your application:
|
|
106
105
|
end
|
107
106
|
|
108
107
|
# Sets up proxies and transfers
|
109
|
-
def
|
108
|
+
def proxies
|
110
109
|
generate "sufia:models:proxies"
|
111
110
|
end
|
112
111
|
|
112
|
+
# Sets up cached usage stats
|
113
|
+
def cached_stats
|
114
|
+
generate 'sufia:models:cached_stats'
|
115
|
+
end
|
116
|
+
|
113
117
|
private
|
114
118
|
|
115
119
|
def better_migration_template(file)
|
@@ -42,4 +42,9 @@ Gem::Specification.new do |spec|
|
|
42
42
|
spec.add_dependency 'google-api-client', '~> 0.7'
|
43
43
|
spec.add_dependency 'legato', '~> 0.3'
|
44
44
|
spec.add_dependency 'activerecord-import', '~> 0.5'
|
45
|
+
if RUBY_VERSION < '2.1.0'
|
46
|
+
spec.add_dependency 'mini_magick', '< 4'
|
47
|
+
else
|
48
|
+
spec.add_dependency 'mini_magick'
|
49
|
+
end
|
45
50
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sufia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Coyne
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-11-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sufia-models
|
@@ -17,14 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - '='
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: 4.
|
20
|
+
version: 4.2.0
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - '='
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: 4.
|
27
|
+
version: 4.2.0
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: blacklight_advanced_search
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -629,6 +629,7 @@ files:
|
|
629
629
|
- app/views/_flash_msg.html.erb
|
630
630
|
- app/views/_footer.html.erb
|
631
631
|
- app/views/_ga.html.erb
|
632
|
+
- app/views/_head_tag_extras.html.erb
|
632
633
|
- app/views/_logo.html.erb
|
633
634
|
- app/views/_masthead.html.erb
|
634
635
|
- app/views/_user_util_links.html.erb
|
@@ -977,7 +978,9 @@ files:
|
|
977
978
|
- spec/models/featured_work_list_spec.rb
|
978
979
|
- spec/models/featured_work_spec.rb
|
979
980
|
- spec/models/file_content_datastream_spec.rb
|
981
|
+
- spec/models/file_download_stat_spec.rb
|
980
982
|
- spec/models/file_usage_spec.rb
|
983
|
+
- spec/models/file_view_stat_spec.rb
|
981
984
|
- spec/models/fits_datastream_spec.rb
|
982
985
|
- spec/models/generic_file/reload_on_save_spec.rb
|
983
986
|
- spec/models/generic_file/visibility_spec.rb
|
@@ -1007,6 +1010,7 @@ files:
|
|
1007
1010
|
- spec/support/poltergeist.rb
|
1008
1011
|
- spec/support/proxies.rb
|
1009
1012
|
- spec/support/selectors.rb
|
1013
|
+
- spec/support/statistic_helper.rb
|
1010
1014
|
- spec/support/uploaded_file_monkeypatch.rb
|
1011
1015
|
- spec/test_app_templates/lib/generators/test_app_generator.rb
|
1012
1016
|
- spec/views/batch/edit.html.erb_spec.rb
|
@@ -1044,6 +1048,7 @@ files:
|
|
1044
1048
|
- sufia-models/app/models/collection.rb
|
1045
1049
|
- sufia-models/app/models/concerns/sufia/ability.rb
|
1046
1050
|
- sufia-models/app/models/concerns/sufia/collection.rb
|
1051
|
+
- sufia-models/app/models/concerns/sufia/file_stat_utils.rb
|
1047
1052
|
- sufia-models/app/models/concerns/sufia/generic_file.rb
|
1048
1053
|
- sufia-models/app/models/concerns/sufia/generic_file/accessible_attributes.rb
|
1049
1054
|
- sufia-models/app/models/concerns/sufia/generic_file/audit.rb
|
@@ -1072,7 +1077,9 @@ files:
|
|
1072
1077
|
- sufia-models/app/models/datastreams/properties_datastream.rb
|
1073
1078
|
- sufia-models/app/models/domain_term.rb
|
1074
1079
|
- sufia-models/app/models/featured_work.rb
|
1080
|
+
- sufia-models/app/models/file_download_stat.rb
|
1075
1081
|
- sufia-models/app/models/file_usage.rb
|
1082
|
+
- sufia-models/app/models/file_view_stat.rb
|
1076
1083
|
- sufia-models/app/models/follow.rb
|
1077
1084
|
- sufia-models/app/models/generic_file.rb
|
1078
1085
|
- sufia-models/app/models/geo_names_resource.rb
|
@@ -1093,6 +1100,7 @@ files:
|
|
1093
1100
|
- sufia-models/app/services/sufia/id_service.rb
|
1094
1101
|
- sufia-models/app/services/sufia/noid.rb
|
1095
1102
|
- sufia-models/config/locales/sufia.en.yml
|
1103
|
+
- sufia-models/lib/generators/sufia/models/cached_stats_generator.rb
|
1096
1104
|
- sufia-models/lib/generators/sufia/models/fulltext_generator.rb
|
1097
1105
|
- sufia-models/lib/generators/sufia/models/install_generator.rb
|
1098
1106
|
- sufia-models/lib/generators/sufia/models/proxies_generator.rb
|
@@ -1117,6 +1125,8 @@ files:
|
|
1117
1125
|
- sufia-models/lib/generators/sufia/models/templates/migrations/create_checksum_audit_logs.rb
|
1118
1126
|
- sufia-models/lib/generators/sufia/models/templates/migrations/create_content_blocks.rb
|
1119
1127
|
- sufia-models/lib/generators/sufia/models/templates/migrations/create_featured_works.rb
|
1128
|
+
- sufia-models/lib/generators/sufia/models/templates/migrations/create_file_download_stats.rb
|
1129
|
+
- sufia-models/lib/generators/sufia/models/templates/migrations/create_file_view_stats.rb
|
1120
1130
|
- sufia-models/lib/generators/sufia/models/templates/migrations/create_local_authorities.rb
|
1121
1131
|
- sufia-models/lib/generators/sufia/models/templates/migrations/create_proxy_deposit_requests.rb
|
1122
1132
|
- sufia-models/lib/generators/sufia/models/templates/migrations/create_proxy_deposit_rights.rb
|
@@ -1206,7 +1216,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1206
1216
|
version: '0'
|
1207
1217
|
requirements: []
|
1208
1218
|
rubyforge_project:
|
1209
|
-
rubygems_version: 2.4.
|
1219
|
+
rubygems_version: 2.4.3
|
1210
1220
|
signing_key:
|
1211
1221
|
specification_version: 4
|
1212
1222
|
summary: Sufia was extracted from ScholarSphere developed by Penn State University
|
@@ -1321,7 +1331,9 @@ test_files:
|
|
1321
1331
|
- spec/models/featured_work_list_spec.rb
|
1322
1332
|
- spec/models/featured_work_spec.rb
|
1323
1333
|
- spec/models/file_content_datastream_spec.rb
|
1334
|
+
- spec/models/file_download_stat_spec.rb
|
1324
1335
|
- spec/models/file_usage_spec.rb
|
1336
|
+
- spec/models/file_view_stat_spec.rb
|
1325
1337
|
- spec/models/fits_datastream_spec.rb
|
1326
1338
|
- spec/models/generic_file/reload_on_save_spec.rb
|
1327
1339
|
- spec/models/generic_file/visibility_spec.rb
|
@@ -1351,6 +1363,7 @@ test_files:
|
|
1351
1363
|
- spec/support/poltergeist.rb
|
1352
1364
|
- spec/support/proxies.rb
|
1353
1365
|
- spec/support/selectors.rb
|
1366
|
+
- spec/support/statistic_helper.rb
|
1354
1367
|
- spec/support/uploaded_file_monkeypatch.rb
|
1355
1368
|
- spec/test_app_templates/lib/generators/test_app_generator.rb
|
1356
1369
|
- spec/views/batch/edit.html.erb_spec.rb
|