refinerycms-calendar 1.0

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 (56) hide show
  1. data/app/controllers/admin/event_categories_controller.rb +9 -0
  2. data/app/controllers/admin/events_controller.rb +26 -0
  3. data/app/controllers/event_categories_controller.rb +10 -0
  4. data/app/controllers/events_controller.rb +64 -0
  5. data/app/helpers/event_categories_helper.rb +3 -0
  6. data/app/helpers/events_helper.rb +38 -0
  7. data/app/models/event.rb +72 -0
  8. data/app/models/event_categorization.rb +4 -0
  9. data/app/models/event_category.rb +10 -0
  10. data/app/views/admin/event_categories/_event_categories.html.erb +1 -0
  11. data/app/views/admin/event_categories/_event_category.html.erb +18 -0
  12. data/app/views/admin/event_categories/_form.html.erb +26 -0
  13. data/app/views/admin/event_categories/_sortable_list.html.erb +3 -0
  14. data/app/views/admin/event_categories/edit.html.erb +1 -0
  15. data/app/views/admin/event_categories/index.html.erb +40 -0
  16. data/app/views/admin/event_categories/new.html.erb +1 -0
  17. data/app/views/admin/events/_event.html.erb +18 -0
  18. data/app/views/admin/events/_events.html.erb +1 -0
  19. data/app/views/admin/events/_form.html.erb +126 -0
  20. data/app/views/admin/events/_sortable_list.html.erb +20 -0
  21. data/app/views/admin/events/edit.html.erb +1 -0
  22. data/app/views/admin/events/index.html.erb +41 -0
  23. data/app/views/admin/events/new.html.erb +1 -0
  24. data/app/views/event_categories/show.html.erb +15 -0
  25. data/app/views/events/_event.html.erb +103 -0
  26. data/app/views/events/_sidebar.html.erb +38 -0
  27. data/app/views/events/archive.html.erb +17 -0
  28. data/app/views/events/index.html.erb +17 -0
  29. data/app/views/events/index.rss.builder +24 -0
  30. data/app/views/events/show.html.erb +15 -0
  31. data/changelog.md +22 -0
  32. data/config/locales/en.yml +39 -0
  33. data/config/locales/lolcat.yml +24 -0
  34. data/config/locales/nb.yml +20 -0
  35. data/config/locales/nl.yml +20 -0
  36. data/config/routes.rb +11 -0
  37. data/db/migrate/01_create_events.rb +33 -0
  38. data/db/migrate/02_create_event_categories.rb +13 -0
  39. data/db/migrate/03_create_event_categorizations.rb +17 -0
  40. data/db/seeds/events.rb +17 -0
  41. data/features/manage_events.feature +64 -0
  42. data/features/step_definitions/event_steps.rb +14 -0
  43. data/features/support/factories/event_categories.rb +3 -0
  44. data/features/support/factories/events.rb +6 -0
  45. data/features/support/paths.rb +17 -0
  46. data/lib/generators/refinerycms_events_generator.rb +6 -0
  47. data/lib/refinerycms-events.rb +23 -0
  48. data/lib/tasks/events.rake +13 -0
  49. data/public/stylesheets/refinerycms-events.css +73 -0
  50. data/readme.md +49 -0
  51. data/refinerycms-calendar.gemspec +17 -0
  52. data/spec/controllers/events_controller_spec.rb +14 -0
  53. data/spec/helpers/events_helper_spec.rb +16 -0
  54. data/spec/models/event_category_spec.rb +29 -0
  55. data/spec/models/event_spec.rb +82 -0
  56. metadata +133 -0
