radiant-reader-extension 0.9.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/README.md +15 -11
  2. data/VERSION +1 -1
  3. data/app/controllers/admin/messages_controller.rb +45 -6
  4. data/app/controllers/admin/reader_configuration_controller.rb +3 -0
  5. data/app/controllers/password_resets_controller.rb +8 -10
  6. data/app/controllers/reader_action_controller.rb +2 -2
  7. data/app/controllers/reader_activations_controller.rb +6 -7
  8. data/app/controllers/reader_sessions_controller.rb +3 -3
  9. data/app/controllers/readers_controller.rb +9 -10
  10. data/app/models/message.rb +2 -2
  11. data/app/models/message_function.rb +4 -0
  12. data/app/models/reader_notifier.rb +10 -7
  13. data/app/views/admin/messages/_form.html.haml +3 -1
  14. data/app/views/admin/messages/_list_function.haml +3 -0
  15. data/app/views/admin/messages/index.haml +42 -0
  16. data/app/views/admin/messages/preview.html.haml +1 -0
  17. data/app/views/admin/messages/show.html.haml +72 -0
  18. data/app/views/admin/reader_configuration/edit.html.haml +41 -0
  19. data/app/views/admin/reader_configuration/show.html.haml +46 -0
  20. data/app/views/admin/readers/_form.html.haml +2 -1
  21. data/app/views/admin/readers/index.html.haml +33 -2
  22. data/app/views/password_resets/create.html.haml +6 -9
  23. data/app/views/password_resets/edit.html.haml +26 -30
  24. data/app/views/password_resets/new.html.haml +10 -11
  25. data/app/views/reader_activations/show.html.haml +17 -26
  26. data/app/views/reader_sessions/_login_form.html.haml +19 -25
  27. data/app/views/reader_sessions/new.html.haml +17 -15
  28. data/app/views/readers/_flasher.html.haml +2 -2
  29. data/app/views/readers/_form.html.haml +30 -36
  30. data/app/views/readers/edit.html.haml +17 -19
  31. data/app/views/readers/index.html.haml +5 -7
  32. data/app/views/readers/login.html.haml +6 -5
  33. data/app/views/readers/new.html.haml +21 -20
  34. data/app/views/readers/permission_denied.html.haml +13 -9
  35. data/app/views/readers/show.html.haml +12 -9
  36. data/config/initializers/radiant_config.rb +12 -0
  37. data/config/locales/en.yml +147 -0
  38. data/config/routes.rb +5 -6
  39. data/db/migrate/20101019094714_message_sent_date.rb +11 -0
  40. data/lib/reader_admin_ui.rb +25 -10
  41. data/lib/reader_helper.rb +0 -7
  42. data/lib/reader_tags.rb +15 -10
  43. data/public/images/admin/delta.png +0 -0
  44. data/public/stylesheets/sass/admin/reader.sass +72 -81
  45. data/radiant-reader-extension.gemspec +13 -19
  46. data/reader_extension.rb +6 -7
  47. data/spec/controllers/admin/messages_controller_spec.rb +26 -9
  48. data/spec/controllers/readers_controller_spec.rb +1 -1
  49. data/spec/models/message_spec.rb +1 -2
  50. data/spec/models/reader_notifier_spec.rb +1 -2
  51. metadata +16 -22
  52. data/app/controllers/admin/reader_settings_controller.rb +0 -92
  53. data/app/helpers/admin/reader_settings_helper.rb +0 -36
  54. data/app/views/admin/reader_settings/_setting.html.haml +0 -24
  55. data/app/views/admin/reader_settings/edit.html.haml +0 -10
  56. data/app/views/admin/reader_settings/index.html.haml +0 -35
  57. data/app/views/admin/reader_settings/show.html.haml +0 -1
  58. data/app/views/admin/readers/_list_head.html.haml +0 -9
  59. data/app/views/admin/readers/_listed.html.haml +0 -22
  60. data/app/views/reader_activations/_activation_required.html.haml +0 -34
  61. data/app/views/reader_activations/_on_activation.html.haml +0 -4
  62. data/app/views/readers/create.html.haml +0 -28
  63. data/app/views/wrappers/_field_errors.html.haml +0 -5
  64. data/config/settings.rb +0 -9
  65. data/pkg/radiant-reader-extension-0.9.0.gem +0 -0
  66. data/public/images/admin/new-message.png +0 -0
  67. data/public/images/admin/new-reader.png +0 -0
  68. data/public/javascripts/admin/messages.js +0 -13
