Skip to content
Permalink
a70f869938
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
227 lines (178 sloc) 7.42 KB
# frozen_string_literal: true
require_dependency "devise/models/decidim_validatable"
require_dependency "devise/models/decidim_newsletterable"
require "valid_email2"
module Decidim
# A User is a citizen that wants to join the platform to participate.
class User < UserBaseEntity
include Decidim::DataPortability
include Decidim::Searchable
OMNIAUTH_PROVIDERS = [:facebook, :twitter, :google_oauth2, (:developer if Rails.env.development?)].compact
class Roles
def self.all
Decidim.config.user_roles
end
end
devise :invitable, :database_authenticatable, :registerable, :confirmable, :timeoutable,
:recoverable, :rememberable, :trackable, :decidim_validatable,
:decidim_newsletterable,
:omniauthable, omniauth_providers: OMNIAUTH_PROVIDERS,
request_keys: [:env], reset_password_keys: [:decidim_organization_id, :email],
confirmation_keys: [:decidim_organization_id, :email]
has_many :identities, foreign_key: "decidim_user_id", class_name: "Decidim::Identity", dependent: :destroy
has_many :memberships, class_name: "Decidim::UserGroupMembership", foreign_key: :decidim_user_id, dependent: :destroy
has_many :user_groups, through: :memberships, class_name: "Decidim::UserGroup", foreign_key: :decidim_user_group_id
has_many :access_grants, class_name: "Doorkeeper::AccessGrant", foreign_key: :resource_owner_id, dependent: :destroy
has_many :access_tokens, class_name: "Doorkeeper::AccessToken", foreign_key: :resource_owner_id, dependent: :destroy
validates :name, presence: true, unless: -> { deleted? }
validates :nickname, presence: true, unless: -> { deleted? || managed? }, length: { maximum: Decidim::User.nickname_max_length }
validates :locale, inclusion: { in: :available_locales }, allow_blank: true
validates :tos_agreement, acceptance: true, allow_nil: false, on: :create
validates :tos_agreement, acceptance: true, if: :user_invited?
validates :email, :nickname, uniqueness: { scope: :organization }, unless: -> { deleted? || managed? || nickname.blank? }
validate :all_roles_are_valid
mount_uploader :avatar, Decidim::AvatarUploader
scope :not_deleted, -> { where(deleted_at: nil) }
scope :managed, -> { where(managed: true) }
scope :not_managed, -> { where(managed: false) }
scope :officialized, -> { where.not(officialized_at: nil) }
scope :not_officialized, -> { where(officialized_at: nil) }
scope :confirmed, -> { where.not(confirmed_at: nil) }
scope :not_confirmed, -> { where(confirmed_at: nil) }
scope :interested_in_scopes, lambda { |scope_ids|
ids = scope_ids.map { |i| "%#{i}%" }.join(",")
where("extended_data->>'interested_scopes' ~~ ANY('{#{ids}}')")
}
attr_accessor :newsletter_notifications
searchable_fields({
# scope_id: :decidim_scope_id,
organization_id: :decidim_organization_id,
A: :name,
datetime: :created_at
},
index_on_create: ->(user) { !user.deleted? },
index_on_update: ->(user) { !user.deleted? })
before_save :ensure_encrypted_password
def user_invited?
invitation_token_changed? && invitation_accepted_at_changed?
end
# Public: Allows customizing the invitation instruction email content when
# inviting a user.
#
# Returns a String.
attr_accessor :invitation_instructions
def self.log_presenter_class_for(_log)
Decidim::AdminLog::UserPresenter
end
# Checks if the user has the given `role` or not.
#
# role - a String or a Symbol that represents the role that is being
# checked
#
# Returns a boolean.
def role?(role)
roles.include?(role.to_s)
end
# Public: Returns the active role of the user
def active_role
admin ? "admin" : roles.first
end
# Public: returns the user's name or the default one
def name
super || I18n.t("decidim.anonymous_user")
end
# Check if the user account has been deleted or not
def deleted?
deleted_at.present?
end
# Public: whether the user has been officialized or not
def officialized?
!officialized_at.nil?
end
def follows?(followable)
Decidim::Follow.where(user: self, followable: followable).any?
end
def unread_conversations
Decidim::Messaging::Conversation.unread_by(self)
end
# Check if the user exists with the given email and the current organization
#
# warden_conditions - A hash with the authentication conditions
# * email - a String that represents user's email.
# * env - A Hash containing environment variables.
# Returns a User.
def self.find_for_authentication(warden_conditions)
organization = warden_conditions.dig(:env, "decidim.current_organization")
find_by(
email: warden_conditions[:email].to_s.downcase,
decidim_organization_id: organization.id
)
end
def self.user_collection(user)
where(id: user.id)
end
def self.export_serializer
Decidim::DataPortabilitySerializers::DataPortabilityUserSerializer
end
def self.data_portability_images(user)
user_collection(user).map(&:avatar)
end
def tos_accepted?
return true if managed
return false if accepted_tos_version.nil?
# For some reason, if we don't use `#to_i` here we get some
# cases where the comparison returns false, but calling `#to_i` returns
# the same number :/
accepted_tos_version.to_i >= organization.tos_version.to_i
end
# Whether this user can be verified against some authorization or not.
def verifiable?
confirmed? || managed? || being_impersonated?
end
def being_impersonated?
ImpersonationLog.active.where(user: self).exists?
end
def interested_scopes_ids
extended_data["interested_scopes"] || []
end
def interested_scopes
@interested_scopes ||= organization.scopes.where(id: interested_scopes_ids)
end
protected
# Overrides devise email required validation.
# If the user has been deleted or it is managed the email field is not required anymore.
def email_required?
return false if deleted? || managed?
super
end
# Overrides devise password required validation.
# If the user is managed the password field is not required anymore.
def password_required?
return false if managed?
super
end
def after_confirmation
return unless organization.send_welcome_notification?
Decidim::EventsManager.publish(
event: "decidim.events.core.welcome_notification",
event_class: WelcomeNotificationEvent,
resource: self,
affected_users: [self]
)
end
private
# Changes default Devise behaviour to use ActiveJob to send async emails.
def send_devise_notification(notification, *args)
devise_mailer.send(notification, self, *args).deliver_later
end
def all_roles_are_valid
errors.add(:roles, :invalid) unless roles.compact.all? { |role| Roles.all.include?(role) }
end
def available_locales
Decidim.available_locales.map(&:to_s)
end
def ensure_encrypted_password
restore_encrypted_password! if will_save_change_to_encrypted_password? && encrypted_password.blank?
end
end
end