411 lines
14 KiB
Ruby
411 lines
14 KiB
Ruby
require 'time'
|
|
require 'date'
|
|
|
|
class Event
|
|
include Mongoid::Document
|
|
include Mongoid::Timestamps
|
|
include OrbitTag::Taggable
|
|
# include Mongoid::MultiParameterAttributes
|
|
|
|
field :title
|
|
field :note
|
|
field :title_translations,type: Hash, default: {}
|
|
field :note_translations,type: Hash, default: {}
|
|
field :start, type: DateTime
|
|
field :end, type: DateTime
|
|
field :all_day, type: Boolean, default: false
|
|
field :recurring, type: Boolean, default: false
|
|
field :frequency
|
|
field :period
|
|
field :weekdays, type: Array, default: []
|
|
field :recurring_end_date, type: DateTime
|
|
field :create_user_id
|
|
field :update_user_id
|
|
field :module_key
|
|
field :model_cat
|
|
field :model_page_id
|
|
field :model_tags, type: Array, default: []
|
|
field :is_weekdays, type: Boolean, default: false
|
|
belongs_to :calendar_type
|
|
field :url
|
|
field :url_translations, type: Hash, default: {}
|
|
field :hide_start, type: Array, default: [] # store date string, ex: ["2022-07-29"]
|
|
def get_module_url
|
|
page = !self.model_page_id.blank? ? Page.find(self.model_page_id): Page.where(:module => self.module_key).where(:categories.in => Array(self.model_cat)+[[]],:tags.in=>Array(self.model_tags)+[[]]).first
|
|
page.nil? ? '' : (page.url+'/'+eval(self.model_class).where(:id=>self.model_id).first.to_calendar_param)
|
|
end
|
|
def url_to_fronted
|
|
tmp_url = self.url
|
|
tmp_url.blank? ? (self.model_class.blank? ? '' : (self.get_module_url rescue '')) : tmp_url
|
|
end
|
|
attr_accessor :agenda_start, :agenda_end, :get_agenda_events
|
|
|
|
#let other model can connect to this model
|
|
field :key
|
|
field :model_class
|
|
field :model_id
|
|
before_destroy do
|
|
if !self.model_class.blank?
|
|
m = eval(self.model_class).where(id: self.model_id).first rescue nil
|
|
if !m.nil?
|
|
if self.key.nil?
|
|
m.event_id = nil
|
|
m.add_to_calendar = false
|
|
else
|
|
m.calendar_dict.delete(self.key)
|
|
if !m['calendar_data'].nil?
|
|
tmp = m['calendar_data']
|
|
tmp['key'] = Array(tmp['key']) - [self.key]
|
|
m['calendar_data'] = tmp
|
|
end
|
|
end
|
|
m.save
|
|
end
|
|
end
|
|
end
|
|
before_save do
|
|
self['title'] = self.title
|
|
self['note'] = self.note
|
|
self['url'] = self.url
|
|
if self.hide_start_changed?
|
|
self.hide_start.sort!
|
|
end
|
|
if self.is_weekdays
|
|
self.weekdays = (1..5).to_a #平日
|
|
else
|
|
self.weekdays = self.weekdays.map{|s| s.to_i}.sort
|
|
end
|
|
true
|
|
end
|
|
########################################
|
|
validates_presence_of :title, :message => "Please fill the title of the Event", :if => lambda { self['title_translations'].blank? }
|
|
validates_presence_of :title_translations, :message => "Please fill the title of the Event", :if => lambda { self['title'].blank? }
|
|
def title(locale=I18n.locale)
|
|
tp = self['title_translations'][locale] rescue nil
|
|
tp.nil? ? self['title'] : tp
|
|
end
|
|
def note(locale=I18n.locale)
|
|
tp = self['note_translations'][locale]
|
|
tp.nil? ? self['note'] : tp
|
|
end
|
|
def url(locale=I18n.locale)
|
|
tp = self['url_translations'][locale]
|
|
tp.nil? ? self['url'] : tp
|
|
end
|
|
def self.with_categories(cat_ids=[])
|
|
if cat_ids.blank?
|
|
self.all
|
|
else
|
|
self.where(:calendar_type_id.in => cat_ids)
|
|
end
|
|
end
|
|
def bulletin
|
|
model_class=='Bulletin' ? (Bulletin.find(self.model_id) rescue nil) : nil
|
|
end
|
|
def self.format_date(date_time)
|
|
Time.at(date_time.to_i).to_formatted_s(:db)
|
|
end
|
|
|
|
REPEATS = [
|
|
"Daily" ,
|
|
"Weekly" ,
|
|
"Monthly" ,
|
|
"Yearly"
|
|
]
|
|
|
|
def as_json(options = {}, preserve_hide = false)
|
|
tmp_note = self.note || ""
|
|
if self.recurring
|
|
freq = self.frequency.to_i
|
|
if @week_titles.nil?
|
|
@week_titles = CalendarSetting.first.week_title
|
|
@weekdayst = I18n.t("calendar.weekdays")
|
|
@dailyt = I18n.t("calendar.daily")
|
|
@weeklyt = I18n.t("calendar.weekly")
|
|
@monthlyt = I18n.t("calendar.monthly")
|
|
@yearlyt = I18n.t("calendar.yearly")
|
|
@conjt = I18n.t('calendar.conj')
|
|
@andt = I18n.t('calendar.and')
|
|
end
|
|
case self.period
|
|
when 'Daily'
|
|
every_n_days = (freq == 1 ? @dailyt : I18n.t("calendar.every_n_days", {:num=>self.frequency}))
|
|
tmp_note = every_n_days + "<br>" + tmp_note
|
|
when 'Weekly'
|
|
if self.is_weekdays
|
|
days = @weekdayst
|
|
elsif self.weekdays.present?
|
|
days = self.weekdays.map{|i| @week_titles[i]}
|
|
if days.count > 1
|
|
days = days[0...-1].join(@conjt) + @andt + days[-1]
|
|
else
|
|
days = days[0]
|
|
end
|
|
end
|
|
every_n_weeks = (freq == 1 ? @weeklyt : I18n.t("calendar.every_n_weeks", {:num=>self.frequency}))
|
|
tmp_note = I18n.t("calendar.every_week_day", {:every_n_weeks=>every_n_weeks,:days=>days}) + "<br>" + tmp_note
|
|
when 'Monthly'
|
|
days = self.start.day
|
|
every_n_months = (freq == 1 ? @monthlyt : I18n.t("calendar.every_n_months", {:num=>self.frequency}))
|
|
tmp_note = I18n.t("calendar.every_month_day", {:every_n_months=>every_n_months,:days=>days}) + "<br>" + tmp_note
|
|
when 'Yearly'
|
|
date = self.start.strftime('%m/%d')
|
|
every_n_years = (freq == 1 ? @yearlyt : I18n.t("calendar.every_n_years", {:num=>self.frequency}))
|
|
tmp_note = I18n.t("calendar.every_year_day", {:every_n_years=>every_n_years,:date=>date}) + "<br>" + tmp_note
|
|
end
|
|
end
|
|
hide = false
|
|
if options["frontend"]
|
|
if (self.recurring && self.hide_start.include?(self.start))
|
|
hide = true
|
|
nil
|
|
else
|
|
{
|
|
:id => self.id.to_s,
|
|
:title => self.title,
|
|
:note => tmp_note,
|
|
:start => self.start.to_json.gsub('"',''),
|
|
:end => self.end.to_json.gsub('"',''),
|
|
:allDay => self.all_day,
|
|
:recurring => self.recurring,
|
|
:calendar => self.calendar_type_id.to_s,
|
|
:color => (self.calendar_type.color rescue nil),
|
|
:diff_day => self.all_day,
|
|
:url_linked => self.url
|
|
}
|
|
end
|
|
else
|
|
need_hide = (self.recurring && self.hide_start.include?(self.start.strftime("%Y-%m-%d")))
|
|
unless preserve_hide
|
|
hide = need_hide
|
|
end
|
|
if hide
|
|
nil
|
|
else
|
|
org_color = (self.calendar_type.color rescue nil)
|
|
{
|
|
:id => self.id.to_s,
|
|
:title => self.title,
|
|
:note => tmp_note,
|
|
:start => self.start.to_json.gsub('"',''),
|
|
:end => self.end.to_json.gsub('"',''),
|
|
:allDay => self.all_day,
|
|
:recurring => self.recurring,
|
|
:calendar => self.calendar_type_id.to_s,
|
|
:color => (need_hide ? "#c0c0c0" : org_color),
|
|
:diff_day => self.all_day,
|
|
:edit_url => Rails.application.routes.url_helpers.edit_admin_calendar_path(:locale=>I18n.locale, :id=>self.id),
|
|
:delete_url => Rails.application.routes.url_helpers.admin_calendar_path(:locale=>I18n.locale, :id=>self.id),
|
|
:url_linked => self.url,
|
|
:hide => need_hide,
|
|
:org_color => org_color,
|
|
:hide_color => "#c0c0c0"
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.monthly_event(start_date,end_date)
|
|
self.any_of({:start.lte => start_date,:end.gte => start_date},{:start.gte => start_date,:end.lte => end_date},{:start.lte => end_date,:end.gte => end_date}).asc(:start)
|
|
end
|
|
def self.convert_front(preserve_hide=false)
|
|
self.all.collect do |re|
|
|
re.as_json({}, preserve_hide)
|
|
end.compact
|
|
end
|
|
def self.get_diff_month(date1,date2)
|
|
(date2.year-date1.year)*12+(date2.month-date1.month)
|
|
end
|
|
def self.recurring_event(start_date, end_date, preserve_hide=false)
|
|
@recurring_events = self.where(:recurring => true).any_of({:recurring_end_date=>nil}, {:recurring_end_date.gte=>start_date.utc})
|
|
@recurring = []
|
|
start_date_utc_mjd = start_date.to_datetime.new_offset(0).mjd
|
|
@recurring_events.each do |re|
|
|
has_recurring_end_date = re.recurring_end_date.present?
|
|
data = re.as_json({}, true)
|
|
period_str = nil
|
|
is_month = false
|
|
is_year = false
|
|
days = 1
|
|
interval = nil
|
|
weekdays = nil
|
|
if re.period == 'Daily'
|
|
period_str = 'day'
|
|
interval = 1.day
|
|
elsif re.period == 'Weekly'
|
|
period_str = 'week'
|
|
days = 7
|
|
interval = 1.week
|
|
weekdays = re.weekdays
|
|
weekdays = nil if weekdays.blank?
|
|
elsif re.period == 'Monthly'
|
|
period_str = 'month'
|
|
is_month = true
|
|
days = 30
|
|
elsif re.period == 'Yearly'
|
|
period_str = 'year'
|
|
is_year = true
|
|
days = 365
|
|
end
|
|
if period_str
|
|
org_start = re.start
|
|
@start_date = re.start
|
|
@end_date = re.end
|
|
freq = re.frequency.to_i
|
|
interval = freq.send(period_str)
|
|
tmp_hide_start = re.hide_start.clone
|
|
if is_month
|
|
add_interval = ((start_date.year * 12 + start_date.month) - (@start_date.year * 12 + @start_date.month))
|
|
add_interval = 0 if add_interval < 0
|
|
elsif is_year
|
|
add_interval = (start_date.year - @start_date.year)
|
|
add_interval = 0 if add_interval < 0
|
|
else
|
|
add_interval = (start_date_utc_mjd - @start_date.new_offset(0).mjd)
|
|
if add_interval < 0
|
|
add_interval = 0
|
|
else
|
|
add_interval = add_interval / days
|
|
end
|
|
end
|
|
rest = add_interval % freq
|
|
if rest != 0
|
|
add_interval += (freq - rest)
|
|
end
|
|
add_interval = add_interval.send(period_str)
|
|
need_check_start = false
|
|
if weekdays
|
|
add_interval -= @start_date.wday.day
|
|
need_check_start = true
|
|
end
|
|
tmp_start_date = [start_date, @start_date].max
|
|
@start_date += add_interval
|
|
if @end_date
|
|
@end_date += add_interval
|
|
end
|
|
new_end_date = has_recurring_end_date ? [re.recurring_end_date,end_date].min : end_date
|
|
need_check_hide = false
|
|
if tmp_hide_start.count != 0
|
|
tmp = @start_date.strftime("%Y-%m-%d")
|
|
st_idx = tmp_hide_start.index{|s| s >= tmp}
|
|
if st_idx.nil?
|
|
tmp_hide_start = []
|
|
else
|
|
tmp_hide_start = tmp_hide_start[st_idx..-1]
|
|
end
|
|
need_check_hide = true
|
|
else
|
|
need_check_hide = false
|
|
end
|
|
while @start_date <= new_end_date do
|
|
if weekdays
|
|
if need_check_hide
|
|
tmp_hide_start2 = tmp_hide_start[0..-1] #clone array
|
|
end_check = (@start_date + 6.day).strftime("%Y-%m-%d")
|
|
last_idx = tmp_hide_start2.index{|s| s > end_check}
|
|
if last_idx
|
|
tmp_hide_start2 = tmp_hide_start2[0...last_idx]
|
|
tmp_hide_start = tmp_hide_start[last_idx..-1]
|
|
need_check_hide = tmp_hide_start.count != 0
|
|
end
|
|
else
|
|
tmp_hide_start2 = []
|
|
end
|
|
weekdays.each do |w|
|
|
new_start = (@start_date + w.day)
|
|
if need_check_start && new_start < tmp_start_date
|
|
next
|
|
end
|
|
if new_start != org_start
|
|
new_end = @end_date ? @end_date + w.day : nil
|
|
hide = need_check_hide && tmp_hide_start2.include?(new_start.strftime("%Y-%m-%d"))
|
|
if hide
|
|
if preserve_hide
|
|
@recurring << data.merge({:start => new_start.to_json.gsub('"',''), :end => new_end.to_json.gsub('"',''), :hide=>true, :color=>"#c0c0c0"})
|
|
end
|
|
else
|
|
@recurring << data.merge({:start => new_start.to_json.gsub('"',''), :end => new_end.to_json.gsub('"',''), :hide=>false, :color => data[:org_color]})
|
|
end
|
|
end
|
|
end
|
|
need_check_start = false
|
|
else
|
|
if @start_date != org_start
|
|
hide = need_check_hide && tmp_hide_start.include?(@start_date.strftime("%Y-%m-%d"))
|
|
if hide
|
|
if preserve_hide
|
|
@recurring << data.merge({:start => @start_date.to_json.gsub('"',''), :end => @end_date.to_json.gsub('"',''), :hide=>true, :color=>"#c0c0c0"})
|
|
end
|
|
else
|
|
@recurring << data.merge({:start => @start_date.to_json.gsub('"',''), :end => @end_date.to_json.gsub('"',''), :hide=>false, :color => data[:org_color]})
|
|
end
|
|
end
|
|
end
|
|
@start_date += interval
|
|
if @end_date
|
|
@end_date += interval
|
|
end
|
|
end
|
|
else
|
|
next
|
|
end
|
|
end
|
|
|
|
@recurring
|
|
end
|
|
|
|
def self.agenda_events(agenda_start, agenda_end, preserve_hide=false)
|
|
recurring = self.recurring_event(agenda_start,agenda_end, preserve_hide)
|
|
events = self.monthly_event(agenda_start, agenda_end).convert_front(preserve_hide)
|
|
recurring = recurring.concat(events)
|
|
recurring
|
|
end
|
|
def self.convertToText(str)
|
|
# Ensure string.
|
|
value = str.to_s
|
|
|
|
# Convert encoding.
|
|
value = value.gsub(/ /i, ' ')
|
|
value = value.gsub(/&/i, '&')
|
|
|
|
# Replace `<br>`.
|
|
value = value.gsub(/<br>/i, "\n")
|
|
|
|
# Replace `<div>` (from Chrome).
|
|
value = value.gsub(/<div>/i, "\n")
|
|
|
|
# Replace `<p>` (from IE).
|
|
value = value.gsub(/<p>/i, "\n")
|
|
|
|
# Remove extra tags.
|
|
value = value.gsub(/<(.*?)>/, '')
|
|
|
|
# Trim each line.
|
|
value = value.split("\n").map{|line| line.strip}.join("\n")
|
|
|
|
# No more than 2x newline, per "paragraph".
|
|
value = value.gsub(/\n\n+/, "\n\n")
|
|
|
|
# Clean up spaces.
|
|
value = value.gsub(/[ ]+/, ' ')
|
|
value = value.strip
|
|
|
|
# Expose string.
|
|
return value
|
|
end
|
|
def self.fix_all_white_spaces
|
|
self.all.each do |event|
|
|
new_attrs = {}
|
|
localize_fields = ["title", "note"]
|
|
localize_fields.each do |f|
|
|
f_trans = "#{f}_translations"
|
|
new_attrs[f] = self.convertToText(event[f])
|
|
new_attrs[f_trans] = {}
|
|
event[f_trans].each do |l, s|
|
|
new_attrs[f_trans][l] = self.convertToText(s)
|
|
end
|
|
end
|
|
Event.where(:id=>event.id).update_all(new_attrs)
|
|
end
|
|
end
|
|
end |