muck-services 0.1.2

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.
Files changed (818) hide show
  1. data/.document +5 -0
  2. data/.gitignore +5 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +100 -0
  5. data/Rakefile +84 -0
  6. data/VERSION +1 -0
  7. data/app/controllers/admin/muck/feeds_controller.rb +40 -0
  8. data/app/controllers/admin/muck/oai_endpoints_controller.rb +13 -0
  9. data/app/controllers/muck/aggregation_feeds_controller.rb +43 -0
  10. data/app/controllers/muck/aggregations_controller.rb +234 -0
  11. data/app/controllers/muck/entries_controller.rb +102 -0
  12. data/app/controllers/muck/feed_previews_controller.rb +33 -0
  13. data/app/controllers/muck/feeds_controller.rb +157 -0
  14. data/app/controllers/muck/identity_feeds_controller.rb +155 -0
  15. data/app/controllers/muck/oai_endpoints_controller.rb +96 -0
  16. data/app/controllers/muck/recommendations_controller.rb +62 -0
  17. data/app/controllers/muck/topics_controller.rb +162 -0
  18. data/app/controllers/muck/visits_controller.rb +26 -0
  19. data/app/helpers/muck_services_aggregations_helper.rb +32 -0
  20. data/app/helpers/muck_services_feeds_helper.rb +32 -0
  21. data/app/helpers/muck_services_helper.rb +95 -0
  22. data/app/helpers/muck_services_service_helper.rb +117 -0
  23. data/app/models/aggregation.rb +92 -0
  24. data/app/models/aggregation_feed.rb +14 -0
  25. data/app/models/attention.rb +14 -0
  26. data/app/models/click.rb +14 -0
  27. data/app/models/entry.rb +341 -0
  28. data/app/models/feed.rb +224 -0
  29. data/app/models/feed_parent.rb +18 -0
  30. data/app/models/identity_feed.rb +26 -0
  31. data/app/models/oai_endpoint.rb +39 -0
  32. data/app/models/recommendation.rb +15 -0
  33. data/app/models/service.rb +486 -0
  34. data/app/models/service_category.rb +15 -0
  35. data/app/models/services_mailer.rb +25 -0
  36. data/app/models/subject.rb +10 -0
  37. data/app/models/tag_cloud.rb +21 -0
  38. data/app/views/activity_templates/_entry_comment.html.erb +8 -0
  39. data/app/views/activity_templates/_entry_share.html.erb +8 -0
  40. data/app/views/admin/feeds/index.html.erb +35 -0
  41. data/app/views/admin/oai_endpoints/index.html.erb +31 -0
  42. data/app/views/aggregations/_aggregation.html.erb +1 -0
  43. data/app/views/aggregations/_data_source.html.erb +4 -0
  44. data/app/views/aggregations/_data_sources.html.erb +10 -0
  45. data/app/views/aggregations/_feeds.html.erb +1 -0
  46. data/app/views/aggregations/_preview_form.html.erb +12 -0
  47. data/app/views/aggregations/edit.html.erb +65 -0
  48. data/app/views/aggregations/index.html.erb +17 -0
  49. data/app/views/aggregations/index.iphone.erb +0 -0
  50. data/app/views/aggregations/new.html.erb +12 -0
  51. data/app/views/aggregations/preview.html.erb +46 -0
  52. data/app/views/aggregations/preview.iphone.erb +0 -0
  53. data/app/views/aggregations/rss_discovery.html.erb +3 -0
  54. data/app/views/aggregations/show.html.erb +0 -0
  55. data/app/views/default/_language_list.html.erb +5 -0
  56. data/app/views/entries/_related_entry.html.erb +4 -0
  57. data/app/views/entries/_result.html.erb +7 -0
  58. data/app/views/entries/_result_status.html.erb +16 -0
  59. data/app/views/entries/_results.html.erb +3 -0
  60. data/app/views/entries/_tag_cloud.html.erb +18 -0
  61. data/app/views/entries/browse_by_tags.html.erb +16 -0
  62. data/app/views/entries/collections.html.erb +28 -0
  63. data/app/views/entries/details.html.erb +25 -0
  64. data/app/views/entries/index.html.erb +3 -0
  65. data/app/views/entries/search.html.erb +10 -0
  66. data/app/views/entries/show.html.erb +7 -0
  67. data/app/views/entries/track_clicks.html.erb +0 -0
  68. data/app/views/feed_previews/new.html.erb +1 -0
  69. data/app/views/feed_previews/select_feeds.html.erb +6 -0
  70. data/app/views/feeds/_entry.html.erb +1 -0
  71. data/app/views/feeds/_feed.html.erb +28 -0
  72. data/app/views/feeds/_feed_row.html.erb +29 -0
  73. data/app/views/feeds/_feed_selection.html.erb +1 -0
  74. data/app/views/feeds/_form.html.erb +20 -0
  75. data/app/views/feeds/edit.html.erb +107 -0
  76. data/app/views/feeds/harvest_now.html.erb +3 -0
  77. data/app/views/feeds/index.html.erb +34 -0
  78. data/app/views/feeds/new.html.erb +21 -0
  79. data/app/views/feeds/new_extended.html.erb +32 -0
  80. data/app/views/feeds/new_oai_rss.html.erb +50 -0
  81. data/app/views/feeds/show.html.erb +1 -0
  82. data/app/views/feeds/unban.html.erb +3 -0
  83. data/app/views/identity_feeds/_available_service_categories.html.erb +13 -0
  84. data/app/views/identity_feeds/_form.html.erb +20 -0
  85. data/app/views/identity_feeds/_services_for_user.html.erb +25 -0
  86. data/app/views/identity_feeds/edit.html.erb +2 -0
  87. data/app/views/identity_feeds/index.html.erb +32 -0
  88. data/app/views/identity_feeds/new.html.erb +1 -0
  89. data/app/views/oai_endpoints/_form.html.erb +22 -0
  90. data/app/views/oai_endpoints/_oai_endpoint_row.html.erb +25 -0
  91. data/app/views/oai_endpoints/new.html.erb +2 -0
  92. data/app/views/oai_endpoints/show.html.erb +5 -0
  93. data/app/views/parts/_add_feed.html.erb +20 -0
  94. data/app/views/parts/_select_feed.html.erb +4 -0
  95. data/app/views/recommendations/index.html.erb +5 -0
  96. data/app/views/recommendations/index.pjs.erb +44 -0
  97. data/app/views/recommendations/index.rss.builder +37 -0
  98. data/app/views/recommendations/index.xml.builder +36 -0
  99. data/app/views/recommendations/index_js.pjs.erb +39 -0
  100. data/app/views/recommendations/index_real_time.pjs.erb +44 -0
  101. data/app/views/recommendations/index_real_time.xml.builder +25 -0
  102. data/app/views/search/_languages.html.erb +6 -0
  103. data/app/views/search/_result.html.erb +9 -0
  104. data/app/views/search/_search_box.html.erb +9 -0
  105. data/app/views/search/index.html.erb +5 -0
  106. data/app/views/search/results.atom.builder +27 -0
  107. data/app/views/search/results.html.erb +35 -0
  108. data/app/views/search/results.pjs.erb +13 -0
  109. data/app/views/search/results.rdf.builder +24 -0
  110. data/app/views/search/results.rss.builder +31 -0
  111. data/app/views/search/results.xml.builder +19 -0
  112. data/app/views/service_templates/_facebook.html.erb +4 -0
  113. data/app/views/service_templates/_friendfeed.html.erb +2 -0
  114. data/app/views/service_templates/_goodreads.html.erb +2 -0
  115. data/app/views/service_templates/_linkedin.html.erb +2 -0
  116. data/app/views/service_templates/_netflix.html.erb +2 -0
  117. data/app/views/service_templates/_polyvore.html.erb +2 -0
  118. data/app/views/service_templates/_zotero_group.html.erb +2 -0
  119. data/app/views/services/_edit_service.html.erb +1 -0
  120. data/app/views/services/_new_service.html.erb +1 -0
  121. data/app/views/services/_summary.html.erb +5 -0
  122. data/app/views/services/_view_service.html.erb +1 -0
  123. data/app/views/services_mailer/notification_feed_added.text.ar.html.erb +4 -0
  124. data/app/views/services_mailer/notification_feed_added.text.ar.plain.erb +7 -0
  125. data/app/views/services_mailer/notification_feed_added.text.bg.html.erb +4 -0
  126. data/app/views/services_mailer/notification_feed_added.text.bg.plain.erb +7 -0
  127. data/app/views/services_mailer/notification_feed_added.text.ca.html.erb +4 -0
  128. data/app/views/services_mailer/notification_feed_added.text.ca.plain.erb +7 -0
  129. data/app/views/services_mailer/notification_feed_added.text.cs.html.erb +4 -0
  130. data/app/views/services_mailer/notification_feed_added.text.cs.plain.erb +7 -0
  131. data/app/views/services_mailer/notification_feed_added.text.da.html.erb +4 -0
  132. data/app/views/services_mailer/notification_feed_added.text.da.plain.erb +7 -0
  133. data/app/views/services_mailer/notification_feed_added.text.de.html.erb +4 -0
  134. data/app/views/services_mailer/notification_feed_added.text.de.plain.erb +7 -0
  135. data/app/views/services_mailer/notification_feed_added.text.el.html.erb +4 -0
  136. data/app/views/services_mailer/notification_feed_added.text.el.plain.erb +7 -0
  137. data/app/views/services_mailer/notification_feed_added.text.es.html.erb +4 -0
  138. data/app/views/services_mailer/notification_feed_added.text.es.plain.erb +7 -0
  139. data/app/views/services_mailer/notification_feed_added.text.et.html.erb +4 -0
  140. data/app/views/services_mailer/notification_feed_added.text.et.plain.erb +7 -0
  141. data/app/views/services_mailer/notification_feed_added.text.fa.html.erb +4 -0
  142. data/app/views/services_mailer/notification_feed_added.text.fa.plain.erb +7 -0
  143. data/app/views/services_mailer/notification_feed_added.text.fi.html.erb +4 -0
  144. data/app/views/services_mailer/notification_feed_added.text.fi.plain.erb +7 -0
  145. data/app/views/services_mailer/notification_feed_added.text.fr.html.erb +4 -0
  146. data/app/views/services_mailer/notification_feed_added.text.fr.plain.erb +7 -0
  147. data/app/views/services_mailer/notification_feed_added.text.gl.html.erb +4 -0
  148. data/app/views/services_mailer/notification_feed_added.text.gl.plain.erb +7 -0
  149. data/app/views/services_mailer/notification_feed_added.text.hi.html.erb +4 -0
  150. data/app/views/services_mailer/notification_feed_added.text.hi.plain.erb +7 -0
  151. data/app/views/services_mailer/notification_feed_added.text.hr.html.erb +4 -0
  152. data/app/views/services_mailer/notification_feed_added.text.hr.plain.erb +7 -0
  153. data/app/views/services_mailer/notification_feed_added.text.html.erb +4 -0
  154. data/app/views/services_mailer/notification_feed_added.text.hu.html.erb +4 -0
  155. data/app/views/services_mailer/notification_feed_added.text.hu.plain.erb +7 -0
  156. data/app/views/services_mailer/notification_feed_added.text.id.html.erb +4 -0
  157. data/app/views/services_mailer/notification_feed_added.text.id.plain.erb +7 -0
  158. data/app/views/services_mailer/notification_feed_added.text.it.html.erb +4 -0
  159. data/app/views/services_mailer/notification_feed_added.text.it.plain.erb +7 -0
  160. data/app/views/services_mailer/notification_feed_added.text.iw.html.erb +4 -0
  161. data/app/views/services_mailer/notification_feed_added.text.iw.plain.erb +7 -0
  162. data/app/views/services_mailer/notification_feed_added.text.ja.html.erb +4 -0
  163. data/app/views/services_mailer/notification_feed_added.text.ja.plain.erb +7 -0
  164. data/app/views/services_mailer/notification_feed_added.text.ko.html.erb +4 -0
  165. data/app/views/services_mailer/notification_feed_added.text.ko.plain.erb +7 -0
  166. data/app/views/services_mailer/notification_feed_added.text.lt.html.erb +4 -0
  167. data/app/views/services_mailer/notification_feed_added.text.lt.plain.erb +7 -0
  168. data/app/views/services_mailer/notification_feed_added.text.lv.html.erb +4 -0
  169. data/app/views/services_mailer/notification_feed_added.text.lv.plain.erb +7 -0
  170. data/app/views/services_mailer/notification_feed_added.text.mt.html.erb +4 -0
  171. data/app/views/services_mailer/notification_feed_added.text.mt.plain.erb +7 -0
  172. data/app/views/services_mailer/notification_feed_added.text.nl.html.erb +4 -0
  173. data/app/views/services_mailer/notification_feed_added.text.nl.plain.erb +7 -0
  174. data/app/views/services_mailer/notification_feed_added.text.no.html.erb +4 -0
  175. data/app/views/services_mailer/notification_feed_added.text.no.plain.erb +7 -0
  176. data/app/views/services_mailer/notification_feed_added.text.pl.html.erb +4 -0
  177. data/app/views/services_mailer/notification_feed_added.text.pl.plain.erb +7 -0
  178. data/app/views/services_mailer/notification_feed_added.text.plain.erb +7 -0
  179. data/app/views/services_mailer/notification_feed_added.text.pt-PT.html.erb +4 -0
  180. data/app/views/services_mailer/notification_feed_added.text.pt-PT.plain.erb +7 -0
  181. data/app/views/services_mailer/notification_feed_added.text.ro.html.erb +4 -0
  182. data/app/views/services_mailer/notification_feed_added.text.ro.plain.erb +7 -0
  183. data/app/views/services_mailer/notification_feed_added.text.ru.html.erb +4 -0
  184. data/app/views/services_mailer/notification_feed_added.text.ru.plain.erb +7 -0
  185. data/app/views/services_mailer/notification_feed_added.text.sk.html.erb +4 -0
  186. data/app/views/services_mailer/notification_feed_added.text.sk.plain.erb +7 -0
  187. data/app/views/services_mailer/notification_feed_added.text.sl.html.erb +4 -0
  188. data/app/views/services_mailer/notification_feed_added.text.sl.plain.erb +7 -0
  189. data/app/views/services_mailer/notification_feed_added.text.sq.html.erb +4 -0
  190. data/app/views/services_mailer/notification_feed_added.text.sq.plain.erb +7 -0
  191. data/app/views/services_mailer/notification_feed_added.text.sr.html.erb +4 -0
  192. data/app/views/services_mailer/notification_feed_added.text.sr.plain.erb +7 -0
  193. data/app/views/services_mailer/notification_feed_added.text.sv.html.erb +4 -0
  194. data/app/views/services_mailer/notification_feed_added.text.sv.plain.erb +7 -0
  195. data/app/views/services_mailer/notification_feed_added.text.th.html.erb +4 -0
  196. data/app/views/services_mailer/notification_feed_added.text.th.plain.erb +7 -0
  197. data/app/views/services_mailer/notification_feed_added.text.tl.html.erb +4 -0
  198. data/app/views/services_mailer/notification_feed_added.text.tl.plain.erb +7 -0
  199. data/app/views/services_mailer/notification_feed_added.text.tr.html.erb +4 -0
  200. data/app/views/services_mailer/notification_feed_added.text.tr.plain.erb +7 -0
  201. data/app/views/services_mailer/notification_feed_added.text.uk.html.erb +4 -0
  202. data/app/views/services_mailer/notification_feed_added.text.uk.plain.erb +7 -0
  203. data/app/views/services_mailer/notification_feed_added.text.vi.html.erb +4 -0
  204. data/app/views/services_mailer/notification_feed_added.text.vi.plain.erb +7 -0
  205. data/app/views/services_mailer/notification_feed_added.text.zh-CN.html.erb +4 -0
  206. data/app/views/services_mailer/notification_feed_added.text.zh-CN.plain.erb +7 -0
  207. data/app/views/services_mailer/notification_feed_added.text.zh-TW.html.erb +4 -0
  208. data/app/views/services_mailer/notification_feed_added.text.zh-TW.plain.erb +7 -0
  209. data/app/views/services_mailer/notification_feed_added.text.zh.html.erb +4 -0
  210. data/app/views/services_mailer/notification_feed_added.text.zh.plain.erb +7 -0
  211. data/app/views/services_mailer/notification_oai_endpoint_added.text.ar.html.erb +4 -0
  212. data/app/views/services_mailer/notification_oai_endpoint_added.text.ar.plain.erb +4 -0
  213. data/app/views/services_mailer/notification_oai_endpoint_added.text.bg.html.erb +4 -0
  214. data/app/views/services_mailer/notification_oai_endpoint_added.text.bg.plain.erb +4 -0
  215. data/app/views/services_mailer/notification_oai_endpoint_added.text.ca.html.erb +4 -0
  216. data/app/views/services_mailer/notification_oai_endpoint_added.text.ca.plain.erb +4 -0
  217. data/app/views/services_mailer/notification_oai_endpoint_added.text.cs.html.erb +4 -0
  218. data/app/views/services_mailer/notification_oai_endpoint_added.text.cs.plain.erb +4 -0
  219. data/app/views/services_mailer/notification_oai_endpoint_added.text.da.html.erb +4 -0
  220. data/app/views/services_mailer/notification_oai_endpoint_added.text.da.plain.erb +4 -0
  221. data/app/views/services_mailer/notification_oai_endpoint_added.text.de.html.erb +4 -0
  222. data/app/views/services_mailer/notification_oai_endpoint_added.text.de.plain.erb +4 -0
  223. data/app/views/services_mailer/notification_oai_endpoint_added.text.el.html.erb +4 -0
  224. data/app/views/services_mailer/notification_oai_endpoint_added.text.el.plain.erb +4 -0
  225. data/app/views/services_mailer/notification_oai_endpoint_added.text.es.html.erb +4 -0
  226. data/app/views/services_mailer/notification_oai_endpoint_added.text.es.plain.erb +4 -0
  227. data/app/views/services_mailer/notification_oai_endpoint_added.text.et.html.erb +4 -0
  228. data/app/views/services_mailer/notification_oai_endpoint_added.text.et.plain.erb +4 -0
  229. data/app/views/services_mailer/notification_oai_endpoint_added.text.fa.html.erb +4 -0
  230. data/app/views/services_mailer/notification_oai_endpoint_added.text.fa.plain.erb +4 -0
  231. data/app/views/services_mailer/notification_oai_endpoint_added.text.fi.html.erb +4 -0
  232. data/app/views/services_mailer/notification_oai_endpoint_added.text.fi.plain.erb +4 -0
  233. data/app/views/services_mailer/notification_oai_endpoint_added.text.fr.html.erb +4 -0
  234. data/app/views/services_mailer/notification_oai_endpoint_added.text.fr.plain.erb +4 -0
  235. data/app/views/services_mailer/notification_oai_endpoint_added.text.gl.html.erb +4 -0
  236. data/app/views/services_mailer/notification_oai_endpoint_added.text.gl.plain.erb +4 -0
  237. data/app/views/services_mailer/notification_oai_endpoint_added.text.hi.html.erb +4 -0
  238. data/app/views/services_mailer/notification_oai_endpoint_added.text.hi.plain.erb +4 -0
  239. data/app/views/services_mailer/notification_oai_endpoint_added.text.hr.html.erb +4 -0
  240. data/app/views/services_mailer/notification_oai_endpoint_added.text.hr.plain.erb +4 -0
  241. data/app/views/services_mailer/notification_oai_endpoint_added.text.html.erb +4 -0
  242. data/app/views/services_mailer/notification_oai_endpoint_added.text.hu.html.erb +4 -0
  243. data/app/views/services_mailer/notification_oai_endpoint_added.text.hu.plain.erb +4 -0
  244. data/app/views/services_mailer/notification_oai_endpoint_added.text.id.html.erb +4 -0
  245. data/app/views/services_mailer/notification_oai_endpoint_added.text.id.plain.erb +4 -0
  246. data/app/views/services_mailer/notification_oai_endpoint_added.text.it.html.erb +4 -0
  247. data/app/views/services_mailer/notification_oai_endpoint_added.text.it.plain.erb +4 -0
  248. data/app/views/services_mailer/notification_oai_endpoint_added.text.iw.html.erb +4 -0
  249. data/app/views/services_mailer/notification_oai_endpoint_added.text.iw.plain.erb +4 -0
  250. data/app/views/services_mailer/notification_oai_endpoint_added.text.ja.html.erb +4 -0
  251. data/app/views/services_mailer/notification_oai_endpoint_added.text.ja.plain.erb +4 -0
  252. data/app/views/services_mailer/notification_oai_endpoint_added.text.ko.html.erb +4 -0
  253. data/app/views/services_mailer/notification_oai_endpoint_added.text.ko.plain.erb +4 -0
  254. data/app/views/services_mailer/notification_oai_endpoint_added.text.lt.html.erb +4 -0
  255. data/app/views/services_mailer/notification_oai_endpoint_added.text.lt.plain.erb +4 -0
  256. data/app/views/services_mailer/notification_oai_endpoint_added.text.lv.html.erb +4 -0
  257. data/app/views/services_mailer/notification_oai_endpoint_added.text.lv.plain.erb +4 -0
  258. data/app/views/services_mailer/notification_oai_endpoint_added.text.mt.html.erb +4 -0
  259. data/app/views/services_mailer/notification_oai_endpoint_added.text.mt.plain.erb +4 -0
  260. data/app/views/services_mailer/notification_oai_endpoint_added.text.nl.html.erb +4 -0
  261. data/app/views/services_mailer/notification_oai_endpoint_added.text.nl.plain.erb +4 -0
  262. data/app/views/services_mailer/notification_oai_endpoint_added.text.no.html.erb +4 -0
  263. data/app/views/services_mailer/notification_oai_endpoint_added.text.no.plain.erb +4 -0
  264. data/app/views/services_mailer/notification_oai_endpoint_added.text.pl.html.erb +4 -0
  265. data/app/views/services_mailer/notification_oai_endpoint_added.text.pl.plain.erb +4 -0
  266. data/app/views/services_mailer/notification_oai_endpoint_added.text.plain.erb +4 -0
  267. data/app/views/services_mailer/notification_oai_endpoint_added.text.pt-PT.html.erb +4 -0
  268. data/app/views/services_mailer/notification_oai_endpoint_added.text.pt-PT.plain.erb +4 -0
  269. data/app/views/services_mailer/notification_oai_endpoint_added.text.ro.html.erb +4 -0
  270. data/app/views/services_mailer/notification_oai_endpoint_added.text.ro.plain.erb +4 -0
  271. data/app/views/services_mailer/notification_oai_endpoint_added.text.ru.html.erb +4 -0
  272. data/app/views/services_mailer/notification_oai_endpoint_added.text.ru.plain.erb +4 -0
  273. data/app/views/services_mailer/notification_oai_endpoint_added.text.sk.html.erb +4 -0
  274. data/app/views/services_mailer/notification_oai_endpoint_added.text.sk.plain.erb +4 -0
  275. data/app/views/services_mailer/notification_oai_endpoint_added.text.sl.html.erb +4 -0
  276. data/app/views/services_mailer/notification_oai_endpoint_added.text.sl.plain.erb +4 -0
  277. data/app/views/services_mailer/notification_oai_endpoint_added.text.sq.html.erb +4 -0
  278. data/app/views/services_mailer/notification_oai_endpoint_added.text.sq.plain.erb +4 -0
  279. data/app/views/services_mailer/notification_oai_endpoint_added.text.sr.html.erb +4 -0
  280. data/app/views/services_mailer/notification_oai_endpoint_added.text.sr.plain.erb +4 -0
  281. data/app/views/services_mailer/notification_oai_endpoint_added.text.sv.html.erb +4 -0
  282. data/app/views/services_mailer/notification_oai_endpoint_added.text.sv.plain.erb +4 -0
  283. data/app/views/services_mailer/notification_oai_endpoint_added.text.th.html.erb +4 -0
  284. data/app/views/services_mailer/notification_oai_endpoint_added.text.th.plain.erb +4 -0
  285. data/app/views/services_mailer/notification_oai_endpoint_added.text.tl.html.erb +4 -0
  286. data/app/views/services_mailer/notification_oai_endpoint_added.text.tl.plain.erb +4 -0
  287. data/app/views/services_mailer/notification_oai_endpoint_added.text.tr.html.erb +4 -0
  288. data/app/views/services_mailer/notification_oai_endpoint_added.text.tr.plain.erb +4 -0
  289. data/app/views/services_mailer/notification_oai_endpoint_added.text.uk.html.erb +4 -0
  290. data/app/views/services_mailer/notification_oai_endpoint_added.text.uk.plain.erb +4 -0
  291. data/app/views/services_mailer/notification_oai_endpoint_added.text.vi.html.erb +4 -0
  292. data/app/views/services_mailer/notification_oai_endpoint_added.text.vi.plain.erb +4 -0
  293. data/app/views/services_mailer/notification_oai_endpoint_added.text.zh-CN.html.erb +4 -0
  294. data/app/views/services_mailer/notification_oai_endpoint_added.text.zh-CN.plain.erb +4 -0
  295. data/app/views/services_mailer/notification_oai_endpoint_added.text.zh-TW.html.erb +4 -0
  296. data/app/views/services_mailer/notification_oai_endpoint_added.text.zh-TW.plain.erb +4 -0
  297. data/app/views/services_mailer/notification_oai_endpoint_added.text.zh.html.erb +4 -0
  298. data/app/views/services_mailer/notification_oai_endpoint_added.text.zh.plain.erb +4 -0
  299. data/app/views/topics/_entry.html.erb +19 -0
  300. data/app/views/topics/_feed.html.erb +24 -0
  301. data/app/views/topics/_feed_preview.html.erb +18 -0
  302. data/app/views/topics/_form.html.erb +15 -0
  303. data/app/views/topics/_rss_discover.html.erb +1 -0
  304. data/app/views/topics/_simple_entry.html.erb +7 -0
  305. data/app/views/topics/new.html.erb +27 -0
  306. data/app/views/topics/photos.html.erb +14 -0
  307. data/app/views/topics/show.html.erb +80 -0
  308. data/app/views/topics/show.opml.builder +18 -0
  309. data/app/views/topics/videos.html.erb +14 -0
  310. data/app/views/visits/_comments_tool.html.erb +19 -0
  311. data/app/views/visits/_frame_scripts.html.erb +26 -0
  312. data/app/views/visits/_share_tool.html.erb +22 -0
  313. data/app/views/visits/_toolbar.html.erb +25 -0
  314. data/app/views/visits/show.html.erb +7 -0
  315. data/config/muck_services_routes.rb +37 -0
  316. data/config/solr/README.txt +0 -0
  317. data/config/solr/cores/de/conf/protwords.txt +21 -0
  318. data/config/solr/cores/de/conf/schema.xml +81 -0
  319. data/config/solr/cores/de/conf/solrconfig.xml +311 -0
  320. data/config/solr/cores/de/conf/stopwords.txt +341 -0
  321. data/config/solr/cores/de/conf/synonyms.txt +31 -0
  322. data/config/solr/cores/en/conf/protwords.txt +21 -0
  323. data/config/solr/cores/en/conf/schema.xml +83 -0
  324. data/config/solr/cores/en/conf/solrconfig.xml +311 -0
  325. data/config/solr/cores/en/conf/stopwords.txt +341 -0
  326. data/config/solr/cores/en/conf/synonyms.txt +31 -0
  327. data/config/solr/cores/es/conf/protwords.txt +21 -0
  328. data/config/solr/cores/es/conf/schema.xml +81 -0
  329. data/config/solr/cores/es/conf/solrconfig.xml +311 -0
  330. data/config/solr/cores/es/conf/stopwords.txt +206 -0
  331. data/config/solr/cores/es/conf/synonyms.txt +31 -0
  332. data/config/solr/cores/fr/conf/protwords.txt +21 -0
  333. data/config/solr/cores/fr/conf/schema.xml +82 -0
  334. data/config/solr/cores/fr/conf/solrconfig.xml +311 -0
  335. data/config/solr/cores/fr/conf/stopwords.txt +57 -0
  336. data/config/solr/cores/fr/conf/synonyms.txt +31 -0
  337. data/config/solr/cores/ja/conf/protwords.txt +21 -0
  338. data/config/solr/cores/ja/conf/schema.xml +69 -0
  339. data/config/solr/cores/ja/conf/solrconfig.xml +311 -0
  340. data/config/solr/cores/ja/conf/stopwords.txt +341 -0
  341. data/config/solr/cores/ja/conf/synonyms.txt +31 -0
  342. data/config/solr/cores/nl/conf/protwords.txt +21 -0
  343. data/config/solr/cores/nl/conf/schema.xml +78 -0
  344. data/config/solr/cores/nl/conf/solrconfig.xml +311 -0
  345. data/config/solr/cores/nl/conf/stopwords.txt +45691 -0
  346. data/config/solr/cores/nl/conf/synonyms.txt +31 -0
  347. data/config/solr/cores/ru/conf/protwords.txt +21 -0
  348. data/config/solr/cores/ru/conf/schema.xml +78 -0
  349. data/config/solr/cores/ru/conf/solrconfig.xml +311 -0
  350. data/config/solr/cores/ru/conf/stopwords.txt +341 -0
  351. data/config/solr/cores/ru/conf/synonyms.txt +31 -0
  352. data/config/solr/cores/zh/conf/protwords.txt +21 -0
  353. data/config/solr/cores/zh/conf/schema.xml +72 -0
  354. data/config/solr/cores/zh/conf/solrconfig.xml +311 -0
  355. data/config/solr/cores/zh/conf/stopwords.txt +341 -0
  356. data/config/solr/cores/zh/conf/synonyms.txt +31 -0
  357. data/config/solr/solr.xml +50 -0
  358. data/db/bootstrap/attention.yml +6 -0
  359. data/db/bootstrap/feeds.yml +4268 -0
  360. data/db/bootstrap/oai_endpoints.yml +6 -0
  361. data/db/bootstrap/service_categories.yml +52 -0
  362. data/db/bootstrap/services.yml +967 -0
  363. data/db/migrate/20090602191243_create_muck_raker.rb +322 -0
  364. data/db/migrate/20090619211125_create_tag_clouds.rb +19 -0
  365. data/db/migrate/20090623181458_add_grain_size_to_entries.rb +16 -0
  366. data/db/migrate/20090623193525_add_grain_size_to_tag_clouds.rb +12 -0
  367. data/db/migrate/20090703175825_denormalize_entries_subjects.rb +39 -0
  368. data/db/migrate/20090704220055_create_slugs.rb +18 -0
  369. data/db/migrate/20090716035935_change_tag_cloud_grain_sizes.rb +9 -0
  370. data/db/migrate/20090717173900_add_contributor_to_feeds.rb +9 -0
  371. data/db/migrate/20090717175825_normalize_entries_subjects.rb +41 -0
  372. data/db/migrate/20090721043213_change_services_title_to_name.rb +9 -0
  373. data/db/migrate/20090721054927_remove_services_not_null_from_feeds.rb +9 -0
  374. data/db/migrate/20090723050510_create_feed_parents.rb +17 -0
  375. data/db/migrate/20090728165716_add_etag_to_feeds.rb +9 -0
  376. data/db/migrate/20090730045848_add_comment_cache_to_entries.rb +9 -0
  377. data/db/migrate/20090804211240_add_entry_id_to_shares.rb +9 -0
  378. data/db/migrate/20090826220530_change_services_sequence_to_sort.rb +9 -0
  379. data/db/migrate/20090826225652_create_identity_feeds.rb +14 -0
  380. data/db/migrate/20090827005105_add_identity_fields_to_services.rb +13 -0
  381. data/db/migrate/20090827015308_create_service_categories.rb +12 -0
  382. data/db/migrate/20090827221502_add_prompt_and_template_to_services.rb +11 -0
  383. data/db/migrate/20090915041650_aggregations_to_polymorphic.rb +15 -0
  384. data/db/migrate/20090922174200_update_oai_endpoints.rb +13 -0
  385. data/db/migrate/20090922231552_add_dates_to_oai_endpoints.rb +11 -0
  386. data/db/migrate/20090923150807_rename_name_in_aggregation.rb +9 -0
  387. data/db/migrate/20090924200750_add_uri_data_template_to_services.rb +9 -0
  388. data/db/migrate/20091006183742_add_feed_count_to_aggregation.rb +9 -0
  389. data/db/migrate/20091022150615_add_uri_key_to_services.rb +9 -0
  390. data/lib/active_record/acts/muck_aggregation_owner.rb +30 -0
  391. data/lib/active_record/acts/muck_feed_owner.rb +31 -0
  392. data/lib/active_record/acts/muck_feed_parent.rb +23 -0
  393. data/lib/active_record/acts/muck_services_comment.rb +39 -0
  394. data/lib/active_record/acts/muck_services_share.rb +32 -0
  395. data/lib/muck_services.rb +21 -0
  396. data/lib/muck_services/exceptions.rb +5 -0
  397. data/lib/muck_services/initialize_routes.rb +8 -0
  398. data/lib/muck_services/languages.rb +57 -0
  399. data/lib/muck_services/muck_custom_form_builder.rb +22 -0
  400. data/lib/muck_services/services.rb +12 -0
  401. data/lib/muck_services/tasks.rb +97 -0
  402. data/locales/ar.yml +210 -0
  403. data/locales/bg.yml +210 -0
  404. data/locales/ca.yml +210 -0
  405. data/locales/cs.yml +210 -0
  406. data/locales/da.yml +210 -0
  407. data/locales/de.yml +210 -0
  408. data/locales/el.yml +210 -0
  409. data/locales/en.yml +213 -0
  410. data/locales/es.yml +210 -0
  411. data/locales/et.yml +210 -0
  412. data/locales/fa.yml +210 -0
  413. data/locales/fi.yml +210 -0
  414. data/locales/fr.yml +210 -0
  415. data/locales/gl.yml +210 -0
  416. data/locales/hi.yml +210 -0
  417. data/locales/hr.yml +210 -0
  418. data/locales/hu.yml +210 -0
  419. data/locales/id.yml +210 -0
  420. data/locales/it.yml +210 -0
  421. data/locales/iw.yml +210 -0
  422. data/locales/ja.yml +210 -0
  423. data/locales/ko.yml +210 -0
  424. data/locales/lt.yml +210 -0
  425. data/locales/lv.yml +210 -0
  426. data/locales/mt.yml +210 -0
  427. data/locales/nl.yml +210 -0
  428. data/locales/no.yml +211 -0
  429. data/locales/pl.yml +210 -0
  430. data/locales/pt-PT.yml +210 -0
  431. data/locales/ro.yml +210 -0
  432. data/locales/ru.yml +210 -0
  433. data/locales/sk.yml +210 -0
  434. data/locales/sl.yml +210 -0
  435. data/locales/sq.yml +210 -0
  436. data/locales/sr.yml +210 -0
  437. data/locales/sv.yml +210 -0
  438. data/locales/th.yml +210 -0
  439. data/locales/tl.yml +210 -0
  440. data/locales/tr.yml +210 -0
  441. data/locales/uk.yml +210 -0
  442. data/locales/vi.yml +210 -0
  443. data/locales/zh-CN.yml +210 -0
  444. data/locales/zh-TW.yml +210 -0
  445. data/locales/zh.yml +210 -0
  446. data/muck-services.gemspec +891 -0
  447. data/public/images/service_icons/16/amazon.png +0 -0
  448. data/public/images/service_icons/16/ask.png +0 -0
  449. data/public/images/service_icons/16/bibsonomy.png +0 -0
  450. data/public/images/service_icons/16/bing.png +0 -0
  451. data/public/images/service_icons/16/blogger.png +0 -0
  452. data/public/images/service_icons/16/bloglines.png +0 -0
  453. data/public/images/service_icons/16/citeulike.png +0 -0
  454. data/public/images/service_icons/16/clipmarks.png +0 -0
  455. data/public/images/service_icons/16/connotea.png +0 -0
  456. data/public/images/service_icons/16/dailymotion.png +0 -0
  457. data/public/images/service_icons/16/delicious.png +0 -0
  458. data/public/images/service_icons/16/digg.png +0 -0
  459. data/public/images/service_icons/16/diigo.png +0 -0
  460. data/public/images/service_icons/16/facebook.png +0 -0
  461. data/public/images/service_icons/16/feed.png +0 -0
  462. data/public/images/service_icons/16/flickr.png +0 -0
  463. data/public/images/service_icons/16/fotolog.png +0 -0
  464. data/public/images/service_icons/16/friendfeed.png +0 -0
  465. data/public/images/service_icons/16/friendster.png +0 -0
  466. data/public/images/service_icons/16/furl.png +0 -0
  467. data/public/images/service_icons/16/goodreads.png +0 -0
  468. data/public/images/service_icons/16/google.png +0 -0
  469. data/public/images/service_icons/16/googleblog.png +0 -0
  470. data/public/images/service_icons/16/googlenews.png +0 -0
  471. data/public/images/service_icons/16/icerocket.png +0 -0
  472. data/public/images/service_icons/16/identica.png +0 -0
  473. data/public/images/service_icons/16/joost.png +0 -0
  474. data/public/images/service_icons/16/lastfm.png +0 -0
  475. data/public/images/service_icons/16/librarything.png +0 -0
  476. data/public/images/service_icons/16/linkedin.png +0 -0
  477. data/public/images/service_icons/16/livejournal.png +0 -0
  478. data/public/images/service_icons/16/magnolia.png +0 -0
  479. data/public/images/service_icons/16/mendeley.png +0 -0
  480. data/public/images/service_icons/16/metacafe.png +0 -0
  481. data/public/images/service_icons/16/mixx.png +0 -0
  482. data/public/images/service_icons/16/myspace.png +0 -0
  483. data/public/images/service_icons/16/netflix.png +0 -0
  484. data/public/images/service_icons/16/netvibes.png +0 -0
  485. data/public/images/service_icons/16/newsvine.png +0 -0
  486. data/public/images/service_icons/16/oai.png +0 -0
  487. data/public/images/service_icons/16/odeo.png +0 -0
  488. data/public/images/service_icons/16/opml.png +0 -0
  489. data/public/images/service_icons/16/pandora.png +0 -0
  490. data/public/images/service_icons/16/photobucket.png +0 -0
  491. data/public/images/service_icons/16/picasa.png +0 -0
  492. data/public/images/service_icons/16/polyvore.png +0 -0
  493. data/public/images/service_icons/16/pownce.png +0 -0
  494. data/public/images/service_icons/16/reddit.png +0 -0
  495. data/public/images/service_icons/16/simpy.png +0 -0
  496. data/public/images/service_icons/16/smugmug.png +0 -0
  497. data/public/images/service_icons/16/stumbleupon.png +0 -0
  498. data/public/images/service_icons/16/tag.png +0 -0
  499. data/public/images/service_icons/16/technorati.png +0 -0
  500. data/public/images/service_icons/16/tumblr.png +0 -0
  501. data/public/images/service_icons/16/twine.png +0 -0
  502. data/public/images/service_icons/16/twitter.png +0 -0
  503. data/public/images/service_icons/16/vimeo.png +0 -0
  504. data/public/images/service_icons/16/webshots.png +0 -0
  505. data/public/images/service_icons/16/wordpress.png +0 -0
  506. data/public/images/service_icons/16/xanga.png +0 -0
  507. data/public/images/service_icons/16/yahoo.png +0 -0
  508. data/public/images/service_icons/16/yelp.png +0 -0
  509. data/public/images/service_icons/16/youtube.png +0 -0
  510. data/public/images/service_icons/16/zooomr.png +0 -0
  511. data/public/images/service_icons/16/zotero.png +0 -0
  512. data/public/images/service_icons/24/amazon.png +0 -0
  513. data/public/images/service_icons/24/ask.png +0 -0
  514. data/public/images/service_icons/24/bibsonomy.png +0 -0
  515. data/public/images/service_icons/24/bing.png +0 -0
  516. data/public/images/service_icons/24/blogger.png +0 -0
  517. data/public/images/service_icons/24/bloglines.png +0 -0
  518. data/public/images/service_icons/24/citeulike.png +0 -0
  519. data/public/images/service_icons/24/clipmarks.png +0 -0
  520. data/public/images/service_icons/24/connotea.png +0 -0
  521. data/public/images/service_icons/24/dailymotion.png +0 -0
  522. data/public/images/service_icons/24/delicious.png +0 -0
  523. data/public/images/service_icons/24/digg.png +0 -0
  524. data/public/images/service_icons/24/diigo.png +0 -0
  525. data/public/images/service_icons/24/facebook.png +0 -0
  526. data/public/images/service_icons/24/feed.png +0 -0
  527. data/public/images/service_icons/24/flickr.png +0 -0
  528. data/public/images/service_icons/24/fotolog.png +0 -0
  529. data/public/images/service_icons/24/friendfeed.png +0 -0
  530. data/public/images/service_icons/24/friendster.png +0 -0
  531. data/public/images/service_icons/24/furl.png +0 -0
  532. data/public/images/service_icons/24/goodreads.png +0 -0
  533. data/public/images/service_icons/24/google.png +0 -0
  534. data/public/images/service_icons/24/googleblog.png +0 -0
  535. data/public/images/service_icons/24/googlenews.png +0 -0
  536. data/public/images/service_icons/24/icerocket.png +0 -0
  537. data/public/images/service_icons/24/identica.png +0 -0
  538. data/public/images/service_icons/24/joost.png +0 -0
  539. data/public/images/service_icons/24/lastfm.png +0 -0
  540. data/public/images/service_icons/24/librarything.png +0 -0
  541. data/public/images/service_icons/24/linkedin.png +0 -0
  542. data/public/images/service_icons/24/livejournal.png +0 -0
  543. data/public/images/service_icons/24/magnolia.png +0 -0
  544. data/public/images/service_icons/24/mendeley.png +0 -0
  545. data/public/images/service_icons/24/metacafe.png +0 -0
  546. data/public/images/service_icons/24/mixx.png +0 -0
  547. data/public/images/service_icons/24/myspace.png +0 -0
  548. data/public/images/service_icons/24/netflix.png +0 -0
  549. data/public/images/service_icons/24/netvibes.png +0 -0
  550. data/public/images/service_icons/24/newsvine.png +0 -0
  551. data/public/images/service_icons/24/oai.png +0 -0
  552. data/public/images/service_icons/24/odeo.png +0 -0
  553. data/public/images/service_icons/24/opml.png +0 -0
  554. data/public/images/service_icons/24/pandora.png +0 -0
  555. data/public/images/service_icons/24/photobucket.png +0 -0
  556. data/public/images/service_icons/24/picasa.png +0 -0
  557. data/public/images/service_icons/24/polyvore.png +0 -0
  558. data/public/images/service_icons/24/pownce.png +0 -0
  559. data/public/images/service_icons/24/reddit.png +0 -0
  560. data/public/images/service_icons/24/simpy.png +0 -0
  561. data/public/images/service_icons/24/smugmug.png +0 -0
  562. data/public/images/service_icons/24/stumbleupon.png +0 -0
  563. data/public/images/service_icons/24/tag.png +0 -0
  564. data/public/images/service_icons/24/technorati.png +0 -0
  565. data/public/images/service_icons/24/tumblr.png +0 -0
  566. data/public/images/service_icons/24/twine.png +0 -0
  567. data/public/images/service_icons/24/twitter.png +0 -0
  568. data/public/images/service_icons/24/vimeo.png +0 -0
  569. data/public/images/service_icons/24/webshots.png +0 -0
  570. data/public/images/service_icons/24/wordpress.png +0 -0
  571. data/public/images/service_icons/24/xanga.png +0 -0
  572. data/public/images/service_icons/24/yahoo.png +0 -0
  573. data/public/images/service_icons/24/yelp.png +0 -0
  574. data/public/images/service_icons/24/youtube.png +0 -0
  575. data/public/images/service_icons/24/zooomr.png +0 -0
  576. data/public/images/service_icons/24/zotero.png +0 -0
  577. data/public/images/service_icons/48/amazon.png +0 -0
  578. data/public/images/service_icons/48/ask.png +0 -0
  579. data/public/images/service_icons/48/bibsonomy.png +0 -0
  580. data/public/images/service_icons/48/bing.png +0 -0
  581. data/public/images/service_icons/48/blogger.png +0 -0
  582. data/public/images/service_icons/48/bloglines.png +0 -0
  583. data/public/images/service_icons/48/citeulike.png +0 -0
  584. data/public/images/service_icons/48/clipmarks.png +0 -0
  585. data/public/images/service_icons/48/connotea.png +0 -0
  586. data/public/images/service_icons/48/dailymotion.png +0 -0
  587. data/public/images/service_icons/48/delicious.png +0 -0
  588. data/public/images/service_icons/48/digg.png +0 -0
  589. data/public/images/service_icons/48/diigo.png +0 -0
  590. data/public/images/service_icons/48/facebook.png +0 -0
  591. data/public/images/service_icons/48/feed.png +0 -0
  592. data/public/images/service_icons/48/flickr.png +0 -0
  593. data/public/images/service_icons/48/fotolog.png +0 -0
  594. data/public/images/service_icons/48/friendfeed.png +0 -0
  595. data/public/images/service_icons/48/friendster.png +0 -0
  596. data/public/images/service_icons/48/furl.png +0 -0
  597. data/public/images/service_icons/48/goodreads.png +0 -0
  598. data/public/images/service_icons/48/google.png +0 -0
  599. data/public/images/service_icons/48/googleblog.png +0 -0
  600. data/public/images/service_icons/48/googlenews.png +0 -0
  601. data/public/images/service_icons/48/icerocket.png +0 -0
  602. data/public/images/service_icons/48/identica.png +0 -0
  603. data/public/images/service_icons/48/joost.png +0 -0
  604. data/public/images/service_icons/48/lastfm.png +0 -0
  605. data/public/images/service_icons/48/librarything.png +0 -0
  606. data/public/images/service_icons/48/linkedin.png +0 -0
  607. data/public/images/service_icons/48/livejournal.png +0 -0
  608. data/public/images/service_icons/48/magnolia.png +0 -0
  609. data/public/images/service_icons/48/mendeley.png +0 -0
  610. data/public/images/service_icons/48/metacafe.png +0 -0
  611. data/public/images/service_icons/48/mixx.png +0 -0
  612. data/public/images/service_icons/48/myspace.png +0 -0
  613. data/public/images/service_icons/48/netflix.png +0 -0
  614. data/public/images/service_icons/48/netvibes.png +0 -0
  615. data/public/images/service_icons/48/newsvine.png +0 -0
  616. data/public/images/service_icons/48/oai.png +0 -0
  617. data/public/images/service_icons/48/odeo.png +0 -0
  618. data/public/images/service_icons/48/opml.png +0 -0
  619. data/public/images/service_icons/48/pandora.png +0 -0
  620. data/public/images/service_icons/48/photobucket.png +0 -0
  621. data/public/images/service_icons/48/picasa.png +0 -0
  622. data/public/images/service_icons/48/polyvore.png +0 -0
  623. data/public/images/service_icons/48/pownce.png +0 -0
  624. data/public/images/service_icons/48/reddit.png +0 -0
  625. data/public/images/service_icons/48/simpy.png +0 -0
  626. data/public/images/service_icons/48/smugmug.png +0 -0
  627. data/public/images/service_icons/48/stumbleupon.png +0 -0
  628. data/public/images/service_icons/48/tag.png +0 -0
  629. data/public/images/service_icons/48/technorati.png +0 -0
  630. data/public/images/service_icons/48/tumblr.png +0 -0
  631. data/public/images/service_icons/48/twine.png +0 -0
  632. data/public/images/service_icons/48/twitter.png +0 -0
  633. data/public/images/service_icons/48/vimeo.png +0 -0
  634. data/public/images/service_icons/48/webshots.png +0 -0
  635. data/public/images/service_icons/48/wordpress.png +0 -0
  636. data/public/images/service_icons/48/xanga.png +0 -0
  637. data/public/images/service_icons/48/yahoo.png +0 -0
  638. data/public/images/service_icons/48/yelp.png +0 -0
  639. data/public/images/service_icons/48/youtube.png +0 -0
  640. data/public/images/service_icons/48/zooomr.png +0 -0
  641. data/public/images/service_icons/48/zotero.png +0 -0
  642. data/public/images/service_icons/60/amazon.png +0 -0
  643. data/public/images/service_icons/60/ask.png +0 -0
  644. data/public/images/service_icons/60/bibsonomy.png +0 -0
  645. data/public/images/service_icons/60/bing.png +0 -0
  646. data/public/images/service_icons/60/blogger.png +0 -0
  647. data/public/images/service_icons/60/bloglines.png +0 -0
  648. data/public/images/service_icons/60/citeulike.png +0 -0
  649. data/public/images/service_icons/60/clipmarks.png +0 -0
  650. data/public/images/service_icons/60/connotea.png +0 -0
  651. data/public/images/service_icons/60/dailymotion.png +0 -0
  652. data/public/images/service_icons/60/delicious.png +0 -0
  653. data/public/images/service_icons/60/digg.png +0 -0
  654. data/public/images/service_icons/60/diigo.png +0 -0
  655. data/public/images/service_icons/60/facebook.png +0 -0
  656. data/public/images/service_icons/60/feed.png +0 -0
  657. data/public/images/service_icons/60/flickr.png +0 -0
  658. data/public/images/service_icons/60/fotolog.png +0 -0
  659. data/public/images/service_icons/60/friendfeed.png +0 -0
  660. data/public/images/service_icons/60/friendster.png +0 -0
  661. data/public/images/service_icons/60/furl.png +0 -0
  662. data/public/images/service_icons/60/goodreads.png +0 -0
  663. data/public/images/service_icons/60/google.png +0 -0
  664. data/public/images/service_icons/60/googleblog.png +0 -0
  665. data/public/images/service_icons/60/googlenews.png +0 -0
  666. data/public/images/service_icons/60/icerocket.png +0 -0
  667. data/public/images/service_icons/60/identica.png +0 -0
  668. data/public/images/service_icons/60/joost.png +0 -0
  669. data/public/images/service_icons/60/lastfm.png +0 -0
  670. data/public/images/service_icons/60/librarything.png +0 -0
  671. data/public/images/service_icons/60/linkedin.png +0 -0
  672. data/public/images/service_icons/60/livejournal.png +0 -0
  673. data/public/images/service_icons/60/magnolia.png +0 -0
  674. data/public/images/service_icons/60/mendeley.png +0 -0
  675. data/public/images/service_icons/60/metacafe.png +0 -0
  676. data/public/images/service_icons/60/mixx.png +0 -0
  677. data/public/images/service_icons/60/myspace.png +0 -0
  678. data/public/images/service_icons/60/netflix.png +0 -0
  679. data/public/images/service_icons/60/netvibes.png +0 -0
  680. data/public/images/service_icons/60/newsvine.png +0 -0
  681. data/public/images/service_icons/60/oai.png +0 -0
  682. data/public/images/service_icons/60/odeo.png +0 -0
  683. data/public/images/service_icons/60/opml.png +0 -0
  684. data/public/images/service_icons/60/pandora.png +0 -0
  685. data/public/images/service_icons/60/photobucket.png +0 -0
  686. data/public/images/service_icons/60/picasa.png +0 -0
  687. data/public/images/service_icons/60/polyvore.png +0 -0
  688. data/public/images/service_icons/60/pownce.png +0 -0
  689. data/public/images/service_icons/60/reddit.png +0 -0
  690. data/public/images/service_icons/60/simpy.png +0 -0
  691. data/public/images/service_icons/60/smugmug.png +0 -0
  692. data/public/images/service_icons/60/stumbleupon.png +0 -0
  693. data/public/images/service_icons/60/tag.png +0 -0
  694. data/public/images/service_icons/60/technorati.png +0 -0
  695. data/public/images/service_icons/60/tumblr.png +0 -0
  696. data/public/images/service_icons/60/twine.png +0 -0
  697. data/public/images/service_icons/60/twitter.png +0 -0
  698. data/public/images/service_icons/60/vimeo.png +0 -0
  699. data/public/images/service_icons/60/webshots.png +0 -0
  700. data/public/images/service_icons/60/wordpress.png +0 -0
  701. data/public/images/service_icons/60/xanga.png +0 -0
  702. data/public/images/service_icons/60/yahoo.png +0 -0
  703. data/public/images/service_icons/60/yelp.png +0 -0
  704. data/public/images/service_icons/60/youtube.png +0 -0
  705. data/public/images/service_icons/60/zooomr.png +0 -0
  706. data/public/images/service_icons/60/zotero.png +0 -0
  707. data/public/images/service_icons/facebook_friend_links.jpg +0 -0
  708. data/public/images/service_icons/facebook_my_links.jpg +0 -0
  709. data/public/javascripts/muck_services.js +94 -0
  710. data/public/stylesheets/frame.css +56 -0
  711. data/public/stylesheets/muck_services.css +90 -0
  712. data/rails/init.rb +18 -0
  713. data/test/rails_root/app/controllers/application_controller.rb +32 -0
  714. data/test/rails_root/app/controllers/default_controller.rb +7 -0
  715. data/test/rails_root/app/helpers/application_helper.rb +3 -0
  716. data/test/rails_root/app/models/activity.rb +24 -0
  717. data/test/rails_root/app/models/comment.rb +23 -0
  718. data/test/rails_root/app/models/share.rb +20 -0
  719. data/test/rails_root/app/models/user.rb +43 -0
  720. data/test/rails_root/app/models/user_session.rb +2 -0
  721. data/test/rails_root/config/boot.rb +109 -0
  722. data/test/rails_root/config/environment.rb +37 -0
  723. data/test/rails_root/config/environments/cucumber.rb +21 -0
  724. data/test/rails_root/config/environments/development.rb +36 -0
  725. data/test/rails_root/config/environments/production.rb +1 -0
  726. data/test/rails_root/config/environments/test.rb +34 -0
  727. data/test/rails_root/config/initializers/inflections.rb +10 -0
  728. data/test/rails_root/config/initializers/mime_types.rb +5 -0
  729. data/test/rails_root/config/initializers/requires.rb +13 -0
  730. data/test/rails_root/config/initializers/session_store.rb +8 -0
  731. data/test/rails_root/config/routes.rb +11 -0
  732. data/test/rails_root/db/migrate/20090320174818_create_muck_permissions_and_roles.rb +16 -0
  733. data/test/rails_root/db/migrate/20090327231918_create_users.rb +40 -0
  734. data/test/rails_root/db/migrate/20090402033319_add_muck_activities.rb +36 -0
  735. data/test/rails_root/db/migrate/20090402234137_create_languages.rb +18 -0
  736. data/test/rails_root/db/migrate/20090426041056_create_countries.rb +15 -0
  737. data/test/rails_root/db/migrate/20090426041103_create_states.rb +18 -0
  738. data/test/rails_root/db/migrate/20090602191243_create_muck_raker.rb +322 -0
  739. data/test/rails_root/db/migrate/20090613173314_create_comments.rb +24 -0
  740. data/test/rails_root/db/migrate/20090619211125_create_tag_clouds.rb +19 -0
  741. data/test/rails_root/db/migrate/20090623181458_add_grain_size_to_entries.rb +16 -0
  742. data/test/rails_root/db/migrate/20090623193525_add_grain_size_to_tag_clouds.rb +12 -0
  743. data/test/rails_root/db/migrate/20090703175825_denormalize_entries_subjects.rb +39 -0
  744. data/test/rails_root/db/migrate/20090704220055_create_slugs.rb +18 -0
  745. data/test/rails_root/db/migrate/20090716035935_change_tag_cloud_grain_sizes.rb +9 -0
  746. data/test/rails_root/db/migrate/20090717173900_add_contributor_to_feeds.rb +9 -0
  747. data/test/rails_root/db/migrate/20090717175825_normalize_entries_subjects.rb +41 -0
  748. data/test/rails_root/db/migrate/20090721043213_change_services_title_to_name.rb +9 -0
  749. data/test/rails_root/db/migrate/20090721054927_remove_services_not_null_from_feeds.rb +9 -0
  750. data/test/rails_root/db/migrate/20090723050510_create_feed_parents.rb +17 -0
  751. data/test/rails_root/db/migrate/20090728165716_add_etag_to_feeds.rb +9 -0
  752. data/test/rails_root/db/migrate/20090730044139_add_comment_cache.rb +9 -0
  753. data/test/rails_root/db/migrate/20090730045848_add_comment_cache_to_entries.rb +9 -0
  754. data/test/rails_root/db/migrate/20090730154102_allow_null_user.rb +9 -0
  755. data/test/rails_root/db/migrate/20090803185323_create_shares.rb +16 -0
  756. data/test/rails_root/db/migrate/20090804184247_add_comment_count_to_shares.rb +9 -0
  757. data/test/rails_root/db/migrate/20090804211240_add_entry_id_to_shares.rb +9 -0
  758. data/test/rails_root/db/migrate/20090804231857_add_shares_uri_index.rb +9 -0
  759. data/test/rails_root/db/migrate/20090818204527_add_activity_indexes.rb +9 -0
  760. data/test/rails_root/db/migrate/20090819030523_add_attachable_to_activities.rb +13 -0
  761. data/test/rails_root/db/migrate/20090826220530_change_services_sequence_to_sort.rb +9 -0
  762. data/test/rails_root/db/migrate/20090826225652_create_identity_feeds.rb +14 -0
  763. data/test/rails_root/db/migrate/20090827005105_add_identity_fields_to_services.rb +13 -0
  764. data/test/rails_root/db/migrate/20090827015308_create_service_categories.rb +12 -0
  765. data/test/rails_root/db/migrate/20090827221502_add_prompt_and_template_to_services.rb +11 -0
  766. data/test/rails_root/db/migrate/20090915041650_aggregations_to_polymorphic.rb +15 -0
  767. data/test/rails_root/db/migrate/20090922174200_update_oai_endpoints.rb +13 -0
  768. data/test/rails_root/db/migrate/20090922231552_add_dates_to_oai_endpoints.rb +11 -0
  769. data/test/rails_root/db/migrate/20090923150807_rename_name_in_aggregation.rb +9 -0
  770. data/test/rails_root/db/migrate/20090924200750_add_uri_data_template_to_services.rb +9 -0
  771. data/test/rails_root/db/migrate/20091006183742_add_feed_count_to_aggregation.rb +9 -0
  772. data/test/rails_root/db/migrate/20091022150615_add_uri_key_to_services.rb +9 -0
  773. data/test/rails_root/db/schema.rb +474 -0
  774. data/test/rails_root/features/step_definitions/common_steps.rb +93 -0
  775. data/test/rails_root/features/step_definitions/visit_steps.rb +6 -0
  776. data/test/rails_root/features/step_definitions/webrat_steps.rb +128 -0
  777. data/test/rails_root/features/support/env.rb +14 -0
  778. data/test/rails_root/features/support/paths.rb +36 -0
  779. data/test/rails_root/public/dispatch.rb +10 -0
  780. data/test/rails_root/script/create_project.rb +52 -0
  781. data/test/rails_root/test/factories.rb +151 -0
  782. data/test/rails_root/test/functional/admin/feeds_controller_test.rb +37 -0
  783. data/test/rails_root/test/functional/admin/oai_endpoints_controller_test.rb +30 -0
  784. data/test/rails_root/test/functional/aggregation_feeds_controller_test.rb +67 -0
  785. data/test/rails_root/test/functional/aggregations_controller_test.rb +89 -0
  786. data/test/rails_root/test/functional/feed_previews_controller_test.rb +32 -0
  787. data/test/rails_root/test/functional/feeds_controller_test.rb +77 -0
  788. data/test/rails_root/test/functional/identity_feeds_controller_test.rb +110 -0
  789. data/test/rails_root/test/functional/oai_endpoints_controller_test.rb +42 -0
  790. data/test/rails_root/test/functional/topics_controller_test.rb +46 -0
  791. data/test/rails_root/test/functional/visits_controller_test.rb +21 -0
  792. data/test/rails_root/test/shoulda_macros/controller.rb +49 -0
  793. data/test/rails_root/test/shoulda_macros/forms.rb +32 -0
  794. data/test/rails_root/test/shoulda_macros/models.rb +50 -0
  795. data/test/rails_root/test/shoulda_macros/pagination.rb +53 -0
  796. data/test/rails_root/test/shoulda_macros/plugins.rb +34 -0
  797. data/test/rails_root/test/test_helper.rb +85 -0
  798. data/test/rails_root/test/unit/aggregation_feed_test.rb +25 -0
  799. data/test/rails_root/test/unit/aggregation_test.rb +120 -0
  800. data/test/rails_root/test/unit/comment_test.rb +38 -0
  801. data/test/rails_root/test/unit/entry_test.rb +65 -0
  802. data/test/rails_root/test/unit/feed_parent_test.rb +22 -0
  803. data/test/rails_root/test/unit/feed_test.rb +177 -0
  804. data/test/rails_root/test/unit/identity_feed_test.rb +18 -0
  805. data/test/rails_root/test/unit/oai_endpoint_test.rb +40 -0
  806. data/test/rails_root/test/unit/service_category_test.rb +19 -0
  807. data/test/rails_root/test/unit/service_test.rb +331 -0
  808. data/test/rails_root/test/unit/services_mailer_test.rb +35 -0
  809. data/test/rails_root/test/unit/share_test.rb +30 -0
  810. data/test/rails_root/test/unit/tag_cloud_test.rb +23 -0
  811. data/test/rails_root/test/unit/user_test.rb +43 -0
  812. data/test/rails_root/vendor/plugins/jrails/init.rb +1 -0
  813. data/test/rails_root/vendor/plugins/jrails/install.rb +9 -0
  814. data/test/rails_root/vendor/plugins/jrails/lib/jrails.rb +421 -0
  815. data/test/rails_root/vendor/plugins/jrails/rails/init.rb +15 -0
  816. data/test/rails_root/vendor/plugins/ssl_requirement/lib/ssl_requirement.rb +62 -0
  817. data/test/rails_root/vendor/plugins/ssl_requirement/test/ssl_requirement_test.rb +132 -0
  818. metadata +991 -0
