module Mautic # Virtual model for Mautic endpoint # @see https://developer.mautic.org/#endpoints class Model < OpenStruct extend ActiveModel::Callbacks class MauticHash < Hash def []=(name, value) @changes ||= {} @changes[name] = value super end def changes @changes || {} end end class Attribute < OpenStruct def name @alias end end class << self def endpoint name.demodulize.underscore.pluralize end def in(connection) Proxy.new(connection, endpoint) end end define_model_callbacks :create, :update, :save attr_reader :connection attr_accessor :errors attr_writer :changed # @param [Mautic::Connection] connection def initialize(connection, hash = nil) @connection = connection @table = MauticHash.new self.attributes = { id: hash['id'], created_at: hash['dateAdded']&.to_time, updated_at: hash['dateModified']&.to_time } if hash assign_attributes(hash) clear_changes end def mautic_id "#{id}/#{@connection.id}" end def save(force = false) run_callbacks :save do id.present? ? update(force) : create end end def update(force = false) return false unless changed? begin run_callbacks :create do json = @connection.request((force && :put || :patch), "api/#{endpoint}/#{id}/edit", body: to_mautic) assign_attributes json[endpoint.singularize] end clear_changes rescue ValidationError => e self.errors = e.errors end errors.blank? end def update_columns(attributes = {}) json = @connection.request(:patch, "api/#{endpoint}/#{id}/edit", body: to_mautic(attributes)) assign_attributes json[endpoint.singularize] clear_changes rescue ValidationError => e self.errors = e.errors end def create begin run_callbacks :create do json = @connection.request(:post, "api/#{endpoint}/#{id && "#{id}/"}new", body: to_mautic) assign_attributes json[endpoint.singularize] end clear_changes rescue ValidationError => e self.errors = e.errors end errors.blank? end def destroy begin @connection.request(:delete, "api/#{endpoint}/#{id}/delete") true rescue RequestError => e self.errors = e.errors false end end def changes @table.changes end def changed? return @changed unless @changed.nil? @changed = !changes.empty? end def attributes @table.to_h end def attributes=(hash) hash.each_pair do |k, v| k = k.to_sym @table[k] = v end end def to_mautic(data = @table) data.transform_values do |val| if val.respond_to?(:to_mautic) val.to_mautic elsif val.is_a?(Array) val.join("|") else val end end end private def clear_changes @changed = nil @table.instance_variable_set(:@changes, nil) end def endpoint self.class.endpoint end def assign_attributes(source = nil) @mautic_attributes = [] source ||= {} data = if (fields = source['fields']) attributes_from_fields(fields) elsif source source end self.attributes = data end def attributes_from_fields(fields) data = {} if fields['all'] @mautic_attributes = fields['all'].collect do |key, value| data[key] = value Attribute.new(alias: key, value: value) end else fields.each do |_group, pairs| next unless pairs.is_a?(Hash) pairs.each do |key, attrs| @mautic_attributes << (a = Attribute.new(attrs)) data[key] = a.value end end end data end end end