calendar_subscriptions.rb 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'icalendar/tzinfo'
  3. class CalendarSubscriptions
  4. def initialize(user)
  5. @user = user
  6. @preferences = {}
  7. @time_zone = Setting.get('timezone_default')
  8. default_preferences = Setting.where(area: 'Defaults::CalendarSubscriptions')
  9. default_preferences.each do |calendar_subscription|
  10. next if calendar_subscription.name !~ %r{\Adefaults_calendar_subscriptions_(.*)\z}
  11. object_name = $1 # rubocop:disable Lint/OutOfRangeRegexpRef
  12. @preferences[ object_name ] = calendar_subscription.state_current[:value]
  13. end
  14. return if @user.preferences[:calendar_subscriptions].blank?
  15. @preferences = @preferences.merge(@user.preferences[:calendar_subscriptions])
  16. end
  17. def all
  18. events_data = []
  19. @preferences.each_key do |object_name|
  20. result = generic_call(object_name)
  21. events_data += result
  22. end
  23. to_ical(events_data)
  24. end
  25. def generic(object_name, method_name = 'all')
  26. events_data = generic_call(object_name, method_name)
  27. to_ical(events_data)
  28. end
  29. def generic_call(object_name, method_name = 'all')
  30. method_name ||= 'all'
  31. events_data = []
  32. if @preferences[ object_name ].present?
  33. sub_class_name = object_name.to_s.capitalize
  34. object = "CalendarSubscriptions::#{sub_class_name}".constantize
  35. instance = object.new(@user, @preferences[ object_name ], @time_zone)
  36. raise Exceptions::UnprocessableEntity, __('An unknown method name was requested.') if object::ALLOWED_METHODS.exclude?(method_name)
  37. method = instance.method(method_name)
  38. events_data += method.call
  39. end
  40. events_data
  41. end
  42. def to_ical(events_data)
  43. cal = Icalendar::Calendar.new
  44. tz = ActiveSupport::TimeZone.find_tzinfo(@time_zone)
  45. # https://github.com/zammad/zammad/issues/3989
  46. # https://datatracker.ietf.org/doc/html/rfc5545#section-3.2.19
  47. if events_data.first.present?
  48. timezone = tz.ical_timezone(DateTime.parse(events_data.first[:dtstart].to_s))
  49. cal.add_timezone(timezone)
  50. end
  51. events_data.each do |event_data|
  52. cal.event do |e|
  53. dtstart = DateTime.parse(event_data[:dtstart].to_s)
  54. dtend = DateTime.parse(event_data[:dtend].to_s)
  55. # by design all new/open ticket events are scheduled at midnight:
  56. # skip adding TZ offset
  57. if !event_data[:type].match('new_open')
  58. dtstart = tz.utc_to_local(dtstart)
  59. dtend = tz.utc_to_local(dtend)
  60. end
  61. e.dtstart = Icalendar::Values::DateTime.new(dtstart, 'tzid' => @time_zone)
  62. e.dtend = Icalendar::Values::DateTime.new(dtend, 'tzid' => @time_zone)
  63. if event_data[:alarm]
  64. e.alarm do |a|
  65. a.action = 'DISPLAY'
  66. a.summary = event_data[:alarm][:summary]
  67. a.trigger = event_data[:alarm][:trigger]
  68. end
  69. end
  70. e.summary = event_data[:summary]
  71. e.description = event_data[:description]
  72. e.ip_class = 'PRIVATE'
  73. end
  74. end
  75. cal.to_ical
  76. end
  77. end