refinerycms-calendar 1.0

Sign up to get free protection for your applications and to get access to all the features.
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 -%>