Module: Maestrano::Connector::Rails::Concerns::ConnecHelper::ClassMethods

Defined in:
app/models/maestrano/connector/rails/concerns/connec_helper.rb

Instance Method Summary collapse

Instance Method Details

#build_id_references_tree(id_references) ⇒ Object

Builds a tree from an array of id_references input: %w(lines/id lines/linked/id linked/id) output: “lines”=>{“id”=>{, “linked”=>“id”=>{}}, “linked”=>“id”=>{}}



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 197

def build_id_references_tree(id_references)
  tree = {}

  id_references.each do |id_reference|
    array_of_refs = id_reference.split('/')

    t = tree
    array_of_refs.each do |ref|
      t[ref] ||= {}
      t = t[ref]
    end
  end

  tree
end

#connec_version(organization) ⇒ Object

Returns a string of the tenant’s current connec version. Can use Gem::Version for version comparison



22
23
24
25
26
27
28
29
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 22

def connec_version(organization)
  @@connec_version = Rails.cache.fetch("connec_version_#{organization.tenant}", namespace: 'maestrano', expires_in: 1.day) do
    response = get_client(organization).class.get("#{Maestrano[organization.tenant].param('connec.host')}/version", headers: {'Accept' => 'application/json'})
    response = JSON.parse(response.body)
    @@connec_version = response['ci_branch'].delete('v')
  end
  @@connec_version
end

#connec_version_lt?(version, organization) ⇒ Boolean

Returns:

  • (Boolean)


31
32
33
34
35
36
37
38
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 31

def connec_version_lt?(version, organization)
  version = Gem::Version.new(version)
  current_version = Gem::Version.new(connec_version(organization))

  current_version < version
rescue
  true
end

#dependanciesObject



5
6
7
8
9
10
11
12
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 5

def dependancies
  # Meant to be overloaded if needed
  {
    connec: '1.0',
    impac: '1.0',
    maestrano_hub: '1.0'
  }
end

#filter_connec_entity_for_id_refs(connec_entity, id_references) ⇒ Object

Returns the connec_entity without all the fields that are not id_references



163
164
165
166
167
168
169
170
171
172
173
174
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 163

def filter_connec_entity_for_id_refs(connec_entity, id_references)
  return {} if id_references.empty?

  entity = connec_entity.dup.with_indifferent_access
  tree = build_id_references_tree(id_references)

  filter_connec_entity_for_id_refs_helper(entity, tree)

  # TODO, improve performance by returning an empty hash if all the id_references have their id in the connec hash
  # We should still return all of them if at least one is missing as we are relying on the id
  entity
end

#filter_connec_entity_for_id_refs_helper(entity_hash, tree) ⇒ Object

Recursive method for filtering connec entities



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 177

def filter_connec_entity_for_id_refs_helper(entity_hash, tree)
  return if tree.empty?

  entity_hash.slice!(*tree.keys)

  tree.each do |key, children|
    case entity_hash[key]
    when Array
      entity_hash[key].each do |hash|
        filter_connec_entity_for_id_refs_helper(hash, children)
      end
    when Hash
      filter_connec_entity_for_id_refs_helper(entity_hash[key], children)
    end
  end
end

#fold_references(mapped_external_entity, references, organization) ⇒ Object

Replaces ids from the external application by arrays containing them



73
74
75
76
77
78
79
80
81
82
83
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 73

def fold_references(mapped_external_entity, references, organization)
  references = format_references(references)
  mapped_external_entity = mapped_external_entity.with_indifferent_access

  # Use both record_references and id_references + the id
  (references.values.flatten + ['id']).each do |reference|
    fold_references_helper(mapped_external_entity, reference.split('/'), organization)
  end

  mapped_external_entity
end

#fold_references_helper(entity, array_of_refs, organization) ⇒ Object

Recursive method for folding references



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 95

def fold_references_helper(entity, array_of_refs, organization)
  ref = array_of_refs.shift
  field = entity[ref]
  return if field.blank?

  # Follow embedment path, remplace if it's not an array or a hash
  case field
  when Array
    field.each do |f|
      fold_references_helper(f, array_of_refs.dup, organization)
    end
  when Hash
    fold_references_helper(entity[ref], array_of_refs, organization)
  else
    id = field
    entity[ref] = [id_hash(id, organization)]
  end
end

#format_references(references) ⇒ Object

Transforms the references into an hash [], id_references: [] References can either be an array (only record references), or a hash



154
155
156
157
158
159
160
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 154

def format_references(references)
  return {record_references: references, id_references: []} if references.is_a?(Array)

  references[:record_references] ||= []
  references[:id_references] ||= []
  references
end

#get_client(organization) ⇒ Object



14
15
16
17
18
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 14

def get_client(organization)
  client = Maestrano::Connec::Client[organization.tenant].new(organization.uid)
  client.class.headers('CONNEC-EXTERNAL-IDS' => 'true')
  client
end

#id_hash(id, organization) ⇒ Object

Builds an id_hash from the id and organization