@@ -0,0 +1,117 @@
1
+ module MuckServicesServiceHelper
2
+
3
+ # Render a summary of all services for the given parent. The parent should 'acts_as_muck_feed_owner'
4
+ def services_summary(parent)
5
+ identity_feeds = parent.identity_feeds.find(:all, :include => [{:feed => :service}])
6
+ render :partial => 'services/summary', :locals => { :identity_feeds => identity_feeds }
7
+ end
8
+
9
+ # Render a view with all services in categories.
10
+ # service_categories: Results from a query to service_categories. For performance try something like this:
11
+ # ServiceCategory.sorted.find(:all, :include => [:identity_services])
12
+ # title: Optional title. Default is 'Available Services' - from I18n.t('muck.services.available_services')
13
+ # css: Optional css to be added to the div that surrounds the categories
14
+ def available_service_categories(service_categories, title = nil, css = '')
15
+ render :partial => 'identity_feeds/available_service_categories', :locals => { :service_categories => service_categories, :css => css, :title => title }
16
+ end
17
+
18
+ # Render a view with the user's registered services.
19
+ # identity_feeds: Results from a query to service_categories. For performance try something like this:
20
+ # @user.identity_feeds.find(:all, :include => [{:feed => :service}])
21
+ # title: Optional title. Default is 'My Services' - from I18n.t('muck.services.my_services')
22
+ # css: Optional css to be added to the div that surrounds the categories
23
+ def services_for_user(identity_feeds, title = nil, css = '')
24
+ render :partial => 'identity_feeds/services_for_user', :locals => { :identity_feeds => identity_feeds, :css => css, :title => title, :edit => false }
25
+ end
26
+
27
+ # Render an edit view with the user's registered services.
28
+ # identity_feeds: Results from a query to service_categories. For performance try something like this:
29
+ # @user.identity_feeds.find(:all, :include => [{:feed => :service}])
30
+ # title: Optional title. Default is 'My Services' - from I18n.t('muck.services.my_services')
31
+ # css: Optional css to be added to the div that surrounds the categories
32
+ def services_for_user_edit(identity_feeds, title = nil, css = '')
33
+ render :partial => 'identity_feeds/services_for_user', :locals => { :identity_feeds => identity_feeds, :css => css, :title => title, :edit => true }
34
+ end
35
+
36
+ # Renders an icon for the given service
37
+ # Name is the name of the image file associated with the service
38
+ # Size can be one of 16, 24, 48 or 60.
39
+ def service_icon(name, size = 24)
40
+ %Q{<img src="/images/service_icons/#{size}/#{name}" />}
41
+ end
42
+
43
+ def service_image(name, size = 24)
44
+ %Q{/images/service_icons/#{size}/#{name}}
45
+ end
46
+
47
+ # Renders name and icon for the service
48
+ def service_title(service)
49
+ %Q{<div class="identity-service-title" #{service_icon_background(service)}>#{service_prompt(service)}</div>}
50
+ end
51
+
52
+ # By default renders Service username e.g. Flickr username
53
+ # If the service has a 'prompt' set it will look for a value in the localization
54
+ # files. For example, setting service.prompt to 'blog_url' will cause this method
55
+ # to look for a translation at muck.services.blog_url and will pass the name of the service
56
+ # using 'service' so your translation might look like:
57
+ # muck.services.blog_url: "Blog Url" or
58
+ # muck.services.facebook_prompt: "{{service}} Feeds"
59
+ def service_prompt(service)
60
+ if @service.prompt.blank?
61
+ I18n.t('muck.services.service_username', :service => @service.name)
62
+ else
63
+ I18n.t("muck.services.#{@service.prompt}", :service => @service.name)
64
+ end
65
+ end
66
+
67
+ # Renders a link for a new user service with class 'lightbox' or optional css set on the link.
68
+ def service_lightbox(parent, service, link_css = 'lightbox', wrapper = 'li')
69
+ path = new_polymorphic_url([parent, :identity_feed], :service_id => service.to_param)
70
+ service_link(path, service, link_css, wrapper, nil, nil, "#{service.name.parameterize}-link")
71
+ end
72
+
73
+ # Renders a link for editing a user feed with class 'lightbox' or optional css set on the link.
74
+ def service_lightbox_edit(parent, identity_feed, link_css = 'lightbox', wrapper = nil)
75
+ path = edit_polymorphic_url([parent, identity_feed])
76
+ link_text = identity_feed.feed.title unless identity_feed.feed.title.blank?
77
+ service_link(path, identity_feed.feed.service, link_css, wrapper, link_text)
78
+ end
79
+
80
+ def service_external_link(identity_feed, link_css = nil, wrapper = nil)
81
+ path = identity_feed.feed.display_uri || identity_feed.feed.uri
82
+ link_text = identity_feed.feed.title unless identity_feed.feed.title.blank?
83
+ service_link(path, identity_feed.feed.service, link_css, wrapper, link_text, 'blank')
84
+ end
85
+
86
+ # Renders a delete button for an identity_feed
87
+ def service_delete(identity_feed, button_type = :button, button_text = t("muck.general.delete"))
88
+ render :partial => 'shared/delete', :locals => { :delete_object => identity_feed,
89
+ :button_type => button_type,
90
+ :button_text => button_text,
91
+ :form_class => 'identity-feed-delete',
92
+ :delete_path => identity_feed_path(identity_feed, :format => 'js') }
93
+ end
94
+
95
+ # Renders a service link optionally wrapping it in the specified element
96
+ def service_link(path, service, link_css, wrapper, link_text = nil, target = nil, id = nil)
97
+ link = %Q{<a #{'id=' + id if id} href="#{path}" #{service_icon_background(service)} #{'target=' + target if target} class="service-link #{link_css}">#{link_text || service.name}</a>}
98
+ if wrapper
99
+ content_tag wrapper, link, :class => 'identity-service'
100
+ else
101
+ link
102
+ end
103
+ end
104
+
105
+ def service_icon_background(service)
106
+ %Q{style="background: transparent url('#{service_image(service.icon, 24)}') no-repeat scroll left top;"}
107
+ end
108
+
109
+ def url_by_identity_feed(owner, identity_feed, service)
110
+ if identity_feed
111
+ polymorphic_url([owner, identity_feed], :service_id => service.to_param)
112
+ else
113
+ polymorphic_url([owner, :identity_feeds], :service_id => service.to_param)
114
+ end
115
+ end
116
+
117
+ end
@@ -0,0 +1,92 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: aggregations
4
+ #
5
+ # id :integer(4) not null, primary key
6
+ # terms :string(255)
7
+ # title :string(255)
8
+ # description :text
9
+ # top_tags :text
10
+ # created_at :datetime
11
+ # updated_at :datetime
12
+ # ownable_id :integer(4)
13
+ # ownable_type :string(255)
14
+ #
15
+
16
+ class Aggregation < ActiveRecord::Base
17
+ unloadable
18
+
19
+ has_friendly_id :terms, :use_slug => true
20
+
21
+ belongs_to :ownable, :polymorphic => true
22
+ has_many :aggregation_feeds
23
+ has_many :feeds, :through => :aggregation_feeds
24
+
25
+ named_scope :by_title, :order => "title ASC"
26
+ named_scope :recent, lambda { { :conditions => ['created_at > ?', 1.week.ago] } }
27
+ named_scope :newest, :order => "created_at DESC"
28
+
29
+ # Builds and then adds feeds for a given terms
30
+ # user: User to be associated with each feed. Default is nil which makes each feed global.
31
+ # service_ids: An array of service ids. Nil will generate a feed for every available service.
32
+ # refresh_services: By default all tag services are cached. Setting this value to true
33
+ # will result in the values being repopulated from the database
34
+ def add_feeds(user = nil, service_ids = nil, refresh_services = false)
35
+ safe_add_feeds(Service.create_tag_feeds(self.terms, user, service_ids, refresh_services))
36
+ end
37
+
38
+ def add_feeds_by_uri(user = nil, uris = nil)
39
+ safe_add_feeds(Feed.create_tag_feeds(user, uris))
40
+ end
41
+
42
+ # Only add feeds that aren't already part of the aggregation
43
+ def safe_add_feeds(new_feeds)
44
+ new_feeds.each do |feed|
45
+ begin
46
+ self.feeds << feed
47
+ rescue ActiveRecord::RecordInvalid => ex
48
+ # Throw away exception. Feed already exists so we don't need to do anything.
49
+ end
50
+ end
51
+ new_feeds
52
+ end
53
+
54
+ # Get only photo feeds
55
+ def photo_feeds(refresh_services = false)
56
+ all_feeds.find_all{ |feed| feed.service.photo?(refresh_services) rescue nil }
57
+ end
58
+
59
+ # Get only video feeds
60
+ def video_feeds(refresh_services = false)
61
+ all_feeds.find_all{ |feed| feed.service.video?(refresh_services) rescue nil }
62
+ end
63
+
64
+ # Get only bookmark feeds
65
+ def bookmark_feeds(refresh_services = false)
66
+ all_feeds.find_all{ |feed| feed.service.bookmark?(refresh_services) rescue nil }
67
+ end
68
+
69
+ # Get only music feeds
70
+ def music_feeds(refresh_services = false)
71
+ all_feeds.find_all{ |feed| feed.service.music?(refresh_services) rescue nil}
72
+ end
73
+
74
+ # Get only general feeds (exclude all specific feeds such as photos, videos, etc)
75
+ def general_feeds(refresh_services = false)
76
+ all_feeds.find_all{ |feed| feed.service.general?(refresh_services) rescue nil }
77
+ end
78
+
79
+ def all_feeds
80
+ @all_feeds ||= self.feeds.find(:all, :include => :service)
81
+ end
82
+
83
+ # Determines whether or not he given user can edit the aggregation
84
+ def can_edit?(user)
85
+ if ownable == user || user.admin?
86
+ true
87
+ else
88
+ false
89
+ end
90
+ end
91
+
92
+ end
@@ -0,0 +1,14 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: aggregation_feeds
4
+ #
5
+ # id :integer(4) not null, primary key
6
+ # aggregation_id :integer(4)
7
+ # feed_id :integer(4)
8
+ #
9
+
10
+ class AggregationFeed < ActiveRecord::Base
11
+ belongs_to :aggregation, :counter_cache => 'feed_count', :touch => true
12
+ belongs_to :feed
13
+ validates_uniqueness_of :feed_id, :scope => :aggregation_id
14
+ end
@@ -0,0 +1,14 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: attentions
4
+ #
5
+ # id :integer(4) not null, primary key
6
+ # attentionable_id :integer(4)
7
+ # attentionable_type :string(255)
8
+ # entry_id :integer(4)
9
+ # action_type :string(255)
10
+ # weight :float
11
+ #
12
+
13
+ class Attention < ActiveRecord::Base
14
+ end
@@ -0,0 +1,14 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: clicks
4
+ #
5
+ # id :integer(4) not null, primary key
6
+ # recommendation_id :integer(4)
7
+ # when :datetime not null
8
+ # referrer :string(2083)
9
+ # requester :string(255)
10
+ # user_agent :string(2083)
11
+ #
12
+
13
+ class Click < ActiveRecord::Base
14
+ end
@@ -0,0 +1,341 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: entries
4
+ #
5
+ # id :integer(4) not null, primary key
6
+ # feed_id :integer(4) not null
7
+ # permalink :string(2083) default(""), not null
8
+ # author :string(2083)
9
+ # title :text default(""), not null
10
+ # description :text
11
+ # content :text
12
+ # unique_content :boolean(1)
13
+ # published_at :datetime not null
14
+ # entry_updated_at :datetime
15
+ # harvested_at :datetime
16
+ # oai_identifier :string(2083)
17
+ # language_id :integer(4)
18
+ # direct_link :string(2083)
19
+ # indexed_at :datetime default(Fri Jan 01 01:01:01 UTC 1971), not null
20
+ # relevance_calculated_at :datetime default(Fri Jan 01 01:01:01 UTC 1971), not null
21
+ # popular :text
22
+ # relevant :text
23
+ # other :text
24
+ # grain_size :string(255) default("unknown")
25
+ #
26
+ # Indexes
27
+ #
28
+ # index_entries_on_direct_link (direct_link)
29
+ # index_entries_on_feed_id (feed_id)
30
+ # index_entries_on_indexed_at (indexed_at)
31
+ # index_entries_on_language_id (language_id)
32
+ # index_entries_on_oai_identifier (oai_identifier)
33
+ # index_entries_on_permalink (permalink)
34
+ # index_entries_on_published_at (published_at)
35
+ # index_entries_on_relevance_calculated_at (relevance_calculated_at)
36
+ # index_entries_on_grain_size (grain_size)
37
+ #
38
+
39
+ class Entry < ActiveRecord::Base
40
+
41
+ unloadable
42
+
43
+ belongs_to :feed
44
+ belongs_to :language
45
+ has_many :activities, :as => :attachable, :dependent => :destroy
46
+ has_many :attentions, :dependent => :destroy
47
+ acts_as_commentable
48
+ acts_as_taggable
49
+
50
+ @@default_time_on_page = 60.0
51
+
52
+ acts_as_solr({:if => false, :fields => [{:feed_id => :integer}, {:grain_size => :string}]}, {:type_field => :type_s})
53
+
54
+ def resource_uri
55
+ self.direct_link.nil? ? self.permalink : self.direct_link
56
+ end
57
+
58
+ def self.top_tags(tags = nil)
59
+
60
+ end
61
+
62
+ def self.search(search_terms, grain_size = nil, language = "en", limit = 10, offset = 0, operator = :or)
63
+ raise MuckServices::Exceptions::LanguageNotSupported, I18n.t('muck.services.language_not_supported') unless Recommender::Languages.supported_languages.include?(language)
64
+ query = (!grain_size.nil? && grain_size != 'all') ? (search_terms + ") AND (grain_size:#{grain_size}") : search_terms
65
+ return find_by_solr(query, :limit => limit, :offset => offset, :scores => true, :select => "entries.id, entries.title, entries.permalink, entries.direct_link, entries.published_at, entries.description, entries.feed_id, feeds.short_title AS collection", :joins => "INNER JOIN feeds ON feeds.id = entries.feed_id", :core => language, :operator => operator)
66
+ end
67
+
68
+ def self.recommender_entry(uri)
69
+ uri = normalized_uri(uri)
70
+ Entry.find(:first, :conditions => ['permalink = ? OR direct_link = ?', uri, uri], :order => 'direct_link IS NULL DESC') || Entry.new(:permalink => uri)
71
+ end
72
+
73
+ def recommendations(limit = 20, order = "relevance", details = false, omit_feeds = nil)
74
+ sql = "SELECT recommendations.id, dest_entry_id, entries.permalink, entries.title, entries.description, entries.direct_link, feeds.short_title AS collection "
75
+ sql << ", relevance_calculated_at, relevance, clicks, avg_time_at_dest AS avg_time_on_target, author, published_at " if details == true
76
+ sql << "FROM recommendations "
77
+ sql << "INNER JOIN entries ON recommendations.dest_entry_id = entries.id "
78
+ sql << "INNER JOIN feeds ON entries.feed_id = feeds.id "
79
+ sql << "WHERE recommendations.entry_id = ? "
80
+ sql << ("AND entries.feed_id NOT IN (" + omit_feeds.gsub(/[^0-9,]/,'') + ") ") if omit_feeds != nil
81
+ sql << "ORDER BY " + order + " DESC "
82
+ sql << "LIMIT " + limit.to_s
83
+ Entry.find_by_sql([sql,self.id])
84
+ end
85
+
86
+ def recommendation_entries(limit = 20, order = "relevance", details = false, omit_feeds = nil)
87
+ sql = "SELECT recommendations.dest_entry_id AS id, entries.permalink, entries.title, entries.description, entries.direct_link, feeds.short_title AS collection "
88
+ sql << ", relevance_calculated_at, relevance, clicks, avg_time_at_dest AS avg_time_on_target, author, published_at " if details == true
89
+ sql << "FROM recommendations "
90
+ sql << "INNER JOIN entries ON recommendations.dest_entry_id = entries.id "
91
+ sql << "INNER JOIN feeds ON entries.feed_id = feeds.id "
92
+ sql << "WHERE recommendations.entry_id = ? "
93
+ sql << ("AND entries.feed_id NOT IN (" + omit_feeds.gsub(/[^0-9,]/,'') + ") ") if omit_feeds != nil
94
+ sql << "ORDER BY " + order + " DESC "
95
+ sql << "LIMIT " + limit.to_s
96
+ Entry.find_by_sql([sql,self.id])
97
+ end
98
+
99
+ def self.track_time_on_page(session, uri)
100
+ recommendation_id = session[:last_clicked_recommendation]
101
+ if !recommendation_id.nil?
102
+ time_on_page = (Time.now - session[:last_clicked_recommendation_time].to_f).to_i
103
+
104
+ # if they spend longer than two minutes on a page, we don't infer anything
105
+ if time_on_page > 5 and time_on_page < 120
106
+ if normalized_uri(uri) != session[:last_clicked_recommendation_uri]
107
+ recommendation = Recommendation.find(recommendation_id)
108
+ entry = Entry.find(recommendation.entry_id)
109
+ new_avg = (recommendation.avg_time_at_dest*recommendation.clicks - @@default_time_on_page + time_on_page)/recommendation.clicks
110
+ recommendation.avg_time_at_dest = new_avg
111
+ recommendation.save!
112
+ entry.rank_recommendations
113
+ session[:last_clicked_recommendation] = nil
114
+ end
115
+ else
116
+ session[:last_clicked_recommendation] = nil if time_on_page > 5
117
+ end
118
+ end
119
+ end
120
+
121
+ def self.avg_time(clicks, old_avg, time_on_page)
122
+ return (old_avg*(clicks-1) + time_on_page)/clicks
123
+ end
124
+
125
+ def self.track_click(session, recommendation_id, referrer, redirect_type = "direct_link", requester = "unknown", user_agent = "unknown")
126
+ # look up the recommendation
127
+ recommendation = Recommendation.find(recommendation_id)
128
+ return "" if !recommendation
129
+
130
+ # get the entries being linked from and to
131
+ entry = Entry.find(recommendation.entry_id)
132
+ target = Entry.find(recommendation.dest_entry_id)
133
+
134
+ # get the list of recommendations that have been clicked during this session
135
+ clicks = session[:rids] || Array.new
136
+
137
+ # redirect to our frame page
138
+ redirect = "/visits/#{recommendation.dest_entry_id}"
139
+
140
+ # track the time on the last page
141
+ track_time_on_page(session, redirect)
142
+
143
+ # if this is first time the user clicked on this recommendation during this session
144
+ if !clicks.include?(recommendation_id)
145
+
146
+ # add this recommendation to the end of the list
147
+ clicks << recommendation_id
148
+ session[:rids] = clicks
149
+
150
+ # update the click time
151
+ recommendation.avg_time_at_dest = ((recommendation.avg_time_at_dest*recommendation.clicks) + @@default_time_on_page)/(recommendation.clicks + 1)
152
+ recommendation.clicks += 1
153
+ recommendation.save!
154
+
155
+ # store info about this click in the session
156
+ now = Time.now
157
+ session[:last_clicked_recommendation] = recommendation_id
158
+ session[:last_clicked_recommendation_time] = now
159
+ session[:last_clicked_recommendation_uri] = redirect
160
+
161
+ # update the recommendation cache for the entry
162
+ entry.rank_recommendations if entry
163
+
164
+ # track the click in the db
165
+ Click.create(:recommendation_id => recommendation_id, :when => now, :referrer => referrer, :requester => requester, :user_agent => user_agent)
166
+ end
167
+
168
+ return redirect
169
+ end
170
+
171
+ def relevant_recommendations(limit = 5, order = "relevance", details = false, omit_feeds = nil)
172
+ return self.recommendations(limit, order, details, omit_feeds)
173
+ end
174
+
175
+ def self.truncate_words(text, length = 30, end_string = ' ...')
176
+ words = text.split()
177
+ words[0..(length-1)].join(' ') + (words.length > length ? end_string : '')
178
+ end
179
+
180
+ def ranked_recommendations(limit = 5, order = "mixed", details = false, omit_feeds = nil)
181
+ # if self.id.nil?
182
+ # return Entry.real_time_recommendations(self.permalink, details, :core => 'en', :limit => limit)
183
+ # else
184
+ return relevant_recommendations(limit, "clicks DESC, relevance", details, omit_feeds) if order == "clicks"
185
+ return relevant_recommendations(limit, "relevance", details, omit_feeds) if (order == "relevance" || details == true)
186
+ return relevant_recommendations_filtered(limit, details, omit_feeds) if omit_feeds != nil
187
+ # end
188
+
189
+ recs = []
190
+ if self.popular != nil && !self.popular.empty?
191
+ recs.concat(ActiveSupport::JSON.decode(self.popular).first(limit))
192
+ end
193
+ if recs.length < limit && self.relevant != nil && !self.relevant.empty?
194
+ relevant_recs = randomize(ActiveSupport::JSON.decode(self.relevant))
195
+ recs.concat(relevant_recs.first(limit - recs.length))
196
+ end
197
+ if recs.length < limit && self.relevant != nil && !self.other.empty?
198
+ other_recs = randomize(ActiveSupport::JSON.decode(self.other))
199
+ recs.concat(other_recs.first(limit - recs.length))
200
+ end
201
+ return recs
202
+ end
203
+
204
+ def relevant_recommendations_filtered(limit, details, omit_feeds)
205
+ # get recommendations for the entry from the recommendations table
206
+ recs = self.recommendations(limit, "mixed", details, omit_feeds)
207
+
208
+ # for storing the various lists
209
+ popular_recs = []
210
+ relevant_recs = []
211
+ other_recs = []
212
+
213
+ # see where to cut draw the lines for popular and relevant
214
+ click_threshold = calc_click_threshold(recs)
215
+ relevance_threshold = calc_relevance_threshold(recs)
216
+
217
+ # store the recommendations
218
+ recs.each do |r|
219
+ if (r["clicks"].to_i > click_threshold)
220
+ popular_recs << r
221
+ elsif (r["relevance"].to_f > relevance_threshold)
222
+ relevant_recs << r
223
+ else
224
+ other_recs << r
225
+ end
226
+ end
227
+
228
+ # order popular items strictly by clicks
229
+ popular_recs.sort{|r1,r2| r2["avg_time_on_target"].to_i <=> r1["avg_time_on_target"].to_i}
230
+
231
+ return popular_recs[0..limit] if popular_recs.size > limit
232
+ return (popular_recs + relevant_recs)[0..limit] if (popular_recs.size + relevant_recs.size) > limit
233
+ return (popular_recs + relevant_recs + other_recs)[0..limit]
234
+ end
235
+
236
+ def json_recommendations(limit = 5, order = "mixed", details = false, omit_feeds = nil)
237
+ ActiveSupport::JSON.encode(ranked_recommendations(limit, order, details, omit_feeds))
238
+ end
239
+
240
+ def rank_recommendations
241
+ return
242
+ # get recommendations for the entry from the recommendations table
243
+ recs = self.recommendations
244
+
245
+ # for storing the various lists
246
+ popular_recs = []
247
+ relevant_recs = []
248
+ other_recs = []
249
+
250
+ # see where to cut draw the lines for popular and relevant
251
+ click_threshold = calc_click_threshold(recs)
252
+ relevance_threshold = calc_relevance_threshold(recs)
253
+
254
+ # store the recommendations
255
+ recs.each do |r|
256
+ if (r["clicks"].to_i > click_threshold)
257
+ popular_recs << r
258
+ elsif (r["relevance"].to_f > relevance_threshold)
259
+ relevant_recs << r
260
+ else
261
+ other_recs << r
262
+ end
263
+ end
264
+
265
+ # order popular items strictly by clicks
266
+ popular_recs.sort{|r1,r2| r2["avg_time_on_target"].to_i <=> r1["avg_time_on_target"].to_i}
267
+
268
+ # cache the JSON for the lists in the entry record
269
+ self.popular = ActiveSupport::JSON.encode(popular_recs)
270
+ self.relevant = ActiveSupport::JSON.encode(relevant_recs)
271
+ self.other = ActiveSupport::JSON.encode(other_recs)
272
+ self.save!
273
+ end
274
+
275
+ def randomize(recs)
276
+ i = recs.length
277
+ return recs if (i == 0)
278
+ while (i > 0)
279
+ i = i - 1
280
+ j = (rand*(i+1)).floor
281
+ ti = recs[i]
282
+ tj =recs[j]
283
+ recs[i] = tj
284
+ recs[j] = ti
285
+ end
286
+ return recs
287
+ end
288
+
289
+ def calc_relevance_threshold(recs)
290
+ sum = 0
291
+ recs.each do |r|
292
+ sum += r["relevance"].to_f
293
+ end
294
+ average = sum/recs.length
295
+ sum = 0
296
+ recs.each do |r|
297
+ sum += (r["relevance"].to_f-average)**2
298
+ end
299
+ standard_deviation = Math.sqrt(sum/recs.length);
300
+ return average + standard_deviation
301
+ end
302
+
303
+ def calc_click_threshold(recs)
304
+ sum = 0
305
+ recs.each do |r|
306
+ sum += r["clicks"].to_f
307
+ end
308
+ average = sum/recs.length
309
+ sum = 0
310
+ recs.each do |r|
311
+ sum += (r["clicks"].to_f-average)**2
312
+ end
313
+ standard_deviation = Math.sqrt(sum/recs.length);
314
+ threshold = average + standard_deviation
315
+ return threshold > 5 ? threshold : 5
316
+ end
317
+
318
+ protected
319
+
320
+ # def self.redirect_uri(target, referrer, redirect_type)
321
+ # if !target.direct_link.nil? and redirect_type != "metadata"
322
+ # return target.direct_link if redirect_type == "direct_link"
323
+ # if !referrer.nil?
324
+ # domain = "http://" + URI.parse(referrer).host
325
+ # return target.direct_link if target.permalink[0..domain.length-1] != domain
326
+ # end
327
+ # end
328
+ # return target.permalink
329
+ # end
330
+
331
+ def self.normalized_uri(uri)
332
+ uri.sub(/index.?\.(html|aspx|shtm|htm|asp|php|cfm|jsp|shtml|jhtml)$/, '')
333
+ end
334
+
335
+ def self.real_time_recommendations(uri, details = false, options = {})
336
+ fields = "entries.id, entries.title, entries.permalink, entries.direct_link, feeds.short_title AS collection"
337
+ fields << ", entries.published_at, entries.description, entries.author" if details == true
338
+ more_like_this(uri, options.merge(:select => fields, :joins => "INNER JOIN feeds ON feeds.id = entries.feed_id"))
339
+ end
340
+
341
+ end