radiant-reader-extension 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/.gitignore +2 -0
  2. data/README.md +89 -0
  3. data/Rakefile +140 -0
  4. data/VERSION +1 -0
  5. data/app/controllers/admin/messages_controller.rb +20 -0
  6. data/app/controllers/admin/reader_settings_controller.rb +92 -0
  7. data/app/controllers/admin/readers_controller.rb +28 -0
  8. data/app/controllers/password_resets_controller.rb +64 -0
  9. data/app/controllers/reader_action_controller.rb +84 -0
  10. data/app/controllers/reader_activations_controller.rb +60 -0
  11. data/app/controllers/reader_sessions_controller.rb +56 -0
  12. data/app/controllers/readers_controller.rb +131 -0
  13. data/app/helpers/admin/reader_settings_helper.rb +36 -0
  14. data/app/models/message.rb +108 -0
  15. data/app/models/message_function.rb +37 -0
  16. data/app/models/message_reader.rb +13 -0
  17. data/app/models/reader.rb +146 -0
  18. data/app/models/reader_notifier.rb +34 -0
  19. data/app/models/reader_session.rb +3 -0
  20. data/app/views/admin/messages/_form.html.haml +29 -0
  21. data/app/views/admin/messages/_help.html.haml +41 -0
  22. data/app/views/admin/messages/_message_description.html.haml +3 -0
  23. data/app/views/admin/messages/edit.html.haml +16 -0
  24. data/app/views/admin/messages/new.html.haml +16 -0
  25. data/app/views/admin/reader_settings/_setting.html.haml +24 -0
  26. data/app/views/admin/reader_settings/edit.html.haml +10 -0
  27. data/app/views/admin/reader_settings/index.html.haml +35 -0
  28. data/app/views/admin/reader_settings/show.html.haml +1 -0
  29. data/app/views/admin/readers/_avatar.html.haml +3 -0
  30. data/app/views/admin/readers/_form.html.haml +50 -0
  31. data/app/views/admin/readers/_list_head.html.haml +9 -0
  32. data/app/views/admin/readers/_listed.html.haml +22 -0
  33. data/app/views/admin/readers/_password_fields.html.haml +18 -0
  34. data/app/views/admin/readers/edit.html.haml +8 -0
  35. data/app/views/admin/readers/index.html.haml +17 -0
  36. data/app/views/admin/readers/new.html.haml +7 -0
  37. data/app/views/admin/readers/remove.html.haml +18 -0
  38. data/app/views/admin/sites/_choose_reader_layout.html.haml +7 -0
  39. data/app/views/password_resets/create.html.haml +13 -0
  40. data/app/views/password_resets/edit.html.haml +71 -0
  41. data/app/views/password_resets/new.html.haml +31 -0
  42. data/app/views/reader_activations/_activation_required.html.haml +34 -0
  43. data/app/views/reader_activations/_on_activation.html.haml +4 -0
  44. data/app/views/reader_activations/show.html.haml +41 -0
  45. data/app/views/reader_notifier/message.html.haml +1 -0
  46. data/app/views/reader_sessions/_login_form.html.haml +59 -0
  47. data/app/views/reader_sessions/new.html.haml +38 -0
  48. data/app/views/readers/_contributions.html.haml +2 -0
  49. data/app/views/readers/_controls.html.haml +25 -0
  50. data/app/views/readers/_extra_controls.html.haml +0 -0
  51. data/app/views/readers/_flasher.html.haml +6 -0
  52. data/app/views/readers/_form.html.haml +73 -0
  53. data/app/views/readers/create.html.haml +28 -0
  54. data/app/views/readers/edit.html.haml +47 -0
  55. data/app/views/readers/index.html.haml +16 -0
  56. data/app/views/readers/login.html.haml +15 -0
  57. data/app/views/readers/new.html.haml +41 -0
  58. data/app/views/readers/permission_denied.html.haml +23 -0
  59. data/app/views/readers/show.html.haml +35 -0
  60. data/app/views/wrappers/_field_errors.html.haml +5 -0
  61. data/config/routes.rb +22 -0
  62. data/config/settings.rb +9 -0
  63. data/db/migrate/001_create_readers.rb +31 -0
  64. data/db/migrate/002_extend_sites.rb +17 -0
  65. data/db/migrate/003_reader_honorifics.rb +12 -0
  66. data/db/migrate/004_user_readers.rb +11 -0
  67. data/db/migrate/005_last_login.rb +15 -0
  68. data/db/migrate/007_adapt_for_authlogic.rb +27 -0
  69. data/db/migrate/20090921125653_reader_messages.rb +27 -0
  70. data/db/migrate/20090924164413_functional_messages.rb +9 -0
  71. data/db/migrate/20090925081225_standard_messages.rb +106 -0
  72. data/db/migrate/20091006102438_message_visibility.rb +9 -0
  73. data/db/migrate/20091010083503_registration_config.rb +10 -0
  74. data/db/migrate/20091019124021_message_functions.rb +9 -0
  75. data/db/migrate/20091020133533_forenames.rb +9 -0
  76. data/db/migrate/20091020135152_contacts.rb +23 -0
  77. data/db/migrate/20091111090819_ensure_functional_messages_visible.rb +9 -0
  78. data/db/migrate/20091119092936_messages_have_layout.rb +9 -0
  79. data/db/migrate/20100922152338_lock_versions.rb +9 -0
  80. data/db/migrate/20100927095703_default_settings.rb +14 -0
  81. data/db/migrate/20101004074945_unlock_version.rb +9 -0
  82. data/lib/config_extensions.rb +5 -0
  83. data/lib/controller_extensions.rb +77 -0
  84. data/lib/reader_admin_ui.rb +64 -0
  85. data/lib/reader_helper.rb +36 -0
  86. data/lib/reader_site.rb +10 -0
  87. data/lib/reader_tags.rb +297 -0
  88. data/lib/rfc822.rb +29 -0
  89. data/lib/tasks/reader_extension_tasks.rake +28 -0
  90. data/pkg/radiant-reader-extension-0.9.0.gem +0 -0
  91. data/public/images/admin/chk_off.png +0 -0
  92. data/public/images/admin/chk_on.png +0 -0
  93. data/public/images/admin/new-message.png +0 -0
  94. data/public/images/admin/new-reader.png +0 -0
  95. data/public/javascripts/admin/messages.js +13 -0
  96. data/public/stylesheets/sass/admin/reader.sass +95 -0
  97. data/radiant-reader-extension.gemspec +184 -0
  98. data/reader_extension.rb +55 -0
  99. data/spec/controllers/admin/messages_controller_spec.rb +38 -0
  100. data/spec/controllers/admin/readers_controller_spec.rb +14 -0
  101. data/spec/controllers/password_resets_controller_spec.rb +140 -0
  102. data/spec/controllers/reader_activations_controller_spec.rb +45 -0
  103. data/spec/controllers/readers_controller_spec.rb +193 -0
  104. data/spec/datasets/messages_dataset.rb +49 -0
  105. data/spec/datasets/reader_layouts_dataset.rb +26 -0
  106. data/spec/datasets/reader_sites_dataset.rb +10 -0
  107. data/spec/datasets/readers_dataset.rb +51 -0
  108. data/spec/lib/reader_admin_ui_spec.rb +35 -0
  109. data/spec/lib/reader_site_spec.rb +18 -0
  110. data/spec/matchers/reader_login_system_matcher.rb +35 -0
  111. data/spec/models/message_spec.rb +109 -0
  112. data/spec/models/reader_notifier_spec.rb +34 -0
  113. data/spec/models/reader_spec.rb +155 -0
  114. data/spec/spec.opts +5 -0
  115. data/spec/spec_helper.rb +48 -0
  116. metadata +267 -0
