calendar_subscriptions_spec.rb 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. RSpec.describe CalendarSubscriptions, :aggregate_failures do
  4. # Set second fraction to zero for easier comparsion.
  5. def dt_now
  6. now = DateTime.now
  7. DateTime.new(now.year, now.month, now.day, now.hour, now.minute, now.second, 0)
  8. end
  9. let(:groups) { create_list(:group, 2) }
  10. let(:agents) do
  11. [
  12. create(:agent, groups: [groups.first]),
  13. create(:agent, groups: [groups.second])
  14. ]
  15. end
  16. let(:tickets) do
  17. tickets = [
  18. create(:ticket,
  19. group: groups.first,
  20. owner: agents.first),
  21. create(:ticket,
  22. group: groups.first,
  23. owner: agents.first,
  24. state: Ticket::State.lookup(name: 'pending reminder'),
  25. pending_time: dt_now + 2.days),
  26. create(:ticket,
  27. group: groups.first,
  28. owner: agents.first),
  29. create(:ticket,
  30. group: groups.second,
  31. owner: agents.second),
  32. create(:ticket,
  33. group: groups.second,
  34. owner: agents.second,
  35. state: Ticket::State.lookup(name: 'pending reminder'),
  36. pending_time: dt_now + 2.days),
  37. create(:ticket,
  38. group: groups.second,
  39. owner: agents.second),
  40. create(:ticket,
  41. group: groups.first,
  42. owner: User.find(1)),
  43. create(:ticket,
  44. group: groups.first,
  45. owner: User.find(1),
  46. state: Ticket::State.lookup(name: 'pending reminder'),
  47. pending_time: dt_now + 2.days),
  48. create(:ticket,
  49. group: groups.first,
  50. owner: User.find(1)),
  51. create(:ticket,
  52. group: groups.second,
  53. owner: User.find(1)),
  54. create(:ticket,
  55. group: groups.second,
  56. owner: User.find(1),
  57. state: Ticket::State.lookup(name: 'pending reminder'),
  58. pending_time: dt_now + 2.days),
  59. create(:ticket,
  60. group: groups.second,
  61. owner: User.find(1))
  62. ]
  63. # set escalation_at manually, clear cache to have correct content later
  64. [2, 5, 8, 11].each do |index|
  65. tickets[index].update_columns(escalation_at: dt_now + 2.weeks)
  66. end
  67. Rails.cache.clear
  68. tickets
  69. end
  70. let(:ical) { described_class.new(agent).all }
  71. let(:calendars) { Icalendar::Calendar.parse(ical) }
  72. # https://github.com/zammad/zammad/issues/3989
  73. # https://datatracker.ietf.org/doc/html/rfc5545#section-3.2.19
  74. shared_examples 'verify ical' do
  75. it 'has timezone information' do
  76. vtimezone = $1 if ical =~ %r{(BEGIN:VTIMEZONE(?:.|\n)+END:VTIMEZONE)}
  77. expect(vtimezone).to be_present
  78. tzid = $1 if vtimezone =~ %r{TZID:(.+)}
  79. expect(tzid).to match(Setting.get('timezone_default'))
  80. end
  81. end
  82. shared_examples 'verify calendar' do |params|
  83. it "has #{params[:count]} calendar with #{params[:events]} events" do
  84. expect(calendars.count).to be(params[:count])
  85. expect(calendars.first.events.count).to be(params[:events])
  86. expect(calendars.first.has_timezone?).to be true
  87. end
  88. end
  89. def event_to_ticket(event)
  90. Ticket.find_by(number: event.description.to_s[2..])
  91. end
  92. shared_examples 'verify events' do |params|
  93. it 'has ticket related events' do
  94. calendars.first.events.each do |event|
  95. ticket = event_to_ticket(event)
  96. expect(event.description.to_s).to match("T##{ticket.number}")
  97. expect(event.summary.to_s).to match(ticket.title)
  98. if !event.summary.to_s.match?(%r{^new})
  99. expect(event.has_alarm?).to be params[:alarm]
  100. end
  101. end
  102. end
  103. end
  104. def verify_timestamp(dtstart, dtend, tstart)
  105. expect(dtstart).to match(tstart)
  106. expect(dtend).to match(tstart)
  107. end
  108. def verify_offset(dtstart, dtend, tstart)
  109. time_zone = Setting.get('timezone_default')
  110. tz = ActiveSupport::TimeZone.find_tzinfo(time_zone)
  111. expect(dtstart.utc_offset).to match(tz.utc_to_local(tstart).utc_offset)
  112. expect(dtend.utc_offset).to match(tz.utc_to_local(tstart).utc_offset)
  113. end
  114. # https://github.com/zammad/zammad/issues/4307
  115. shared_examples 'verify timestamps' do
  116. it 'event timestamps match related ticket timestamps' do
  117. calendars.first.events.each do |event|
  118. ticket = event_to_ticket(event)
  119. dtstart = event.dtstart
  120. dtend = event.dtend
  121. case event.summary.to_s
  122. when %r{new}
  123. tstart = ticket.updated_at
  124. expect(dtstart.strftime('%Y-%m-%d')).to match(ticket.updated_at.strftime('%Y-%m-%d'))
  125. expect(dtend.strftime('%Y-%m-%d')).to match(ticket.updated_at.strftime('%Y-%m-%d'))
  126. verify_offset(dtstart, dtend, tstart)
  127. next
  128. when %r{pending reminder}
  129. tstart = ticket.pending_time
  130. when %r{ticket escalation}
  131. tstart = ticket.escalation_at
  132. end
  133. verify_timestamp(dtstart, dtend, tstart)
  134. verify_offset(dtstart, dtend, tstart)
  135. end
  136. end
  137. end
  138. describe 'with subscriber agent in first group' do
  139. let(:agent) { agents.first }
  140. context 'with default subscriptions' do
  141. before do
  142. tickets
  143. calendars
  144. end
  145. include_examples 'verify ical'
  146. include_examples 'verify calendar', {
  147. count: 1,
  148. events: 4,
  149. }
  150. include_examples 'verify events', { alarm: false }
  151. include_examples 'verify timestamps'
  152. end
  153. context 'with specific subscriptions' do
  154. before do
  155. agent.preferences[:calendar_subscriptions] ||= {}
  156. agent.preferences[:calendar_subscriptions][:tickets] = {
  157. escalation: {
  158. own: true,
  159. not_assigned: true,
  160. },
  161. new_open: {
  162. own: true,
  163. not_assigned: true,
  164. },
  165. pending: {
  166. own: true,
  167. not_assigned: true,
  168. },
  169. alarm: true,
  170. }
  171. agent.save!
  172. tickets
  173. calendars
  174. end
  175. include_examples 'verify ical'
  176. include_examples 'verify calendar', {
  177. count: 1,
  178. events: 8,
  179. }
  180. include_examples 'verify events', { alarm: true }
  181. include_examples 'verify timestamps'
  182. end
  183. end
  184. describe 'with subscriber agent in second group' do
  185. let(:agent) { agents.second }
  186. context 'with default subscriptions' do
  187. before do
  188. Setting.set('timezone_default', 'Europe/Berlin')
  189. tickets
  190. calendars
  191. end
  192. include_examples 'verify ical', {
  193. count: 1,
  194. events: 4,
  195. }
  196. include_examples 'verify events', { alarm: false }
  197. include_examples 'verify timestamps'
  198. end
  199. context 'with specific subscriptions' do
  200. before do
  201. Setting.set('timezone_default', 'Europe/Berlin')
  202. agent.preferences[:calendar_subscriptions] ||= {}
  203. agent.preferences[:calendar_subscriptions][:tickets] = {
  204. escalation: {
  205. own: true,
  206. not_assigned: true,
  207. },
  208. new_open: {
  209. own: true,
  210. not_assigned: true,
  211. },
  212. pending: {
  213. own: true,
  214. not_assigned: true,
  215. },
  216. alarm: false,
  217. }
  218. agent.save!
  219. tickets
  220. calendars
  221. end
  222. include_examples 'verify ical'
  223. include_examples 'verify calendar', {
  224. count: 1,
  225. events: 8,
  226. }
  227. include_examples 'verify events', { alarm: false }
  228. include_examples 'verify timestamps'
  229. end
  230. context 'with pending only' do
  231. before do
  232. Setting.set('timezone_default', 'Europe/Berlin')
  233. agent.preferences[:calendar_subscriptions] ||= {}
  234. agent.preferences[:calendar_subscriptions][:tickets] = {
  235. escalation: {
  236. own: false,
  237. not_assigned: false,
  238. },
  239. new_open: {
  240. own: false,
  241. not_assigned: false,
  242. },
  243. pending: {
  244. own: true,
  245. not_assigned: true,
  246. },
  247. alarm: false,
  248. }
  249. agent.save!
  250. tickets
  251. calendars
  252. end
  253. include_examples 'verify ical'
  254. include_examples 'verify calendar', {
  255. count: 1,
  256. events: 2,
  257. }
  258. include_examples 'verify events', { alarm: false }
  259. include_examples 'verify timestamps'
  260. end
  261. end
  262. end