86
87
88
89
90
91
92
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 86

def id_hash(id, organization)
  {
    id: id,
    provider: organization.oauth_provider,
    realm: organization.oauth_uid
  }
end

#merge_id_hashes(dist, src, id_references) ⇒ Object

Merges the id arrays from two hashes while keeping only the id_references fields



214
215
216
217
218
219
220
221
222
223
224
225
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 214

def merge_id_hashes(dist, src, id_references)
  dist = dist.with_indifferent_access
  src = src.with_indifferent_access

  id_references.each do |id_reference|
    array_of_refs = id_reference.split('/')

    merge_id_hashes_helper(dist, array_of_refs, src)
  end

  dist
end

#merge_id_hashes_helper(hash, array_of_refs, src, path = []) ⇒ Object

Recursive helper for merging id hashes



228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 228

def merge_id_hashes_helper(hash, array_of_refs, src, path = [])
  ref = array_of_refs.shift
  field = hash[ref]

  if array_of_refs.empty? && field
    value = value_from_hash(src, path + [ref])
    if value.is_a?(Array)
      hash[ref] = (field + value).uniq
    else
      hash.delete(ref)
    end
  else
    case field
    when Array
      field.each_with_index do |f, index|
        merge_id_hashes_helper(f, array_of_refs.dup, src, path + [ref, index])
      end
    when Hash
      merge_id_hashes_helper(field, array_of_refs, src, path + [ref])
    end
  end
end

#unfold_references(connec_entity, references, organization) ⇒ Object

Replaces the arrays of id received from Connec! by the id of the external application Returns a hash {, connec_id: ”, id_refs_only_connec_entity: {}} If an array has no id for this oauth_provider and oauth_uid but has one for connec, it returns a nil entity (skip the record)



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 43

def unfold_references(connec_entity, references, organization)
  references = format_references(references)
  unfolded_connec_entity = connec_entity.deep_dup.with_indifferent_access
  not_nil = true

  # Id
  id_hash = unfolded_connec_entity['id'].find { |id| id['provider'] == organization.oauth_provider && id['realm'] == organization.oauth_uid }
  connec_id = unfolded_connec_entity['id'].find { |id| id['provider'] == 'connec' }['id']
  unfolded_connec_entity['id'] = id_hash ? id_hash['id'] : nil

  # Other references
  # Record references are references to other records (organization_id, item_id, ...)
  references[:record_references].each do |reference|
    not_nil &= unfold_references_helper(unfolded_connec_entity, reference.split('/'), organization)
  end
  # Id references are references to sub entities ids (invoice lines id, ...)
  # We do not return nil if we're missing an id reference
  references[:id_references].each do |reference|
    unfold_references_helper(unfolded_connec_entity, reference.split('/'), organization)
  end
  unfolded_connec_entity = not_nil ? unfolded_connec_entity : nil

  # Filter the connec entity to keep only the id_references fields (in order to save some memory)
  # Give an empty hash if there's nothing left
  id_refs_only_connec_entity = filter_connec_entity_for_id_refs(connec_entity, references[:id_references])

  {entity: unfolded_connec_entity, connec_id: connec_id, id_refs_only_connec_entity: id_refs_only_connec_entity}
end

#unfold_references_helper(entity, array_of_refs, organization) ⇒ Object

Recursive method for unfolding references



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 115

def unfold_references_helper(entity, array_of_refs, organization)
  ref = array_of_refs.shift
  field = entity[ref]

  # Unfold the id
  if array_of_refs.empty? && field
    return entity.delete(ref) if field.is_a?(String) # ~retro-compatibility to ease transition aroud Connec! idmaps rework. Should be removed eventually.

    id_hash = field.find { |id| id[:provider] == organization.oauth_provider && id[:realm] == organization.oauth_uid }
    if id_hash
      entity[ref] = id_hash['id']
    elsif field.find { |id| id[:provider] == 'connec' } # Should always be true as ids will always contain a connec id
      # We may enqueue a fetch on the endpoint of the missing association, followed by a re-fetch on this one.
      # However it's expected to be an edge case, so for now we rely on the fact that the webhooks should be relativly in order.
      # Worst case it'll be done on following sync
      entity.delete(ref)
      return nil
    end
    true

  # Follow embedment path
  else
    return true if field.blank?

    case field
    when Array
      bool = true
      field.each do |f|
        bool &= unfold_references_helper(f, array_of_refs.dup, organization)
      end
      bool
    when Hash
      unfold_references_helper(entity[ref], array_of_refs, organization)
    end
  end
end

#value_from_hash(hash, path) ⇒ Object

Returns the value from a hash following the given path Path sould be an array like [:lines, 0, :id]



253
254
255
256
257
258
259
260
261
262
263
264
# File 'app/models/maestrano/connector/rails/concerns/connec_helper.rb', line 253

def value_from_hash(hash, path)
  value = hash

  begin
    path.each do |p|
      value = value[p]
    end
    value
  rescue NoMethodError
    nil
  end
end