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 + "
" + 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}) + "
" + 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}) + "
" + 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}) + "
" + 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 @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 new_end = @end_date + w.day 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 @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 def self.convertToText(str) # Ensure string. value = str.to_s # Convert encoding. value = value.gsub(/ /i, ' ') value = value.gsub(/&/i, '&') # Replace `
`. value = value.gsub(/
/i, "\n") # Replace `
` (from Chrome). value = value.gsub(/
/i, "\n") # Replace `

` (from IE). value = value.gsub(/

/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