muck-services 0.1.23 → 0.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +4 -2
- data/Rakefile +3 -3
- data/VERSION +1 -1
- data/app/models/entry.rb +88 -91
- data/app/models/oai_endpoint.rb +1 -13
- data/app/models/personal_recommendation.rb +6 -2
- data/app/models/service.rb +14 -14
- data/app/views/recommendations/index.pjs.erb +4 -3
- data/config/muck_services_routes.rb +1 -0
- data/lib/active_record/acts/muck_recommendations.rb +2 -0
- data/muck-services.gemspec +4 -6
- data/public/stylesheets/muck-services.css +1 -1
- data/test/rails_root/config/environment.rb +1 -0
- data/test/rails_root/test/unit/aggregation_test.rb +4 -38
- data/test/rails_root/test/unit/feed_test.rb +32 -5
- data/test/rails_root/test/unit/oai_endpoint_test.rb +37 -10
- data/test/rails_root/test/unit/service_category_test.rb +1 -1
- data/test/rails_root/test/unit/service_test.rb +57 -4
- metadata +2 -3
- data/app/views/services/_personal_recommendations.html.erb +0 -5
data/README.rdoc
CHANGED
@@ -78,8 +78,10 @@ muck-services uses muck-comments and muck-activities to add comments to entries
|
|
78
78
|
muck-services also uses muck-shares and muck-activities to share entries with other users. Again you can omit these gems if you don't desire the share capability.
|
79
79
|
|
80
80
|
To turn on this functionality add these lines to your global_config.yml file:
|
81
|
-
|
82
|
-
|
81
|
+
inform_admin_of_global_feed: true # If true then the 'admin_email' will recieve an email anytime a global feed (one that is not
|
82
|
+
# attached to any object) is added.
|
83
|
+
enable_services_comments: true # Enables or disables comments in the frame that wraps content as a user browses recommendation results
|
84
|
+
enable_services_shares: true # Enables or disables sharing in the frame that wraps content as a user browses recommendation results
|
83
85
|
|
84
86
|
To install these gems:
|
85
87
|
sudo gem install muck-comments
|
data/Rakefile
CHANGED
@@ -3,6 +3,9 @@ require 'rake'
|
|
3
3
|
require 'rake/testtask'
|
4
4
|
require 'rake/rdoctask'
|
5
5
|
|
6
|
+
desc 'Default: run unit tests.'
|
7
|
+
task :default => :test
|
8
|
+
|
6
9
|
desc 'Translate this gem'
|
7
10
|
task :translate do
|
8
11
|
file = File.join(File.dirname(__FILE__), 'locales', 'en.yml')
|
@@ -35,9 +38,6 @@ Rake::TestTask.new(:test) do |t|
|
|
35
38
|
t.verbose = true
|
36
39
|
end
|
37
40
|
|
38
|
-
task :test => :check_dependencies
|
39
|
-
task :default => :test
|
40
|
-
|
41
41
|
begin
|
42
42
|
require 'jeweler'
|
43
43
|
Jeweler::Tasks.new do |gem|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.24
|
data/app/models/entry.rb
CHANGED
@@ -46,10 +46,6 @@ class Entry < ActiveRecord::Base
|
|
46
46
|
self.direct_link.nil? ? self.permalink : self.direct_link
|
47
47
|
end
|
48
48
|
|
49
|
-
def self.top_tags(tags = nil)
|
50
|
-
|
51
|
-
end
|
52
|
-
|
53
49
|
def self.search(search_terms, grain_size = nil, language = "en", limit = 10, offset = 0, operator = :or)
|
54
50
|
raise MuckServices::Exceptions::LanguageNotSupported, I18n.t('muck.services.language_not_supported') unless Recommender::Languages.supported_languages.include?(language)
|
55
51
|
query = ((!grain_size.nil? && grain_size != 'all') ? (search_terms + ") AND (grain_size:#{grain_size}") : search_terms) + ") AND (aggregation:#{Aggregation.global_feeds_id}"
|
@@ -63,8 +59,8 @@ class Entry < ActiveRecord::Base
|
|
63
59
|
Entry.find(:first, :conditions => ['permalink = ? OR direct_link = ?', uri, uri], :order => 'direct_link IS NULL DESC') || Entry.new(:permalink => uri)
|
64
60
|
end
|
65
61
|
|
66
|
-
def
|
67
|
-
sql = "SELECT recommendations.id,
|
62
|
+
def recommendation_entries(limit = 20, order = "relevance", details = false, omit_feeds = nil)
|
63
|
+
sql = "SELECT recommendations.dest_entry_id AS id, entries.permalink, entries.title, entries.description, entries.direct_link, feeds.short_title AS collection "
|
68
64
|
sql << ", relevance_calculated_at, relevance, clicks, avg_time_at_dest AS avg_time_on_target, author, published_at " if details == true
|
69
65
|
sql << "FROM recommendations "
|
70
66
|
sql << "INNER JOIN entries ON recommendations.dest_entry_id = entries.id "
|
@@ -76,8 +72,8 @@ class Entry < ActiveRecord::Base
|
|
76
72
|
Entry.find_by_sql([sql,self.id])
|
77
73
|
end
|
78
74
|
|
79
|
-
def
|
80
|
-
sql = "SELECT recommendations.
|
75
|
+
def recommendations(limit = 20, order = "relevance", details = false, omit_feeds = nil)
|
76
|
+
sql = "SELECT recommendations.id, dest_entry_id, entries.permalink, entries.title, entries.description, entries.direct_link, feeds.short_title AS collection "
|
81
77
|
sql << ", relevance_calculated_at, relevance, clicks, avg_time_at_dest AS avg_time_on_target, author, published_at " if details == true
|
82
78
|
sql << "FROM recommendations "
|
83
79
|
sql << "INNER JOIN entries ON recommendations.dest_entry_id = entries.id "
|
@@ -89,90 +85,13 @@ class Entry < ActiveRecord::Base
|
|
89
85
|
Entry.find_by_sql([sql,self.id])
|
90
86
|
end
|
91
87
|
|
92
|
-
def self.track_time_on_page(session, uri)
|
93
|
-
recommendation_id = session[:last_clicked_recommendation]
|
94
|
-
if !recommendation_id.nil?
|
95
|
-
time_on_page = (Time.now - session[:last_clicked_recommendation_time].to_f).to_i
|
96
|
-
|
97
|
-
# if they spend longer than two minutes on a page, we don't infer anything
|
98
|
-
if time_on_page > 5 and time_on_page < 120
|
99
|
-
if normalized_uri(uri) != session[:last_clicked_recommendation_uri]
|
100
|
-
recommendation = Recommendation.find(recommendation_id)
|
101
|
-
entry = Entry.find(recommendation.entry_id)
|
102
|
-
new_avg = (recommendation.avg_time_at_dest*recommendation.clicks - @@default_time_on_page + time_on_page)/recommendation.clicks
|
103
|
-
recommendation.avg_time_at_dest = new_avg
|
104
|
-
recommendation.save!
|
105
|
-
entry.rank_recommendations
|
106
|
-
session[:last_clicked_recommendation] = nil
|
107
|
-
end
|
108
|
-
else
|
109
|
-
session[:last_clicked_recommendation] = nil if time_on_page > 5
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def self.avg_time(clicks, old_avg, time_on_page)
|
115
|
-
return (old_avg*(clicks-1) + time_on_page)/clicks
|
116
|
-
end
|
117
|
-
|
118
|
-
def self.track_click(session, recommendation_id, referrer, redirect_type = "direct_link", requester = "unknown", user_agent = "unknown")
|
119
|
-
# look up the recommendation
|
120
|
-
recommendation = Recommendation.find(recommendation_id)
|
121
|
-
return "" if !recommendation
|
122
|
-
|
123
|
-
# get the entries being linked from and to
|
124
|
-
entry = Entry.find(recommendation.entry_id)
|
125
|
-
target = Entry.find(recommendation.dest_entry_id)
|
126
|
-
|
127
|
-
# get the list of recommendations that have been clicked during this session
|
128
|
-
clicks = session[:rids] || Array.new
|
129
|
-
|
130
|
-
# redirect to our frame page
|
131
|
-
redirect = "/visits/#{recommendation.dest_entry_id}"
|
132
|
-
|
133
|
-
# track the time on the last page
|
134
|
-
track_time_on_page(session, redirect)
|
135
|
-
|
136
|
-
# if this is first time the user clicked on this recommendation during this session
|
137
|
-
if !clicks.include?(recommendation_id)
|
138
|
-
|
139
|
-
# add this recommendation to the end of the list
|
140
|
-
clicks << recommendation_id
|
141
|
-
session[:rids] = clicks
|
142
|
-
|
143
|
-
# update the click time
|
144
|
-
recommendation.avg_time_at_dest = ((recommendation.avg_time_at_dest*recommendation.clicks) + @@default_time_on_page)/(recommendation.clicks + 1)
|
145
|
-
recommendation.clicks += 1
|
146
|
-
recommendation.save!
|
147
|
-
|
148
|
-
# store info about this click in the session
|
149
|
-
now = Time.now
|
150
|
-
session[:last_clicked_recommendation] = recommendation_id
|
151
|
-
session[:last_clicked_recommendation_time] = now
|
152
|
-
session[:last_clicked_recommendation_uri] = redirect
|
153
|
-
|
154
|
-
# update the recommendation cache for the entry
|
155
|
-
entry.rank_recommendations if entry
|
156
|
-
|
157
|
-
# track the click in the db
|
158
|
-
Click.create(:recommendation_id => recommendation_id, :when => now, :referrer => referrer, :requester => requester, :user_agent => user_agent)
|
159
|
-
end
|
160
|
-
|
161
|
-
return redirect
|
162
|
-
end
|
163
|
-
|
164
88
|
def relevant_recommendations(limit = 5, order = "relevance", details = false, omit_feeds = nil)
|
165
89
|
return self.recommendations(limit, order, details, omit_feeds)
|
166
90
|
end
|
167
91
|
|
168
|
-
def self.truncate_words(text, length = 30, end_string = ' ...')
|
169
|
-
words = text.split()
|
170
|
-
words[0..(length-1)].join(' ') + (words.length > length ? end_string : '')
|
171
|
-
end
|
172
|
-
|
173
92
|
def ranked_recommendations(limit = 5, order = "mixed", details = false, omit_feeds = nil)
|
174
|
-
return
|
175
|
-
return
|
93
|
+
return self.recommendations(limit, "clicks DESC, relevance", details, omit_feeds) if order == "clicks"
|
94
|
+
return self.recommendations(limit, "relevance", details, omit_feeds) if (order == "relevance" || details == true)
|
176
95
|
return relevant_recommendations_filtered(limit, details, omit_feeds) if omit_feeds != nil
|
177
96
|
|
178
97
|
recs = []
|
@@ -190,6 +109,11 @@ class Entry < ActiveRecord::Base
|
|
190
109
|
return recs
|
191
110
|
end
|
192
111
|
|
112
|
+
def json_recommendations(limit = 5, order = "mixed", details = false, omit_feeds = nil)
|
113
|
+
recs = ranked_recommendations(limit, order, details, omit_feeds)
|
114
|
+
(recs.nil? || recs.empty?) ? "" : ActiveSupport::JSON.encode(recs)
|
115
|
+
end
|
116
|
+
|
193
117
|
def relevant_recommendations_filtered(limit, details, omit_feeds)
|
194
118
|
# get recommendations for the entry from the recommendations table
|
195
119
|
recs = self.recommendations(limit, "mixed", details, omit_feeds)
|
@@ -222,10 +146,6 @@ class Entry < ActiveRecord::Base
|
|
222
146
|
return (popular_recs + relevant_recs + other_recs)[0..limit]
|
223
147
|
end
|
224
148
|
|
225
|
-
def json_recommendations(limit = 5, order = "mixed", details = false, omit_feeds = nil)
|
226
|
-
ActiveSupport::JSON.encode(ranked_recommendations(limit, order, details, omit_feeds))
|
227
|
-
end
|
228
|
-
|
229
149
|
def rank_recommendations
|
230
150
|
return
|
231
151
|
# get recommendations for the entry from the recommendations table
|
@@ -304,6 +224,83 @@ class Entry < ActiveRecord::Base
|
|
304
224
|
return threshold > 5 ? threshold : 5
|
305
225
|
end
|
306
226
|
|
227
|
+
def self.avg_time(clicks, old_avg, time_on_page)
|
228
|
+
return (old_avg*(clicks-1) + time_on_page)/clicks
|
229
|
+
end
|
230
|
+
|
231
|
+
def self.track_time_on_page(session, uri)
|
232
|
+
recommendation_id = session[:last_clicked_recommendation]
|
233
|
+
if !recommendation_id.nil?
|
234
|
+
time_on_page = (Time.now - session[:last_clicked_recommendation_time].to_f).to_i
|
235
|
+
|
236
|
+
# if they spend longer than two minutes on a page, we don't infer anything
|
237
|
+
if time_on_page > 5 and time_on_page < 120
|
238
|
+
if normalized_uri(uri) != session[:last_clicked_recommendation_uri]
|
239
|
+
recommendation = Recommendation.find(recommendation_id)
|
240
|
+
entry = Entry.find(recommendation.entry_id)
|
241
|
+
new_avg = (recommendation.avg_time_at_dest*recommendation.clicks - @@default_time_on_page + time_on_page)/recommendation.clicks
|
242
|
+
recommendation.avg_time_at_dest = new_avg
|
243
|
+
recommendation.save!
|
244
|
+
entry.rank_recommendations
|
245
|
+
session[:last_clicked_recommendation] = nil
|
246
|
+
end
|
247
|
+
else
|
248
|
+
session[:last_clicked_recommendation] = nil if time_on_page > 5
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def self.track_click(session, recommendation_id, referrer, redirect_type = "direct_link", requester = "unknown", user_agent = "unknown")
|
254
|
+
# look up the recommendation
|
255
|
+
recommendation = Recommendation.find(recommendation_id)
|
256
|
+
return "" if !recommendation
|
257
|
+
|
258
|
+
# get the entries being linked from and to
|
259
|
+
entry = Entry.find(recommendation.entry_id)
|
260
|
+
target = Entry.find(recommendation.dest_entry_id)
|
261
|
+
|
262
|
+
# get the list of recommendations that have been clicked during this session
|
263
|
+
clicks = session[:rids] || Array.new
|
264
|
+
|
265
|
+
# redirect to our frame page
|
266
|
+
redirect = "/visits/#{recommendation.dest_entry_id}"
|
267
|
+
|
268
|
+
# track the time on the last page
|
269
|
+
track_time_on_page(session, redirect)
|
270
|
+
|
271
|
+
# if this is first time the user clicked on this recommendation during this session
|
272
|
+
if !clicks.include?(recommendation_id)
|
273
|
+
|
274
|
+
# add this recommendation to the end of the list
|
275
|
+
clicks << recommendation_id
|
276
|
+
session[:rids] = clicks
|
277
|
+
|
278
|
+
# update the click time
|
279
|
+
recommendation.avg_time_at_dest = ((recommendation.avg_time_at_dest*recommendation.clicks) + @@default_time_on_page)/(recommendation.clicks + 1)
|
280
|
+
recommendation.clicks += 1
|
281
|
+
recommendation.save!
|
282
|
+
|
283
|
+
# store info about this click in the session
|
284
|
+
now = Time.now
|
285
|
+
session[:last_clicked_recommendation] = recommendation_id
|
286
|
+
session[:last_clicked_recommendation_time] = now
|
287
|
+
session[:last_clicked_recommendation_uri] = redirect
|
288
|
+
|
289
|
+
# update the recommendation cache for the entry
|
290
|
+
entry.rank_recommendations if entry
|
291
|
+
|
292
|
+
# track the click in the db
|
293
|
+
Click.create(:recommendation_id => recommendation_id, :when => now, :referrer => referrer, :requester => requester, :user_agent => user_agent)
|
294
|
+
end
|
295
|
+
|
296
|
+
return redirect
|
297
|
+
end
|
298
|
+
|
299
|
+
def self.truncate_words(text, length = 30, end_string = ' ...')
|
300
|
+
words = text.split()
|
301
|
+
words[0..(length-1)].join(' ') + (words.length > length ? end_string : '')
|
302
|
+
end
|
303
|
+
|
307
304
|
protected
|
308
305
|
|
309
306
|
# def self.redirect_uri(target, referrer, redirect_type)
|
data/app/models/oai_endpoint.rb
CHANGED
@@ -14,18 +14,6 @@
|
|
14
14
|
# created_at :datetime
|
15
15
|
# updated_at :datetime
|
16
16
|
#
|
17
|
-
|
18
|
-
# == Schema Information
|
19
|
-
#
|
20
|
-
# Table name: oai_endpoints
|
21
|
-
#
|
22
|
-
# id :integer(4) not null, primary key
|
23
|
-
# uri :string(2083)
|
24
|
-
# display_uri :string(2083)
|
25
|
-
# metadata_prefix :string(255)
|
26
|
-
# title :string(1000)
|
27
|
-
# short_title :string(100)
|
28
|
-
#
|
29
17
|
class OaiEndpoint < ActiveRecord::Base
|
30
18
|
|
31
19
|
belongs_to :contributor, :class_name => 'User', :foreign_key => 'contributor_id'
|
@@ -33,7 +21,7 @@ class OaiEndpoint < ActiveRecord::Base
|
|
33
21
|
|
34
22
|
validates_presence_of :uri
|
35
23
|
|
36
|
-
named_scope :banned, :conditions => "status
|
24
|
+
named_scope :banned, :conditions => ["status = ?", MuckServices::Status::BANNED]
|
37
25
|
named_scope :valid, :conditions => "status >= 0"
|
38
26
|
named_scope :by_title, :order => "title ASC"
|
39
27
|
named_scope :recent, lambda { { :conditions => ['created_at > ?', 1.week.ago] } }
|
@@ -13,10 +13,14 @@
|
|
13
13
|
#
|
14
14
|
|
15
15
|
class PersonalRecommendation < ActiveRecord::Base
|
16
|
-
|
16
|
+
unloadable
|
17
|
+
|
17
18
|
belongs_to :personal_recommendable, :polymorphic => true
|
18
19
|
belongs_to :destination, :polymorphic => true
|
19
|
-
|
20
|
+
|
21
|
+
belongs_to :entry, :class_name => 'Entry', :foreign_key => 'destination_id', :include => :feed
|
22
|
+
belongs_to :user, :class_name => 'User', :foreign_key => 'destination_id'
|
23
|
+
|
20
24
|
named_scope :limit, lambda { |num| { :limit => num } }
|
21
25
|
named_scope :recent, lambda { { :conditions => ['created_at > ?', 1.week.ago] } }
|
22
26
|
named_scope :newest, :order => "created_at DESC"
|
data/app/models/service.rb
CHANGED
@@ -230,7 +230,7 @@ class Service < ActiveRecord::Base
|
|
230
230
|
# will result in the values being repopulated from the database
|
231
231
|
def self.get_photo_services(refresh_services = false)
|
232
232
|
@photo_services = nil if refresh_services
|
233
|
-
@photo_services ||= get_services(refresh_services).find_all{|service| service.service_category.name == 'Photos' }
|
233
|
+
@photo_services ||= get_services(refresh_services).find_all{|service| !service.service_category.blank? && service.service_category.name == 'Photos' }
|
234
234
|
end
|
235
235
|
|
236
236
|
# Get all video services
|
@@ -239,7 +239,7 @@ class Service < ActiveRecord::Base
|
|
239
239
|
# will result in the values being repopulated from the database
|
240
240
|
def self.get_video_services(refresh_services = false)
|
241
241
|
@video_services = nil if refresh_services
|
242
|
-
@video_services ||= get_services(refresh_services).find_all{|service| service.service_category.name == 'Videos' }
|
242
|
+
@video_services ||= get_services(refresh_services).find_all{|service| !service.service_category.blank? && service.service_category.name == 'Videos' }
|
243
243
|
end
|
244
244
|
|
245
245
|
# Get all bookmark services
|
@@ -248,7 +248,7 @@ class Service < ActiveRecord::Base
|
|
248
248
|
# will result in the values being repopulated from the database
|
249
249
|
def self.get_bookmark_services(refresh_services = false)
|
250
250
|
@bookmark_services = nil if refresh_services
|
251
|
-
@bookmark_services ||= get_services(refresh_services).find_all{|service| service.service_category.name == 'Bookmarks' }
|
251
|
+
@bookmark_services ||= get_services(refresh_services).find_all{|service| !service.service_category.blank? && service.service_category.name == 'Bookmarks' }
|
252
252
|
end
|
253
253
|
|
254
254
|
# Get all music services
|
@@ -257,7 +257,7 @@ class Service < ActiveRecord::Base
|
|
257
257
|
# will result in the values being repopulated from the database
|
258
258
|
def self.get_music_services(refresh_services = false)
|
259
259
|
@music_services = nil if refresh_services
|
260
|
-
@music_services ||= get_services(refresh_services).find_all{|service| service.service_category.name == 'Music' }
|
260
|
+
@music_services ||= get_services(refresh_services).find_all{|service| !service.service_category.blank? && service.service_category.name == 'Music' }
|
261
261
|
end
|
262
262
|
|
263
263
|
# Get all news services
|
@@ -266,7 +266,7 @@ class Service < ActiveRecord::Base
|
|
266
266
|
# will result in the values being repopulated from the database
|
267
267
|
def self.get_news_services(refresh_services = false)
|
268
268
|
@news_services = nil if refresh_services
|
269
|
-
@news_services ||= get_services(refresh_services).find_all{|service| service.service_category.name == 'News' }
|
269
|
+
@news_services ||= get_services(refresh_services).find_all{|service| !service.service_category.blank? && service.service_category.name == 'News' }
|
270
270
|
end
|
271
271
|
|
272
272
|
# Get all blog services
|
@@ -275,7 +275,7 @@ class Service < ActiveRecord::Base
|
|
275
275
|
# will result in the values being repopulated from the database
|
276
276
|
def self.get_blog_services(refresh_services = false)
|
277
277
|
@blog_services = nil if refresh_services
|
278
|
-
@blog_services ||= get_services(refresh_services).find_all{|service| service.service_category.name == 'Blogging' }
|
278
|
+
@blog_services ||= get_services(refresh_services).find_all{|service| !service.service_category.blank? && service.service_category.name == 'Blogging' }
|
279
279
|
end
|
280
280
|
|
281
281
|
# Get all search services
|
@@ -284,7 +284,7 @@ class Service < ActiveRecord::Base
|
|
284
284
|
# will result in the values being repopulated from the database
|
285
285
|
def self.get_search_services(refresh_services = false)
|
286
286
|
@search_services = nil if refresh_services
|
287
|
-
@search_services ||= get_services(refresh_services).find_all{|service| service.service_category.name == 'Search' }
|
287
|
+
@search_services ||= get_services(refresh_services).find_all{|service| !service.service_category.blank? && service.service_category.name == 'Search' }
|
288
288
|
end
|
289
289
|
|
290
290
|
# Get all general services. These are all services except photo, video, bookmark and music.
|
@@ -304,7 +304,7 @@ class Service < ActiveRecord::Base
|
|
304
304
|
# will result in the values being repopulated from the database
|
305
305
|
def self.get_photo_tag_services(refresh_services = false)
|
306
306
|
@photo_services = nil if refresh_services
|
307
|
-
@photo_services ||= get_tag_services(nil, refresh_services).find_all{|service| service.service_category.name == 'Photos' }
|
307
|
+
@photo_services ||= get_tag_services(nil, refresh_services).find_all{|service| !service.service_category.blank? && service.service_category.name == 'Photos' }
|
308
308
|
end
|
309
309
|
|
310
310
|
# Get all video services that are used to generate tag feeds
|
@@ -313,7 +313,7 @@ class Service < ActiveRecord::Base
|
|
313
313
|
# will result in the values being repopulated from the database
|
314
314
|
def self.get_video_tag_services(refresh_services = false)
|
315
315
|
@video_services = nil if refresh_services
|
316
|
-
@video_services ||= get_tag_services(nil, refresh_services).find_all{|service| service.service_category.name == 'Videos' }
|
316
|
+
@video_services ||= get_tag_services(nil, refresh_services).find_all{|service| !service.service_category.blank? && service.service_category.name == 'Videos' }
|
317
317
|
end
|
318
318
|
|
319
319
|
# Get all bookmark services that are used to generate tag feeds
|
@@ -322,7 +322,7 @@ class Service < ActiveRecord::Base
|
|
322
322
|
# will result in the values being repopulated from the database
|
323
323
|
def self.get_bookmark_tag_services(refresh_services = false)
|
324
324
|
@bookmark_services = nil if refresh_services
|
325
|
-
@bookmark_services ||= get_tag_services(nil, refresh_services).find_all{|service| service.service_category.name == 'Bookmarks' }
|
325
|
+
@bookmark_services ||= get_tag_services(nil, refresh_services).find_all{|service| !service.service_category.blank? && service.service_category.name == 'Bookmarks' }
|
326
326
|
end
|
327
327
|
|
328
328
|
# Get all music services that are used to generate tag feeds
|
@@ -331,7 +331,7 @@ class Service < ActiveRecord::Base
|
|
331
331
|
# will result in the values being repopulated from the database
|
332
332
|
def self.get_music_tag_services(refresh_services = false)
|
333
333
|
@music_services = nil if refresh_services
|
334
|
-
@music_services ||= get_tag_services(nil, refresh_services).find_all{|service| service.service_category.name == 'Music' }
|
334
|
+
@music_services ||= get_tag_services(nil, refresh_services).find_all{|service| !service.service_category.blank? && service.service_category.name == 'Music' }
|
335
335
|
end
|
336
336
|
|
337
337
|
# Get all news services that are used to generate tag feeds
|
@@ -340,7 +340,7 @@ class Service < ActiveRecord::Base
|
|
340
340
|
# will result in the values being repopulated from the database
|
341
341
|
def self.get_news_tag_services(refresh_services = false)
|
342
342
|
@news_services = nil if refresh_services
|
343
|
-
@news_services ||= get_tag_services(nil, refresh_services).find_all{|service| service.service_category.name == 'News' }
|
343
|
+
@news_services ||= get_tag_services(nil, refresh_services).find_all{|service| !service.service_category.blank? && service.service_category.name == 'News' }
|
344
344
|
end
|
345
345
|
|
346
346
|
# Get all blog services that are used to generate tag feeds
|
@@ -349,7 +349,7 @@ class Service < ActiveRecord::Base
|
|
349
349
|
# will result in the values being repopulated from the database
|
350
350
|
def self.get_blog_tag_services(refresh_services = false)
|
351
351
|
@blog_services = nil if refresh_services
|
352
|
-
@blog_services ||= get_tag_services(nil, refresh_services).find_all{|service| service.service_category.name == 'Blogging' }
|
352
|
+
@blog_services ||= get_tag_services(nil, refresh_services).find_all{|service| !service.service_category.blank? && service.service_category.name == 'Blogging' }
|
353
353
|
end
|
354
354
|
|
355
355
|
# Get all search services that are used to generate tag feeds
|
@@ -358,7 +358,7 @@ class Service < ActiveRecord::Base
|
|
358
358
|
# will result in the values being repopulated from the database
|
359
359
|
def self.get_search_tag_services(refresh_services = false)
|
360
360
|
@search_services = nil if refresh_services
|
361
|
-
@search_services ||= get_tag_services(nil, refresh_services).find_all{|service| service.service_category.name == 'Search' }
|
361
|
+
@search_services ||= get_tag_services(nil, refresh_services).find_all{|service| !service.service_category.blank? && service.service_category.name == 'Search' }
|
362
362
|
end
|
363
363
|
|
364
364
|
# Get all general services that are used to generate tag feeds
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<%
|
2
2
|
@json_recommendations = @entry.json_recommendations(@limit, params[:order] || "mixed", true, params[:omit_feeds] || nil)
|
3
|
-
if !@json_recommendations.
|
3
|
+
if !@json_recommendations.empty?
|
4
4
|
@direct_link_text = params[:direct_link_text] || t('muck.services.direct_link')
|
5
5
|
%>
|
6
6
|
var catalog_page = <%= !@entry.direct_link.nil? and @uri == @entry.permalink %>;
|
@@ -26,6 +26,7 @@ document.write('<div class="oer_recommender_list">');
|
|
26
26
|
for(nRec = 0; nRec < recs.length; nRec++) {
|
27
27
|
r = recs[nRec].entry;
|
28
28
|
if (r == null) r = recs[nRec].attributes;
|
29
|
+
if (r == null) r = recs[nRec];
|
29
30
|
metadata_link = catalog_page && document_host == r.uri.substring(0, document_host.length);
|
30
31
|
direct_link = metadata_link && r.direct_link;
|
31
32
|
document.write('<p class="oer_recommender_item">');
|
@@ -35,11 +36,11 @@ for(nRec = 0; nRec < recs.length; nRec++) {
|
|
35
36
|
document.write(' <span class="oer_recommender_published_at">(' + format_date(r.published_at) + ')</span>');
|
36
37
|
document.write(' <span class="oer_recommender_relevance_score"><%= t('muck.services.relevance')%>: ' + Math.round(r.relevance*100)/100 + '</span>');
|
37
38
|
document.write('<br/><span class="oer_recommender_description">' + truncate(r.description) + '</span>');
|
38
|
-
document.write('<br/><span class="oer_recommender_uri">' + r.
|
39
|
+
document.write('<br/><span class="oer_recommender_uri">' + r.permalink + '</span>');
|
39
40
|
<% end -%>
|
40
41
|
document.write('</a></p>');
|
41
42
|
}
|
42
43
|
document.write('</div>');
|
43
|
-
<% if params[:more_link] %>document.write('<div class="oer_recommender_more_link"><a href="' + app + '
|
44
|
+
<% if params[:more_link] %>document.write('<div class="oer_recommender_more_link"><a href="' + app + 'resources/<%= @entry.id %>"><%= t('muck.services.gm_more_prompt') %></a></div>');<% end %>
|
44
45
|
document.write('</div>');
|
45
46
|
<% end %>
|
@@ -25,6 +25,7 @@ ActionController::Routing::Routes.draw do |map|
|
|
25
25
|
map.resources :oai_endpoints, :controller => 'muck/oai_endpoints', :has_many => :feeds
|
26
26
|
|
27
27
|
map.resources :feeds, :controller => 'muck/feeds', :collection => { :new_extended => :get, :new_oai_rss => :get }, :has_many => :entries
|
28
|
+
map.connection 'users/:login/recommendations', :controller => 'muck/personal_recommendations', :action => 'index'
|
28
29
|
|
29
30
|
map.connect 'recommendations/real_time', :controller => 'muck/recommendations', :action => 'real_time'
|
30
31
|
map.connect 'recommendations/get_button', :controller => 'muck/recommendations', :action => 'get_button'
|
@@ -11,6 +11,8 @@ module ActiveRecord
|
|
11
11
|
# +has_muck_recommendations+ gives the class it is called on personalized recommendations
|
12
12
|
def has_muck_recommendations
|
13
13
|
has_many :personal_recommendations, :as => :personal_recommendable
|
14
|
+
has_many :recommended_entries, :through => :personal_recommendations, :source => :entry,
|
15
|
+
:conditions => "personal_recommendations.destination_type = 'Entry'"
|
14
16
|
end
|
15
17
|
|
16
18
|
def acts_as_muck_recommendation
|
data/muck-services.gemspec
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{muck-services}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.24"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Joel Duffin", "Justin Ball"]
|
12
|
-
s.date = %q{2009-12-
|
12
|
+
s.date = %q{2009-12-19}
|
13
13
|
s.description = %q{This gem contains the rails specific code for dealing with feeds, aggregations and recommendations. It is meant to work with the muck-raker gem.}
|
14
14
|
s.email = %q{justin@tatemae.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -140,7 +140,6 @@ Gem::Specification.new do |s|
|
|
140
140
|
"app/views/service_templates/_zotero_group.html.erb",
|
141
141
|
"app/views/services/_edit_service.html.erb",
|
142
142
|
"app/views/services/_new_service.html.erb",
|
143
|
-
"app/views/services/_personal_recommendations.html.erb",
|
144
143
|
"app/views/services/_summary.html.erb",
|
145
144
|
"app/views/services/_view_service.html.erb",
|
146
145
|
"app/views/services_mailer/notification_feed_added.text.ar.html.erb",
|
@@ -857,4 +856,3 @@ Gem::Specification.new do |s|
|
|
857
856
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
858
857
|
end
|
859
858
|
end
|
860
|
-
|
@@ -98,7 +98,7 @@ ul#add_oai_rss_feed_menu li{display:inline;margin:0 5px;}
|
|
98
98
|
#recs_header{color:#777;background-color:white;font-weight:bold;font-size:16px;font-family:Arial,Helvetica,sans-serif;margin: 2px 3px 0 3px; padding: 2px;}
|
99
99
|
#recs_list{margin: 1px; padding: 1px; list-style-type: none;}
|
100
100
|
#recs_list li{margin-left: 0px; padding: 3px; list-style-type: none; font-size: 12px;}
|
101
|
-
.even{background-color:#
|
101
|
+
.even{background-color:#DDD;}
|
102
102
|
#more_recs{margin:4px 0 6px;padding:0;text-align:center;}
|
103
103
|
#recs_panel a{color:#3987DC;text-decoration:none;}
|
104
104
|
#recs_panel a:hover{text-decoration:underline;}
|
@@ -31,6 +31,7 @@ Rails::Initializer.run do |config|
|
|
31
31
|
config.gem "geokit"
|
32
32
|
config.gem 'muck-engine', :lib => 'muck_engine'
|
33
33
|
config.gem 'muck-users', :lib => 'muck_users'
|
34
|
+
config.gem 'muck-profiles', :lib => 'muck_profiles'
|
34
35
|
config.gem 'muck-comments', :lib => 'muck_comments'
|
35
36
|
config.gem 'muck-activities', :lib => 'muck_activities'
|
36
37
|
config.gem 'muck-shares', :lib => 'muck_shares'
|
@@ -29,44 +29,10 @@ class AggregationTest < ActiveSupport::TestCase
|
|
29
29
|
should_have_many :aggregation_feeds
|
30
30
|
should_have_many :feeds
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
@first = Factory(:aggregation, :title => 'a')
|
37
|
-
@second = Factory(:aggregation, :title => 'b')
|
38
|
-
end
|
39
|
-
should "sort by title" do
|
40
|
-
assert_equal @first, Aggregation.by_title[0]
|
41
|
-
assert_equal @second, Aggregation.by_title[1]
|
42
|
-
end
|
43
|
-
end
|
44
|
-
context "recent" do
|
45
|
-
setup do
|
46
|
-
Aggregation.delete_all
|
47
|
-
@recent = Factory(:aggregation)
|
48
|
-
@not_recent = Factory(:aggregation, :created_at => 10.weeks.ago)
|
49
|
-
end
|
50
|
-
should "get recent aggregations" do
|
51
|
-
assert Aggregation.recent.include?(@recent)
|
52
|
-
end
|
53
|
-
should "not get recent aggregations" do
|
54
|
-
assert !Aggregation.recent.include?(@not_recent)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
context "newest" do
|
58
|
-
setup do
|
59
|
-
Aggregation.delete_all
|
60
|
-
@first = Factory(:aggregation, :created_at => 1.day.ago)
|
61
|
-
@second = Factory(:aggregation, :created_at => 1.week.ago)
|
62
|
-
end
|
63
|
-
should "sort by created_at" do
|
64
|
-
assert_equal @first, Aggregation.newest[0]
|
65
|
-
assert_equal @second, Aggregation.newest[1]
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
32
|
+
should_scope_by_title
|
33
|
+
should_scope_recent
|
34
|
+
should_scope_newest
|
35
|
+
|
70
36
|
context "filter feed types" do
|
71
37
|
setup do
|
72
38
|
build_music_service
|
@@ -53,11 +53,9 @@ class FeedTest < ActiveSupport::TestCase
|
|
53
53
|
|
54
54
|
should_validate_presence_of :uri
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
should_have_named_scope :by_title
|
60
|
-
should_have_named_scope :recent
|
56
|
+
should_scope_by_title
|
57
|
+
should_scope_recent
|
58
|
+
should_scope_by_newest
|
61
59
|
|
62
60
|
should "set 24 hours as default interval" do
|
63
61
|
assert_equal @feed.harvest_interval_hours, 24
|
@@ -68,6 +66,35 @@ class FeedTest < ActiveSupport::TestCase
|
|
68
66
|
assert_equal @feed.harvest_interval, 10 * 3600
|
69
67
|
end
|
70
68
|
|
69
|
+
context "named scope" do
|
70
|
+
context "banned" do
|
71
|
+
# named_scope :banned, :conditions => ["status = ?", MuckServices::Status::BANNED]
|
72
|
+
setup do
|
73
|
+
@feed = Factory(:feed, :status => MuckServices::Status::BANNED)
|
74
|
+
@feed_not = Factory(:feed)
|
75
|
+
end
|
76
|
+
should "find feeds that are banned" do
|
77
|
+
assert Feed.banned.include?(@feed)
|
78
|
+
end
|
79
|
+
should "not find feeds that are not banned" do
|
80
|
+
assert !Feed.banned.include?(@feed_not)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
context "valid" do
|
84
|
+
# named_scope :valid, :conditions => "status >= 0", :include => [:default_language]
|
85
|
+
setup do
|
86
|
+
@feed = Factory(:feed, :status => 0)
|
87
|
+
@feed_not = Factory(:feed, :status => MuckServices::Status::BANNED)
|
88
|
+
end
|
89
|
+
should "find valid feeds" do
|
90
|
+
assert Feed.valid.include?(@feed)
|
91
|
+
end
|
92
|
+
should "not find invalid feeds" do
|
93
|
+
assert !Feed.valid.include?(@feed_not)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
71
98
|
end
|
72
99
|
|
73
100
|
context "Feed status" do
|
@@ -32,25 +32,52 @@ class OaiEndpointTest < ActiveSupport::TestCase
|
|
32
32
|
|
33
33
|
should_validate_presence_of :uri
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
should_scope_by_title
|
36
|
+
should_scope_recent
|
37
|
+
should_scope_by_newest
|
38
|
+
|
39
|
+
context "named scope" do
|
40
|
+
context "banned" do
|
41
|
+
# named_scope :banned, :conditions => ["status = ?", MuckServices::Status::BANNED]
|
42
|
+
setup do
|
43
|
+
@oai_endpoint = Factory(:oai_endpoint, :status => MuckServices::Status::BANNED)
|
44
|
+
@oai_endpoint_not = Factory(:oai_endpoint)
|
45
|
+
end
|
46
|
+
should "find oai_endpoints that are banned" do
|
47
|
+
assert OaiEndpoint.banned.include?(@oai_endpoint)
|
48
|
+
end
|
49
|
+
should "not find oai_endpoints that are not banned" do
|
50
|
+
assert !OaiEndpoint.banned.include?(@oai_endpoint_not)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
context "valid" do
|
54
|
+
# named_scope :valid, :conditions => "status >= 0", :include => [:default_language]
|
55
|
+
setup do
|
56
|
+
@oai_endpoint = Factory(:oai_endpoint, :status => 0)
|
57
|
+
@oai_endpoint_not = Factory(:oai_endpoint, :status => MuckServices::Status::BANNED)
|
58
|
+
end
|
59
|
+
should "find valid oai_endpoints" do
|
60
|
+
assert OaiEndpoint.valid.include?(@oai_endpoint)
|
61
|
+
end
|
62
|
+
should "not find invalid oai_endpoints" do
|
63
|
+
assert !OaiEndpoint.valid.include?(@oai_endpoint_not)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
40
67
|
|
41
68
|
end
|
42
69
|
|
43
70
|
context "banned/unbanned" do
|
44
71
|
setup do
|
45
|
-
@
|
72
|
+
@oai_endpoint = Factory(:oai_endpoint)
|
46
73
|
end
|
47
74
|
should "be banned" do
|
48
|
-
@
|
49
|
-
assert @
|
75
|
+
@oai_endpoint.status = -1
|
76
|
+
assert @oai_endpoint.banned?
|
50
77
|
end
|
51
78
|
should "not be banned" do
|
52
|
-
@
|
53
|
-
assert !@
|
79
|
+
@oai_endpoint.status = 0
|
80
|
+
assert !@oai_endpoint.banned?
|
54
81
|
end
|
55
82
|
end
|
56
83
|
|
@@ -24,11 +24,64 @@ require File.dirname(__FILE__) + '/../test_helper'
|
|
24
24
|
class ServiceTest < ActiveSupport::TestCase
|
25
25
|
|
26
26
|
context "service instance" do
|
27
|
-
|
27
|
+
|
28
28
|
should_belong_to :service_category
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
should_scope_sorted
|
30
|
+
|
31
|
+
context "named scope" do
|
32
|
+
context "identity_services" do
|
33
|
+
# named_scope :identity_services, :conditions => ['use_for = ?', 'identity']
|
34
|
+
setup do
|
35
|
+
@service = Factory(:service, :use_for => 'identity')
|
36
|
+
@service_not = Factory(:service, :use_for => 'not')
|
37
|
+
end
|
38
|
+
should "find services that have use_for=='identity_services'" do
|
39
|
+
assert Service.identity_services.include?(@service)
|
40
|
+
end
|
41
|
+
should "not find services that where use_for!='identity_services'" do
|
42
|
+
assert !Service.identity_services.include?(@service_not)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
context "tag_services" do
|
46
|
+
# named_scope :tag_services, :conditions => ['use_for = ?', 'tags']
|
47
|
+
setup do
|
48
|
+
@service = Factory(:service, :use_for => 'tags')
|
49
|
+
@service_not = Factory(:service, :use_for => 'not')
|
50
|
+
end
|
51
|
+
should "find services that have use_for=='tags'" do
|
52
|
+
assert Service.tag_services.include?(@service)
|
53
|
+
end
|
54
|
+
should "not find services that where use_for!='tags'" do
|
55
|
+
assert !Service.tag_services.include?(@service_not)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
context "sorted_id" do
|
59
|
+
# named_scope :sorted_id, :order => "id ASC"
|
60
|
+
setup do
|
61
|
+
Service.delete_all
|
62
|
+
@first = Factory(:service)
|
63
|
+
@second = Factory(:service)
|
64
|
+
end
|
65
|
+
should "sort by 'sort' field" do
|
66
|
+
assert_equal @first, Service.sorted_id[0]
|
67
|
+
assert_equal @second, Service.sorted_id[1]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
context "photo_services" do
|
71
|
+
# named_scope :photo_services, :conditions => ["service_categories.id = services.service_category_id AND service_categories.name = 'Photos'"], :include => ['service_category']
|
72
|
+
setup do
|
73
|
+
@service_category = Factory(:service_category, :name => 'Photos')
|
74
|
+
@service = Factory(:service, :service_category => @service_category)
|
75
|
+
@service_not = Factory(:service)
|
76
|
+
end
|
77
|
+
should "find services that have 'Photos' for a service category" do
|
78
|
+
assert Service.photo_services.include?(@service)
|
79
|
+
end
|
80
|
+
should "not find services that don't have 'Photos' for a service category" do
|
81
|
+
assert !Service.photo_services.include?(@service_not)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
32
85
|
|
33
86
|
context "photos" do
|
34
87
|
setup do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: muck-services
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.24
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Duffin
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-12-
|
13
|
+
date: 2009-12-19 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -266,7 +266,6 @@ files:
|
|
266
266
|
- app/views/service_templates/_zotero_group.html.erb
|
267
267
|
- app/views/services/_edit_service.html.erb
|
268
268
|
- app/views/services/_new_service.html.erb
|
269
|
-
- app/views/services/_personal_recommendations.html.erb
|
270
269
|
- app/views/services/_summary.html.erb
|
271
270
|
- app/views/services/_view_service.html.erb
|
272
271
|
- app/views/services_mailer/notification_feed_added.text.ar.html.erb
|