tag.rb 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
  2. class Tag < ApplicationModel
  3. belongs_to :tag_object, class_name: 'Tag::Object'
  4. belongs_to :tag_item, class_name: 'Tag::Item'
  5. # the noop is needed since Layout/EmptyLines detects
  6. # the block commend below wrongly as the measurement of
  7. # the wanted indentation of the rubocop re-enabling above
  8. def noop; end
  9. =begin
  10. add tags for certain object
  11. Tag.tag_add(
  12. object: 'Ticket',
  13. o_id: ticket.id,
  14. item: 'some tag',
  15. created_by_id: current_user.id,
  16. )
  17. =end
  18. def self.tag_add(data)
  19. data[:item].strip!
  20. # lookups
  21. if data[:object]
  22. tag_object_id = Tag::Object.lookup_by_name_and_create(data[:object]).id
  23. end
  24. if data[:item]
  25. tag_item_id = Tag::Item.lookup_by_name_and_create(data[:item]).id
  26. end
  27. # return if duplicate
  28. current_tags = tag_list(data)
  29. return true if current_tags.include?(data[:item])
  30. # create history
  31. Tag.create(
  32. tag_object_id: tag_object_id,
  33. tag_item_id: tag_item_id,
  34. o_id: data[:o_id],
  35. created_by_id: data[:created_by_id],
  36. )
  37. # touch reference
  38. touch_reference_by_params(data)
  39. true
  40. end
  41. =begin
  42. remove tags of certain object
  43. Tag.tag_remove(
  44. object: 'Ticket',
  45. o_id: ticket.id,
  46. item: 'some tag',
  47. created_by_id: current_user.id,
  48. )
  49. or by ids
  50. Tag.tag_remove(
  51. tag_object_id: 123,
  52. o_id: ticket.id,
  53. tag_item_id: 123,
  54. created_by_id: current_user.id,
  55. )
  56. =end
  57. def self.tag_remove(data)
  58. # lookups
  59. if data[:object]
  60. data[:tag_object_id] = Tag::Object.lookup_by_name_and_create(data[:object]).id
  61. else
  62. data[:object] = Tag::Object.lookup(id: data[:tag_object_id]).name
  63. end
  64. if data[:item]
  65. data[:item].strip!
  66. data[:tag_item_id] = Tag::Item.lookup_by_name_and_create(data[:item]).id
  67. end
  68. # create history
  69. result = Tag.where(
  70. tag_object_id: data[:tag_object_id],
  71. tag_item_id: data[:tag_item_id],
  72. o_id: data[:o_id],
  73. )
  74. result.each(&:destroy)
  75. # touch reference
  76. touch_reference_by_params(data)
  77. true
  78. end
  79. =begin
  80. remove all tags of certain object
  81. Tag.tag_destroy(
  82. object: 'Ticket',
  83. o_id: ticket.id,
  84. created_by_id: current_user.id,
  85. )
  86. =end
  87. def self.tag_destroy(data)
  88. # lookups
  89. if data[:object]
  90. data[:tag_object_id] = Tag::Object.lookup_by_name_and_create(data[:object]).id
  91. else
  92. data[:object] = Tag::Object.lookup(id: data[:tag_object_id]).name
  93. end
  94. # create history
  95. result = Tag.where(
  96. tag_object_id: data[:tag_object_id],
  97. o_id: data[:o_id],
  98. )
  99. result.each(&:destroy)
  100. true
  101. end
  102. =begin
  103. tag list for certain object
  104. tags = Tag.tag_list(
  105. object: 'Ticket',
  106. o_id: ticket.id,
  107. )
  108. returns
  109. ['tag 1', 'tag2', ...]
  110. =end
  111. def self.tag_list(data)
  112. Tag.joins(:tag_item, :tag_object)
  113. .where(o_id: data[:o_id], tag_objects: { name: data[:object] })
  114. .order(:id)
  115. .pluck('tag_items.name')
  116. end
  117. class Object < ApplicationModel
  118. validates :name, presence: true
  119. =begin
  120. lookup by name and create tag item
  121. tag_object = Tag::Object.lookup_by_name_and_create('some tag')
  122. =end
  123. def self.lookup_by_name_and_create(name)
  124. name.strip!
  125. tag_object = Tag::Object.lookup(name: name)
  126. return tag_object if tag_object
  127. Tag::Object.create(name: name)
  128. end
  129. end
  130. class Item < ApplicationModel
  131. validates :name, presence: true
  132. before_save :fill_namedowncase
  133. =begin
  134. lookup by name and create tag item
  135. tag_item = Tag::Item.lookup_by_name_and_create('some tag')
  136. =end
  137. def self.lookup_by_name_and_create(name)
  138. name.strip!
  139. tag_item = Tag::Item.lookup(name: name)
  140. return tag_item if tag_item
  141. Tag::Item.create(name: name)
  142. end
  143. =begin
  144. rename tag items
  145. Tag::Item.rename(
  146. id: existing_tag_item_to_rename,
  147. name: 'new tag item name',
  148. updated_by_id: current_user.id,
  149. )
  150. =end
  151. def self.rename(data)
  152. new_tag_name = data[:name].strip
  153. old_tag_item = Tag::Item.find(data[:id])
  154. already_existing_tag = Tag::Item.lookup(name: new_tag_name)
  155. # check if no remame is needed
  156. return true if new_tag_name == old_tag_item.name
  157. # merge old with new tag if already existing
  158. if already_existing_tag
  159. # re-assign old tag to already existing tag
  160. Tag.where(tag_item_id: old_tag_item.id).each do |tag|
  161. # check if tag already exists on object
  162. if Tag.find_by(tag_object_id: tag.tag_object_id, o_id: tag.o_id, tag_item_id: already_existing_tag.id)
  163. Tag.tag_remove(
  164. tag_object_id: tag.tag_object_id,
  165. o_id: tag.o_id,
  166. tag_item_id: old_tag_item.id,
  167. )
  168. next
  169. end
  170. # re-assign
  171. tag_object = Tag::Object.lookup(id: tag.tag_object_id)
  172. tag.tag_item_id = already_existing_tag.id
  173. tag.save
  174. # touch reference objects
  175. Tag.touch_reference_by_params(
  176. object: tag_object.name,
  177. o_id: tag.o_id,
  178. )
  179. end
  180. # delete not longer used tag
  181. old_tag_item.destroy
  182. return true
  183. end
  184. update_referenced_objects(old_tag_item.name, new_tag_name)
  185. # update new tag name
  186. old_tag_item.name = new_tag_name
  187. old_tag_item.save
  188. # touch reference objects
  189. Tag.where(tag_item_id: old_tag_item.id).each do |tag|
  190. tag_object = Tag::Object.lookup(id: tag.tag_object_id)
  191. Tag.touch_reference_by_params(
  192. object: tag_object.name,
  193. o_id: tag.o_id,
  194. )
  195. end
  196. true
  197. end
  198. =begin
  199. remove tag item (destroy with reverences)
  200. Tag::Item.remove(id)
  201. =end
  202. def self.remove(id)
  203. # search for references, destroy and touch
  204. Tag.where(tag_item_id: id).each do |tag|
  205. tag_object = Tag::Object.lookup(id: tag.tag_object_id)
  206. tag.destroy
  207. Tag.touch_reference_by_params(
  208. object: tag_object.name,
  209. o_id: tag.o_id,
  210. )
  211. end
  212. Tag::Item.find(id).destroy
  213. true
  214. end
  215. def fill_namedowncase
  216. self.name_downcase = name.downcase
  217. true
  218. end
  219. =begin
  220. Update referenced objects such as triggers, overviews, schedulers, and postmaster filters
  221. Specifically, the following fields are updated:
  222. Overview.condition
  223. Trigger.condition Trigger.perform
  224. Job.condition Job.perform
  225. PostmasterFilter.perform
  226. =end
  227. def self.update_referenced_objects(old_name, new_name)
  228. objects = Overview.all + Trigger.all + Job.all + PostmasterFilter.all
  229. objects.each do |object|
  230. changed = false
  231. if object.has_attribute?(:condition)
  232. changed |= update_condition_hash object.condition, old_name, new_name
  233. end
  234. if object.has_attribute?(:perform)
  235. changed |= update_condition_hash object.perform, old_name, new_name
  236. end
  237. object.save if changed
  238. end
  239. end
  240. def self.update_condition_hash(hash, old_name, new_name)
  241. changed = false
  242. hash.each do |key, condition|
  243. next if %w[ticket.tags x-zammad-ticket-tags].exclude? key
  244. next if condition[:value].split(', ').exclude? old_name
  245. condition[:value] = update_name(condition[:value], old_name, new_name)
  246. changed = true
  247. end
  248. changed
  249. end
  250. def self.update_name(condition, old_name, new_name)
  251. tags = condition.split(', ')
  252. return new_name if tags.size == 1
  253. tags = tags.map { |t| t == old_name ? new_name : t }
  254. tags.join(', ')
  255. end
  256. end
  257. end