<commit_before>require 'digest/sha1'

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable, :confirmable, :omniauthable, #:reconfirmable,
         :recoverable, :rememberable, :trackable, :validatable, :blockable, :traceable

  include TutorialAssigneesHelper

  attr_accessor :image_url, :accept_conditions, :subdomain, :accept_privacy

  validates_presence_of :name
  validates_format_of :name, with: AuthenticationModule.name_regex, allow_nil: true
  validates_length_of :name, maximum: 50

  validates_format_of :surname, with: AuthenticationModule.name_regex, allow_nil: true
  validates_length_of :surname, maximum: 50

  validates_confirmation_of :password

  validates_acceptance_of :accept_conditions, message: I18n.t('activerecord.errors.messages.TOS')
  validates_acceptance_of :accept_privacy, message: I18n.t('activerecord.errors.messages.privacy')

  has_many :proposal_presentations, dependent: :destroy # TODO: replace with anonymous
  has_many :proposals, through: :proposal_presentations, class_name: 'Proposal'
  has_many :notifications, through: :alerts, class_name: 'Notification'
  has_many :meeting_participations, dependent: :destroy
  has_one :blog, dependent: :destroy
  has_many :blog_comments, dependent: :destroy
  has_many :blog_posts, dependent: :destroy
  has_many :blocked_alerts, dependent: :destroy
  has_many :blocked_emails, dependent: :destroy

  has_many :event_comments, dependent: :destroy
  has_many :likes, class_name: 'EventCommentLike', dependent: :destroy

  has_many :group_participations, dependent: :destroy
  has_many :groups, through: :group_participations, class_name: 'Group'
  has_many :portavoce_groups, -> { joins(' INNER JOIN participation_roles ON participation_roles.id = group_participations.participation_role_id').where("(participation_roles.name = 'amministratore')") }, through: :group_participations, class_name: 'Group', source: 'group'

  has_many :area_participations, class_name: 'AreaParticipation'
  has_many :group_areas, through: :area_participations, class_name: 'GroupArea'

  has_many :participation_roles, through: :group_participations, class_name: 'ParticipationRole'
  has_many :group_follows, class_name: 'GroupFollow'
  has_many :followed_groups, through: :group_follows, class_name: 'Group', source: :group
  has_many :user_votes, class_name: 'UserVote'
  has_many :proposal_comments, class_name: 'ProposalComment'
  has_many :partecipating_proposals, through: :proposal_comments, class_name: 'Proposal', source: :proposal
  has_many :proposal_comment_rankings, class_name: 'ProposalCommentRanking'
  has_many :proposal_rankings, class_name: 'ProposalRanking'
  belongs_to :user_type, class_name: 'UserType', foreign_key: :user_type_id
  belongs_to :places, class_name: 'Place', foreign_key: :residenza_id
  belongs_to :places, class_name: 'Place', foreign_key: :nascita_id
  belongs_to :image, class_name: 'Image', foreign_key: :image_id
  has_many :authentications, class_name: 'Authentication', dependent: :destroy

  has_many :user_borders, class_name: 'UserBorder'

  # confini di interesse
  has_many :interest_borders, through: :user_borders, class_name: 'InterestBorder'

  has_many :alerts, -> { order('alerts.created_at DESC') }, class_name: 'Alert'
  has_many :unread_alerts, -> { where 'alerts.checked = false' }, class_name: 'Alert'

  has_many :blocked_notifications, through: :blocked_alerts, class_name: 'NotificationType', source: :notification_type
  has_many :blocked_email_notifications, through: :blocked_emails, class_name: 'NotificationType', source: :notification_type

  has_many :group_participation_requests, dependent: :destroy

  # record di tutti coloro che mi seguono
  has_many :followers_user_follow, class_name: 'UserFollow', foreign_key: :followed_id
  # tutti coloro che mi seguono
  has_many :followers, through: :followers_user_follow, class_name: 'User', source: :followed

  # record di tutti coloro che seguo
  has_many :followed_user_follow, class_name: 'UserFollow', foreign_key: :follower_id
  # tutti coloro che seguo
  has_many :followed, through: :followed_user_follow, class_name: 'User', source: :follower

  has_many :tutorial_assignees, dependent: :destroy
  has_many :tutorial_progresses, dependent: :destroy
  has_many :todo_tutorial_assignees, -> { where('tutorial_assignees.completed = false') }, class_name: 'TutorialAssignee'
  # tutorial assegnati all'utente
  has_many :tutorials, through: :tutorial_assignees, class_name: 'Tutorial', source: :user
  has_many :todo_tutorials, through: :todo_tutorial_assignees, class_name: 'Tutorial', source: :user

  belongs_to :locale, class_name: 'SysLocale', foreign_key: 'sys_locale_id'
  belongs_to :original_locale, class_name: 'SysLocale', foreign_key: 'original_sys_locale_id'

  has_many :events

  has_many :proposal_nicknames, dependent: :destroy

  has_one :certification, class_name: 'UserSensitive', foreign_key: :user_id, autosave: true

  # forum
  has_many :viewed, class_name: 'Frm::View'
  has_many :viewed_topics, class_name: 'Frm::Topic', through: :viewed, source: :viewable, source_type: 'Frm::Topic'
  has_many :unread_topics, -> { where 'frm_views.updated_at < frm_topics.last_post_at' }, class_name: 'Frm::Topic', through: :viewed, source: :viewable, source_type: 'Frm::Topic'
  has_many :memberships, class_name: 'Frm::Membership', foreign_key: :member_id
  has_many :frm_mods, through: :memberships, class_name: 'Frm::Mod', source: :mod

  before_create :init

  after_create :assign_tutorials, :block_alerts

  validate :check_uncertified

  # Check for paperclip
  has_attached_file :avatar,
                    styles: {
                      thumb: '100x100#',
                      small: '150x150>'
                    },
                    path: (Paperclip::Attachment.default_options[:storage] == :s3) ?
                      'avatars/:id/:style/:basename.:extension' : ':rails_root/public:url'

  validates_attachment_size :avatar, less_than: 2.megabytes
  validates_attachment_content_type :avatar, content_type: ['image/jpeg', 'image/png', 'image/gif', 'image/jpg']

  scope :all_except, ->(user) { where.not(id: user) }

  scope :blocked, -> { where(blocked: true) }
  scope :unblocked, -> { where(blocked: false) }
  scope :confirmed, -> { where 'confirmed_at is not null' }
  scope :unconfirmed, -> { where 'confirmed_at is null' }
  scope :certified, -> { where(user_type_id: UserType::CERTIFIED) }
  scope :count_active, -> { count.to_f * (ENV['ACTIVE_USERS_PERCENTAGE'].to_f / 100.0) }

  scope :autocomplete, ->(term) { where('lower(users.name) LIKE :term or lower(users.surname) LIKE :term', term: "%#{term.downcase}%").order('users.surname desc, users.name desc').limit(10) }
  scope :non_blocking_notification, ->(notification_type) { User.where.not(id: User.select('users.id').joins(:blocked_alerts).where(blocked_alerts: {notification_type_id: notification_type})) }

  validate :cannot_change_info_if_certified, on: :update
