enju_news 0.0.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 (108) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +3 -0
  3. data/Rakefile +47 -0
  4. data/app/controllers/news_feeds_controller.rb +101 -0
  5. data/app/controllers/news_posts_controller.rb +98 -0
  6. data/app/helpers/news_feeds_helper.rb +2 -0
  7. data/app/helpers/news_posts_helper.rb +2 -0
  8. data/app/models/news_feed.rb +83 -0
  9. data/app/models/news_feed_sweeper.rb +12 -0
  10. data/app/models/news_post.rb +15 -0
  11. data/app/views/news_feeds/_content.html.erb +9 -0
  12. data/app/views/news_feeds/_content_atom.html.erb +16 -0
  13. data/app/views/news_feeds/_content_rss.html.erb +16 -0
  14. data/app/views/news_feeds/_form.html.erb +14 -0
  15. data/app/views/news_feeds/_list.html.erb +7 -0
  16. data/app/views/news_feeds/edit.html.erb +29 -0
  17. data/app/views/news_feeds/index.html.erb +42 -0
  18. data/app/views/news_feeds/new.html.erb +28 -0
  19. data/app/views/news_feeds/show.html.erb +34 -0
  20. data/app/views/news_posts/_form.html.erb +44 -0
  21. data/app/views/news_posts/edit.html.erb +13 -0
  22. data/app/views/news_posts/index.atom.builder +11 -0
  23. data/app/views/news_posts/index.html.erb +42 -0
  24. data/app/views/news_posts/index.rss.builder +32 -0
  25. data/app/views/news_posts/new.html.erb +12 -0
  26. data/app/views/news_posts/show.html.erb +49 -0
  27. data/config/locales/translation_en.yml +28 -0
  28. data/config/locales/translation_ja.yml +28 -0
  29. data/config/routes.rb +4 -0
  30. data/db/migrate/20081031033632_create_news_feeds.rb +13 -0
  31. data/db/migrate/20090126071155_create_news_posts.rb +18 -0
  32. data/db/migrate/20110220103937_add_url_to_news_post.rb +9 -0
  33. data/lib/enju_news.rb +6 -0
  34. data/lib/enju_news/engine.rb +12 -0
  35. data/lib/enju_news/expire_editable_fragment.rb +15 -0
  36. data/lib/enju_news/version.rb +3 -0
  37. data/lib/tasks/enju_news_tasks.rake +4 -0
  38. data/spec/cassette_library/NewsFeed.yml +1998 -0
  39. data/spec/controllers/news_feeds_controller_spec.rb +445 -0
  40. data/spec/controllers/news_posts_controller_spec.rb +443 -0
  41. data/spec/dummy/Rakefile +7 -0
  42. data/spec/dummy/app/assets/javascripts/application.js +9 -0
  43. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  44. data/spec/dummy/app/controllers/application_controller.rb +52 -0
  45. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  46. data/spec/dummy/app/models/ability.rb +22 -0
  47. data/spec/dummy/app/models/library_group.rb +86 -0
  48. data/spec/dummy/app/models/role.rb +46 -0
  49. data/spec/dummy/app/models/user.rb +94 -0
  50. data/spec/dummy/app/models/user_group.rb +40 -0
  51. data/spec/dummy/app/models/user_has_role.rb +5 -0
  52. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  53. data/spec/dummy/app/views/page/403.html.erb +9 -0
  54. data/spec/dummy/app/views/page/403.mobile.erb +5 -0
  55. data/spec/dummy/app/views/page/403.xml.erb +4 -0
  56. data/spec/dummy/app/views/page/404.html.erb +9 -0
  57. data/spec/dummy/app/views/page/404.mobile.erb +5 -0
  58. data/spec/dummy/app/views/page/404.xml.erb +4 -0
  59. data/spec/dummy/config.ru +4 -0
  60. data/spec/dummy/config/application.rb +47 -0
  61. data/spec/dummy/config/boot.rb +10 -0
  62. data/spec/dummy/config/database.yml +25 -0
  63. data/spec/dummy/config/environment.rb +5 -0
  64. data/spec/dummy/config/environments/development.rb +30 -0
  65. data/spec/dummy/config/environments/production.rb +60 -0
  66. data/spec/dummy/config/environments/test.rb +39 -0
  67. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  68. data/spec/dummy/config/initializers/devise.rb +205 -0
  69. data/spec/dummy/config/initializers/inflections.rb +10 -0
  70. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  71. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  72. data/spec/dummy/config/initializers/session_store.rb +8 -0
  73. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  74. data/spec/dummy/config/locales/en.yml +5 -0
  75. data/spec/dummy/config/routes.rb +60 -0
  76. data/spec/dummy/db/migrate/077_create_user_groups.rb +16 -0
  77. data/spec/dummy/db/migrate/080_create_library_groups.rb +20 -0
  78. data/spec/dummy/db/migrate/20110222073537_add_url_to_library_group.rb +9 -0
  79. data/spec/dummy/db/migrate/20110318183304_add_valid_period_for_new_user_to_user_group.rb +13 -0
  80. data/spec/dummy/db/migrate/20111201121844_create_roles.rb +12 -0
  81. data/spec/dummy/db/migrate/20111201155456_create_users.rb +16 -0
  82. data/spec/dummy/db/migrate/20111201155513_add_devise_to_users.rb +44 -0
  83. data/spec/dummy/db/migrate/20111201163718_create_user_has_roles.rb +10 -0
  84. data/spec/dummy/db/schema.rb +116 -0
  85. data/spec/dummy/db/test.sqlite3 +0 -0
  86. data/spec/dummy/lib/master_model.rb +19 -0
  87. data/spec/dummy/lib/url_validator.rb +10 -0
  88. data/spec/dummy/public/404.html +26 -0
  89. data/spec/dummy/public/422.html +26 -0
  90. data/spec/dummy/public/500.html +26 -0
  91. data/spec/dummy/public/favicon.ico +0 -0
  92. data/spec/dummy/script/rails +6 -0
  93. data/spec/factories/news_feed.rb +6 -0
  94. data/spec/factories/news_post.rb +7 -0
  95. data/spec/factories/user.rb +37 -0
  96. data/spec/fixtures/library_groups.yml +33 -0
  97. data/spec/fixtures/news_feeds.yml +11 -0
  98. data/spec/fixtures/news_posts.yml +13 -0
  99. data/spec/fixtures/roles.yml +21 -0
  100. data/spec/fixtures/user_has_roles.yml +41 -0
  101. data/spec/fixtures/users.yml +93 -0
  102. data/spec/models/news_feed_spec.rb +31 -0
  103. data/spec/models/news_post_spec.rb +5 -0
  104. data/spec/spec_helper.rb +42 -0
  105. data/spec/support/controller_macros.rb +46 -0
  106. data/spec/support/devise.rb +4 -0
  107. data/spec/support/vcr.rb +9 -0
  108. metadata +430 -0
