radiant-event_calendar-extension 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitmodules +0 -0
- data/README.md +198 -0
- data/Rakefile +139 -0
- data/VERSION +1 -0
- data/app/controllers/admin/calendars_controller.rb +18 -0
- data/app/controllers/admin/event_venues_controller.rb +3 -0
- data/app/controllers/admin/events_controller.rb +9 -0
- data/app/controllers/admin/icals_controller.rb +26 -0
- data/app/controllers/events_controller.rb +201 -0
- data/app/models/calendar.rb +57 -0
- data/app/models/event.rb +409 -0
- data/app/models/event_calendar_page.rb +138 -0
- data/app/models/event_occurrence.rb +89 -0
- data/app/models/event_recurrence_rule.rb +85 -0
- data/app/models/event_venue.rb +17 -0
- data/app/models/ical.rb +132 -0
- data/app/views/admin/calendars/_actions.html.haml +6 -0
- data/app/views/admin/calendars/_form.html.haml +56 -0
- data/app/views/admin/calendars/edit.html.haml +11 -0
- data/app/views/admin/calendars/help.html.erb +22 -0
- data/app/views/admin/calendars/index.html.haml +60 -0
- data/app/views/admin/calendars/new.html.haml +10 -0
- data/app/views/admin/calendars/show.html.haml +36 -0
- data/app/views/admin/event_venues/_event_venue.html.haml +18 -0
- data/app/views/admin/event_venues/_form.html.haml +44 -0
- data/app/views/admin/event_venues/edit.html.haml +32 -0
- data/app/views/admin/event_venues/index.html.haml +33 -0
- data/app/views/admin/event_venues/new.html.haml +32 -0
- data/app/views/admin/event_venues/remove.html.haml +17 -0
- data/app/views/admin/events/_event.html.haml +47 -0
- data/app/views/admin/events/_form.html.haml +116 -0
- data/app/views/admin/events/_list_head.html.haml +18 -0
- data/app/views/admin/events/edit.html.haml +6 -0
- data/app/views/admin/events/index.html.haml +23 -0
- data/app/views/admin/events/new.html.haml +6 -0
- data/app/views/admin/events/remove.html.haml +17 -0
- data/app/views/admin/icals/refresh.html.haml +11 -0
- data/app/views/admin/icals/refresh_all.html.haml +0 -0
- data/app/views/events/_defacet.html.haml +2 -0
- data/app/views/events/_event.html.haml +29 -0
- data/app/views/events/_event_postscript.html.haml +0 -0
- data/app/views/events/_faceting.html.haml +27 -0
- data/app/views/events/_minicalendar.html.haml +49 -0
- data/app/views/events/_other_page_parts.html.haml +0 -0
- data/app/views/events/_views.html.haml +6 -0
- data/app/views/events/index.html.haml +56 -0
- data/app/views/events/index.ics.erb +7 -0
- data/app/views/events/index.rss.builder +20 -0
- data/config/routes.rb +13 -0
- data/db/migrate/001_create_calendar_and_events.rb +21 -0
- data/db/migrate/002_calendar_add_ical_url.rb +9 -0
- data/db/migrate/003_add_calendar_category.rb +9 -0
- data/db/migrate/004_add_slug.rb +9 -0
- data/db/migrate/005_add_subscription_refresh_history.rb +11 -0
- data/db/migrate/006_create_icals.rb +13 -0
- data/db/migrate/007_move_subscriptions_to_ical.rb +15 -0
- data/db/migrate/008_clean_out_calendar.rb +12 -0
- data/db/migrate/009_basic_authentication.rb +12 -0
- data/db/migrate/010_refresh_interval.rb +9 -0
- data/db/migrate/011_more_properties.rb +8 -0
- data/db/migrate/20090818133511_simpler_ical_columns.rb +17 -0
- data/db/migrate/20090819130919_ownership.rb +17 -0
- data/db/migrate/20090820073805_site_scope.rb +13 -0
- data/db/migrate/20091118100725_event_status.rb +9 -0
- data/db/migrate/20100216080944_more_event_data.rb +31 -0
- data/db/migrate/20100218131410_recurrence_parts.rb +19 -0
- data/db/migrate/20100219102227_venues_and_categories.rb +23 -0
- data/db/migrate/20100221180539_recurrence_rules.rb +34 -0
- data/db/migrate/20100222182112_occurrences.rb +13 -0
- data/event_calendar_extension.rb +32 -0
- data/lib/calendar_period.rb +151 -0
- data/lib/event_calendar_admin_ui.rb +78 -0
- data/lib/event_calendar_tags.rb +1021 -0
- data/lib/event_search.rb +22 -0
- data/lib/event_statuses.rb +24 -0
- data/lib/tasks/event_calendar_extension_tasks.rake +29 -0
- data/pkg/radiant-event_calendar-extension-1.0.0.gem +0 -0
- data/public/icals/blank +0 -0
- data/public/images/admin/calendar.png +0 -0
- data/public/images/event_calendar/calendarlinkbg.png +0 -0
- data/public/images/event_calendar/event_shadow.png +0 -0
- data/public/images/event_calendar/ical16.png +0 -0
- data/public/images/event_calendar/maplinkbg.png +0 -0
- data/public/images/event_calendar/one_event.png +0 -0
- data/public/images/event_calendar/several_events.png +0 -0
- data/public/javascripts/admin/event_calendar.js +240 -0
- data/public/stylesheets/sass/admin/event_calendar.sass +266 -0
- data/public/stylesheets/sass/admin/modules/_grid.sass +56 -0
- data/public/stylesheets/sass/constants.sass +80 -0
- data/public/stylesheets/sass/event_calendar.sass +203 -0
- data/radiant-event_calendar-extension.gemspec +166 -0
- data/spec/datasets/calendar_events_dataset.rb +43 -0
- data/spec/datasets/calendar_pages_dataset.rb +8 -0
- data/spec/datasets/calendar_sites_dataset.rb +6 -0
- data/spec/datasets/calendars_dataset.rb +34 -0
- data/spec/datasets/recurrence_dataset.rb +7 -0
- data/spec/files/dummy.ics +59 -0
- data/spec/files/ny.ics +36 -0
- data/spec/lib/event_calendar_page_spec.rb +24 -0
- data/spec/models/calendar_spec.rb +11 -0
- data/spec/models/event_spec.rb +98 -0
- data/spec/models/ical_spec.rb +63 -0
- data/spec/models/recurrence_rule_spec.rb +82 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +36 -0
- metadata +238 -0
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'rack/utils'
|
2
|
+
|
3
|
+
class EventCalendarPage < Page
|
4
|
+
include WillPaginate::ViewHelpers
|
5
|
+
|
6
|
+
attr_accessor :filters, :calendar_parameters, :calendar_filters, :calendar_year, :calendar_month, :calendar_page, :calendar_category, :calendar_slug, :calendar_period
|
7
|
+
|
8
|
+
description %{ Create a viewer for calendar data. }
|
9
|
+
|
10
|
+
def self.sphinx_indexes
|
11
|
+
[]
|
12
|
+
end
|
13
|
+
|
14
|
+
def cache?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def find_by_url(url, live = true, clean = false)
|
19
|
+
url = clean_url(url) if clean
|
20
|
+
my_url = self.url_without_parts
|
21
|
+
if url =~ /^#{Regexp.quote(my_url)}(.*)/
|
22
|
+
read_parameters($1)
|
23
|
+
self
|
24
|
+
else
|
25
|
+
super
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def read_parameters(path)
|
30
|
+
@calendar_parameters = []
|
31
|
+
unless path.blank?
|
32
|
+
parts = path.split(/\/+/)
|
33
|
+
@calendar_page = parts.pop if parts.last =~ /^\d{1,3}$/
|
34
|
+
@period = {}
|
35
|
+
parts.each do |part|
|
36
|
+
if part.match(/^\d\d\d\d$/)
|
37
|
+
@calendar_year = part
|
38
|
+
elsif part.match(/^\d+$/)
|
39
|
+
@calendar_day = part
|
40
|
+
elsif Date::MONTHNAMES.include?(part.titlecase)
|
41
|
+
@calendar_month = Date::MONTHNAMES.index(part.titlecase)
|
42
|
+
elsif Calendar.categories.include?(part)
|
43
|
+
@calendar_category = part
|
44
|
+
elsif Calendar.slugs.include?(part)
|
45
|
+
@calendar_slug = part
|
46
|
+
else
|
47
|
+
@calendar_parameters.push(part)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
if @calendar_year && @calendar_month
|
52
|
+
start = Date.civil(@calendar_year.to_i, @calendar_month.to_i)
|
53
|
+
@calendar_period = CalendarPeriod.between(start, start.to_datetime.end_of_month)
|
54
|
+
elsif calendar_year
|
55
|
+
start = Date.civil(@calendar_year.to_i)
|
56
|
+
@calendar_period = CalendarPeriod.between(start, start.to_datetime.end_of_year)
|
57
|
+
end
|
58
|
+
|
59
|
+
@calendar_parameters
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def calendar_set
|
64
|
+
if calendar_category and calendar_slug
|
65
|
+
calendars.in_category(calendar_category).with_slugs(calendar_slug)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def url_parts
|
70
|
+
{
|
71
|
+
:path => url_without_parts,
|
72
|
+
:day => @calendar_day,
|
73
|
+
:month => @calendar_month,
|
74
|
+
:year => @calendar_year,
|
75
|
+
:category => @calendar_category,
|
76
|
+
:slug => @calendar_slug
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
def url_with_parts(overrides={})
|
81
|
+
parts = url_parts.merge(overrides)
|
82
|
+
page = parts.delete(:page)
|
83
|
+
path = parts.delete(:path)
|
84
|
+
parts[:month] = month_names[parts[:month]].downcase unless parts[:month].blank? || parts[:month] =~ /[a-zA-Z]/
|
85
|
+
clean_url([path, parts.values, page].select{|p| !p.blank?}.join('/'))
|
86
|
+
end
|
87
|
+
alias_method_chain :url, :parts
|
88
|
+
|
89
|
+
def month_names
|
90
|
+
@month_names ||= Date::MONTHNAMES.dup
|
91
|
+
end
|
92
|
+
|
93
|
+
def day_names
|
94
|
+
unless @day_names
|
95
|
+
@day_names = Date::DAYNAMES.dup
|
96
|
+
@day_names.push(@day_names.shift) # Class::Date and ActiveSupport::CoreExtensions::Time::Calculations have different ideas of when is the start of the week. we've gone for the rails standard.
|
97
|
+
end
|
98
|
+
@day_names
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
desc %{
|
103
|
+
Renders a trail of breadcrumbs to the current page. On an event calendar page this tag is
|
104
|
+
overridden to show the filters applied to calendar data (including category, slug and date rage)
|
105
|
+
as well as the path to this page.
|
106
|
+
|
107
|
+
*Usage:*
|
108
|
+
|
109
|
+
<pre><code><r:breadcrumbs [separator="separator_string"] [nolinks="true"] /></code></pre>
|
110
|
+
}
|
111
|
+
tag 'breadcrumbs' do |tag|
|
112
|
+
page = tag.locals.page
|
113
|
+
nolinks = (tag.attr['nolinks'] == 'true')
|
114
|
+
|
115
|
+
if calendar_category
|
116
|
+
crumbs = nolinks ? [page.breadcrumb] : [%{<a href="#{url}">#{tag.render('breadcrumb')}</a>}]
|
117
|
+
if calendar_slug
|
118
|
+
crumbs << (nolinks ? calendar_category : %{<a href="#{url}/#{calendar_category}">#{calendar_category}</a>})
|
119
|
+
crumbs << calendar_slug
|
120
|
+
else
|
121
|
+
crumbs << calendar_category
|
122
|
+
end
|
123
|
+
else
|
124
|
+
crumbs = [page.breadcrumb]
|
125
|
+
end
|
126
|
+
page.ancestors.each do |ancestor|
|
127
|
+
tag.locals.page = ancestor
|
128
|
+
if nolinks
|
129
|
+
crumbs.unshift tag.render('breadcrumb')
|
130
|
+
else
|
131
|
+
crumbs.unshift %{<a href="#{tag.render('url')}">#{tag.render('breadcrumb')}</a>}
|
132
|
+
end
|
133
|
+
end
|
134
|
+
separator = tag.attr['separator'] || ' > '
|
135
|
+
crumbs.join(separator)
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
class EventOccurrence < ActiveRecord::Base
|
2
|
+
|
3
|
+
belongs_to :event
|
4
|
+
belongs_to :calendar # for efficient retrieval
|
5
|
+
belongs_to :event_venue # we can just grab occurrences
|
6
|
+
|
7
|
+
has_site if respond_to? :has_site
|
8
|
+
|
9
|
+
delegate :title, :description, :location, :postcode, :url, :keywords, :contact, :all_day, :one_day?, :within_day?, :to => :event
|
10
|
+
|
11
|
+
before_validation_on_create :set_defaults
|
12
|
+
|
13
|
+
named_scope :imported, { :conditions => ["status_id = ?", Status[:imported].to_s] }
|
14
|
+
named_scope :submitted, { :conditions => ["status_id = ?", Status[:submitted].to_s] }
|
15
|
+
named_scope :approved, { :conditions => ["status_id >= (?)", Status[:published].to_s] }
|
16
|
+
|
17
|
+
named_scope :in_calendars, lambda { |calendars| # list of calendar objects
|
18
|
+
ids = calendars.map{ |c| c.id }
|
19
|
+
{ :conditions => [ ids.map{"calendar_id = ?"}.join(" OR "), *ids] }
|
20
|
+
}
|
21
|
+
|
22
|
+
named_scope :after, lambda { |datetime| # datetime. eg calendar.occurrences.after(Time.now)
|
23
|
+
{ :conditions => ['start_date > ?', datetime] }
|
24
|
+
}
|
25
|
+
|
26
|
+
named_scope :before, lambda { |datetime| # datetime. eg calendar.occurrences.before(Time.now)
|
27
|
+
{ :conditions => ['start_date < ?', datetime] }
|
28
|
+
}
|
29
|
+
|
30
|
+
named_scope :between, lambda { |start, finish| # datetimable objects. eg. Event.between(reader.last_login, Time.now)
|
31
|
+
{ :conditions => ['(start_date < :finish AND end_date > :start) OR (end_date IS NULL AND start_date < :finish AND start_date > :start)', {:start => start, :finish => finish}] }
|
32
|
+
}
|
33
|
+
|
34
|
+
named_scope :within, lambda { |period| # seconds. eg calendar.occurrences.within(6.months)
|
35
|
+
start = Time.now
|
36
|
+
finish = start + period
|
37
|
+
between(start, finish)
|
38
|
+
}
|
39
|
+
|
40
|
+
named_scope :in_the_last, lambda { |period| # seconds. eg calendar.occurrences.in_the_last(1.week)
|
41
|
+
finish = Time.now
|
42
|
+
start = finish - period
|
43
|
+
between(start, finish)
|
44
|
+
}
|
45
|
+
|
46
|
+
named_scope :in_year, lambda { |year| # just a number. eg calendar.occurrences.in_year(2010)
|
47
|
+
start = DateTime.civil(year)
|
48
|
+
finish = start + 1.year
|
49
|
+
between(start, finish)
|
50
|
+
}
|
51
|
+
|
52
|
+
named_scope :in_month, lambda { |year, month| # numbers. eg calendar.occurrences.in_month(2010, 12)
|
53
|
+
start = DateTime.civil(year, month)
|
54
|
+
finish = start + 1.month
|
55
|
+
between(start, finish)
|
56
|
+
}
|
57
|
+
|
58
|
+
named_scope :in_week, lambda { |year, week| # numbers, with a commercial week: eg calendar.occurrences.in_week(2010, 35)
|
59
|
+
start = DateTime.commercial(year, week)
|
60
|
+
finish = start + 1.week
|
61
|
+
between(start, finish)
|
62
|
+
}
|
63
|
+
|
64
|
+
named_scope :on_day, lambda { |year, month, day| # numbers: eg calendar.occurrences.on_day(2010, 12, 12)
|
65
|
+
start = DateTime.civil(year, month, day)
|
66
|
+
finish = start + 1.day
|
67
|
+
between(start, finish)
|
68
|
+
}
|
69
|
+
|
70
|
+
def status
|
71
|
+
Status.find(self.status_id)
|
72
|
+
end
|
73
|
+
|
74
|
+
def status=(value)
|
75
|
+
self.status_id = value.id
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
|
80
|
+
# the default occurrence just echoes the event
|
81
|
+
# recurrences will override at least start_date.
|
82
|
+
|
83
|
+
def set_defaults
|
84
|
+
[:start_date, :end_date, :calendar_id, :event_venue_id, :status_id].each do |col|
|
85
|
+
self[col] ||= event.send(col)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
class EventRecurrenceRule < ActiveRecord::Base
|
2
|
+
include ActionView::Helpers::TextHelper
|
3
|
+
|
4
|
+
belongs_to :created_by, :class_name => 'User'
|
5
|
+
belongs_to :updated_by, :class_name => 'User'
|
6
|
+
belongs_to :event
|
7
|
+
has_site if respond_to? :has_site
|
8
|
+
|
9
|
+
def active
|
10
|
+
new_record? ? false : read_attribute(:active)
|
11
|
+
end
|
12
|
+
|
13
|
+
def basis
|
14
|
+
basis = read_attribute(:basis)
|
15
|
+
return nil unless basis == 'count' || basis == 'limit'
|
16
|
+
basis
|
17
|
+
end
|
18
|
+
|
19
|
+
def unbounded?
|
20
|
+
basis.nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
def single?
|
24
|
+
true if basis == 'limit' && limiting_count == 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
summary = []
|
29
|
+
if interval > 1
|
30
|
+
unit = period.downcase.sub(/ly$/, '')
|
31
|
+
unit = "day" if unit == 'dai'
|
32
|
+
summary << "every #{interval} #{unit.pluralize}"
|
33
|
+
else
|
34
|
+
summary << period.downcase
|
35
|
+
end
|
36
|
+
if unbounded?
|
37
|
+
summary.last << ","
|
38
|
+
summary << 'indefinitely'
|
39
|
+
elsif basis == 'limit' && limiting_date
|
40
|
+
summary << "until #{limiting_date.to_datetime.strftime('%d %B %Y')}" if limiting_date
|
41
|
+
elsif basis == 'count' && limiting_count
|
42
|
+
summary.last << ","
|
43
|
+
summary << "#{limiting_count} times"
|
44
|
+
end
|
45
|
+
summary.join(' ')
|
46
|
+
end
|
47
|
+
|
48
|
+
def rule=(rule)
|
49
|
+
rule = RiCal::PropertyValue::RecurrenceRule.convert(nil, rule) unless rule.is_a? RiCal::PropertyValue::RecurrenceRule
|
50
|
+
self.period = rule.freq
|
51
|
+
self.interval = rule.interval
|
52
|
+
if rule.until
|
53
|
+
self.basis = 'limit'
|
54
|
+
self.limiting_date = rule.until.value
|
55
|
+
elsif rule.count
|
56
|
+
self.basis = 'count'
|
57
|
+
self.limiting_count = rule.count
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def rule
|
62
|
+
rule = RiCal::PropertyValue::RecurrenceRule.convert(nil, "") unless rule.is_a? RiCal::PropertyValue::RecurrenceRule
|
63
|
+
rule.freq = period.upcase
|
64
|
+
rule.until = limiting_date if basis == 'limit' && limiting_date
|
65
|
+
rule.count = limiting_count if basis == 'count' && limiting_count
|
66
|
+
rule.interval = interval
|
67
|
+
rule
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.from(rule) # ical string or RiCal::PropertyValue::RecurrenceRule
|
71
|
+
rrule = self.new
|
72
|
+
rrule.rule = rule
|
73
|
+
rrule.active = true
|
74
|
+
rrule
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_ical
|
78
|
+
rule.to_ical
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class EventVenue < ActiveRecord::Base
|
2
|
+
has_many :events, :dependent => :nullify
|
3
|
+
has_site if respond_to? :has_site
|
4
|
+
validates_presence_of :title, :address
|
5
|
+
default_scope :order => 'title asc'
|
6
|
+
|
7
|
+
def to_s
|
8
|
+
%{#{title}, #{address}}
|
9
|
+
end
|
10
|
+
|
11
|
+
def location
|
12
|
+
address
|
13
|
+
end
|
14
|
+
def location=(location)
|
15
|
+
address = location
|
16
|
+
end
|
17
|
+
end
|
data/app/models/ical.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'net/http'
|
3
|
+
require 'ri_cal'
|
4
|
+
require 'date'
|
5
|
+
require 'ftools'
|
6
|
+
|
7
|
+
class Ical < ActiveRecord::Base
|
8
|
+
belongs_to :calendar
|
9
|
+
validates_presence_of :url
|
10
|
+
has_site if respond_to? :has_site
|
11
|
+
|
12
|
+
@@calendars_path = Radiant::Config["event_calendar.icals_path"]
|
13
|
+
|
14
|
+
def refresh
|
15
|
+
retrieve_file
|
16
|
+
parse_file
|
17
|
+
logger.info self.calendar.category + "/" + self.calendar.name + " - iCalendar subscription refreshed on " + Time.now.strftime("%m/%d at %H:%M")
|
18
|
+
end
|
19
|
+
|
20
|
+
def retrieve_file
|
21
|
+
File.makedirs filepath
|
22
|
+
begin
|
23
|
+
uri = URI.parse(url)
|
24
|
+
if authenticated?
|
25
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
26
|
+
http.use_ssl = uri.scheme == 'https'
|
27
|
+
req = Net::HTTP::Get.new(uri.path)
|
28
|
+
req.basic_auth username, password
|
29
|
+
response = http.request(req)
|
30
|
+
else
|
31
|
+
response = Net::HTTP.get_response(uri)
|
32
|
+
end
|
33
|
+
File.open(filename, "w") do |file|
|
34
|
+
file << response.body
|
35
|
+
end
|
36
|
+
rescue => error
|
37
|
+
logger.error "iCal url or file error with: #{self.calendar.name} - #{url} -> (#{filename}): #{error}."
|
38
|
+
raise
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_file(thisfile=filename)
|
43
|
+
begin
|
44
|
+
Ical.transaction do
|
45
|
+
self.last_refresh_count = 0
|
46
|
+
event_count = 0
|
47
|
+
File.open(thisfile, "r") do |file|
|
48
|
+
components = RiCal.parse(file)
|
49
|
+
cal = components.first
|
50
|
+
cal.events.each do |cal_event|
|
51
|
+
if event = Event.find_by_uuid(cal_event.uid)
|
52
|
+
if cal_event.dtstamp > event.updated_at
|
53
|
+
event.update_from(cal_event)
|
54
|
+
else
|
55
|
+
end
|
56
|
+
event_count += 1
|
57
|
+
else
|
58
|
+
event = Event.create_from(cal_event)
|
59
|
+
event.site = self.calendar.site if event.respond_to? :site=
|
60
|
+
self.calendar.events << event
|
61
|
+
event.save!
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
self.last_refresh_count = event_count
|
66
|
+
self.last_refresh_date = Time.now.utc
|
67
|
+
self.save!
|
68
|
+
end
|
69
|
+
rescue => error
|
70
|
+
logger.error "RiCal parse error with: #{self.calendar.name}: #{error}."
|
71
|
+
raise
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def filepath
|
76
|
+
File.join RAILS_ROOT, "public", ics_path
|
77
|
+
end
|
78
|
+
|
79
|
+
def filename
|
80
|
+
File.join filepath, ics_file
|
81
|
+
end
|
82
|
+
|
83
|
+
def ics_path
|
84
|
+
File.join @@calendars_path, self.calendar.category
|
85
|
+
end
|
86
|
+
|
87
|
+
def ics_file
|
88
|
+
"#{self.calendar.slug}.ics"
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_ics
|
92
|
+
File.join "", ics_path, ics_file
|
93
|
+
end
|
94
|
+
|
95
|
+
# I've changed this to make the ical refresh decision a simple yes or no
|
96
|
+
# and to make the refresh interval a global value
|
97
|
+
def refresh_interval
|
98
|
+
(Radiant::Config['event_calendar.refresh_interval'] || 3600).to_i.seconds
|
99
|
+
end
|
100
|
+
|
101
|
+
def refresh_automatically?
|
102
|
+
refresh_interval.nil? || refresh_interval.to_i != 0
|
103
|
+
end
|
104
|
+
|
105
|
+
def needs_refreshment?
|
106
|
+
last_refresh_date.nil? || Time.now > last_refresh_date + refresh_interval
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.check_refreshments
|
110
|
+
find(:all).each do |i|
|
111
|
+
i.refresh if i.refresh_automatically? && i.needs_refreshment?
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.refresh_all
|
116
|
+
find(:all).each do |i|
|
117
|
+
i.refresh
|
118
|
+
end
|
119
|
+
return true
|
120
|
+
end
|
121
|
+
|
122
|
+
protected
|
123
|
+
|
124
|
+
def authenticated?
|
125
|
+
!username.blank?
|
126
|
+
end
|
127
|
+
|
128
|
+
def secured?
|
129
|
+
url.match(/^https/)
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|