link.rb 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class Link < ApplicationModel
  3. include Link::TriggersSubscriptions
  4. belongs_to :link_type, class_name: 'Link::Type', optional: true
  5. belongs_to :link_object, class_name: 'Link::Object', optional: true
  6. after_destroy :touch_link_references
  7. @map = {
  8. 'normal' => 'normal',
  9. 'parent' => 'child',
  10. 'child' => 'parent',
  11. }
  12. =begin
  13. links = Link.list(
  14. link_object: 'Ticket',
  15. link_object_value: 1
  16. )
  17. =end
  18. def self.list(data)
  19. linkobject = link_object_get(name: data[:link_object])
  20. return if !linkobject
  21. items = []
  22. # get links for one site
  23. list = Link.where(
  24. 'link_object_source_id = ? AND link_object_source_value = ?', linkobject.id, data[:link_object_value]
  25. )
  26. list.each do |item|
  27. link = {}
  28. link['link_type'] = @map[ Link::Type.find(item.link_type_id).name ]
  29. link['link_object'] = Link::Object.find(item.link_object_target_id).name
  30. link['link_object_value'] = item.link_object_target_value
  31. items.push link
  32. end
  33. # get links for the other site
  34. list = Link.where(
  35. 'link_object_target_id = ? AND link_object_target_value = ?', linkobject.id, data[:link_object_value]
  36. )
  37. list.each do |item|
  38. link = {}
  39. link['link_type'] = Link::Type.find(item.link_type_id).name
  40. link['link_object'] = Link::Object.find(item.link_object_source_id).name
  41. link['link_object_value'] = item.link_object_source_value
  42. items.push link
  43. end
  44. return items if data[:user].blank?
  45. items.select do |item|
  46. authorized_item?(data[:user], item)
  47. end
  48. end
  49. =begin
  50. Link.add(
  51. link_type: 'normal',
  52. link_object_source: 'Ticket',
  53. link_object_source_value: 6,
  54. link_object_target: 'Ticket',
  55. link_object_target_value: 31
  56. )
  57. Link.add(
  58. link_types_id: 12,
  59. link_object_source_id: 1,
  60. link_object_source_value: 1,
  61. link_object_target_id: 1,
  62. link_object_target_value: 1
  63. )
  64. =end
  65. def self.add(data)
  66. if data.key?(:link_type)
  67. linktype = link_type_get(name: data[:link_type])
  68. data[:link_type_id] = linktype.id
  69. data.delete(:link_type)
  70. end
  71. if data.key?(:link_object_source)
  72. linkobject = link_object_get(name: data[:link_object_source])
  73. data[:link_object_source_id] = linkobject.id
  74. touch_reference_by_params(
  75. object: data[:link_object_source],
  76. o_id: data[:link_object_source_value],
  77. )
  78. data.delete(:link_object_source)
  79. end
  80. if data.key?(:link_object_target)
  81. linkobject = link_object_get(name: data[:link_object_target])
  82. data[:link_object_target_id] = linkobject.id
  83. touch_reference_by_params(
  84. object: data[:link_object_target],
  85. o_id: data[:link_object_target_value],
  86. )
  87. data.delete(:link_object_target)
  88. end
  89. Link.create(data)
  90. end
  91. =begin
  92. Link.remove(
  93. link_type: 'normal',
  94. link_object_source: 'Ticket',
  95. link_object_source_value: 6,
  96. link_object_target: 'Ticket',
  97. link_object_target_value: 31
  98. )
  99. =end
  100. def self.remove(data)
  101. if data.key?(:link_object_source)
  102. linkobject = link_object_get(name: data[:link_object_source])
  103. data[:link_object_source_id] = linkobject.id
  104. end
  105. if data.key?(:link_object_target)
  106. linkobject = link_object_get(name: data[:link_object_target])
  107. data[:link_object_target_id] = linkobject.id
  108. end
  109. # from one site
  110. if data.key?(:link_type)
  111. linktype = link_type_get(name: data[:link_type])
  112. data[:link_type_id] = linktype.id
  113. end
  114. Link.where(
  115. link_type_id: data[:link_type_id],
  116. link_object_source_id: data[:link_object_source_id],
  117. link_object_source_value: data[:link_object_source_value],
  118. link_object_target_id: data[:link_object_target_id],
  119. link_object_target_value: data[:link_object_target_value]
  120. ).destroy_all
  121. # from the other site
  122. if data.key?(:link_type)
  123. linktype = link_type_get(name: @map[ data[:link_type] ])
  124. data[:link_type_id] = linktype.id
  125. end
  126. Link.where(
  127. link_type_id: data[:link_type_id],
  128. link_object_target_id: data[:link_object_source_id],
  129. link_object_target_value: data[:link_object_source_value],
  130. link_object_source_id: data[:link_object_target_id],
  131. link_object_source_value: data[:link_object_target_value]
  132. ).destroy_all
  133. end
  134. =begin
  135. Link.remove_all(
  136. link_object: 'Ticket',
  137. link_object_value: 6,
  138. )
  139. =end
  140. def self.remove_all(data)
  141. if data.key?(:link_object)
  142. linkobject = link_object_get(name: data[:link_object])
  143. data[:link_object_id] = linkobject.id
  144. end
  145. Link.where(
  146. link_object_target_id: data[:link_object_id],
  147. link_object_target_value: data[:link_object_value],
  148. ).destroy_all
  149. Link.where(
  150. link_object_source_id: data[:link_object_id],
  151. link_object_source_value: data[:link_object_value],
  152. ).destroy_all
  153. true
  154. end
  155. def touch_link_references
  156. Link.touch_reference_by_params(
  157. object: Link::Object.lookup(id: link_object_source_id).name,
  158. o_id: link_object_source_value,
  159. )
  160. Link.touch_reference_by_params(
  161. object: Link::Object.lookup(id: link_object_target_id).name,
  162. o_id: link_object_target_value,
  163. )
  164. end
  165. def self.link_type_get(data)
  166. linktype = Link::Type.find_by(name: data[:name])
  167. if !linktype
  168. linktype = Link::Type.create(name: data[:name])
  169. end
  170. linktype
  171. end
  172. def self.link_object_get(data)
  173. linkobject = Link::Object.find_by(name: data[:name])
  174. if !linkobject
  175. linkobject = Link::Object.create(name: data[:name])
  176. end
  177. linkobject
  178. end
  179. =begin
  180. Update assets according to given references list
  181. @param assets [Hash] hash with assets
  182. @param link_references [Array<Hash>] @see #list
  183. @return [Hash] assets including linked items
  184. @example Link.reduce_assets(assets, link_references)
  185. =end
  186. def self.reduce_assets(assets, link_references)
  187. link_items = link_references
  188. .filter_map { |elem| lookup_linked_object(elem) }
  189. ApplicationModel::CanAssets.reduce(link_items, assets)
  190. end
  191. def self.lookup_linked_object(elem)
  192. klass = elem['link_object'].safe_constantize
  193. id = elem['link_object_value']
  194. case klass.to_s
  195. when KnowledgeBase::Answer::Translation.to_s
  196. Setting.get('kb_active') ? klass.lookup(id: id) : nil
  197. else
  198. klass&.lookup(id: id)
  199. end
  200. end
  201. def self.duplicates(object1_id:, object1_value:, object2_value:, object2_id: nil)
  202. if !object2_id
  203. object2_id = object1_id
  204. end
  205. Link.joins(', links as linksb').where('
  206. (
  207. links.link_type_id = linksb.link_type_id
  208. AND links.link_object_source_id = linksb.link_object_source_id
  209. AND links.link_object_source_value = linksb.link_object_source_value
  210. AND links.link_object_target_id = ?
  211. AND linksb.link_object_target_id = ?
  212. AND links.link_object_target_value = ?
  213. AND linksb.link_object_target_value = ?
  214. )
  215. OR
  216. (
  217. links.link_type_id = linksb.link_type_id
  218. AND links.link_object_target_id = linksb.link_object_target_id
  219. AND links.link_object_target_value = linksb.link_object_target_value
  220. AND links.link_object_source_id = ?
  221. AND linksb.link_object_source_id = ?
  222. AND links.link_object_source_value = ?
  223. AND linksb.link_object_source_value = ?
  224. )
  225. ', object1_id, object2_id, object1_value, object2_value, object1_id, object2_id, object1_value, object2_value)
  226. end
  227. def self.authorized_item?(user, item)
  228. record = item['link_object'].constantize.lookup(id: item['link_object_value'])
  229. # non-ID records are not checked for authorization
  230. return true if record.blank?
  231. Pundit.authorize(user, record, :show?).present?
  232. rescue Pundit::NotAuthorizedError
  233. false
  234. rescue NameError, Pundit::NotDefinedError
  235. # NameError: no Model means no authorization check possible
  236. # Pundit::NotDefinedError: no Policy means no authorization check necessary
  237. true
  238. end
  239. end