@@ -0,0 +1,20 @@
1
+ Copyright 2012 Kosuke Tanabe
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,3 @@
1
+ = EnjuNews
2
+
3
+ This project rocks and uses MIT-LICENSE.
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'EnjuNews'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
24
+ load 'rails/tasks/engine.rake'
25
+
26
+
27
+
28
+ Bundler::GemHelper.install_tasks
29
+
30
+ require 'rake/testtask'
31
+
32
+ Rake::TestTask.new(:test) do |t|
33
+ t.libs << 'lib'
34
+ t.libs << 'test'
35
+ t.pattern = 'test/**/*_test.rb'
36
+ t.verbose = false
37
+ end
38
+
39
+ require 'rspec/core'
40
+ require 'rspec/core/rake_task'
41
+
42
+ RSpec::Core::RakeTask.new(:spec) do |spec|
43
+ spec.pattern = FileList['spec/**/*_spec.rb']
44
+ end
45
+
46
+
47
+ task :default => :spec
@@ -0,0 +1,101 @@
1
+ class NewsFeedsController < ApplicationController
2
+ load_and_authorize_resource
3
+ cache_sweeper :news_feed_sweeper, :only => [:create, :update, :destroy]
4
+
5
+ # GET /news_feeds
6
+ # GET /news_feeds.json
7
+ def index
8
+ @news_feeds = NewsFeed.page(params[:page])
9
+ respond_to do |format|
10
+ format.html # index.html.erb
11
+ format.json { render :json => @news_feeds }
12
+ end
13
+ end
14
+
15
+ # GET /news_feeds/1
16
+ # GET /news_feeds/1.json
17
+ def show
18
+ if params[:mode] == 'force_reload'
19
+ expire_cache
20
+ end
21
+
22
+ respond_to do |format|
23
+ format.html # show.html.erb
24
+ format.json { render :json => @news_feed }
25
+ end
26
+ end
27
+
28
+ # GET /news_feeds/new
29
+ # GET /news_feeds/new.json
30
+ def new
31
+ @news_feed = NewsFeed.new
32
+
33
+ respond_to do |format|
34
+ format.html # new.html.erb
35
+ format.json { render :json => @news_feed }
36
+ end
37
+ end
38
+
39
+ # GET /news_feeds/1/edit
40
+ def edit
41
+ end
42
+
43
+ # POST /news_feeds
44
+ # POST /news_feeds.json
45
+ def create
46
+ @news_feed = NewsFeed.new(params[:news_feed])
47
+
48
+ respond_to do |format|
49
+ if @news_feed.save
50
+ flash[:notice] = t('controller.successfully_created', :model => t('activerecord.models.news_feed'))
51
+ format.html { redirect_to(@news_feed) }
52
+ format.json { render :json => @news_feed, :status => :created, :location => @news_feed }
53
+ else
54
+ format.html { render :action => "new" }
55
+ format.json { render :json => @news_feed.errors, :status => :unprocessable_entity }
56
+ end
57
+ end
58
+ end
59
+
60
+ # PUT /news_feeds/1
61
+ # PUT /news_feeds/1.json
62
+ def update
63
+ if params[:move]
64
+ move_position(@news_feed, params[:move])
65
+ return
66
+ end
67
+ if params[:mode] == 'force_reload'
68
+ expire_cache
69
+ end
70
+
71
+ respond_to do |format|
72
+ if @news_feed.update_attributes(params[:news_feed])
73
+ flash[:notice] = t('controller.successfully_updated', :model => t('activerecord.models.news_feed'))
74
+ format.html { redirect_to(@news_feed) }
75
+ format.json { head :no_content }
76
+ else
77
+ format.html { render :action => "edit" }
78
+ format.json { render :json => @news_feed.errors, :status => :unprocessable_entity }
79
+ end
80
+ end
81
+ end
82
+
83
+ # DELETE /news_feeds/1
84
+ # DELETE /news_feeds/1.json
85
+ def destroy
86
+ @news_feed.destroy
87
+
88
+ respond_to do |format|
89
+ format.html { redirect_to news_feeds_url }
90
+ format.json { head :no_content }
91
+ end
92
+ end
93
+
94
+ private
95
+ def expire_cache
96
+ Role.all.each do |role|
97
+ expire_fragment(:controller => :news_feeds, :action => :show, :id => @news_feed.id, :page => 'title', :role => role.name)
98
+ end
99
+ @news_feed.force_reload
100
+ end
101
+ end
@@ -0,0 +1,98 @@
1
+ class NewsPostsController < ApplicationController
2
+ load_and_authorize_resource
3
+ before_filter :prepare_options, :only => [:new, :edit]
4
+
5
+ # GET /news_posts
6
+ # GET /news_posts.json
7
+ def index
8
+ if current_user.try(:has_role?, 'Librarian')
9
+ @news_posts = NewsPost.page(params[:page])
10
+ else
11
+ @news_posts = NewsPost.published.page(params[:page])
12
+ end
13
+
14
+ respond_to do |format|
15
+ format.html # index.html.erb
16
+ format.json { render :json => @news_posts }
17
+ format.rss { render :layout => false }
18
+ format.atom
19
+ end
20
+ end
21
+
22
+ # GET /news_posts/1
23
+ # GET /news_posts/1.json
24
+ def show
25
+ respond_to do |format|
26
+ format.html # show.html.erb
27
+ format.json { render :json => @news_post }
28
+ end
29
+ end
30
+
31
+ # GET /news_posts/new
32
+ # GET /news_posts/new.json
33
+ def new
34
+ @news_post = NewsPost.new
35
+
36
+ respond_to do |format|
37
+ format.html # new.html.erb
38
+ format.json { render :json => @news_post }
39
+ end
40
+ end
41
+
42
+ # GET /news_posts/1/edit
43
+ def edit
44
+ end
45
+
46
+ # POST /news_posts
47
+ # POST /news_posts.json
48
+ def create
49
+ @news_post = NewsPost.new(params[:news_post])
50
+ @news_post.user = current_user
51
+
52
+ respond_to do |format|
53
+ if @news_post.save
54
+ format.html { redirect_to(@news_post, :notice => t('controller.successfully_created', :model => t('activerecord.models.news_post'))) }
55
+ format.json { render :json => @news_post, :status => :created, :location => @news_post }
56
+ else
57
+ prepare_options
58
+ format.html { render :action => "new" }
59
+ format.json { render :json => @news_post.errors, :status => :unprocessable_entity }
60
+ end
61
+ end
62
+ end
63
+
64
+ # PUT /news_posts/1
65
+ # PUT /news_posts/1.json
66
+ def update
67
+ if params[:move]
68
+ move_position(@news_post, params[:move])
69
+ return
70
+ end
71
+
72
+ respond_to do |format|
73
+ if @news_post.update_attributes(params[:news_post])
74
+ format.html { redirect_to(@news_post, :notice => t('controller.successfully_updated', :model => t('activerecord.models.news_post'))) }
75
+ format.json { head :no_content }
76
+ else
77
+ prepare_options
78
+ format.html { render :action => "edit" }
79
+ format.json { render :json => @news_post.errors, :status => :unprocessable_entity }
80
+ end
81
+ end
82
+ end
83
+
84
+ # DELETE /news_posts/1
85
+ # DELETE /news_posts/1.json
86
+ def destroy
87
+ @news_post.destroy
88
+
89
+ respond_to do |format|
90
+ format.html { redirect_to(news_posts_url) }
91
+ format.json { head :no_content }
92
+ end
93
+ end
94
+
95
+ def prepare_options
96
+ @roles = Role.all
97
+ end
98
+ end
@@ -0,0 +1,2 @@
1
+ module NewsFeedsHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ module NewsPostsHelper
2
+ end
@@ -0,0 +1,83 @@
1
+ class NewsFeed < ActiveRecord::Base
2
+ attr_accessible :title, :url
3
+ include ExpireEditableFragment
4
+ default_scope :order => "news_feeds.position"
5
+ belongs_to :library_group, :validate => true
6
+
7
+ validates_presence_of :title, :url, :library_group
8
+ validates_associated :library_group
9
+ validates_length_of :url, :maximum => 255
10
+
11
+ acts_as_list
12
+
13
+ after_save :expire_cache
14
+ after_destroy :expire_cache
15
+
16
+ def self.per_page
17
+ 10
18
+ end
19
+
20
+ def expire_cache
21
+ expire_fragment_cache
22
+ Rails.cache.delete('news_feed_all')
23
+ true
24
+ end
25
+
26
+ def expire_fragment_cache
27
+ Role.all.each do |role|
28
+ Rails.cache.delete("views/news_feed_content_#{id}_#{role.name}")
29
+ logger.info "#{Time.zone.now} feed reloaded! : #{url}"
30
+ end
31
+ end
32
+
33
+ def content(clear_cache = false)
34
+ #page_url = URI.parse(url.rewrite_my_url)
35
+ #if page_url.port == 80
36
+ # if Feedbag.feed?(url)
37
+ # feed_url = url
38
+ # else
39
+ # feed_url = Feedbag.find(url).first
40
+ # end
41
+ #else
42
+ # auto-discovery 非対応
43
+ feed_url = url
44
+ #end
45
+ begin
46
+ if clear_cache or body.blank?
47
+ feed = open(feed_url) do |f|
48
+ f.read
49
+ end
50
+ if rss = RSS::Parser.parse(feed, false)
51
+ self.body = feed
52
+ save!
53
+ end
54
+ end
55
+ rescue StandardError, Timeout::Error
56
+ nil
57
+ end
58
+ # tDiary の RSS をパースした際に to_s が空になる
59
+ # rss = RSS::Parser.parse(feed)
60
+ # rss.to_s
61
+ # => ""
62
+ #if rss.nil?
63
+ begin
64
+ rss = RSS::Parser.parse(body)
65
+ rescue RSS::InvalidRSSError
66
+ rss = RSS::Parser.parse(body, false)
67
+ rescue RSS::NotWellFormedError, TypeError
68
+ nil
69
+ end
70
+ #end
71
+ end
72
+
73
+ def force_reload
74
+ expire_cache
75
+ content(true)
76
+ end
77
+
78
+ def self.fetch_feeds
79
+ NewsFeed.all.each do |news_feed|
80
+ news_feed.force_reload
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,12 @@
1
+ class NewsFeedSweeper < ActionController::Caching::Sweeper
2
+ observe NewsFeed
3
+ def after_save(record)
4
+ Role.all.each do |role|
5
+ expire_fragment(:controller => :news_feeds, :action => :index, :id => record.id, :page => 'title', :role => role.name)
6
+ end
7
+ end
8
+
9
+ def after_destroy(record)
10
+ after_save(record)
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ class NewsPost < ActiveRecord::Base
2
+ attr_accessible :title, :body
3
+ scope :published, where(:draft => false)
4
+ belongs_to :user
5
+ belongs_to :required_role, :class_name => 'Role', :foreign_key => 'required_role_id', :validate => true
6
+
7
+ validates_presence_of :title, :body, :user_id
8
+ validates_associated :user
9
+
10
+ acts_as_list
11
+
12
+ def self.per_page
13
+ 10
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ <%
2
+ cache("news_feed_content_#{news_feed.id}_#{current_user_role_name}") do
3
+ %>
4
+ <%- if news_feed.content.is_a?(RSS::Atom::Feed) -%>
5
+ <%= render :partial => 'news_feeds/content_atom', :locals => {:news_feed => news_feed} -%>
6
+ <%- else -%>
7
+ <%= render :partial => 'news_feeds/content_rss', :locals => {:news_feed => news_feed} -%>
8
+ <%- end -%>
9
+ <%- end -%>
@@ -0,0 +1,16 @@
1
+ <%- if news_feed.content -%>
2
+ <h3><%= link_to h(news_feed.content.title.content), h(news_feed.content.link.href) -%></h3>
3
+ <ul>
4
+ <%- news_feed.content.items[0..2].each do |item| -%>
5
+ <li><%= link_to h(item.title.content), h(item.link.href) -%>
6
+ <%- if date = Time.zone.parse(item.updated.content.to_s) rescue nil -%>
7
+ (<%= l(date, :format => :short) -%>)
8
+ <%- end -%>
9
+ <%- if item.summary -%>
10
+ <br />
11
+ <%= truncate(h(item.summary.content)) -%>
12
+ <%- end -%>
13
+ </li>
14
+ <%- end -%>
15
+ </ul>
16
+ <%- end -%>
@@ -0,0 +1,16 @@
1
+ <%- if news_feed.content -%>
2
+ <h3><%= link_to h(news_feed.content.channel.title), h(news_feed.content.channel.link) -%></h3>
3
+ <ul>
4
+ <%- news_feed.content.items[0..2].each do |item| -%>
5
+ <li><%= link_to h(item.title), h(item.link) -%>
6
+ <%- if date = Time.zone.parse(item.pubDate.to_s) rescue nil -%>
7
+ (<%= l(date, :format => :short) -%>)
8
+ <%- end -%>
9
+ <%- if item.description -%>
10
+ <br />
11
+ <%= truncate(h(item.description)) -%>
12
+ <%- end -%>
13
+ </li>
14
+ <%- end -%>
15
+ </ul>
16
+ <%- end -%>
@@ -0,0 +1,14 @@
1
+ <%= form_for(@news_feed) do |f| -%>
2
+ <%= f.error_messages -%>
3
+ <div class="field">
4
+ <%= f.label t('activerecord.attributes.news_feed.title') -%><br />
5
+ <%= f.text_field :title, :class => 'resource_title' -%>
6
+ </div>
7
+ <div class="field">
8
+ <%= f.label t('activerecord.attributes.news_feed.url') -%><br />
9
+ <%= f.url_field :url, :class => 'resource_url' -%>
10
+ </div>
11
+ <div class="actions">
12
+ <%= f.submit -%>
13
+ </div>
14
+ <%- end -%>