calendar/app/models/event.rb

359 lines
13 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.utc.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))
elsif is_year
add_interval = (start_date.year - @start_date.year)
else
add_interval = (start_date_utc_mjd - @start_date.utc.mjd)
if add_interval < 0
add_interval = -(-add_interval / days)
else
add_interval = add_interval / days
end
end
if add_interval < 0
add_interval = add_interval % freq
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
@end_date += add_interval
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
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 => (@end_date + w.day).to_json.gsub('"',''), :hide=>true, :color=>"#c0c0c0"})
end
else
@recurring << data.merge({:start => new_start.to_json.gsub('"',''), :end => (@end_date + w.day).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
@end_date += interval
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
end