<commit_msg>exclude blocked users from the count of active users<commit_after>require 'digest/sha1'

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable, :confirmable, :omniauthable, #:reconfirmable,
         :recoverable, :rememberable, :trackable, :validatable, :blockable, :traceable

  include TutorialAssigneesHelper

  attr_accessor :image_url, :accept_conditions, :subdomain, :accept_privacy

  validates_presence_of :name
  validates_format_of :name, with: AuthenticationModule.name_regex, allow_nil: true
  validates_length_of :name, maximum: 50

  validates_format_of :surname, with: AuthenticationModule.name_regex, allow_nil: true
  validates_length_of :surname, maximum: 50

  validates_confirmation_of :password

  validates_acceptance_of :accept_conditions, message: I18n.t('activerecord.errors.messages.TOS')
  validates_acceptance_of :accept_privacy, message: I18n.t('activerecord.errors.messages.privacy')

  has_many :proposal_presentations, dependent: :destroy # TODO: replace with anonymous
  has_many :proposals, through: :proposal_presentations, class_name: 'Proposal'
  has_many :notifications, through: :alerts, class_name: 'Notification'
  has_many :meeting_participations, dependent: :destroy
  has_one :blog, dependent: :destroy
  has_many :blog_comments, dependent: :destroy
  has_many :blog_posts, dependent: :destroy
  has_many :blocked_alerts, dependent: :destroy
  has_many :blocked_emails, dependent: :destroy

  has_many :event_comments, dependent: :destroy
  has_many :likes, class_name: 'EventCommentLike', dependent: :destroy

  has_many :group_participations, dependent: :destroy
  has_many :groups, through: :group_participations, class_name: 'Group'
  has_many :portavoce_groups, -> { joins(' INNER JOIN participation_roles ON participation_roles.id = group_participations.participation_role_id').where("(participation_roles.name = 'amministratore')") }, through: :group_participations, class_name: 'Group', source: 'group'

  has_many :area_participations, class_name: 'AreaParticipation'
  has_many :group_areas, through: :area_participations, class_name: 'GroupArea'

  has_many :participation_roles, through: :group_participations, class_name: 'ParticipationRole'
  has_many :group_follows, class_name: 'GroupFollow'
  has_many :followed_groups, through: :group_follows, class_name: 'Group', source: :group
  has_many :user_votes, class_name: 'UserVote'
  has_many :proposal_comments, class_name: 'ProposalComment'
  has_many :partecipating_proposals, through: :proposal_comments, class_name: 'Proposal', source: :proposal
  has_many :proposal_comment_rankings, class_name: 'ProposalCommentRanking'
  has_many :proposal_rankings, class_name: 'ProposalRanking'
  belongs_to :user_type, class_name: 'UserType', foreign_key: :user_type_id
  belongs_to :places, class_name: 'Place', foreign_key: :residenza_id
  belongs_to :places, class_name: 'Place', foreign_key: :nascita_id
  belongs_to :image, class_name: 'Image', foreign_key: :image_id
  has_many :authentications, class_name: 'Authentication', dependent: :destroy

  has_many :user_borders, class_name: 'UserBorder'

  # confini di interesse
  has_many :interest_borders, through: :user_borders, class_name: 'InterestBorder'

  has_many :alerts, -> { order('alerts.created_at DESC') }, class_name: 'Alert'
  has_many :unread_alerts, -> { where 'alerts.checked = false' }, class_name: 'Alert'

  has_many :blocked_notifications, through: :blocked_alerts, class_name: 'NotificationType', source: :notification_type
  has_many :blocked_email_notifications, through: :blocked_emails, class_name: 'NotificationType', source: :notification_type

  has_many :group_participation_requests, dependent: :destroy

  # record di tutti coloro che mi seguono
  has_many :followers_user_follow, class_name: 'UserFollow', foreign_key: :followed_id
  # tutti coloro che mi seguono
  has_many :followers, through: :followers_user_follow, class_name: 'User', source: :followed

  # record di tutti coloro che seguo
  has_many :followed_user_follow, class_name: 'UserFollow', foreign_key: :follower_id
  # tutti coloro che seguo
  has_many :followed, through: :followed_user_follow, class_name: 'User', source: :follower

  has_many :tutorial_assignees, dependent: :destroy
  has_many :tutorial_progresses, dependent: :destroy
  has_many :todo_tutorial_assignees, -> { where('tutorial_assignees.completed = false') }, class_name: 'TutorialAssignee'
  # tutorial assegnati all'utente
  has_many :tutorials, through: :tutorial_assignees, class_name: 'Tutorial', source: :user
  has_many :todo_tutorials, through: :todo_tutorial_assignees, class_name: 'Tutorial', source: :user

  belongs_to :locale, class_name: 'SysLocale', foreign_key: 'sys_locale_id'
  belongs_to :original_locale, class_name: 'SysLocale', foreign_key: 'original_sys_locale_id'

  has_many :events

  has_many :proposal_nicknames, dependent: :destroy

  has_one :certification, class_name: 'UserSensitive', foreign_key: :user_id, autosave: true

  # forum
  has_many :viewed, class_name: 'Frm::View'
  has_many :viewed_topics, class_name: 'Frm::Topic', through: :viewed, source: :viewable, source_type: 'Frm::Topic'
  has_many :unread_topics, -> { where 'frm_views.updated_at < frm_topics.last_post_at' }, class_name: 'Frm::Topic', through: :viewed, source: :viewable, source_type: 'Frm::Topic'
  has_many :memberships, class_name: 'Frm::Membership', foreign_key: :member_id
  has_many :frm_mods, through: :memberships, class_name: 'Frm::Mod', source: :mod

  before_create :init

  after_create :assign_tutorials, :block_alerts

  validate :check_uncertified

  # Check for paperclip
  has_attached_file :avatar,
                    styles: {
                      thumb: '100x100#',
                      small: '150x150>'
                    },
                    path: (Paperclip::Attachment.default_options[:storage] == :s3) ?
                      'avatars/:id/:style/:basename.:extension' : ':rails_root/public:url'

  validates_attachment_size :avatar, less_than: 2.megabytes
  validates_attachment_content_type :avatar, content_type: ['image/jpeg', 'image/png', 'image/gif', 'image/jpg']

  scope :all_except, ->(user) { where.not(id: user) }

  scope :blocked, -> { where(blocked: true) }
  scope :unblocked, -> { where(blocked: false) }
  scope :confirmed, -> { where 'confirmed_at is not null' }
  scope :unconfirmed, -> { where 'confirmed_at is null' }
  scope :certified, -> { where(user_type_id: UserType::CERTIFIED) }
  scope :count_active, -> { unblocked.count.to_f * (ENV['ACTIVE_USERS_PERCENTAGE'].to_f / 100.0) }

  scope :autocomplete, ->(term) { where('lower(users.name) LIKE :term or lower(users.surname) LIKE :term', term: "%#{term.downcase}%").order('users.surname desc, users.name desc').limit(10) }
  scope :non_blocking_notification, ->(notification_type) { User.where.not(id: User.select('users.id').joins(:blocked_alerts).where(blocked_alerts: {notification_type_id: notification_type})) }

  validate :cannot_change_info_if_certified, on: :update

{'fraction_non_alphanumeric': 0.11218747774057981, 'fraction_numerical': 0.004131348386637225, 'mean_word_length': 6.112462006079028, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4074219', 'n_tokens_mistral': 4838, 'n_tokens_neox': 4600, 'n_words': 1026}