@@ -0,0 +1,27 @@
1
+ class ReaderMessages < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :messages do |t|
4
+ t.column :site_id, :integer
5
+ t.column :subject, :string
6
+ t.column :body, :text
7
+ t.column :filter_id, :text
8
+ t.column :created_at, :datetime
9
+ t.column :updated_at, :datetime
10
+ t.column :created_by_id, :integer
11
+ t.column :updated_by_id, :integer
12
+ t.column :lock_version, :integer
13
+ end
14
+
15
+ create_table :message_readers do |t|
16
+ t.column :site_id, :integer
17
+ t.column :message_id, :integer
18
+ t.column :reader_id, :integer
19
+ t.column :sent_at, :datetime
20
+ end
21
+ end
22
+
23
+ def self.down
24
+ drop_table :messages
25
+ drop_table :message_readers
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ class FunctionalMessages < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :messages, :function, :string
4
+ end
5
+
6
+ def self.down
7
+ remove_column :messages, :function
8
+ end
9
+ end
@@ -0,0 +1,106 @@
1
+ class StandardMessages < ActiveRecord::Migration
2
+ def self.up
3
+ Message.reset_column_information
4
+ messages = []
5
+
6
+ messages.push(Message.create(
7
+ :subject => 'Welcome!',
8
+ :function => 'welcome',
9
+ :filter_id => nil,
10
+ :body => %{
11
+ <p>Hello <r:recipient:name />.</p>
12
+
13
+ <p>Welcome to the <strong><a href="<r:site:url />"><r:site:name /></a></strong> site, and thank you for persevering with the registration process. Your account is now active and you will have been logged in automatically.</p>
14
+
15
+ <p>You can put in a bit more information about yourself at any time by visiting <a href="<r:recipient:edit_url />">your preferences page</a>.</p>
16
+
17
+ <p>Next time you visit, you will need to log in. Here's another reminder before we discard the plain text version of your password:</p>
18
+
19
+ <ul>
20
+ <li>username: <strong><r:recipient:login /></strong></li>
21
+ <li>password: <strong><r:recipient:password /></strong></li>
22
+ </ul>
23
+
24
+ <p>Best wishes,</p>
25
+
26
+ <p><r:sender:name /></p>
27
+ }
28
+ ))
29
+
30
+ messages.push(Message.create(
31
+ :subject => 'Please activate your account',
32
+ :function => 'activation',
33
+ :filter_id => nil,
34
+ :body => %{
35
+ <p>Hello <r:recipient:name />.</p>
36
+
37
+ <p>Welcome! Your account has been created at the <strong><r:site:name /></strong> site. To activate it, all you have to do is <strong><a href="<r:recipient:activation_url />">click on this link</a></strong>.</p>
38
+
39
+ <p>On this first visit you'll be logged in automatically, but next time you'll need to know your username and password:</p>
40
+
41
+ <ul>
42
+ <li>username: <strong><r:recipient:login /></strong></li>
43
+ <li>password: <strong><r:recipient:password /></strong></li>
44
+ </ul>
45
+
46
+ <p>To see yourself as others might see you, have a look at <a href="<r:recipient:url />">your page</a>. You can change that listing in your <a href="<r:recipient:edit_url />">preferences</a> and if you'd like a picture to appear, you need a <a href="http://www.gravatar.com/signup">gravatar</a>.</p>
47
+
48
+ <p>We're about to forget your password, so we won't be able to remind you what it is, but if you get stuck you can always make a new one by clicking on the 'forgot my password' link on the login page.</p>
49
+
50
+ <p>Best wishes,</p>
51
+
52
+ <p><r:sender:name /></p>
53
+ }
54
+ ))
55
+
56
+ messages.push(Message.create(
57
+ :subject => 'You are invited!',
58
+ :function => 'invitation',
59
+ :filter_id => nil,
60
+ :body => %{
61
+ <p>Hello <r:recipient:name />.</p>
62
+
63
+ <p>You are invited to join the <strong><r:site:name /></strong> site. To accept the invitation, all you have to do is <strong><a href="<r:recipient:activation_url />">click on this link</a></strong>.</p>
64
+
65
+ <p>On this first visit you'll be logged in automatically, but next time you'll need to know your username and password. Most of this has been generated automatically:</p>
66
+
67
+ <ul>
68
+ <li>username: <strong><r:recipient:login /></strong></li>
69
+ <li>password: <strong><r:recipient:password /></strong></li>
70
+ </ul>
71
+
72
+ So you will want to change it in your <a href="<r:recipient:edit_url />">preferences</a>, where you can also edit the text that will appear on your <a href="<r:recipient:url />">listing page</a> whenever someone follows a link from one of your contributions to the site.</p>
73
+
74
+ <p>Once you've logged in we'll forget your password, so we won't be able to remind you what it is. If you get stuck you can always make a new one by clicking on the 'forgot my password' link on the login page.</p>
75
+
76
+ <p>Best wishes,</p>
77
+
78
+ <p><r:sender:name /></p>
79
+ }
80
+ ))
81
+
82
+ messages.push(Message.create(
83
+ :subject => 'Reset your password',
84
+ :function => 'password_reset',
85
+ :filter_id => nil,
86
+ :body => %{
87
+ <p>Hello <r:recipient:name />.</p>
88
+
89
+ <p>Someone has requested that a new password be generated for your account at the <strong><a href="<r:site:url />"><r:site:name /></a></strong> site. If that person wasn't you, please don't be concerned: you are seeing this message, not they, and your password hasn't changed. You can safely delete this message and forget about it.</p>
90
+
91
+ <p>If that person was you, please <strong><a href="<r:recipient:repassword_url />">click here to enter a new password</a></strong>. Nothing will actually change until you submit the password-reset form.</p>
92
+
93
+ <p>If you have remembered your current password and all you want to do is change it, you can skip this step and go straight to your <a href="<r:recipient:edit_url />">preferences</a>.</p>
94
+ }
95
+ ))
96
+
97
+ if admin = User.find_by_admin(true)
98
+ messages.each do |message|
99
+ message.update_attribute(:created_by_id, admin.id)
100
+ end
101
+ end
102
+ end
103
+
104
+ def self.down
105
+ end
106
+ end
@@ -0,0 +1,9 @@
1
+ class MessageVisibility < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :messages, :status_id, :integer, :default => 1
4
+ end
5
+
6
+ def self.down
7
+ remove_column :messages, :status_id
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ class RegistrationConfig < ActiveRecord::Migration
2
+ def self.up
3
+ if Radiant::Config['reader.allow_registration?'].nil?
4
+ Radiant::Config['reader.allow_registration?'] = true
5
+ end
6
+ end
7
+
8
+ def self.down
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ class MessageFunctions < ActiveRecord::Migration
2
+ def self.up
3
+ rename_column :messages, :function, :function_id
4
+ end
5
+
6
+ def self.down
7
+ rename_column :messages, :function_id, :function
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class Forenames < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :readers, :forename, :string
4
+ end
5
+
6
+ def self.down
7
+ remove_column :readers, :forename
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ class Contacts < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :readers, :phone, :string
4
+ add_column :readers, :organisation, :string
5
+ add_column :readers, :post_building, :string
6
+ add_column :readers, :post_street, :string
7
+ add_column :readers, :post_place, :string
8
+ add_column :readers, :post_town, :string
9
+ add_column :readers, :post_county, :string
10
+ add_column :readers, :postcode, :string
11
+ end
12
+
13
+ def self.down
14
+ remove_column :readers, :phone
15
+ remove_column :readers, :organisation
16
+ remove_column :readers, :post_building
17
+ remove_column :readers, :post_street
18
+ remove_column :readers, :post_place
19
+ remove_column :readers, :post_town
20
+ remove_column :readers, :post_county
21
+ remove_column :readers, :postcode
22
+ end
23
+ end
@@ -0,0 +1,9 @@
1
+ class EnsureFunctionalMessagesVisible < ActiveRecord::Migration
2
+ def self.up
3
+ Message.reset_column_information
4
+ Message.administrative.each {|m| m.update_attribute(:status_id, 100)}
5
+ end
6
+
7
+ def self.down
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class MessagesHaveLayout < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :messages, :layout_id, :integer
4
+ end
5
+
6
+ def self.down
7
+ remove_column :messages, :layout_id
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class LockVersions < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :readers, :lock_version, :integer, :default => 0
4
+ end
5
+
6
+ def self.down
7
+ remove_column :readers, :lock_version
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ class DefaultSettings < ActiveRecord::Migration
2
+ def self.up
3
+ Radiant::Config['reader.allow_registration?'] ||= true
4
+ Radiant::Config['reader.require_confirmation?'] ||= true
5
+ Radiant::Config['site.url'] ||= 'www.example.com'
6
+ Radiant::Config['site.title'] ||= 'Your site name here'
7
+ Radiant::Config['reader.mail_from_name'] ||= "Administrator"
8
+ Radiant::Config['reader.mail_from_address'] ||= "admin@example.com"
9
+ Radiant::Config['reader.layout'] ||= 'undefined'
10
+ end
11
+
12
+ def self.down
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ class UnlockVersion < ActiveRecord::Migration
2
+ def self.up
3
+ remove_column :readers, :lock_version
4
+ end
5
+
6
+ def self.down
7
+ add_column :readers, :lock_version, :integer, :default => 0
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module ConfigExtensions # for inclusion into Radiant::Config
2
+ def boolean?
3
+ key.ends_with? "?"
4
+ end
5
+ end
@@ -0,0 +1,77 @@
1
+ module ControllerExtensions # for inclusion into ApplicationController
2
+
3
+ def self.included(base)
4
+
5
+ base.class_eval do
6
+ before_filter :set_reader_for_user
7
+ before_filter :set_reader
8
+ helper_method :current_reader_session, :current_reader, :current_reader=
9
+ end
10
+
11
+ protected
12
+
13
+ def current_reader_session
14
+ return @current_reader_session if @current_reader_session.is_a?(ReaderSession)
15
+ @current_reader_session = ReaderSession.find
16
+ Reader.current = @current_reader_session.record if @current_reader_session
17
+ @current_reader_session
18
+ end
19
+
20
+ def current_reader_session=(reader_session)
21
+ @current_reader_session = reader_session
22
+ end
23
+
24
+ def current_reader
25
+ current_reader_session.record if current_reader_session
26
+ end
27
+
28
+ def current_reader=(reader)
29
+ if reader && reader.is_a?(Reader)
30
+ current_reader_session = ReaderSession.create!(reader)
31
+ else
32
+ current_reader_session.destroy
33
+ end
34
+ end
35
+
36
+ def set_reader_for_user
37
+ if current_user
38
+ current_reader_session = ReaderSession.create!(Reader.find_or_create_for_user(current_user))
39
+ end
40
+ end
41
+
42
+ def set_reader
43
+ Reader.current = current_reader
44
+ end
45
+
46
+ def store_location(location = request.request_uri)
47
+ session[:return_to] = location
48
+ end
49
+
50
+ def redirect_back_or_to(default)
51
+ redirect_to(session[:return_to] || default)
52
+ session[:return_to] = nil
53
+ end
54
+
55
+ def redirect_back_with_format(format = 'html')
56
+ address = session[:return_to]
57
+ raise StandardError, "Can't add format to an already formatted url: #{address}" unless File.extname(address).blank?
58
+ redirect_to address + ".#{format}" # nasty! but necessary for inline login.
59
+ end
60
+
61
+ def render_page_or_feed(template_name = action_name)
62
+ respond_to do |format|
63
+ format.html { render :action => template_name }
64
+ format.rss { render :action => template_name, :layout => 'feed' }
65
+ format.js { render :action => template_name, :layout => false }
66
+ end
67
+ end
68
+
69
+ end
70
+ end
71
+
72
+
73
+
74
+
75
+
76
+
77
+
@@ -0,0 +1,64 @@
1
+ module ReaderAdminUI
2
+
3
+ def self.included(base)
4
+ base.class_eval do
5
+
6
+ attr_accessor :reader, :message, :reader_setting
7
+ alias_method :readers, :reader
8
+ alias_method :messages, :message
9
+ alias_method :reader_settings, :reader_setting
10
+
11
+ def load_reader_extension_regions
12
+ reader = load_default_reader_regions
13
+ message = load_default_message_regions
14
+ reader_setting = load_default_reader_setting_regions
15
+ end
16
+
17
+ def load_default_regions_with_reader
18
+ load_default_regions_without_reader
19
+ load_reader_extension_regions
20
+ end
21
+ alias_method_chain :load_default_regions, :reader
22
+
23
+ protected
24
+
25
+ def load_default_reader_regions
26
+ returning OpenStruct.new do |reader|
27
+ reader.edit = Radiant::AdminUI::RegionSet.new do |edit|
28
+ edit.main.concat %w{edit_header edit_form}
29
+ edit.form.concat %w{edit_name edit_email edit_username edit_password edit_description edit_notes}
30
+ edit.form_bottom.concat %w{edit_timestamp edit_buttons}
31
+ end
32
+ reader.index = Radiant::AdminUI::RegionSet.new do |index|
33
+ index.thead.concat %w{title_header description_header modify_header}
34
+ index.tbody.concat %w{title_cell description_cell modify_cell}
35
+ index.bottom.concat %w{buttons}
36
+ end
37
+ reader.remove = reader.index
38
+ reader.new = reader.edit
39
+ end
40
+ end
41
+
42
+ def load_default_reader_setting_regions
43
+ returning OpenStruct.new do |reader_settings|
44
+ reader_settings.index = Radiant::AdminUI::RegionSet.new do |index|
45
+ index.settings.concat %w{registration site sender}
46
+ index.messages.concat %w{administration}
47
+ end
48
+ end
49
+ end
50
+
51
+ def load_default_message_regions
52
+ returning OpenStruct.new do |message|
53
+ message.edit = Radiant::AdminUI::RegionSet.new do |edit|
54
+ edit.main.concat %w{edit_header edit_form edit_footer}
55
+ edit.form.concat %w{edit_subject edit_body}
56
+ edit.form_bottom.concat %w{edit_timestamp edit_buttons}
57
+ end
58
+ message.new = message.edit
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
@@ -0,0 +1,36 @@
1
+ require 'sanitize'
2
+ module ReaderHelper
3
+ def self.included(base)
4
+
5
+ base.module_eval do
6
+
7
+ # wraps the block in a p with the right class and shows the errors nicely, if there are any
8
+
9
+ def with_error_report(errors, &block)
10
+ render({:layout => 'wrappers/field_errors', :locals => {:errors => errors}}, {}, &block)
11
+ end
12
+
13
+ def clean_textilize(text)
14
+ Sanitize.clean(textilize(text), Sanitize::Config::RELAXED)
15
+ end
16
+
17
+ def clean_textilize_without_paragraph(text)
18
+ textiled = clean_textilize(text)
19
+ if textiled[0..2] == "<p>" then textiled = textiled[3..-1] end
20
+ if textiled[-4..-1] == "</p>" then textiled = textiled[0..-5] end
21
+ return textiled
22
+ end
23
+
24
+ def truncate_words(text='', length=64, omission="...")
25
+ return '' if text.blank?
26
+ words = text.split
27
+ omission = '' unless words.size > length
28
+ words[0..(length-1)].join(" ") + omission
29
+ end
30
+
31
+ def truncate_and_textilize(text, length=64)
32
+ clean_textilize( truncate_words(text, length) )
33
+ end
34
+ end
35
+ end
36
+ end