link.rb 8.0 KB

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