data/README.md CHANGED
@@ -10,21 +10,18 @@ The purpose of this extension is to provide a common core that supports other vi
10
10
 
11
11
  ## Latest
12
12
 
13
+ * **currently requires the `preconfiguration` branch of radiant**
14
+ * public interface internationalized
13
15
  * New configuration interface
14
-
15
- * Provisionally updated for 0.9, but still being tweaked and tested: not definitely stable yet
16
-
17
- * I'm about to start cleaning out the messaging interface. Some of its extra clutter will be moved into a newsletter extension so that here we can concentrate on making administrative messages easy to edit.
16
+ * Messaging much simplified: now intended to be purely administrative.
18
17
 
19
18
  ## Status
20
19
 
21
- Compatible with radiant 0.9 but currently undergoing some renovation.
22
-
23
- Tests are thorough. A lot of our work relies on this extension.
20
+ Compatible with radiant 0.9.2, which isn't out yet. You can use the preconfiguration branch of radiant edge to try this out. Expect changes.
24
21
 
25
22
  ## Requirements
26
23
 
27
- Radiant 0.8.1 (we need the new config machinery) or 0.9. [share_layouts](http://github.com/spanner/radiant-share-layouts-extension) (currently you need our version, which works with ActionMailer too). If you're on 0.8.1 you will probably want the [submenu](https://github.com/spanner/radiant-submenu-extension/tree) extension too.
24
+ Radiant 0.9.2. The [layouts](http://github.com/squaretalent/radiant-layouts-extension) and [mailer_layouts](http://github.com/spanner/radiant-mailer_layouts-extension) extensions.
28
25
 
29
26
  You also need three gems (in addition to those that radiant requires): authlogic, gravtastic and sanitize. They're declared in the extension so you should be able just to run
30
27
 
@@ -38,15 +35,22 @@ in your environment.rb before you can migrate anything. Authlogic has to load be
38
35
 
39
36
  ## Installation
40
37
 
38
+ As a gem:
39
+
40
+ gem install 'radiant_reader_extension'
41
+
42
+ or for more control:
43
+
41
44
  git submodule add git://github.com/spanner/radiant-reader-extension.git vendor/extensions/reader
45
+
46
+ and then:
47
+
42
48
  rake radiant:extensions:reader:migrate
43
49
  rake radiant:extensions:reader:update
44
50
 
45
- The update task will install a /stylesheets/admin/reader.css that you can leave alone and a /stylesheets/reader.css that you should call from your reader layout (see below) and will want to improve upon. There is also a very thin /javascripts/reader.js: all it does is fade notifications. The forum extension has a lot more javascripts for you to deplore.
46
-
47
51
  ## Configuration
48
52
 
49
- If you want to allow public registration, set `reader.allow_registration?` to true in your configuration. If it is false, then reader accounts can only be created by the administrator.
53
+ If you want to allow public registration, set `reader.allow_registration?` to true. If it is false, then reader accounts can only be created by the administrator.
50
54
 
51
55
  Under multi_site Reader adds a `reader_layout` column to the site table and a layout-chooser to the site-edit view. In a single-site installation you will also need these configuration entries:
52
56
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.2
1
+ 1.0.0
@@ -1,20 +1,59 @@
1
1
  class Admin::MessagesController < Admin::ResourceController
2
+ skip_before_filter :load_model
3
+ before_filter :load_model, :except => :index # we want the filter to run before :show too
2
4
  before_filter :set_function, :only => :new
3
-
4
- def index
5
- redirect_to admin_reader_settings_url
5
+
6
+ # here :show is the preview/send page
7
+ def show
8
+
6
9
  end
7
10
 
11
+ # mock email view called into an iframe in the :show view
12
+ # the view calls @message.preview, which returns the message body
13
+ def preview
14
+ render :layout => false
15
+ end
16
+
17
+ def deliver
18
+ case params['delivery']
19
+ when "all"
20
+ @readers = @message.possible_readers
21
+ when "inactive"
22
+ @readers = @message.inactive_readers
23
+ when "unsent"
24
+ @readers = @message.undelivered_readers
25
+ else
26
+ redirect_to admin_message_url(@message)
27
+ return
28
+ end
29
+ failures = @message.deliver(@readers) || []
30
+ if failures.any?
31
+ if failures.length == @readers.length
32
+ flash[:error] = "all_deliveries_failed"
33
+ else
34
+ addresses = failures.map(&:email).to_sentence
35
+ flash[:notice] = "some_deliveries_failed"
36
+ end
37
+ else
38
+ flash[:notice] = "message_delivered"
39
+ end
40
+ redirect_to admin_message_url(@message)
41
+ end
42
+
8
43
  protected
9
44
 
10
45
  def continue_url(options)
11
- admin_reader_settings_url
46
+ if action_name == "destroy"
47
+ redirect_to :back
48
+ else
49
+ options[:redirect_to] || (params[:continue] ? {:action => 'edit', :id => model.id} : admin_message_url(model))
50
+ end
12
51
  end
13
52
 
14
53
  def set_function
15
54
  if params[:function]
16
- @message.function_id = params[:function]
55
+ model.function_id = params[:function]
17
56
  end
18
57
  end
19
-
58
+
20
59
  end
@@ -0,0 +1,3 @@
1
+ class Admin::ReaderConfigurationController < Admin::ConfigurationController
2
+
3
+ end
@@ -15,24 +15,22 @@ class PasswordResetsController < ApplicationController
15
15
  if @reader
16
16
  if @reader.activated?
17
17
  @reader.send_password_reset_message
18
- flash[:notice] = "Password reset instructions have been emailed to you."
18
+ flash[:notice] = "reset_message_sent"
19
19
  render
20
20
  else
21
21
  @reader.send_activation_message
22
- flash[:notice] = "Account activation instructions have been emailed to you."
22
+ flash[:notice] = "activation_message_sent"
23
23
  redirect_to new_reader_activation_url
24
24
  end
25
25
  else
26
- @error = flash[:error] = "Sorry. That email address is not known here."
26
+ @error = flash[:error] = "email_unknown"
27
27
  render :action => :new
28
28
  end
29
29
  end
30
30
 
31
31
  def edit
32
- if @reader
33
- flash[:notice] = "Thank you. Please enter and confirm a new password."
34
- else
35
- flash[:error] = "Sorry: can't find you."
32
+ unless @reader
33
+ flash[:error] = 'reset_not_found'
36
34
  end
37
35
  render
38
36
  end
@@ -43,14 +41,14 @@ class PasswordResetsController < ApplicationController
43
41
  @reader.password_confirmation = params[:reader][:password_confirmation]
44
42
  if @reader.save
45
43
  self.current_reader = @reader
46
- flash[:notice] = "Thank you. Your password has been updated and you are now logged in."
44
+ flash[:notice] = 'password_updated_notice'
47
45
  redirect_to url_for(@reader)
48
46
  else
49
- flash[:error] = "Passwords don't match! Please try again."
47
+ flash[:error] = 'password_mismatch'
50
48
  render :action => :edit
51
49
  end
52
50
  else
53
- flash[:error] = "Sorry: can't find you."
51
+ flash[:error] = 'reset_not_found'
54
52
  render :action => :edit # without @reader, this will take us back to the enter-your-code form
55
53
  end
56
54
  end
@@ -25,7 +25,7 @@ class ReaderActionController < ApplicationController
25
25
 
26
26
  def permission_denied
27
27
  session[:return_to] ||= request.referer
28
- @title = flash[:error] || "Sorry: permission denied"
28
+ @title = flash[:error] || t('permission_denied')
29
29
  render
30
30
  end
31
31
 
@@ -75,7 +75,7 @@ protected
75
75
  def require_no_reader
76
76
  if set_reader
77
77
  store_location
78
- flash[:notice] = "Please log out first"
78
+ flash[:notice] = 'please_log_out'
79
79
  redirect_back_or_to url_for(current_reader)
80
80
  return false
81
81
  end
@@ -7,7 +7,7 @@ class ReaderActivationsController < ReaderActionController
7
7
 
8
8
  radiant_layout { |controller| Radiant::Config['reader.layout'] }
9
9
 
10
- # this is just fake REST: we're actually working on the reader, not an activation object, but in a usefully restricted way:
10
+ # this is just fake REST: we're actually working on the reader, not an activation object.
11
11
  # .show sends out an activation message if we can identify the current reader
12
12
  # .update activates the reader, if the token is correct
13
13
 
@@ -19,7 +19,7 @@ class ReaderActivationsController < ReaderActionController
19
19
  if current_reader
20
20
  @reader = current_reader
21
21
  @reader.send_activation_message
22
- flash[:notice] = "Account activation instructions have been emailed to you."
22
+ flash[:notice] = "activation_message_sent"
23
23
  end
24
24
  render :action => 'show'
25
25
  end
@@ -28,12 +28,11 @@ class ReaderActivationsController < ReaderActionController
28
28
  if @reader
29
29
  @reader.activate!
30
30
  self.current_reader = @reader
31
- flash[:notice] = "Thank you! Your account has been activated."
31
+ flash[:notice] = "thanks_activated"
32
32
  redirect_back_or_to default_activated_url
33
-
34
33
  else
35
- @error = "Sorry: something was wrong in that link. Please check your email message."
36
- flash[:error] = "Activation failed."
34
+ @error = "please_check_message"
35
+ flash[:error] = "activation_failed."
37
36
  render :action => 'show'
38
37
  end
39
38
  end
@@ -47,7 +46,7 @@ protected
47
46
 
48
47
  def check_reader_inactive
49
48
  if @reader && @reader.activated?
50
- flash[:notice] = "Hello #{@reader.name}! Your account is already active."
49
+ flash[:notice] = t('hello').titlecase + " #{@reader.name}! " + t('already_active')
51
50
  redirect_back_or_to default_activated_url
52
51
  false
53
52
  end
@@ -16,7 +16,7 @@ class ReaderSessionsController < ReaderActionController
16
16
  end
17
17
  respond_to do |format|
18
18
  format.html {
19
- flash[:notice] = "Hello #{@reader_session.reader.name}. Welcome back."
19
+ flash[:notice] = t('hello').titlecase + " #{@reader_session.reader.name}. " + t('welcome_back')
20
20
  redirect_back_or_to default_loggedin_url
21
21
  }
22
22
  format.js {
@@ -27,7 +27,7 @@ class ReaderSessionsController < ReaderActionController
27
27
  else
28
28
  respond_to do |format|
29
29
  format.html {
30
- flash[:error] = "Sorry: that combination of login and password is not known here."
30
+ flash[:error] = 'login_unknown'
31
31
  render :action => :new
32
32
  }
33
33
  format.js { render :action => :new, :layout => false }
@@ -43,7 +43,7 @@ class ReaderSessionsController < ReaderActionController
43
43
  session['user_id'] = nil
44
44
  current_user = nil
45
45
  end
46
- flash[:notice] = "You are logged out. Bye!"
46
+ flash[:notice] = 'logout_message'
47
47
  redirect_back_or_to reader_login_url
48
48
  end
49
49
 
@@ -29,7 +29,6 @@ class ReadersController < ReaderActionController
29
29
  render :partial => 'readers/controls'
30
30
  }
31
31
  end
32
-
33
32
  end
34
33
 
35
34
  def new
@@ -50,14 +49,14 @@ class ReadersController < ReaderActionController
50
49
  @reader.clear_password = params[:reader][:password]
51
50
 
52
51
  unless @reader.email.blank?
53
- flash[:error] = "Please don't fill in the spam trap field."
52
+ flash[:error] = 'please_avoid_spam_trap'
54
53
  @reader.email = ''
55
- @reader.errors.add(:trap, "must be empty")
54
+ @reader.errors.add(:trap, "must_be_empty")
56
55
  render :action => 'new' and return
57
56
  end
58
57
 
59
58
  unless @email_field = session[:email_field]
60
- flash[:error] = "Please use the registration form."
59
+ flash[:error] = 'please_use_form'
61
60
  redirect_to new_reader_url and return
62
61
  end
63
62
 
@@ -76,7 +75,7 @@ class ReadersController < ReaderActionController
76
75
  @reader.attributes = params[:reader]
77
76
  @reader.clear_password = params[:reader][:password] if params[:reader][:password]
78
77
  if @reader.save
79
- flash[:notice] = "Your account has been updated"
78
+ flash[:notice] = 'account_updated'
80
79
  redirect_to url_for(@reader)
81
80
  else
82
81
  render :action => 'edit'
@@ -90,7 +89,7 @@ protected
90
89
  end
91
90
 
92
91
  def restrict_to_self
93
- flash[:error] = "Sorry. You are not allowed to edit other people's accounts." if params[:id] && params[:id] != current_reader.id
92
+ flash[:error] = "cannot_edit_others" if params[:id] && params[:id] != current_reader.id
94
93
  @reader = current_reader
95
94
  end
96
95
 
@@ -101,19 +100,19 @@ protected
101
100
  @reader.attributes = params[:reader]
102
101
  @reader.valid?
103
102
 
104
- flash[:error] = 'Sorry. Wrong password.'
105
- @reader.errors.add(:current_password, "was not correct")
103
+ flash[:error] = 'password_incorrect'
104
+ @reader.errors.add(:current_password, "not_correct")
106
105
  render :action => 'edit' and return false
107
106
  end
108
107
 
109
108
  def no_removing
110
- flash[:error] = "You can't delete readers here. Please log in to the admin interface."
109
+ flash[:error] = 'cannot_delete_readers'
111
110
  redirect_to admin_readers_url
112
111
  end
113
112
 
114
113
  def check_registration_allowed
115
114
  unless Radiant::Config['reader.allow_registration?']
116
- flash[:error] = "Sorry. This site does not allow public registration."
115
+ flash[:error] = "registration_disallowed"
117
116
  redirect_to reader_login_url
118
117
  false
119
118
  end
@@ -19,8 +19,8 @@ class Message < ActiveRecord::Base
19
19
 
20
20
  default_scope :order => 'updated_at DESC, created_at DESC'
21
21
  named_scope :for_function, lambda { |f| {:conditions => ["function_id = ?", f.to_s]} }
22
- named_scope :administrative, { :conditions => "function_id IS NOT NULL" }
23
- named_scope :ordinary, { :conditions => "function_id IS NULL" }
22
+ named_scope :administrative, { :conditions => "function_id IS NOT NULL AND NOT function_id = ''" }
23
+ named_scope :ordinary, { :conditions => "function_id = '' OR function_id IS NULL" }
24
24
  named_scope :published, { :conditions => "status_id >= 100" }
25
25
 
26
26
  def filtered_body
@@ -14,6 +14,10 @@ class MessageFunction
14
14
  @name
15
15
  end
16
16
 
17
+ def humanize
18
+ to_s.gsub('_', ' ')
19
+ end
20
+
17
21
  def self.[](value)
18
22
  return if value.blank?
19
23
  @@functions.find { |function| function.symbol == value.to_s.downcase.intern }
@@ -1,20 +1,22 @@
1
1
  class ReaderNotifier < ActionMailer::Base
2
2
 
3
3
  # this sets a default that will be overridden by the layout association of each message as it is sent out
4
- radiant_layout "email"
4
+ radiant_layout lambda { Radiant::Config['email.layout'] || 'email'}
5
5
 
6
6
  def message(reader, message, sender=nil)
7
7
  site = reader.site if reader.respond_to?(:site)
8
- prefix = site ? site.abbreviation : Radiant::Config['site.mail_prefix']
9
- host = site ? site.base_domain : Radiant::Config['site.url'] || 'www.example.com'
8
+ prefix = site ? site.abbreviation : Radiant::Config['email.prefix']
9
+ host = site ? site.base_domain : Radiant::Config['site.domain'] || 'www.example.com'
10
10
  default_url_options[:host] = host
11
- sender ||= message.created_by
11
+ sender = Radiant::Config['email.name'] || "sender_not_configured"
12
+ sender_address = Radiant::Config['email.address'] || "admin@#{host}"
12
13
 
13
14
  message_layout(message.layout) if message.layout
14
15
  content_type("text/html")
15
16
  subject (prefix || '') + message.subject
16
17
  recipients(reader.email)
17
- from message.created_by.email
18
+ from ["#{sender} <#{sender_address}>"]
19
+ reply_to = [sender_address]
18
20
  subject message.subject
19
21
  sent_on(Time.now)
20
22
 
@@ -23,10 +25,11 @@ class ReaderNotifier < ActionMailer::Base
23
25
  :title => message.subject,
24
26
  :message => message.filtered_body,
25
27
  :sender => sender,
28
+ :reply_to => sender_address,
26
29
  :reader => reader,
27
30
  :site => site || {
28
- :name => Radiant::Config['site.name'],
29
- :url => Radiant::Config['site.url']
31
+ :name => Radiant::Config['site.title'],
32
+ :url => Radiant::Config['site.domain']
30
33
  }
31
34
  })
