Class: Decidim::ActionLog

Inherits:
ApplicationRecord show all
Includes:
ScopableParticipatorySpace
Defined in:
app/models/decidim/action_log.rb

Overview

This class represents an action of a user on a resource. It is used for transparency reasons, to log all actions so all other users can see the actions being performed.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.for_adminObject

A scope that filters all the logs that should be visible at the admin panel.



96
97
98
# File 'app/models/decidim/action_log.rb', line 96

def self.for_admin
  where(visibility: %w(admin-only all))
end

.lazy_relation(id_method, klass_name, cache) ⇒ Object

Returns a Batchloader for a given class to avoid N+1 queries.

Since ActionLogs are related to many different resources, loading a collection of them would trigger a lot of N+1 queries. We’re using BatchLoader to accumulate and group all the resource by their class and only loading them when it’s necessary.



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'app/models/decidim/action_log.rb', line 195

def self.lazy_relation(id_method, klass_name, cache)
  klass = klass_name.constantize
  BatchLoader.for(id_method).batch(cache: cache, key: klass.name.underscore) do |relation_ids, loader|
    scope = klass.where(id: relation_ids)

    scope = if klass.include?(Decidim::HasComponent)
              scope.where(id: relation_ids).includes(:component).where.not(decidim_components: { published_at: nil })
            elsif klass.reflect_on_association(:organization)
              scope.where(id: relation_ids).includes(:organization)
            elsif klass_name == "Decidim::Comments::Comment"
              scope.where(id: relation_ids).includes([:moderation, :root_commentable, :user_group])
            else
              scope
            end

    scope = scope.published if klass.include?(Decidim::Publicable)

    scope.each { |relation| loader.call(relation.id, relation) }
  end
end

.private_resource_typesObject



120
121
122
123
124
125
126
# File 'app/models/decidim/action_log.rb', line 120

def self.private_resource_types
  @private_resource_types ||= %w(
    Decidim::Budgets::Order
  ).select do |klass|
    klass.safe_constantize.present?
  end
end

.public_resource_typesObject

All the resource types that are eligible to be included as an activity.



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'app/models/decidim/action_log.rb', line 101

def self.public_resource_types
  @public_resource_types ||= %w(
    Decidim::Accountability::Result
    Decidim::Blogs::Post
    Decidim::Comments::Comment
    Decidim::Consultations::Question
    Decidim::Debates::Debate
    Decidim::Meetings::Meeting
    Decidim::Proposals::Proposal
    Decidim::Surveys::Survey
    Decidim::Assembly
    Decidim::Consultation
    Decidim::Initiative
    Decidim::ParticipatoryProcess
  ).select do |klass|
    klass.safe_constantize.present?
  end
end

.publicable_public_resource_typesObject



128
129
130
# File 'app/models/decidim/action_log.rb', line 128

def self.publicable_public_resource_types
  @publicable_public_resource_types ||= public_resource_types.select { |klass| klass.constantize.column_names.include?("published_at") }
end

.ransackable_scopes(_auth_object = nil) ⇒ Object



132
133
134
# File 'app/models/decidim/action_log.rb', line 132

def self.ransackable_scopes(_auth_object = nil)
  [:with_resource_type]
end

Instance Method Details

#component_lazy(cache: true) ⇒ Object

Lazy loads the ‘component` association through BatchLoader, can be used as a regular object.



145
146
147
# File 'app/models/decidim/action_log.rb', line 145

def component_lazy(cache: true)
  self.class.lazy_relation(decidim_component_id, "Decidim::Component", cache)
end

#log_presenter_class_for(log_type) ⇒ Object

Public: Finds the correct presenter class for the given ‘log_type` and the related `resource_type`. If no specific presenter can be found, it falls back to `Decidim::Log::BasePresenter`

log_type - a Symbol representing the log

Returns a Class.



183
184
185
186
187
# File 'app/models/decidim/action_log.rb', line 183

def log_presenter_class_for(log_type)
  resource_type.constantize.log_presenter_class_for(log_type)
rescue NameError
  Decidim::Log::BasePresenter
end

#organization_lazy(cache: true) ⇒ Object

Lazy loads the ‘organization` association through BatchLoader, can be used as a regular object.



151
152
153
# File 'app/models/decidim/action_log.rb', line 151

def organization_lazy(cache: true)
  self.class.lazy_relation(decidim_organization_id, "Decidim::Organization", cache)
end

#participatory_space_lazy(cache: true) ⇒ Object

Lazy loads the ‘participatory_space` association through BatchLoader, can be used as a regular object.



163
164
165
166
167
168
# File 'app/models/decidim/action_log.rb', line 163

def participatory_space_lazy(cache: true)
  return if participatory_space_id.blank? || participatory_space_type.blank?
  return resouce_lazy if participatory_space_id == resource_id && participatory_space_type == resource_type

  self.class.lazy_relation(participatory_space_id, participatory_space_type, cache)
end

#readonly?Boolean

Overwrites the method so that records cannot be modified.

Returns a Boolean.

Returns:

  • (Boolean)


139
140
141
# File 'app/models/decidim/action_log.rb', line 139

def readonly?
  !new_record?
end

#resource_lazy(cache: true) ⇒ Object

Lazy loads the ‘resource` association through BatchLoader, can be used as a regular object.



172
173
174
# File 'app/models/decidim/action_log.rb', line 172

def resource_lazy(cache: true)
  self.class.lazy_relation(resource_id, resource_type, cache)
end

#user_lazy(cache: true) ⇒ Object

Lazy loads the ‘user` association through BatchLoader, can be used as a regular object.



157
158
159
# File 'app/models/decidim/action_log.rb', line 157

def user_lazy(cache: true)
  self.class.lazy_relation(decidim_user_id, "Decidim::User", cache)
end

#visible_for?(user) ⇒ Boolean

Whether this activity or log is visible for a given user (can also be nil)

Returns:

  • (Boolean)


217
218
219
220
221
222
223
224
225
226
227
# File 'app/models/decidim/action_log.rb', line 217

def visible_for?(user)
  resource_lazy.present? &&
    participatory_space_lazy.present? &&
    !resource_lazy.try(:deleted?) &&
    !resource_lazy.try(:hidden?) &&
    (!resource_lazy.respond_to?(:can_participate?) || resource_lazy.try(:can_participate?, user))
rescue NameError => e
  Rails.logger.warn "Failed resource for #{self.class.name}(id=#{id}): #{e.message}"

  false
end