2015-09-09 06:52:05 +00:00
|
|
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
|
|
|
|
|
|
|
class Calendar < ApplicationModel
|
|
|
|
store :business_hours
|
|
|
|
store :public_holidays
|
|
|
|
|
2015-09-25 07:21:55 +00:00
|
|
|
before_create :validate_public_holidays, :fetch_ical
|
|
|
|
before_update :validate_public_holidays, :fetch_ical
|
2015-09-10 19:09:50 +00:00
|
|
|
after_create :sync_default, :min_one_check
|
|
|
|
after_update :sync_default, :min_one_check
|
|
|
|
after_destroy :min_one_check
|
|
|
|
|
2015-09-09 06:52:05 +00:00
|
|
|
=begin
|
|
|
|
|
2015-09-22 14:48:43 +00:00
|
|
|
set inital default calendar
|
|
|
|
|
|
|
|
calendar = Calendar.init_setup
|
|
|
|
|
|
|
|
returns calendar object
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.init_setup(ip = nil)
|
|
|
|
|
|
|
|
# call for calendar suggestion
|
|
|
|
calendar_details = Service::GeoCalendar.location(ip)
|
|
|
|
return if !calendar_details
|
|
|
|
|
|
|
|
calendar_details['name'] = Calendar.genrate_uniq_name(calendar_details['name'])
|
|
|
|
calendar_details['default'] = true
|
|
|
|
calendar_details['created_by_id'] = 1
|
|
|
|
calendar_details['updated_by_id'] = 1
|
|
|
|
|
|
|
|
# find if auto generated calendar exists
|
|
|
|
calendar = Calendar.find_by(default: true, updated_by_id: 1, created_by_id: 1)
|
|
|
|
if calendar
|
|
|
|
calendar.update_attributes(calendar_details)
|
|
|
|
return calendar
|
|
|
|
end
|
|
|
|
create(calendar_details)
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
2015-09-09 06:52:05 +00:00
|
|
|
get default calendar
|
|
|
|
|
|
|
|
calendar = Calendar.default
|
|
|
|
|
|
|
|
returns calendar object
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.default
|
|
|
|
find_by(default: true)
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
returnes preset of ical feeds
|
|
|
|
|
|
|
|
feeds = Calendar.ical_feeds
|
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
{
|
2015-09-22 20:29:37 +00:00
|
|
|
'US' => 'http://www.google.com/calendar/ical/en.usa%23holiday%40group.v.calendar.google.com/public/basic.ics',
|
2015-09-09 06:52:05 +00:00
|
|
|
...
|
|
|
|
}
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.ical_feeds
|
|
|
|
gfeeds = {
|
2015-09-25 07:21:55 +00:00
|
|
|
'Australia' => 'en.australian',
|
|
|
|
'Austria' => 'de.austrian',
|
2015-09-22 20:29:37 +00:00
|
|
|
'Argentina' => 'en.ar',
|
|
|
|
'Bahamas' => 'en.bs',
|
|
|
|
'Belarus' => 'en.by',
|
2015-09-25 07:21:55 +00:00
|
|
|
'Brazil' => 'en.brazilian',
|
2015-09-22 20:29:37 +00:00
|
|
|
'Bulgaria' => 'en.bulgarian',
|
2015-09-25 07:21:55 +00:00
|
|
|
'Canada' => 'en.canadian',
|
2015-09-22 20:29:37 +00:00
|
|
|
'China' => 'en.china',
|
|
|
|
'Chile' => 'en.cl',
|
|
|
|
'Costa Rica' => 'en.cr',
|
|
|
|
'Colombia' => 'en.co',
|
|
|
|
'Croatia' => 'en.croatian',
|
|
|
|
'Cuba' => 'en.cu',
|
|
|
|
'Cyprus' => 'de.cy',
|
|
|
|
'Switzerland' => 'de.ch',
|
2015-09-25 07:21:55 +00:00
|
|
|
'Denmark' => 'da.danish',
|
|
|
|
'Netherlands' => 'nl.dutch',
|
2015-09-22 20:29:37 +00:00
|
|
|
'Egypt' => 'en.eg',
|
|
|
|
'Ethiopia' => 'en.et',
|
|
|
|
'Ecuador' => 'en.ec',
|
|
|
|
'Estonia' => 'en.ee',
|
2015-09-25 07:21:55 +00:00
|
|
|
'Finland' => 'en.finnish',
|
|
|
|
'France' => 'en.french',
|
|
|
|
'Germany' => 'de.german',
|
|
|
|
'Greece' => 'en.greek',
|
2015-09-22 20:29:37 +00:00
|
|
|
'Ghana' => 'en.gh',
|
|
|
|
'Hong Kong' => 'en.hong_kong',
|
|
|
|
'Haiti' => 'en.ht',
|
|
|
|
'Hungary' => 'en.hungarian',
|
2015-09-25 07:21:55 +00:00
|
|
|
'India' => 'en.indian',
|
|
|
|
'Indonesia' => 'en.indonesian',
|
|
|
|
'Iran' => 'en.ir',
|
|
|
|
'Ireland' => 'en.irish',
|
|
|
|
'Italy' => 'it.italian',
|
2015-09-22 20:29:37 +00:00
|
|
|
'Israel' => 'en.jewish',
|
2015-09-25 07:21:55 +00:00
|
|
|
'Japan' => 'en.japanese',
|
2015-09-22 20:29:37 +00:00
|
|
|
'Kuwait' => 'en.kw',
|
|
|
|
'Latvia' => 'en.latvian',
|
|
|
|
'Liechtenstein' => 'en.li',
|
|
|
|
'Lithuania' => 'en.lithuanian',
|
|
|
|
'Luxembourg' => 'en.lu',
|
2015-09-25 07:21:55 +00:00
|
|
|
'Malaysia' => 'en.malaysia',
|
|
|
|
'Mexico' => 'en.mexican',
|
2015-09-22 20:29:37 +00:00
|
|
|
'Morocco' => 'en.ma',
|
|
|
|
'Mauritius' => 'en.mu',
|
|
|
|
'Moldova' => 'en.md',
|
|
|
|
'New Zealand' => 'en.new_zealand',
|
2015-09-25 07:21:55 +00:00
|
|
|
'Norway' => 'en.norwegian',
|
2015-09-22 20:29:37 +00:00
|
|
|
'Philippines' => 'en.philippines',
|
2015-09-25 07:21:55 +00:00
|
|
|
'Poland' => 'en.polish',
|
|
|
|
'Portugal' => 'en.portuguese',
|
2015-09-22 20:29:37 +00:00
|
|
|
'Pakistan' => 'en.pk',
|
2015-09-25 07:21:55 +00:00
|
|
|
'Russia' => 'en.russian',
|
2015-09-22 20:29:37 +00:00
|
|
|
'Senegal' => 'en.sn',
|
|
|
|
'Singapore' => 'en.singapore',
|
|
|
|
'South Africa' => 'en.sa',
|
|
|
|
'South Korean' => 'en.south_korea',
|
|
|
|
'Spain' => 'en.spain',
|
|
|
|
'Slovakia' => 'en.slovak',
|
|
|
|
'Serbia' => 'en.rs',
|
|
|
|
'Slovenia' => 'en.slovenian',
|
2015-09-25 07:21:55 +00:00
|
|
|
'Sweden' => 'en.swedish',
|
2015-09-22 20:29:37 +00:00
|
|
|
'Taiwan' => 'en.taiwan',
|
|
|
|
'Thai' => 'en.th',
|
|
|
|
'Turkey' => 'en.turkish',
|
|
|
|
'UK' => 'en.uk',
|
|
|
|
'US' => 'en.usa',
|
|
|
|
'Ukraine' => 'en.ukrainian',
|
|
|
|
'Uruguay' => 'en.uy',
|
2015-09-25 07:21:55 +00:00
|
|
|
'Vietnam' => 'en.vietnamese',
|
2015-09-22 20:29:37 +00:00
|
|
|
'Venezuela' => 'en.ve',
|
2015-09-09 06:52:05 +00:00
|
|
|
}
|
2015-09-16 08:40:18 +00:00
|
|
|
all_feeds = {}
|
2015-09-09 06:52:05 +00:00
|
|
|
gfeeds.each {|key, name|
|
2015-09-25 07:21:55 +00:00
|
|
|
all_feeds["http://www.google.com/calendar/ical/#{name}%23holiday%40group.v.calendar.google.com/public/basic.ics"] = key
|
2015-09-09 06:52:05 +00:00
|
|
|
}
|
2015-09-16 08:40:18 +00:00
|
|
|
all_feeds
|
2015-09-09 06:52:05 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
get list of available timezones and UTC offsets
|
|
|
|
|
|
|
|
list = Calendar.timezones
|
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
{
|
|
|
|
'America/Los_Angeles' => -7
|
|
|
|
...
|
|
|
|
}
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.timezones
|
|
|
|
list = {}
|
|
|
|
TZInfo::Timezone.all_country_zone_identifiers.each { |timezone|
|
|
|
|
t = TZInfo::Timezone.get(timezone)
|
|
|
|
diff = t.current_period.utc_total_offset / 60 / 60
|
|
|
|
list[ timezone ] = diff
|
|
|
|
}
|
|
|
|
list
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
syn all calendars with ical feeds
|
|
|
|
|
|
|
|
success = Calendar.sync
|
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
true # or false
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.sync
|
|
|
|
Calendar.all.each(&:sync)
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
syn one calendars with ical feed
|
|
|
|
|
|
|
|
calendar = Calendar.find(4711)
|
|
|
|
success = calendar.sync
|
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
true # or false
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
2015-09-23 07:10:07 +00:00
|
|
|
def sync(without_save = nil)
|
2015-09-09 06:52:05 +00:00
|
|
|
return if !ical_url
|
2015-09-23 07:10:07 +00:00
|
|
|
begin
|
|
|
|
events = Calendar.parse(ical_url)
|
2015-09-09 06:52:05 +00:00
|
|
|
|
2015-09-23 07:10:07 +00:00
|
|
|
# sync with public_holidays
|
|
|
|
if !public_holidays
|
|
|
|
self.public_holidays = {}
|
2015-09-09 06:52:05 +00:00
|
|
|
end
|
2015-09-25 07:21:55 +00:00
|
|
|
|
|
|
|
# remove old ical entries if feed has changed
|
|
|
|
public_holidays.each {|day, meta|
|
|
|
|
next if !public_holidays[day]['feed']
|
|
|
|
next if meta['feed'] == Digest::MD5.hexdigest(ical_url)
|
|
|
|
public_holidays.delete(day)
|
|
|
|
}
|
|
|
|
|
|
|
|
# sync new ical feed dates
|
2015-09-23 07:10:07 +00:00
|
|
|
events.each {|day, summary|
|
|
|
|
if !public_holidays[day]
|
|
|
|
public_holidays[day] = {}
|
|
|
|
end
|
|
|
|
|
|
|
|
# ignore if already added or changed
|
|
|
|
next if public_holidays[day].key?('active')
|
|
|
|
|
|
|
|
# create new entry
|
|
|
|
public_holidays[day] = {
|
|
|
|
active: true,
|
|
|
|
summary: summary,
|
2015-09-25 07:21:55 +00:00
|
|
|
feed: Digest::MD5.hexdigest(ical_url)
|
2015-09-23 07:10:07 +00:00
|
|
|
}
|
2015-09-09 06:52:05 +00:00
|
|
|
}
|
2015-09-23 07:10:07 +00:00
|
|
|
self.last_log = nil
|
|
|
|
rescue => e
|
|
|
|
self.last_log = e.inspect
|
|
|
|
end
|
|
|
|
|
2015-09-09 06:52:05 +00:00
|
|
|
self.last_sync = Time.zone.now
|
2015-09-23 07:10:07 +00:00
|
|
|
if !without_save
|
|
|
|
save
|
|
|
|
end
|
2015-09-09 06:52:05 +00:00
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.parse(location)
|
|
|
|
if location =~ /^http/i
|
|
|
|
result = UserAgent.get(location)
|
2015-09-23 07:10:07 +00:00
|
|
|
if !result.success?
|
|
|
|
fail result.error
|
|
|
|
end
|
2015-09-09 06:52:05 +00:00
|
|
|
cal_file = result.body
|
|
|
|
else
|
|
|
|
cal_file = File.open(location)
|
|
|
|
end
|
|
|
|
|
|
|
|
cals = Icalendar.parse(cal_file)
|
|
|
|
cal = cals.first
|
|
|
|
events = {}
|
|
|
|
cal.events.each {|event|
|
|
|
|
next if event.dtstart < Time.zone.now - 1.year
|
|
|
|
next if event.dtstart > Time.zone.now + 3.year
|
|
|
|
day = "#{event.dtstart.year}-#{format('%02d', event.dtstart.month)}-#{format('%02d', event.dtstart.day)}"
|
|
|
|
comment = event.summary || event.description
|
|
|
|
comment = Encode.conv( 'utf8', comment.to_s.force_encoding('utf-8') )
|
|
|
|
if !comment.valid_encoding?
|
|
|
|
comment = comment.encode('utf-8', 'binary', invalid: :replace, undef: :replace, replace: '?')
|
|
|
|
end
|
2015-09-16 08:40:18 +00:00
|
|
|
|
|
|
|
# ignore daylight saving time entries
|
|
|
|
next if comment =~ /(daylight saving|sommerzeit|summertime)/i
|
2015-09-09 06:52:05 +00:00
|
|
|
events[day] = comment
|
|
|
|
}
|
|
|
|
events.sort.to_h
|
|
|
|
end
|
2015-09-10 19:09:50 +00:00
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
# if changed calendar is default, set all others default to false
|
|
|
|
def sync_default
|
|
|
|
return if !default
|
|
|
|
Calendar.all.each {|calendar|
|
|
|
|
next if calendar.id == id
|
|
|
|
next if !calendar.default
|
|
|
|
calendar.default = false
|
|
|
|
calendar.save
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
# check if min one is set to default true
|
|
|
|
def min_one_check
|
|
|
|
Calendar.all.each {|calendar|
|
2015-09-11 08:46:53 +00:00
|
|
|
return true if calendar.default
|
2015-09-10 19:09:50 +00:00
|
|
|
}
|
2015-09-11 08:34:18 +00:00
|
|
|
first = Calendar.order(:created_at, :id).limit(1).first
|
2015-09-10 19:09:50 +00:00
|
|
|
first.default = true
|
|
|
|
first.save
|
2015-09-22 23:22:45 +00:00
|
|
|
|
|
|
|
# check if sla's are refer to an existing calendar
|
|
|
|
Sla.all.each {|sla|
|
|
|
|
if !sla.calendar_id
|
|
|
|
sla.calendar_id = first.id
|
|
|
|
sla.save
|
|
|
|
next
|
|
|
|
end
|
|
|
|
if !Calendar.find_by(id: sla.calendar_id)
|
|
|
|
sla.calendar_id = first.id
|
|
|
|
sla.save
|
|
|
|
end
|
|
|
|
}
|
2015-09-10 19:09:50 +00:00
|
|
|
end
|
2015-09-23 07:10:07 +00:00
|
|
|
|
|
|
|
# fetch ical feed
|
|
|
|
def fetch_ical
|
|
|
|
sync(true)
|
|
|
|
end
|
2015-09-25 07:21:55 +00:00
|
|
|
|
|
|
|
# validate format of public holidays
|
|
|
|
def validate_public_holidays
|
|
|
|
|
|
|
|
# fillup feed info
|
|
|
|
public_holidays.each {|day, meta|
|
|
|
|
if public_holidays_was && public_holidays_was[day] && public_holidays_was[day]['feed']
|
|
|
|
meta['feed'] = public_holidays_was[day]['feed']
|
|
|
|
end
|
|
|
|
if meta['active']
|
|
|
|
meta['active'] = true
|
|
|
|
else
|
|
|
|
meta['active'] = false
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
end
|
2015-09-09 06:52:05 +00:00
|
|
|
end
|