32
35
  end
@@ -18,6 +18,8 @@
18
18
  = form.label :body, "Message Body"
19
19
  = form.text_area :body, :class => 'textarea', :style => 'width: 100%'
20
20
 
21
+ = render_region :body_bottom, :locals => {:form => form}
22
+
21
23
  - render_region :form_bottom do |form_bottom|
22
24
  - form_bottom.edit_timestamp do
23
25
  = updated_stamp @message
@@ -26,4 +28,4 @@
26
28
  = save_model_button(@message)
27
29
  = save_model_and_continue_editing_button(@message)
28
30
  or
29
- = link_to "cancel", admin_messages_url
31
+ = link_to "cancel", admin_reader_configuration_url
@@ -0,0 +1,3 @@
1
+ - if message.has_function?
2
+ %span.function
3
+ = message.function.description
@@ -0,0 +1,42 @@
1
+ - include_stylesheet('admin/reader')
2
+ = render_region :top
3
+
4
+ #messages_table.outset
5
+ %table#messages.index{:cellspacing=>"0", :border=>"0", :cellpadding=>"0"}
6
+ %thead
7
+ %tr
8
+ - render_region :thead do |thead|
9
+ - thead.subject_header do
10
+ %th.message Subject
11
+ - thead.sent_header do
12
+ %th.message_sent Delivery status
13
+ - thead.modify_header do
14
+ %th.modify Modify
15
+ %tbody
16
+ - @messages.each do |message|
17
+ %tr
18
+ - render_region :tbody do |tbody|
19
+ - tbody.subject_cell do
20
+ %td.name
21
+ = link_to message.subject, admin_message_url(message), :class => message.has_function? ? "functional" : "normal"
22
+ = render :partial => '/admin/messages/list_function', :locals => {:message => message}
23
+
24
+ - tbody.sent_cell do
25
+ %td.message_sent
26
+ %p
27
+ - if message.sent_at
28
+ = t('last_sent')
29
+ = l(message.sent_at, :format => :short)
30
+ - else
31
+ = t('never_sent')
32
+ - tbody.modify_cell do
33
+ %td.actions
34
+ = link_to( image('delta') + ' ' + t('edit_message'), edit_admin_message_url(message), :class => "action" )
35
+ = link_to( image('minus') + ' ' + t('delete_message'), admin_message_url(message), {:method => :delete, :class => "action", :confirm => t('really_delete_message', :title => message.subject)})
36
+
37
+ - render_region :bottom do |bottom|
38
+ - bottom.buttons do
39
+ #actions
40
+ = pagination_for @messages
41
+ %ul
42
+ %li= link_to image('plus') + " " + "new message", new_admin_message_url