123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- class Link < ApplicationModel
- include Link::TriggersSubscriptions
- belongs_to :link_type, class_name: 'Link::Type', optional: true
- belongs_to :link_object, class_name: 'Link::Object', optional: true
- after_destroy :touch_link_references
- @map = {
- 'normal' => 'normal',
- 'parent' => 'child',
- 'child' => 'parent',
- }
- =begin
- links = Link.list(
- link_object: 'Ticket',
- link_object_value: 1
- )
- =end
- def self.list(data)
- linkobject = link_object_get(name: data[:link_object])
- return if !linkobject
- items = []
- # get links for one site
- list = Link.where(
- 'link_object_source_id = ? AND link_object_source_value = ?', linkobject.id, data[:link_object_value]
- )
- list.each do |item|
- link = {}
- link['link_type'] = @map[ Link::Type.find(item.link_type_id).name ]
- link['link_object'] = Link::Object.find(item.link_object_target_id).name
- link['link_object_value'] = item.link_object_target_value
- items.push link
- end
- # get links for the other site
- list = Link.where(
- 'link_object_target_id = ? AND link_object_target_value = ?', linkobject.id, data[:link_object_value]
- )
- list.each do |item|
- link = {}
- link['link_type'] = Link::Type.find(item.link_type_id).name
- link['link_object'] = Link::Object.find(item.link_object_source_id).name
- link['link_object_value'] = item.link_object_source_value
- items.push link
- end
- return items if data[:user].blank?
- items.select do |item|
- authorized_item?(data[:user], item)
- end
- end
- =begin
- Link.add(
- link_type: 'normal',
- link_object_source: 'Ticket',
- link_object_source_value: 6,
- link_object_target: 'Ticket',
- link_object_target_value: 31
- )
- Link.add(
- link_types_id: 12,
- link_object_source_id: 1,
- link_object_source_value: 1,
- link_object_target_id: 1,
- link_object_target_value: 1
- )
- =end
- def self.add(data)
- if data.key?(:link_type)
- linktype = link_type_get(name: data[:link_type])
- data[:link_type_id] = linktype.id
- data.delete(:link_type)
- end
- if data.key?(:link_object_source)
- linkobject = link_object_get(name: data[:link_object_source])
- data[:link_object_source_id] = linkobject.id
- touch_reference_by_params(
- object: data[:link_object_source],
- o_id: data[:link_object_source_value],
- )
- data.delete(:link_object_source)
- end
- if data.key?(:link_object_target)
- linkobject = link_object_get(name: data[:link_object_target])
- data[:link_object_target_id] = linkobject.id
- touch_reference_by_params(
- object: data[:link_object_target],
- o_id: data[:link_object_target_value],
- )
- data.delete(:link_object_target)
- end
- Link.create(data)
- end
- =begin
- Link.remove(
- link_type: 'normal',
- link_object_source: 'Ticket',
- link_object_source_value: 6,
- link_object_target: 'Ticket',
- link_object_target_value: 31
- )
- =end
- def self.remove(data)
- if data.key?(:link_object_source)
- linkobject = link_object_get(name: data[:link_object_source])
- data[:link_object_source_id] = linkobject.id
- end
- if data.key?(:link_object_target)
- linkobject = link_object_get(name: data[:link_object_target])
- data[:link_object_target_id] = linkobject.id
- end
- # from one site
- if data.key?(:link_type)
- linktype = link_type_get(name: data[:link_type])
- data[:link_type_id] = linktype.id
- end
- Link.where(
- link_type_id: data[:link_type_id],
- link_object_source_id: data[:link_object_source_id],
- link_object_source_value: data[:link_object_source_value],
- link_object_target_id: data[:link_object_target_id],
- link_object_target_value: data[:link_object_target_value]
- ).destroy_all
- # from the other site
- if data.key?(:link_type)
- linktype = link_type_get(name: @map[ data[:link_type] ])
- data[:link_type_id] = linktype.id
- end
- Link.where(
- link_type_id: data[:link_type_id],
- link_object_target_id: data[:link_object_source_id],
- link_object_target_value: data[:link_object_source_value],
- link_object_source_id: data[:link_object_target_id],
- link_object_source_value: data[:link_object_target_value]
- ).destroy_all
- end
- =begin
- Link.remove_all(
- link_object: 'Ticket',
- link_object_value: 6,
- )
- =end
- def self.remove_all(data)
- if data.key?(:link_object)
- linkobject = link_object_get(name: data[:link_object])
- data[:link_object_id] = linkobject.id
- end
- Link.where(
- link_object_target_id: data[:link_object_id],
- link_object_target_value: data[:link_object_value],
- ).destroy_all
- Link.where(
- link_object_source_id: data[:link_object_id],
- link_object_source_value: data[:link_object_value],
- ).destroy_all
- true
- end
- def touch_link_references
- Link.touch_reference_by_params(
- object: Link::Object.lookup(id: link_object_source_id).name,
- o_id: link_object_source_value,
- )
- Link.touch_reference_by_params(
- object: Link::Object.lookup(id: link_object_target_id).name,
- o_id: link_object_target_value,
- )
- end
- def self.link_type_get(data)
- linktype = Link::Type.find_by(name: data[:name])
- if !linktype
- linktype = Link::Type.create(name: data[:name])
- end
- linktype
- end
- def self.link_object_get(data)
- linkobject = Link::Object.find_by(name: data[:name])
- if !linkobject
- linkobject = Link::Object.create(name: data[:name])
- end
- linkobject
- end
- =begin
- Update assets according to given references list
- @param assets [Hash] hash with assets
- @param link_references [Array<Hash>] @see #list
- @return [Hash] assets including linked items
- @example Link.reduce_assets(assets, link_references)
- =end
- def self.reduce_assets(assets, link_references)
- link_items = link_references
- .filter_map { |elem| lookup_linked_object(elem) }
- ApplicationModel::CanAssets.reduce(link_items, assets)
- end
- def self.lookup_linked_object(elem)
- klass = elem['link_object'].safe_constantize
- id = elem['link_object_value']
- case klass.to_s
- when KnowledgeBase::Answer::Translation.to_s
- Setting.get('kb_active') ? klass.lookup(id: id) : nil
- else
- klass&.lookup(id: id)
- end
- end
- def self.duplicates(object1_id:, object1_value:, object2_value:, object2_id: nil)
- if !object2_id
- object2_id = object1_id
- end
- Link.joins(', links as linksb').where('
- (
- links.link_type_id = linksb.link_type_id
- AND links.link_object_source_id = linksb.link_object_source_id
- AND links.link_object_source_value = linksb.link_object_source_value
- AND links.link_object_target_id = ?
- AND linksb.link_object_target_id = ?
- AND links.link_object_target_value = ?
- AND linksb.link_object_target_value = ?
- )
- OR
- (
- links.link_type_id = linksb.link_type_id
- AND links.link_object_target_id = linksb.link_object_target_id
- AND links.link_object_target_value = linksb.link_object_target_value
- AND links.link_object_source_id = ?
- AND linksb.link_object_source_id = ?
- AND links.link_object_source_value = ?
- AND linksb.link_object_source_value = ?
- )
- ', object1_id, object2_id, object1_value, object2_value, object1_id, object2_id, object1_value, object2_value)
- end
- def self.authorized_item?(user, item)
- record = item['link_object'].constantize.lookup(id: item['link_object_value'])
- # non-ID records are not checked for authorization
- return true if record.blank?
- Pundit.authorize(user, record, :show?).present?
- rescue Pundit::NotAuthorizedError
- false
- rescue NameError, Pundit::NotDefinedError
- # NameError: no Model means no authorization check possible
- # Pundit::NotDefinedError: no Policy means no authorization check necessary
- true
- end
- end
|