user_announcements 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -5,9 +5,15 @@
5
5
  [![Coverage Status](https://coveralls.io/repos/stevedowney/user_announcements/badge.png?branch=master)](https://coveralls.io/r/stevedowney/user_announcements?branch=master)
6
6
  [![Code Climate](https://codeclimate.com/github/stevedowney/user_announcements.png)](https://codeclimate.com/github/stevedowney/user_announcements)
7
7
 
8
- Manage and display site-wide announcements on a per-user basis.
8
+ ## Features:
9
9
 
10
- Coming soon, scope by user role and announcement type.
10
+ * admins
11
+ * page for maintaining announcements
12
+ * announcements can be scoped by user role
13
+ * users
14
+ * hide announcements
15
+ * view past and hidden announcements
16
+ * unhide hidden announcements
11
17
 
12
18
  ### Acknowledgements
13
19
 
@@ -15,6 +21,13 @@ This gem was inspired by the [Site-Wide Announcements (revised)](http://railscas
15
21
  episode of [RailsCasts](http://railscasts.com/). If you don't have a premium account you can see the
16
22
  [original episode](http://railscasts.com/episodes/103-site-wide-announcements).
17
23
 
24
+ ## Assumptions
25
+
26
+ * your controllers respond to `ensure_admin_user` which ensures only admin users can create/edit/delete
27
+ announcemets
28
+ * your controllers respond to `current_user`, which is also a `helper_method`
29
+ * if you implement roles, `current_user` responds to `#has_role?(<role>)`
30
+
18
31
  ## Installation
19
32
 
20
33
  Add it to your Gemfile:
@@ -35,28 +48,53 @@ Install files:
35
48
  rails generate user_announcements:install
36
49
  ```
37
50
 
38
- By default, Bootstrap styling is applied. This can be turned on/off:
39
-
40
- ```ruby
41
- # ../config/initializers/user_announcements.rb
51
+ ## Getting Started
42
52
 
43
- # control Bootstrap styling
44
- # c.bootstrap = false
45
- c.bootstrap = true
53
+ ### Controller Methods Example
46
54
 
55
+ ```ruby
56
+ class ApplicationController < ActionController::Base
57
+ protect_from_forgery
58
+
59
+ private
60
+
61
+ def ensure_admin_user
62
+ current_user.has_role?('admin')
63
+ end
64
+
65
+ def current_user
66
+ @user ||= User.find(session[:user_id])
67
+ end
68
+ helper_method :current_user
69
+
70
+ end
47
71
  ```
48
72
 
49
- Don't forget to restart your Rails server.
73
+ ### User Model Methods
74
+
50
75
 
51
- ## Getting Going
76
+ ```ruby
77
+ class User < ActiveRecord::Base
78
+
79
+ def has_role?(role)
80
+ return true if role.blank?
81
+ return true if role == admin && self.admin?
82
+ # ... more elaborate role checking code here?
83
+ false
84
+ end
85
+
86
+ end
87
+ ```
52
88
 
53
- To create an announcement go to:
89
+ ### Create an Announcement
54
90
 
55
91
  ```
56
92
  http://<your app>/admin/announcements
57
93
  ```
58
94
 
59
- To see the announcment add the helper method to your views, e.g.:
95
+ ### View the Announcement
96
+
97
+ Add the helper method to your layout:
60
98
 
61
99
  ```erb
62
100
  #../layouts/application.html.erb
@@ -66,8 +104,59 @@ To see the announcment add the helper method to your views, e.g.:
66
104
  ...
67
105
  ```
68
106
 
69
- Non-admin users can see (and unhide) announcements they have hidden:
107
+ Now visit some page that uses that layout to see the announcement.
108
+
109
+ Non-admin users can see current and past announcements, including ones they have hidden,
110
+ by visiting:
70
111
 
71
112
  ```
72
113
  http://<your app>/announcements
73
114
  ```
115
+
116
+ ### URL Helpers
117
+
118
+ The following url helpers are available:
119
+
120
+ ```ruby
121
+ # admin manages announcements
122
+ admin_announcements_path
123
+
124
+ # user manages own announcements
125
+ hidden_announcements_path
126
+ ```
127
+
128
+ ## Configuration
129
+
130
+ There are several configuration settings found in `../config/initializers/user_announcements.rb`.
131
+
132
+ ```ruby
133
+ # note: all options accept lambdas
134
+
135
+ UserAnnouncements.config do |config|
136
+
137
+ # Bootstrap
138
+ config.bootstrap = true
139
+ config.styles = [['Yellow', ''], ['Red', 'alert-error'], ['Green', 'alert-success'], ['Blue', 'alert-info']]
140
+
141
+ # non-Bootstrap
142
+ # config.bootstrap = false
143
+ # config.styles = [['Yellow', 'yellow'], ['Red', 'red'], ['Green', 'green'], ['Blue', 'blue']]
144
+
145
+ # Announcement defaults
146
+ config.default_active = true
147
+ config.default_starts_at = lambda { Time.now.in_time_zone }
148
+ config.default_ends_at = lambda { 1.week.from_now.in_time_zone.end_of_day }
149
+ config.default_style = ''
150
+ # config.default_roles = ['admin']
151
+
152
+ # Roles
153
+ # config.roles = []
154
+ # config.roles = ['', 'admin']
155
+ # config.roles = [ ['Public', ''], ['Administrator', 'admin'] ]
156
+ # config.roles = lambda { MyRoleClass.map { |role| [role.name, role.id] } }
157
+
158
+ end
159
+ ```
160
+
161
+ Don't forget to restart your Rails server after changes to the config file.
162
+
@@ -1,8 +1,9 @@
1
- class Admin::AnnouncementsController < Admin::BaseController
1
+ class Admin::AnnouncementsController < ApplicationController
2
+ before_filter :ensure_admin_user
2
3
  before_filter :find_announcement, :only => [:edit, :update, :destroy]
3
4
 
4
5
  def index
5
- @announcements = AnnouncementFinder.ordered
6
+ @announcements = AnnouncementFinder.for_admin
6
7
  end
7
8
 
8
9
  def new
@@ -22,7 +23,10 @@ class Admin::AnnouncementsController < Admin::BaseController
22
23
  end
23
24
 
24
25
  def update
25
- if @announcement.update_attributes(params.fetch(:announcement))
26
+ attributes = params.fetch(:announcement)
27
+ .reverse_merge(roles: [])
28
+
29
+ if @announcement.update_attributes(attributes)
26
30
  redirect_to admin_announcements_path, :flash => { success: 'Announcement updated' }
27
31
  else
28
32
  render "edit"
@@ -1,8 +1,7 @@
1
1
  class HiddenAnnouncementsController < ApplicationController
2
- before_filter :ensure_current_user
3
-
2
+
4
3
  def index
5
- @announcements = AnnouncementFinder.past_or_current
4
+ @announcements = AnnouncementFinder.for_edit(current_user)
6
5
  @hidden_announcement_ids = HiddenAnnouncement.hidden_announcement_ids_for(current_user.id)
7
6
  end
8
7
 
@@ -19,5 +18,5 @@ class HiddenAnnouncementsController < ApplicationController
19
18
  HiddenAnnouncement.delete_all(user_id: current_user.id, announcement_id: params.fetch(:announcement_id))
20
19
  redirect_to action: 'index'
21
20
  end
22
-
21
+
23
22
  end
@@ -0,0 +1,43 @@
1
+ module UserAnnouncements::AdminHelper
2
+
3
+ def _ua_active_model_errors(model)
4
+ return unless model.errors.present?
5
+
6
+ content_tag(:div, class: ['alert', 'alert-error']) do
7
+ content_tag(:h4, "Correct the following errors:") +
8
+ content_tag(:ul) do
9
+ safe_join(model.errors.full_messages.map { |msg| content_tag(:li, msg) }, "\n")
10
+ end
11
+ end
12
+ end
13
+
14
+ def ua_table_tag(options={})
15
+ content_tag(:table, options.merge(ua_table_attrs)) do
16
+ yield
17
+ end
18
+ end
19
+
20
+ def boolean_display(boolean)
21
+ ( boolean ? '&#10004;' : '&nbsp;' ).html_safe
22
+ end
23
+
24
+ def ua_datetime_p(f, method)
25
+ content_tag(:p, class: 'datetime-select') do
26
+ f.label(method) +
27
+ ua_br +
28
+ f.datetime_select(method)
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def ua_table_attrs
35
+ if ua_bootstrap?
36
+ {class: "ua-table bootstrap table table-striped table-bordered table-hover"}
37
+ else
38
+ {class: 'ua-table non-bootstrap'}
39
+ end
40
+ end
41
+
42
+
43
+ end
@@ -0,0 +1,39 @@
1
+ module UserAnnouncements::MiscHelper
2
+
3
+ def ua_datetime_display(datetime)
4
+ if datetime.present?
5
+ datetime.to_s(:short)
6
+ else
7
+ nil
8
+ end
9
+ end
10
+
11
+ # Return a <br> tag if not bootstrap
12
+ def ua_br
13
+ "<br />".html_safe unless ua_bootstrap?
14
+ end
15
+
16
+ def flash_messages
17
+ return nil if flash.empty?
18
+ result = []
19
+ flash.each do |name, msg|
20
+ result << build_message(name, msg)
21
+ end
22
+ result.join("").html_safe
23
+ end
24
+
25
+ def build_message(msg_type, msg)
26
+ content_tag(:div, :class => "alert alert-#{msg_type.to_s}") do
27
+ content_tag(:a, 'x', :class => "close", "data-dismiss" => "alert") + msg.html_safe
28
+ end
29
+ end
30
+
31
+ def ua_bootstrap?
32
+ if params.has_key?(:bootstrap)
33
+ params[:bootstrap] == 'true'
34
+ else
35
+ UserAnnouncements.config.bootstrap
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,44 @@
1
+ module UserAnnouncements::RolesHelper
2
+ Role = Struct.new(:name, :id)
3
+
4
+ # Roles checkboxes for admin detail form
5
+ def ua_roles_html(f)
6
+ return unless _ua_roles.present?
7
+
8
+ f.label(:roles) +
9
+ ua_br +
10
+ _ua_roles_checkboxes(_ua_roles)
11
+ end
12
+
13
+ # Roles display on index page
14
+ def ua_roles_display(announcement)
15
+ role_names = announcement.roles.map { |role_id| _ua_role_id_to_name(role_id) }
16
+
17
+ safe_join(role_names, '<br />'.html_safe)
18
+ end
19
+
20
+ private
21
+
22
+ def _ua_roles_checkboxes(roles)
23
+ safe_join( roles.map { |role| _ua_role_checkbox(role) } )
24
+ end
25
+
26
+ def _ua_role_checkbox(role)
27
+ id = "role_#{role.id}"
28
+ checked = @announcement.roles.include?(role.id)
29
+
30
+ check_box_tag('announcement[roles][]', role.id, checked, id: id) + ' ' +
31
+ label_tag(id, role.name, style: "display: inline; margin-right: 1em")
32
+ end
33
+
34
+ def _ua_role_id_to_name(role_id)
35
+ _ua_roles.detect { |role| role.id == role_id }.try(:name)
36
+ end
37
+
38
+ def _ua_roles
39
+ @_ua_roles ||= Array(UserAnnouncements[:roles]).map do |role|
40
+ name_id = (role.is_a?(Array) ? role : [role, role]).map(&:to_s)
41
+ Role.new(name_id.first, name_id.last)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,66 @@
1
+ module UserAnnouncements::ShowAnnouncements
2
+
3
+ # Helper method for displaying messages for +current_user+.
4
+ def user_announcements(options={})
5
+ return if controller.controller_name == 'hidden_announcements'
6
+
7
+ announcements_rows = AnnouncementFinder.for_display(current_user)
8
+ divs = announcements_rows.map do |announcement|
9
+ _ua_announcement_div(announcement)
10
+ end
11
+
12
+ safe_join(divs, "\n")
13
+ end
14
+
15
+ private
16
+
17
+ def _ua_announcement_div(ann)
18
+ if ua_bootstrap?
19
+ _ua_announcement_div_bootstrap(ann)
20
+ else
21
+ _ua_announcement_div_non_bootstrap(ann)
22
+ end
23
+ end
24
+
25
+ def _ua_announcement_div_bootstrap(ann)
26
+ div_for ann, class: _ua_announcement_classes(ann.style), style: 'width:40em' do
27
+ link_to(*_ua_hide_announcement_link_args(ann)) do
28
+ content_tag(:button, raw('&times;'), type: 'button', class: 'close')
29
+ end +
30
+ ann.message.html_safe
31
+ end
32
+ end
33
+
34
+ def _ua_announcement_div_non_bootstrap(ann)
35
+ div_for(ann, class: _ua_announcement_classes(ann.style)) do
36
+ ann.message.html_safe +
37
+ link_to("hide announcement", *_ua_hide_announcement_link_args(ann))
38
+ end
39
+ end
40
+
41
+ def _ua_hide_announcement_link_args(announcement)
42
+ url = hidden_announcements_path(announcement_id: announcement)
43
+ options = {
44
+ method: :post,
45
+ remote: true,
46
+ id: "hide_#{dom_id(announcement)}"
47
+ }
48
+
49
+ [url, options]
50
+ end
51
+
52
+ def _ua_unhide_announcement_link(announcement)
53
+ if @hidden_announcement_ids.include?(announcement.id)
54
+ content_tag(:div) do
55
+ link_to('Unhide', hidden_announcement_path(announcement, announcement_id: announcement), method: :delete)
56
+ end
57
+ end
58
+ end
59
+
60
+
61
+ def _ua_announcement_classes(style)
62
+ bootstrap_or_non = ua_bootstrap? ? 'bootstrap alert' : 'non-bootstrap'
63
+ [bootstrap_or_non, style.presence].compact.join(' ')
64
+ end
65
+
66
+ end
@@ -0,0 +1,20 @@
1
+ module UserAnnouncements::StyleHelper
2
+
3
+ # Style dropdown for admin detail form
4
+ def ua_style_html(f)
5
+ return unless _ua_styles.present?
6
+
7
+ f.label(:style) +
8
+ ua_br +
9
+ f.select(:style, _ua_styles)
10
+ end
11
+
12
+ private
13
+
14
+ def _ua_styles
15
+ @_ua_styles ||= UserAnnouncements[:styles].map do |style|
16
+ (style.is_a?(Array) ? style : [style, style]).map(&:to_s)
17
+ end
18
+ end
19
+
20
+ end
@@ -1,101 +1,7 @@
1
1
  module UserAnnouncementsHelper
2
-
3
- # Helper method for displaying messages for +current_user+.
4
- def user_announcements(options={})
5
- return if controller.controller_name == 'hidden_announcements'
6
-
7
- announcements_rows = AnnouncementFinder.current_for_user(current_user)
8
- divs = announcements_rows.map do |announcement|
9
- announcement_div(announcement)
10
- end
11
-
12
- safe_join(divs, "\n")
13
- end
14
-
15
- def announcement_div(announcement)
16
- if bootstrap?
17
- announcement_div_bootstrap(announcement)
18
- else
19
- announcement_div_non_bootstrap(announcement)
20
- end
21
- end
22
-
23
- def announcement_div_bootstrap(announcement)
24
- div_for announcement, class: 'alert', style: 'width:40em' do
25
- link_to(*hide_announcement_link_args(announcement)) do
26
- content_tag(:button, raw('&times;'), type: 'button', class: 'close')
27
- end +
28
- announcement.message.html_safe
29
- end
30
- end
31
-
32
- def hide_announcement_link_args(announcement)
33
- url = hidden_announcements_path(announcement_id: announcement)
34
- options = {
35
- method: :post,
36
- remote: true,
37
- id: "hide_#{dom_id(announcement)}"
38
- }
39
-
40
- [url, options]
41
- end
42
-
43
- def announcement_div_non_bootstrap(announcement)
44
- div_for(announcement, class: 'non-bootstrap') do
45
- announcement.message.html_safe +
46
- link_to("hide announcement", *hide_announcement_link_args(announcement))
47
- end
48
- end
49
-
50
- def unhide_announcement_link(announcement)
51
- if @hidden_announcement_ids.include?(announcement.id)
52
- content_tag(:div) do
53
- link_to('Unhide', hidden_announcement_path(announcement, announcement_id: announcement), method: :delete)
54
- end
55
- end
56
- end
57
-
58
- def ua_table_attrs
59
- if bootstrap?
60
- {class: "ua-table bootstrap table table-striped table-bordered table-condensed table-hover"}
61
- else
62
- {class: 'ua-table non-bootstrap'}
63
- end
64
- end
65
-
66
- def ua_table_tag(options={})
67
- content_tag(:table, options.merge(ua_table_attrs)) do
68
- yield
69
- end
70
- end
71
-
72
- def boolean_display(boolean)
73
- ( boolean ? '&#10004;' : '&nbsp;' ).html_safe
74
- end
75
-
76
- def active_model_errors(model)
77
- return unless model.errors.present?
78
-
79
- content_tag(:div, class: ['alert', 'alert-error']) do
80
- content_tag(:h4, "Correct the following errors:") +
81
- content_tag(:ul) do
82
- safe_join(model.errors.full_messages.map { |msg| content_tag(:li, msg) }, "\n")
83
- end
84
- end
85
- end
86
-
87
- def ua_datetime_p(f, method)
88
- content_tag(:p, class: 'datetime-select') do
89
- f.label(method) +
90
- f.datetime_select(method)
91
- end
92
- end
93
-
94
- def bootstrap?
95
- if params.has_key?(:bootstrap)
96
- params[:bootstrap] == 'true'
97
- else
98
- UserAnnouncements.config.bootstrap
99
- end
100
- end
2
+ include UserAnnouncements::AdminHelper
3
+ include UserAnnouncements::RolesHelper
4
+ include UserAnnouncements::MiscHelper
5
+ include UserAnnouncements::StyleHelper
6
+ include UserAnnouncements::ShowAnnouncements
101
7
  end
@@ -1,9 +1,12 @@
1
1
  class Announcement < ActiveRecord::Base
2
- attr_accessible :message, :starts_at, :ends_at, :active
2
+ serialize :roles, class_name = Array
3
+ serialize :types, class_name = Array
4
+
5
+ attr_accessible :message, :starts_at, :ends_at, :active, :roles, :style
3
6
 
4
7
  has_many :hidden_announcements, :dependent => :destroy
5
8
 
6
- validates_presence_of :message, :starts_at, :ends_at
9
+ validates_presence_of :message
7
10
 
8
11
  INACTIVE = 'inactive'
9
12
  PAST = 'past'
@@ -23,6 +26,10 @@ class Announcement < ActiveRecord::Base
23
26
  status == CURRENT
24
27
  end
25
28
 
29
+ def starts_at_for_user
30
+ starts_at || created_at
31
+ end
32
+
26
33
  def status_order
27
34
  { FUTURE => 1, CURRENT => 2, PAST => 3, INACTIVE => 4 }[status]
28
35
  end
@@ -35,24 +42,13 @@ class Announcement < ActiveRecord::Base
35
42
 
36
43
  def new_with_defaults
37
44
  new do |ann|
38
- ann.active = get_default(:active)
39
- ann.starts_at = get_default(:starts_at)
40
- ann.ends_at = get_default(:ends_at)
45
+ ann.active = UserAnnouncements[:default_active]
46
+ ann.starts_at = UserAnnouncements[:default_starts_at]
47
+ ann.ends_at = UserAnnouncements[:default_ends_at]
48
+ ann.roles = Array(UserAnnouncements[:default_roles])
49
+ ann.style = UserAnnouncements[:default_style]
41
50
  end
42
51
  end
43
52
 
44
- private
45
-
46
- def get_default(column)
47
- config_key = "default_#{column}"
48
- default = UserAnnouncements.config.send(config_key)
49
-
50
- if default.is_a?(Proc)
51
- default.call
52
- else
53
- default
54
- end
55
- end
56
-
57
53
  end
58
54
  end
@@ -1,44 +1,87 @@
1
+ # Class to handle fetching +Announcement+ rows for various use cases.
1
2
  class AnnouncementFinder
2
3
 
3
4
  class << self
4
5
 
5
- def ordered
6
- Announcement.all.sort_by(&:status_order)
6
+ # Returns all +Announcement+s for admin edit page.
7
+ #
8
+ # @return [ActiveRecord::Relation<Announcement>]
9
+ def for_admin
10
+ Announcement
11
+ .all
12
+ .sort_by(&:status_order)
7
13
  end
8
14
 
9
- def current
10
- Announcement
11
- .active
12
- .where("starts_at is null or starts_at < :now", now: DateTime.now)
13
- .where("ends_at is null or ends_at > :now", now: DateTime.now)
15
+ # Returns unhidden +Announcement+s that _user_ may see.
16
+ #
17
+ # @param user [User]
18
+ # @return [Array<Announcement>]
19
+ def for_display(user)
20
+ result = current
21
+ result = remove_hidden(user, result)
22
+ result = filter_by_role(user, result)
23
+ result
14
24
  end
15
25
 
16
- def past_or_current
17
- Rails.logger.debug '***** start past_or_current'
18
- r = Announcement
26
+ # Returns +Announcement+s that _user_ may edit.
27
+ #
28
+ # @param user [User]
29
+ # @return [ActiveRecord::Relation<Announcement>]
30
+ def for_edit(user)
31
+ Announcement
19
32
  .active
20
33
  .where("(starts_at is null or starts_at < :now)", :now => DateTime.now)
21
34
  .order('created_at desc')
22
- Rails.logger.debug '***** end past_or_current'
23
- # sleep 1
24
- r
25
- end
26
-
27
- def current_for_user(user)
28
- for_user(user, current)
29
35
  end
30
36
 
31
- # def past_or_current_for_user(user)
32
- # # FIXME: apply roles
33
- # past_or_current
34
- # end
37
+ private
35
38
 
36
- def for_user(user, type)
39
+ # Returns current +Announcement+s
40
+ #
41
+ # @return [ActiveRecord::Relation<Announcement>]
42
+ def current
43
+ Announcement
44
+ .active
45
+ .where("starts_at is null or starts_at < :now", now: DateTime.now)
46
+ .where("ends_at is null or ends_at > :now", now: DateTime.now)
47
+ end
48
+
49
+ # Removes any +Announcement+s from _relation_ that _user_ has hidden.
50
+ #
51
+ # @param user [User]
52
+ # @param relation [ActiveRecord::Relation<Announcement>]
53
+ # @return [ActiveRecord::Relation<Announcement>]
54
+ def remove_hidden(user, relation)
37
55
  hidden_announcement_ids = HiddenAnnouncement.hidden_announcement_ids_for(user.id)
38
- result = type
39
- result = result.where("id not in (?)", hidden_announcement_ids) if hidden_announcement_ids.present?
40
- result.sort_by(&:status_order)
56
+
57
+ if hidden_announcement_ids.present?
58
+ relation.where("id not in (?)", hidden_announcement_ids)
59
+ else
60
+ relation
61
+ end
41
62
  end
63
+
64
+ # Removes any +Announcement+s from _relation_ that _user_ can't see.
65
+ #
66
+ # @param user [User]
67
+ # @param relation [ActiveRecord::Relation<Announcement>]
68
+ def filter_by_role(user, relation)
69
+ relation.select { |announcement| user_can_see(user, announcement.roles) }
70
+ end
71
+
72
+ # Returns +true+ if _user_ can see announcement based on _roles_.
73
+ #
74
+ # @param user [User, #has_role?]
75
+ # @param roles [Array<String>]
76
+ # @return [Boolean]
77
+ def user_can_see(user, roles)
78
+ if roles.detect(&:blank?) || roles.blank?
79
+ true
80
+ else
81
+ roles.any? { |role| user.has_role?(role) }
82
+ end
83
+ end
84
+
42
85
  end
43
86
 
44
87
  end
@@ -1,9 +1,10 @@
1
1
  <tr id="<%= dom_id(announcement) %>" class='<%= announcement.status %>'>
2
2
  <td><%=raw announcement.message %></td>
3
- <td class='date'><%= announcement.starts_at.to_s(:long) %></td>
4
- <td class='date'><%= announcement.ends_at.to_s(:long) %></td>
5
- <td><%= announcement.status %></td>
6
- <td><%= boolean_display(announcement.active)%></td>
3
+ <td class='datetime'><%= ua_datetime_display(announcement.starts_at) %></td>
4
+ <td class='datetime'><%= ua_datetime_display(announcement.ends_at) %></td>
5
+ <td class='status'><%= announcement.status %></td>
6
+ <td class='active'><%= boolean_display(announcement.active)%></td>
7
+ <td><%= ua_roles_display(announcement) %></td>
7
8
  <td><%= link_to('edit', edit_admin_announcement_path(announcement), :class => 'btn btn-mini') %></td>
8
9
  <td><%= link_to('delete', admin_announcement_path(announcement), :data => {confirm: 'Are you sure?'}, :method => :delete, :class => 'btn btn-mini btn-danger') %></td>
9
10
  </tr>
@@ -1,10 +1,14 @@
1
- <%= form_for [:admin, @announcement], :html => {:class => 'form-horizontal'} do |f| %>
2
- <%= active_model_errors(f.object) %>
3
- <%#= f.input :subject, :as => :text, :input_html => {:size => "60x3", class: 'span6'} %>
4
- <%#= f.input(:starts_at, :as => :string, :input_html => {class: 'datepicker'}) %>
5
- <%#= f.input(:ends_at, :as => :string, :input_html => {class: 'datepicker'}) %>
1
+ <%= form_for [:admin, @announcement], :html => {:class => 'form-horizontal announcement-detail'} do |f| %>
2
+ <%= _ua_active_model_errors(f.object) %>
3
+
4
+ <p>
5
+ <%= f.check_box(:active) %>
6
+ <%= f.label :active %>
7
+ </p>
8
+
6
9
  <p>
7
10
  <%= f.label(:message) %>
11
+ <%= ua_br %>
8
12
  <%= f.text_area :message, size: "60x10", class: 'span6' %>
9
13
  </p>
10
14
 
@@ -13,10 +17,13 @@
13
17
  <%= ua_datetime_p(f, :ends_at) %>
14
18
 
15
19
  <p>
16
- <%= f.check_box(:active) %>
17
- <%= f.label :active %>
20
+ <%= ua_roles_html(f) %>
18
21
  </p>
19
-
22
+
23
+ <p>
24
+ <%= ua_style_html(f) %>
25
+ </p>
26
+
20
27
  <div class="form-actions">
21
28
  <%= f.submit :class => 'btn btn-primary' %>
22
29
  <%= link_to("Cancel", admin_announcements_path, :class => 'btn') %>
@@ -11,7 +11,8 @@
11
11
  <th>Starts</th>
12
12
  <th>Ends</th>
13
13
  <th>Status</th>
14
- <th>Active</th>
14
+ <th class='active'>Active</th>
15
+ <th class='roles'>Roles</th>
15
16
  <th colspan="2" width="1%">Actions</th>
16
17
  </tr>
17
18
  </thead>
@@ -1,8 +1,8 @@
1
1
 
2
2
  <tr id="<%= dom_id(announcement) %>">
3
- <td class='date'><%= announcement.created_at.try(:to_s, :db) %></td>
3
+ <td class='datetime'><%= ua_datetime_display(announcement.starts_at_for_user) %></td>
4
4
  <td>
5
5
  <%= announcement.message.html_safe %>
6
- <%= unhide_announcement_link(announcement) %>
6
+ <%= _ua_unhide_announcement_link(announcement) %>
7
7
  </td>
8
8
  </tr>
@@ -9,14 +9,14 @@ module UserAnnouncements
9
9
 
10
10
  desc <<DESC
11
11
  Description:
12
- Copies stylesheet to 'app/assets/stylesheets/user_announcements.css.scss'
12
+ Copies stylesheet to 'app/assets/stylesheets/user_announcements.css'
13
13
  Copies configuration to 'config/initializers/user_announcements.rb'
14
14
  Copies db migration to 'db/migrate/<timestamp>/create_user_announcement_tables.rb'
15
15
 
16
16
  DESC
17
17
 
18
18
  def install
19
- copy_file "css.scss", 'app/assets/stylesheets/user_announcements.css.scss'
19
+ copy_file "template.css", 'app/assets/stylesheets/user_announcements.css'
20
20
  copy_file "initializer.rb", 'config/initializers/user_announcements.rb'
21
21
  migration_template "migration.rb", "db/migrate/create_user_announcement_tables.rb"
22
22
  end
@@ -1,9 +1,26 @@
1
- UserAnnouncements.config do |c|
2
-
3
- # config.bootstrap = true
1
+ # note: all options accept lambdas
2
+
3
+ UserAnnouncements.config do |config|
4
+
5
+ # Bootstrap
6
+ config.bootstrap = true
7
+ config.styles = [['Yellow', ''], ['Red', 'alert-error'], ['Green', 'alert-success'], ['Blue', 'alert-info']]
8
+
9
+ # non-Bootstrap
10
+ # config.bootstrap = false
11
+ # config.styles = [['Yellow', 'yellow'], ['Red', 'red'], ['Green', 'green'], ['Blue', 'blue']]
12
+
13
+ # Announcement defaults
14
+ config.default_active = true
15
+ config.default_starts_at = lambda { Time.now.in_time_zone }
16
+ config.default_ends_at = lambda { 1.week.from_now.in_time_zone.end_of_day }
17
+ config.default_style = ''
18
+ # config.default_roles = ['admin']
4
19
 
5
- # config.default_active = true
6
- # config.default_starts_at = lambda { Time.now.in_time_zone }
7
- # config.default_ends_at = lambda { 1.week.from_now.in_time_zone.end_of_day }
20
+ # Roles
21
+ # config.roles = []
22
+ # config.roles = ['', 'admin']
23
+ # config.roles = [ ['Public', ''], ['Administrator', 'admin'] ]
24
+ # config.roles = lambda { MyRoleClass.map { |role| [role.name, role.id] } }
8
25
 
9
26
  end
@@ -7,6 +7,7 @@ class CreateUserAnnouncementTables < ActiveRecord::Migration
7
7
  t.boolean :active
8
8
  t.text :roles
9
9
  t.text :types
10
+ t.text :style
10
11
  t.timestamps
11
12
  end
12
13
 
@@ -0,0 +1,78 @@
1
+ table.ua-table td.status {
2
+ width: 1%;
3
+ text-align: center;
4
+ }
5
+
6
+ table.ua-table th.active {
7
+ width: 1%;
8
+ }
9
+
10
+ table.ua-table td.active {
11
+ text-align: center;
12
+ }
13
+
14
+ table.ua-table td.datetime {
15
+ width: 6em;
16
+ white-space: nowrap;
17
+ }
18
+
19
+ table.ua-table th.roles {
20
+ width: 1%;
21
+ }
22
+
23
+ table.ua-table.non-bootstrap {
24
+ border-collapse:collapse;
25
+ }
26
+
27
+ table.ua-table.non-bootstrap th, table.ua-table.non-bootstrap td {
28
+ border: 1px solid black;
29
+ padding: 0.5em;
30
+ }
31
+
32
+ table.ua-table td {
33
+ vertical-align: top;
34
+ }
35
+
36
+ .announcement.non-bootstrap {
37
+ background-color: #fcf8e3;
38
+ color: #c09853;
39
+ border-bottom: solid 1px black;
40
+ width: 100%;
41
+ padding: 10px;
42
+ text-align: center;
43
+ }
44
+
45
+
46
+ .announcement.non-bootstrap a {
47
+ font-size: 12px;
48
+ margin-left: 5px;
49
+ color: #6E5910;
50
+ }
51
+ }
52
+
53
+ .announcement.non-bootstrap.yellow {
54
+ background-color: #fcf8e3;
55
+ color: #c09853;
56
+ }
57
+
58
+ .announcement.non-bootstrap.red {
59
+ background-color: #f2dede;
60
+ /* border-color: #eed3d7;*/
61
+ color: #b94a48;
62
+ }
63
+
64
+ .announcement.non-bootstrap.green {
65
+ background-color: #dff0d8;
66
+ /* border-color: #d6e9c6;*/
67
+ color: #468847;
68
+ }
69
+
70
+ .announcement.non-bootstrap.blue {
71
+ background-color: #d9edf7;
72
+ /* border-color: #bce8f1;*/
73
+ color: #3a87ad;
74
+ }
75
+
76
+ form.announcement-detail label{
77
+ margin-bottom: 0.4em;
78
+ }
@@ -1,23 +1,28 @@
1
1
  module UserAnnouncements
2
2
 
3
3
  class Engine < ::Rails::Engine
4
+
4
5
  config.generators.integration_tool :rspec
5
6
  config.generators.test_framework :rspec
6
7
 
7
- config.bootstrap = true
8
-
9
- config.default_active = true
10
- config.default_starts_at = lambda { Time.now.in_time_zone }
11
- config.default_ends_at = lambda { 1.week.from_now.in_time_zone.end_of_day }
12
-
13
- config.roles = []
14
- config.types = []
15
- config.styles = %w(error succes info)
16
-
17
8
  end
18
9
 
19
10
  def self.config(&block)
20
11
  yield Engine.config if block
21
12
  Engine.config
22
13
  end
14
+
15
+ def self.[](key)
16
+ setting = config.send(key)
17
+
18
+ if setting.is_a?(Proc)
19
+ setting.call
20
+ else
21
+ setting
22
+ end
23
+
24
+ rescue NameError
25
+ Rails.logger.debug "[UserAnnouncements] Tried to access unknown UserAnnouncements.config key: #{key.inspect}"
26
+ nil
27
+ end
23
28
  end
@@ -1,3 +1,3 @@
1
1
  module UserAnnouncements
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: user_announcements
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-24 00:00:00.000000000 Z
12
+ date: 2013-05-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -339,8 +339,12 @@ extensions: []
339
339
  extra_rdoc_files: []
340
340
  files:
341
341
  - app/controllers/admin/announcements_controller.rb
342
- - app/controllers/admin/base_controller.rb
343
342
  - app/controllers/hidden_announcements_controller.rb
343
+ - app/helpers/user_announcements/admin_helper.rb
344
+ - app/helpers/user_announcements/misc_helper.rb
345
+ - app/helpers/user_announcements/roles_helper.rb
346
+ - app/helpers/user_announcements/show_announcements.rb
347
+ - app/helpers/user_announcements/style_helper.rb
344
348
  - app/helpers/user_announcements_helper.rb
345
349
  - app/models/announcement.rb
346
350
  - app/models/announcement_finder.rb
@@ -355,9 +359,9 @@ files:
355
359
  - app/views/hidden_announcements/index.html.erb
356
360
  - config/routes.rb
357
361
  - lib/generators/user_announcements/install_generator.rb
358
- - lib/generators/user_announcements/templates/css.scss
359
362
  - lib/generators/user_announcements/templates/initializer.rb
360
363
  - lib/generators/user_announcements/templates/migration.rb
364
+ - lib/generators/user_announcements/templates/template.css
361
365
  - lib/tasks/user_announcements_tasks.rake
362
366
  - lib/user_announcements/engine.rb
363
367
  - lib/user_announcements/version.rb
@@ -389,7 +393,6 @@ rubyforge_project:
389
393
  rubygems_version: 1.8.25
390
394
  signing_key:
391
395
  specification_version: 3
392
- summary: Manage and display site-wide announcements by user, role and announcement
393
- type.
396
+ summary: Manage and display site-wide announcements by user, scoped by user role.
394
397
  test_files: []
395
398
  has_rdoc:
@@ -1,12 +0,0 @@
1
- class Admin::BaseController < ApplicationController
2
- before_filter :ensure_admin_user
3
-
4
- private
5
-
6
- def ensure_admin_user
7
- # FIXME
8
- # unless current_user.has_role?(:admin)
9
- # redirect_to root_path
10
- # end
11
- end
12
- end
@@ -1,33 +0,0 @@
1
- table.ua-table {
2
-
3
- td.date {
4
- white-space: nowrap;
5
- }
6
-
7
- &.non-bootstrap {
8
- border: 1px solid black;
9
-
10
- th, td {
11
- border: 1px solid black;
12
- padding: 0.5em;
13
- }
14
-
15
- td {
16
- vertical-align: top;
17
- }
18
-
19
- }
20
- }
21
-
22
- .announcement.non-bootstrap {
23
- width: 100%;
24
- background-color: #F1F094;
25
- border-bottom: solid 1px black;
26
- padding: 10px;
27
- text-align: center;
28
- a {
29
- font-size: 12px;
30
- margin-left: 5px;
31
- color: #6E5910;
32
- }
33
- }