@@ -0,0 +1,9 @@
1
+ module Admin
2
+ class EventCategoriesController < Admin::BaseController
3
+
4
+ crudify :event_category,
5
+ :title_attribute => :name,
6
+ :xhr_paging => true
7
+
8
+ end
9
+ end
@@ -0,0 +1,26 @@
1
+ module Admin
2
+ class EventsController < Admin::BaseController
3
+ before_filter :find_categories, :except => :index
4
+
5
+ crudify :event, :xhr_paging => true
6
+
7
+ def index
8
+ search_all_events if searching?
9
+
10
+ @archived = Event.archive
11
+ @upcoming = Event.upcoming
12
+ @current = Event.current
13
+
14
+ @events = (@archived | @upcoming | @current)
15
+
16
+ render :partial => 'events' if request.xhr?
17
+ end
18
+
19
+ protected
20
+
21
+ def find_categories
22
+ @event_categories = EventCategory.all
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ class EventCategoriesController < ApplicationController
2
+ helper [:events, :event_categories]
3
+
4
+ def show
5
+ @event_category = EventCategory.find(params[:id])
6
+ @event_categories = EventCategory.all
7
+ @other_events = Event.live.limit(5)
8
+ end
9
+
10
+ end
@@ -0,0 +1,64 @@
1
+ class EventsController < ApplicationController
2
+
3
+ before_filter :find_all_events
4
+ before_filter :find_page
5
+ before_filter :find_categories
6
+
7
+ helper [:events, :event_categories]
8
+
9
+ def index
10
+ # you can use meta fields from your model instead (e.g. browser_title)
11
+ # by swapping @page for @event in the line below:
12
+ present(@page)
13
+ end
14
+
15
+ def show
16
+ @event = Event.find(params[:id])
17
+ # you can use meta fields from your model instead (e.g. browser_title)
18
+ # by swapping @page for @event in the line below:
19
+ present(@page)
20
+ end
21
+
22
+ def archive
23
+ if params[:month].present?
24
+ date = "#{params[:month]}/#{params[:year]}"
25
+ @archive_date = Time.parse(date)
26
+ @date_title = @archive_date.strftime('%B %Y')
27
+ @events = Event.by_archive(@archive_date).paginate({
28
+ :page => params[:page],
29
+ :per_page => RefinerySetting.find_or_set(:events_per_page, 10)
30
+ })
31
+ else
32
+ date = "01/#{params[:year]}"
33
+ @archive_date = Time.parse(date)
34
+ @date_title = @archive_date.strftime('%Y')
35
+ @events = Event.by_year(@archive_date).paginate({
36
+ :page => params[:page],
37
+ :per_page => RefinerySetting.find_or_set(:events_per_page, 10)
38
+ })
39
+ end
40
+ end
41
+
42
+ protected
43
+
44
+ def find_all_events
45
+ upcoming = Event.upcoming.not_featured
46
+ current = Event.current.not_featured
47
+ @events = (upcoming | current).sort { |a,b| a.start_at <=> b.start_at }
48
+
49
+ featured_upcoming = Event.upcoming.featured
50
+ featured_current = Event.current.featured
51
+ @featured_events = (featured_upcoming | featured_current).sort { |a,b| a.start_at <=> b.start_at }
52
+
53
+ @other_events = Event.live.limit(5)
54
+ end
55
+
56
+ def find_page
57
+ @page = Page.find_by_link_url("/events")
58
+ end
59
+
60
+ def find_categories
61
+ @event_categories = EventCategory.all
62
+ end
63
+
64
+ end
@@ -0,0 +1,3 @@
1
+ module EventCategoriesHelper
2
+
3
+ end
@@ -0,0 +1,38 @@
1
+ module EventsHelper
2
+ def events_archive_list
3
+ events = Event.select('start_at').for_archive_list
4
+ return nil if events.blank?
5
+ html = '<ul>'
6
+ links = []
7
+ super_old_links = []
8
+
9
+ events.each do |e|
10
+ if e.start_at >= Time.now.end_of_year.advance(:years => -3)
11
+ links << e.start_at.strftime('%m/%Y')
12
+ else
13
+ super_old_links << e.start_at.strftime('01/%Y')
14
+ end
15
+ end
16
+ links.uniq!
17
+ super_old_links.uniq!
18
+ links.each do |l|
19
+ year = l.split('/')[1]
20
+ month = l.split('/')[0]
21
+ count = Event.by_archive(Time.parse(l)).size
22
+ text = t("date.month_names")[month.to_i] + " #{year} (#{count})"
23
+ html << "<li>"
24
+ html << link_to(text, archive_events_path(:year => year, :month => month))
25
+ html << "</li>"
26
+ end
27
+ super_old_links.each do |l|
28
+ year = l.split('/')[1]
29
+ count = Event.by_year(Time.parse(l)).size
30
+ text = "#{year} (#{count})"
31
+ html << "<li>"
32
+ html << link_to(text, archive_events_path(:year => year))
33
+ html << "</li>"
34
+ end
35
+ html << '</ul>'
36
+ html.html_safe
37
+ end
38
+ end
@@ -0,0 +1,72 @@
1
+ class Event < ActiveRecord::Base
2
+ has_many :event_categorizations
3
+ has_many :categories, :through => :event_categorizations, :source => :event_category
4
+
5
+ default_scope order('start_at ASC')
6
+
7
+ scope :current, where(['start_at < ? and end_at >= ?', Time.now, Time.now])
8
+ scope :upcoming, where(['start_at >= ?', Time.now])
9
+ scope :featured, where(['featured IS NOT NULL and featured = ?', true])
10
+ scope :not_featured, where(['featured IS NULL or featured = ?', false])
11
+ scope :live, where(['end_at > ?', Time.now])
12
+ scope :archive, where(['end_at < ?', Time.now])
13
+ scope :for_archive_list, where(['end_at < ?', Time.now.beginning_of_month])
14
+
15
+ scope :by_archive, lambda { |archive_date|
16
+ where(['start_at between ? and ?', archive_date.beginning_of_month, archive_date.end_of_month])
17
+ }
18
+
19
+ scope :by_year, lambda { |archive_year|
20
+ where(['start_at between ? and ?', archive_year.beginning_of_year, archive_year.end_of_year])
21
+ }
22
+
23
+ acts_as_indexed :fields => [:title, :venue_name, :venue_address, :ticket_link, :description]
24
+
25
+ validates :title, :presence => true, :uniqueness => true
26
+ validates :ticket_price, :numericality => true, :allow_blank => true
27
+ validates :ticket_link, :format => /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$/ix, :allow_blank => true
28
+ validate :ends_after_start
29
+
30
+ has_friendly_id :title, :use_slug => true
31
+
32
+ belongs_to :image
33
+
34
+ def current?
35
+ end_at >= Time.now
36
+ end
37
+
38
+ def upcoming?
39
+ start_at >= Time.now
40
+ end
41
+
42
+ def archived?
43
+ end_at < Time.now
44
+ end
45
+
46
+ def featured?
47
+ featured == true
48
+ end
49
+
50
+ def status
51
+ "current" if current?
52
+ "coming up" if upcoming?
53
+ "archived" if archived?
54
+ end
55
+
56
+ def next
57
+ Event.where(['end_at >= ? AND start_at > ?', Time.now, self.start_at]).first
58
+ end
59
+
60
+ def prev
61
+ Event.where(['end_at >= ? AND start_at < ?', Time.now, self.start_at]).reverse.first
62
+ end
63
+
64
+ private
65
+
66
+ def ends_after_start
67
+ start_at ||= Time.now
68
+ end_at ||= start_at.advance(:hours => 1)
69
+ errors.add(:base, "End at date must be after the start at date") if end_at < start_at
70
+ end
71
+
72
+ end
@@ -0,0 +1,4 @@
1
+ class EventCategorization < ActiveRecord::Base
2
+ belongs_to :event
3
+ belongs_to :event_category
4
+ end
@@ -0,0 +1,10 @@
1
+ class EventCategory < ActiveRecord::Base
2
+ default_scope order('name ASC')
3
+
4
+ has_many :event_categorizations
5
+ has_many :events, :through => :event_categorizations
6
+
7
+ validates :name, :presence => true
8
+
9
+ has_friendly_id :name, :use_slug => true
10
+ end
@@ -0,0 +1 @@
1
+ <%= render :partial => "sortable_list" %>
@@ -0,0 +1,18 @@
1
+ <li class='clearfix record <%= cycle("on", "on-hover") %>' id="<%= dom_id(event_category) -%>">
2
+ <span class='title'>
3
+ <%= event_category.name %>
4
+ <span class="preview"></span>
5
+ </span>
6
+ <span class='actions'>
7
+ <%= link_to refinery_icon_tag("application_go.png"), category_events_url(event_category),
8
+ :title => t('.view_live_html'),
9
+ :target => "_blank" %>
10
+ <%= link_to refinery_icon_tag("application_edit.png"), edit_admin_event_category_path(event_category),
11
+ :title => t('.edit') %>
12
+ <%= link_to refinery_icon_tag("delete.png"), admin_event_category_path(event_category),
13
+ :class => "cancel confirm-delete",
14
+ :title => t('.delete'),
15
+ :confirm => t('message', :scope => 'shared.admin.delete', :title => event_category.name),
16
+ :method => :delete %>
17
+ </span>
18
+ </li>
@@ -0,0 +1,26 @@
1
+ <%= form_for [:admin, @event_category] do |f| -%>
2
+ <%= render :partial => "/shared/admin/error_messages", :locals => {
3
+ :object => @event_category,
4
+ :include_object_name => true
5
+ } %>
6
+
7
+ <div class='field'>
8
+ <%= f.label :name -%>
9
+ <%= f.text_field :name, :class => 'larger widest' -%>
10
+ </div>
11
+
12
+ <%= render :partial => "/shared/admin/form_actions",
13
+ :locals => {
14
+ :f => f,
15
+ :continue_editing => false,
16
+ :delete_title => t('delete', :scope => 'admin.event_categories.event_category'),
17
+ :delete_confirmation => t('message', :scope => 'shared.admin.delete', :title => @event_category.name)
18
+ } %>
19
+ <% end -%>
20
+ <% content_for :javascripts do %>
21
+ <script>
22
+ $(document).ready(function(){
23
+ page_options.init(false, '', '');
24
+ });
25
+ </script>
26
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <ul id='sortable_list'>
2
+ <%= render :partial => 'event_category', :collection => @event_categories %>
3
+ </ul>
@@ -0,0 +1 @@
1
+ <%= render :partial => "form" %>
@@ -0,0 +1,40 @@
1
+ <div id='records'>
2
+ <% if searching? %>
3
+ <h2><%= t('results_for', :scope => 'shared.admin.search', :query => params[:search]) %></h2>
4
+ <% end %>
5
+ <% if @event_categories.any? %>
6
+ <div class='pagination_container'>
7
+ <%= render :partial => 'event_categories' %>
8
+ </div>
9
+ <% else %>
10
+ <p>
11
+ <% unless searching? %>
12
+ <strong>
13
+ <%= t('.no_items_yet') %>
14
+ </strong>
15
+ <% else %>
16
+ <%= t('no_results', :scope => 'shared.admin.search') %>
17
+ <% end %>
18
+ </p>
19
+ <% end %>
20
+ </div>
21
+ <div id='actions'>
22
+ <ul>
23
+ <% if Admin::EventCategoriesController.searchable? %>
24
+ <li>
25
+ <%= render :partial => "/shared/admin/search",
26
+ :locals => {
27
+ :url => admin_event_categories_url
28
+ } %>
29
+ </li>
30
+ <% end %>
31
+ <li>
32
+ <%= link_to t('.create_new'), new_admin_event_category_url,
33
+ :class => "add_icon" %>
34
+ </li>
35
+ <li>
36
+ <%= link_to "Manage Events", admin_events_url,
37
+ :class => "edit_icon" %>
38
+ </li>
39
+ </ul>
40
+ </div>
@@ -0,0 +1 @@
1
+ <%= render :partial => "form" %>
@@ -0,0 +1,18 @@
1
+ <li class='clearfix record <%= cycle("on", "on-hover") %>' id="<%= dom_id(event) -%>">
2
+ <span class='title'>
3
+ <%= event.title %>
4
+ <span class="preview">(<%= event.start_at.strftime('%b %d, %Y') %>) <%= '***Featured***' if event.featured? %></span>
5
+ </span>
6
+ <span class='actions'>
7
+ <%= link_to refinery_icon_tag("application_go.png"), event_url(event),
8
+ :title => t('.view_live_html'),
9
+ :target => "_blank" %>
10
+ <%= link_to refinery_icon_tag("application_edit.png"), edit_admin_event_path(event),
11
+ :title => t('.edit') %>
12
+ <%= link_to refinery_icon_tag("delete.png"), admin_event_path(event),
13
+ :class => "cancel confirm-delete",
14
+ :title => t('.delete'),
15
+ :confirm => t('message', :scope => 'shared.admin.delete', :title => event.title),
16
+ :method => :delete %>
17
+ </span>
18
+ </li>
@@ -0,0 +1 @@
1
+ <%= render :partial => "sortable_list" %>
@@ -0,0 +1,126 @@
1
+ <%= form_for [:admin, @event] do |f| -%>
2
+ <%= render :partial => "/shared/admin/error_messages", :locals => {
3
+ :object => @event,
4
+ :include_object_name => true
5
+ } %>
6
+
7
+ <div class='field'>
8
+ <%= f.label :title -%>
9
+ <%= f.text_field :title, :class => 'larger widest' -%>
10
+ </div>
11
+
12
+ <% if @event_categories.any? -%>
13
+ <div class='field'>
14
+ <h2>Categories</h2>
15
+ <ul class="check_box_list">
16
+ <% @event_categories.each do |category| -%>
17
+ <li>
18
+ <%= check_box_tag 'event[category_ids][]', category.id,
19
+ @event.categories.include?(category),
20
+ :id => (id="event_category_ids_#{category.id}") %>
21
+ <%= label_tag 'event[category_ids][]', category.name,
22
+ :class => 'stripped',
23
+ :for => id %>
24
+ </li>
25
+ <% end -%>
26
+ </ul>
27
+ </div>
28
+ <% end -%>
29
+
30
+ <div class='field'>
31
+ <%= f.label :start_at -%>
32
+ <%= f.datetime_select :start_at, :default => Time.now.change(:hour => 12, :minute => 0) -%>
33
+ </div>
34
+
35
+ <div class='field'>
36
+ <%= f.label :end_at -%>
37
+ <%= f.datetime_select :end_at, :default => Time.now.change(:hour => 13, :minute => 0) -%>
38
+ </div>
39
+
40
+ <div class='field'>
41
+ <div id='page-tabs' class='clearfix ui-tabs ui-widget ui-widget-content ui-corner-all'>
42
+ <ul id='page_parts'>
43
+ <% [:description].each_with_index do |part, part_index| %>
44
+ <li class='ui-state-default<%= ' ui-state-active' if part_index == 0 %>'>
45
+ <%= link_to part.to_s.titleize, "##{part}" %>
46
+ </li>
47
+ <% end %>
48
+ </ul>
49
+
50
+ <div id='page_part_editors'>
51
+ <% [:description].each do |part| %>
52
+ <div class='page_part' id='<%= part %>'>
53
+ <%= f.text_area part, :rows => 20, :class => 'wymeditor widest' -%>
54
+ </div>
55
+ <% end %>
56
+ </div>
57
+ </div>
58
+ </div>
59
+
60
+ <div class='field'>
61
+ <%= f.label :image -%>
62
+ <%= render :partial => "/shared/admin/image_picker", :locals => {
63
+ :f => f,
64
+ :field => :image_id,
65
+ :image => @event.image,
66
+ :toggle_image_display => false
67
+ } %>
68
+ </div>
69
+
70
+ <div class='field'>
71
+ <%= f.label :venue_name -%>
72
+ <%= f.text_field :venue_name -%>
73
+ </div>
74
+
75
+ <div class='field'>
76
+ <%= f.label :venue_address -%>
77
+ <%= f.text_field :venue_address, :class => 'larger wide' -%>
78
+ </div>
79
+
80
+ <div class='field'>
81
+ <%= f.label :ticket_price -%>
82
+ $<%= f.text_field :ticket_price, :size => 3 -%>
83
+ </div>
84
+
85
+ <div class='field'>
86
+ <%= f.label :ticket_link -%>
87
+ <%= f.text_field :ticket_link, :class => 'larger wide' -%>
88
+ </div>
89
+
90
+ <div class='field'>
91
+ <p><%= f.check_box :featured -%> <%= f.label :featured, "Featured event", :class => 'stripped' -%></p>
92
+ </div>
93
+
94
+ <%= render :partial => "/shared/admin/form_actions",
95
+ :locals => {
96
+ :f => f,
97
+ :continue_editing => false,
98
+ :delete_title => t('delete', :scope => 'admin.events.event'),
99
+ :delete_confirmation => t('message', :scope => 'shared.admin.delete', :title => @event.title)
100
+ } %>
101
+ <% end -%>
102
+ <% content_for :javascripts do %>
103
+ <script>
104
+ $(document).ready(function(){
105
+ page_options.init(false, '', '');
106
+ });
107
+ </script>
108
+ <% end %>
109
+
110
+ <% content_for :stylesheets do -%>
111
+ <style>
112
+ ul.check_box_list{
113
+ list-style:none;
114
+ margin:10px 0;
115
+ padding:5px;
116
+ border:1px solid #333;
117
+ overflow:auto;
118
+ height:200px;
119
+ width:300px;
120
+ }
121
+ ul.check_box_list li{
122
+ list-style:none;
123
+ margin:5px 0;
124
+ }
125
+ </style>
126
+ <% end -%>