Class: User

Inherits:
ApplicationRecord show all
Includes:
AuthenticationToken, Connecting, Querying, SocialActions
Defined in:
app/models/user/connecting.rb,
app/models/user.rb,
app/models/user/authentication_token.rb

Overview

Copyright © 2010-2011, Diaspora Inc. This file is

licensed under the Affero General Public License version 3 or later.  See
the COPYRIGHT file.

Defined Under Namespace

Modules: AuthenticationToken, Connecting, Querying, SocialActions

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SocialActions

#build_conversation, #build_message, #comment!, #like!, #participate!, #participate_in_poll!, #reshare!, #update_or_create_participation!

Methods included from Querying

#aspects_with_person, #aspects_with_shareable, #block_for, #contact_for, #contact_for_person_id, #find_visible_shareable_by_id, #has_contact_for?, #people_in_aspects, #photos_from, #posts_from, #visible_shareable_ids, #visible_shareables

Methods included from Connecting

#disconnect, #disconnected_by, #share_with

Methods included from AuthenticationToken

#ensure_authentication_token!, #reset_authentication_token!

Class Method Details

.all_sharing_with_person(person) ⇒ Object


107
108
109
# File 'app/models/user.rb', line 107

def self.all_sharing_with_person(person)
  User.joins(:contacts).where(:contacts => {:person_id => person.id})
end

.build(opts = {}) ⇒ Object

Helpers############


409
410
411
412
413
# File 'app/models/user.rb', line 409

def self.build(opts = {})
  u = User.new(opts.except(:person, :id))
  u.setup(opts)
  u
end

.diaspora_id_hostObject


436
437
438
# File 'app/models/user.rb', line 436

def self.diaspora_id_host
  "@#{AppConfig.bare_pod_uri}"
end

.find_for_database_authentication(conditions = {}) ⇒ User?

This override allows a user to enter either their email address or their username into the username field.

Returns:

  • (User)

    The user that matches the username/email condition.

  • (nil)

    if no user matches that condition.


225
226
227
228
229
230
231
232
# File 'app/models/user.rb', line 225

def self.find_for_database_authentication(conditions={})
  conditions = conditions.dup
  conditions[:username] = conditions[:username].downcase
  if conditions[:username] =~ /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i # email regex
    conditions[:email] = conditions.delete(:username)
  end
  where(conditions).first
end

Instance Method Details

#add_hidden_shareable(key, share_id, opts = {}) ⇒ Object


132
133
134
135
136
137
138
139
140
# File 'app/models/user.rb', line 132

def add_hidden_shareable(key, share_id, opts={})
  if self.hidden_shareables.has_key?(key)
    self.hidden_shareables[key] << share_id
  else
    self.hidden_shareables[key] = [share_id]
  end
  self.save unless opts[:batch]
  self.hidden_shareables
end

#add_to_streams(post, aspects_to_insert) ⇒ Object


260
261
262
263
264
# File 'app/models/user.rb', line 260

def add_to_streams(post, aspects_to_insert)
  aspects_to_insert.each do |aspect|
    aspect << post
  end
end

#admin?Boolean

Returns:

  • (Boolean)

471
472
473
# File 'app/models/user.rb', line 471

def admin?
  Role.is_admin?(self.person)
end

#after_database_authenticationObject


588
589
590
591
592
593
594
# File 'app/models/user.rb', line 588

def after_database_authentication
  # remove any possible remove_after timestamp flag set by maintenance.remove_old_users
  unless self.remove_after.nil?
    self.remove_after = nil
    self.save
  end
end

#aspects_from_ids(aspect_ids) ⇒ Object


266
267
268
269
270
271
272
# File 'app/models/user.rb', line 266

def aspects_from_ids(aspect_ids)
  if aspect_ids == "all" || aspect_ids == :all
    self.aspects
  else
    aspects.where(:id => aspect_ids).to_a
  end
end

#basic_profile_present?Boolean

Returns:

  • (Boolean)

404
405
406
# File 'app/models/user.rb', line 404

def basic_profile_present?
  tag_followings.any? || profile[:image_url]
end

#build_post(class_name, opts = {}) ⇒ Object

Posting ########


241
242
243
244
245
246
# File 'app/models/user.rb', line 241

def build_post(class_name, opts={})
  opts[:author] = person

  model_class = class_name.to_s.camelize.constantize
  model_class.diaspora_initialize(opts)
end

#clear_account!Object


551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
# File 'app/models/user.rb', line 551

def clear_account!
  clearable_fields.each do |field|
    self[field] = nil
  end
  [:getting_started,
   :show_community_spotlight_in_stream,
   :post_default_public].each do |field|
    self[field] = false
  end
  self.remove_export = true
  self.remove_exported_photos_file = true
  self[:disable_mail] = true
  self[:strip_exif] = true
  self[:email] = "deletedaccount_#{self[:id]}@example.org"

  random_password = SecureRandom.hex(20)
  self.password = random_password
  self.password_confirmation = random_password
  self.save(:validate => false)
end

#close_account!Object


541
542
543
544
545
# File 'app/models/user.rb', line 541

def close_account!
  self.person.lock_access!
  self.lock_access!
  AccountDeletion.create(person: person)
end

#closed_account?Boolean

Returns:

  • (Boolean)

547
548
549
# File 'app/models/user.rb', line 547

def closed_account?
  self.person.
end

#compressed_exportObject


336
337
338
# File 'app/models/user.rb', line 336

def compressed_export
  ActiveSupport::Gzip.compress Diaspora::Exporter.new(self).execute
end

#confirm_email(token) ⇒ Object


234
235
236
237
238
# File 'app/models/user.rb', line 234

def confirm_email(token)
  return false if token.blank? || token != confirm_email_token
  self.email = unconfirmed_email
  save
end

#deliver_profile_update(opts = {}) ⇒ Object


400
401
402
# File 'app/models/user.rb', line 400

def deliver_profile_update(opts={})
  Diaspora::Federation::Dispatcher.defer_dispatch(self, profile, opts)
end

#disable_getting_startedObject


210
211
212
# File 'app/models/user.rb', line 210

def disable_getting_started
  self.update_attribute(:getting_started, false) if self.getting_started?
end

#dispatch_post(post, opts = {}) ⇒ Object


248
249
250
251
# File 'app/models/user.rb', line 248

def dispatch_post(post, opts={})
  logger.info "user:#{id} dispatching #{post.class}:#{post.guid}"
  Diaspora::Federation::Dispatcher.defer_dispatch(self, post, opts)
end

#encryption_keyObject


467
468
469
# File 'app/models/user.rb', line 467

def encryption_key
  OpenSSL::PKey::RSA.new(serialized_private_key)
end

#flag_for_removal(remove_after) ⇒ Object


580
581
582
583
584
585
586
# File 'app/models/user.rb', line 580

def flag_for_removal(remove_after)
  # flag inactive user for future removal
  if AppConfig.settings.maintenance.remove_old_users.enable?
    self.remove_after = remove_after
    self.save
  end
end

#generate_keysObject

Generate public/private keys for User and associated Person


524
525
526
527
528
529
530
531
532
# File 'app/models/user.rb', line 524

def generate_keys
  key_size = (Rails.env == "test" ? 512 : 4096)

  self.serialized_private_key = OpenSSL::PKey::RSA.generate(key_size).to_s if serialized_private_key.blank?

  if self.person && self.person.serialized_public_key.blank?
    self.person.serialized_public_key = OpenSSL::PKey::RSA.new(self.serialized_private_key).public_key.to_s
  end
end

#guard_unconfirmed_emailObject


507
508
509
510
511
512
513
# File 'app/models/user.rb', line 507

def guard_unconfirmed_email
  self.unconfirmed_email = nil if unconfirmed_email.blank? || unconfirmed_email == email

  return unless will_save_change_to_unconfirmed_email?

  self.confirm_email_token = unconfirmed_email ? SecureRandom.hex(15) : nil
end

#has_hidden_shareables_of_type?(t = Post) ⇒ Boolean

Returns:

  • (Boolean)

171
172
173
174
# File 'app/models/user.rb', line 171

def has_hidden_shareables_of_type?(t = Post)
  share_type = t.base_class.to_s
  self.hidden_shareables[share_type].present?
end

#hidden_shareablesObject


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

def hidden_shareables
  self[:hidden_shareables] ||= {}
end

#invitation_codeObject


124
125
126
# File 'app/models/user.rb', line 124

def invitation_code
  InvitationCode.find_or_create_by(user_id: self.id)
end

#is_shareable_hidden?(shareable) ⇒ Boolean

Returns:

  • (Boolean)

148
149
150
151
152
153
154
155
# File 'app/models/user.rb', line 148

def is_shareable_hidden?(shareable)
  shareable_type = shareable.class.base_class.name
  if self.hidden_shareables.has_key?(shareable_type)
    self.hidden_shareables[shareable_type].include?(shareable.id.to_s)
  else
    false
  end
end

#like_for(target) ⇒ Like

Get the user's like of a post, if there is one.

Parameters:

Returns:


306
307
308
309
310
311
312
# File 'app/models/user.rb', line 306

def like_for(target)
  if target.likes.loaded?
    target.likes.find {|like| like.author_id == person.id }
  else
    Like.find_by(author_id: person.id, target_type: target.class.base_class.to_s, target_id: target.id)
  end
end

#liked?(target) ⇒ Boolean

Check whether the user has liked a post.

Parameters:

Returns:

  • (Boolean)

291
292
293
294
295
296
297
298
299
300
301
# File 'app/models/user.rb', line 291

def liked?(target)
  if target.likes.loaded?
    if self.like_for(target)
      return true
    else
      return false
    end
  else
    Like.exists?(:author_id => self.person.id, :target_type => target.class.base_class.to_s, :target_id => target.id)
  end
end

#mail(job, *args) ⇒ Object

Mailer #######################


357
358
359
360
361
362
363
# File 'app/models/user.rb', line 357

def mail(job, *args)
  return unless job.present?
  pref = job.to_s.gsub('Workers::Mail::', '').underscore
  if(self.disable_mail == false && !self.user_preferences.exists?(:email_type => pref))
    job.perform_async(*args)
  end
end

#mine?(target) ⇒ Boolean

Returns:

  • (Boolean)

491
492
493
494
495
496
497
# File 'app/models/user.rb', line 491

def mine?(target)
  if target.present? && target.respond_to?(:user_id)
    return self.id == target.user_id
  end

  false
end

#moderator?Boolean

Returns:

  • (Boolean)

475
476
477
# File 'app/models/user.rb', line 475

def moderator?
  Role.moderator?(person)
end

#moderator_only?Boolean

Returns:

  • (Boolean)

479
480
481
# File 'app/models/user.rb', line 479

def moderator_only?
  Role.moderator_only?(person)
end

#no_person_with_same_usernameObject


534
535
536
537
538
539
# File 'app/models/user.rb', line 534

def no_person_with_same_username
  diaspora_id = "#{self.username}#{User.diaspora_id_host}"
  if self.username_changed? && Person.exists?(:diaspora_handle => diaspora_id)
    errors[:base] << 'That username has already been taken'
  end
end

#perform_export!Object


322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/user.rb', line 322

def perform_export!
  export = Tempfile.new([username, ".json.gz"], encoding: "ascii-8bit")
  export.write(compressed_export) && export.close
  if export.present?
    update exporting: false, export: export, exported_at: Time.zone.now
  else
    update exporting: false
  end
rescue => error
  logger.error "Unexpected error while exporting user '#{username}': #{error.class}: #{error.message}\n" \
               "#{error.backtrace.first(15).join("\n")}"
  update exporting: false
end

#perform_export_photos!Object


348
349
350
351
352
353
354
# File 'app/models/user.rb', line 348

def perform_export_photos!
  PhotoExporter.new(self).perform
rescue => error
  logger.error "Unexpected error while exporting photos for '#{username}': #{error.class}: #{error.message}\n" \
               "#{error.backtrace.first(15).join("\n")}"
  update exporting_photos: false
end

#podmin_account?Boolean

Returns:

  • (Boolean)

487
488
489
# File 'app/models/user.rb', line 487

def podmin_account?
  username == AppConfig.admins.
end

#post_default_aspectsObject


274
275
276
277
278
279
280
# File 'app/models/user.rb', line 274

def post_default_aspects
  if post_default_public
    ["public"]
  else
    aspects.where(post_default: true).to_a
  end
end

#process_invite_acceptence(invite) ⇒ Object


119
120
121
122
# File 'app/models/user.rb', line 119

def process_invite_acceptence(invite)
  self.invited_by = invite.user
  invite.use! unless AppConfig.settings.enable_registrations?
end

#queue_exportObject


317
318
319
320
# File 'app/models/user.rb', line 317

def queue_export
  update exporting: true, export: nil, exported_at: nil
  Workers::ExportUser.perform_async(id)
end

#queue_export_photosObject


343
344
345
346
# File 'app/models/user.rb', line 343

def queue_export_photos
  update exporting_photos: true, exported_photos_file: nil, exported_photos_at: nil
  Workers::ExportPhotos.perform_async(id)
end

#remember_meObject


596
597
598
# File 'app/models/user.rb', line 596

def remember_me
  true
end

#remove_hidden_shareable(key, share_id) ⇒ Object


142
143
144
145
146
# File 'app/models/user.rb', line 142

def remove_hidden_shareable(key, share_id)
  if self.hidden_shareables.has_key?(key)
    self.hidden_shareables[key].delete(share_id)
  end
end

#remove_invalid_unconfirmed_emailsObject

Whenever email is set, clear all unconfirmed emails which match


516
517
518
519
520
521
# File 'app/models/user.rb', line 516

def remove_invalid_unconfirmed_emails
  return unless saved_change_to_email?
  # rubocop:disable Rails/SkipsModelValidations
  User.where(unconfirmed_email: email).update_all(unconfirmed_email: nil, confirm_email_token: nil)
  # rubocop:enable Rails/SkipsModelValidations
end

#retract(target) ⇒ Object

Posts and Such ###############


371
372
373
374
375
# File 'app/models/user.rb', line 371

def retract(target)
  retraction = Retraction.for(target)
  retraction.defer_dispatch(self)
  retraction.perform
end

#seed_aspectsObject


440
441
442
443
444
445
446
447
448
449
450
451
# File 'app/models/user.rb', line 440

def seed_aspects
  self.aspects.create(:name => I18n.t('aspects.seed.family'))
  self.aspects.create(:name => I18n.t('aspects.seed.friends'))
  self.aspects.create(:name => I18n.t('aspects.seed.work'))
  aq = self.aspects.create(:name => I18n.t('aspects.seed.acquaintances'))

  if AppConfig.settings.autofollow_on_join?
     = Person.find_or_fetch_by_identifier(AppConfig.settings.autofollow_on_join_user)
    self.share_with(, aq) if 
  end
  aq
end

#send_confirm_emailObject


365
366
367
368
# File 'app/models/user.rb', line 365

def send_confirm_email
  return if unconfirmed_email.blank?
  Workers::Mail::ConfirmEmail.perform_async(id)
end

#send_reset_password_instructionsObject


180
181
182
# File 'app/models/user.rb', line 180

def send_reset_password_instructions
  Workers::ResetPassword.perform_async(self.id)
end

#send_reset_password_instructions!Object

Copy the method provided by Devise to be able to call it later from a Sidekiq job


178
# File 'app/models/user.rb', line 178

alias_method :send_reset_password_instructions!, :send_reset_password_instructions

#send_welcome_messageObject


453
454
455
456
457
458
459
460
461
462
463
464
465
# File 'app/models/user.rb', line 453

def send_welcome_message
  return unless AppConfig.settings.welcome_message.enabled? && AppConfig.admins.account?
  sender_username = AppConfig.admins..get
  sender = User.find_by(username: sender_username)
  return if sender.nil?
  conversation = sender.build_conversation(
    participant_ids: [sender.person.id, person.id],
    subject:         AppConfig.settings.welcome_message.subject.get,
    message:         {text: AppConfig.settings.welcome_message.text.get % {username: username}}
  )

  Diaspora::Federation::Dispatcher.build(sender, conversation).dispatch if conversation.save
end

#set_current_languageObject


214
215
216
# File 'app/models/user.rb', line 214

def set_current_language
  self.language = I18n.locale.to_s if self.language.blank?
end

#set_default_color_themeObject


218
219
220
# File 'app/models/user.rb', line 218

def set_default_color_theme
  self.color_theme ||= AppConfig.settings.default_color_theme
end

#set_person(person) ⇒ Object


431
432
433
434
# File 'app/models/user.rb', line 431

def set_person(person)
  person.diaspora_handle = "#{self.username}#{User.diaspora_id_host}"
  self.person = person
end

#setup(opts) ⇒ Object


415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
# File 'app/models/user.rb', line 415

def setup(opts)
  self.username = opts[:username]
  self.email = opts[:email]
  self.language = opts[:language]
  self.language ||= I18n.locale.to_s
  self.color_theme = opts[:color_theme]
  self.color_theme ||= AppConfig.settings.default_color_theme
  self.valid?
  errors = self.errors
  errors.delete :person
  return if errors.size > 0
  self.set_person(Person.new((opts[:person] || {}).except(:id)))
  self.generate_keys
  self
end

#sign_upObject


572
573
574
575
576
577
578
# File 'app/models/user.rb', line 572

def 
  if AppConfig.settings.captcha.enable?
    save_with_captcha
  else
    save
  end
end

#spotlight?Boolean

Returns:

  • (Boolean)

483
484
485
# File 'app/models/user.rb', line 483

def spotlight?
  Role.spotlight?(person)
end

#strip_and_downcase_usernameObject


203
204
205
206
207
208
# File 'app/models/user.rb', line 203

def strip_and_downcase_username
  if username.present?
    username.strip!
    username.downcase!
  end
end

#toggle_hidden_shareable(share) ⇒ Object


157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'app/models/user.rb', line 157

def toggle_hidden_shareable(share)
  share_id = share.id.to_s
  key = share.class.base_class.to_s
  if self.hidden_shareables.has_key?(key) && self.hidden_shareables[key].include?(share_id)
    self.remove_hidden_shareable(key, share_id)
    self.save
    false
  else
    self.add_hidden_shareable(key, share_id)
    self.save
    true
  end
end

#unconfirmed_email_quasiuniquenessObject

Ensure that the unconfirmed email isn't already someone's email


501
502
503
504
505
# File 'app/models/user.rb', line 501

def unconfirmed_email_quasiuniqueness
  if User.exists?(["id != ? AND email = ?", id, unconfirmed_email])
    errors.add(:unconfirmed_email, I18n.t("errors.messages.taken"))
  end
end

#unread_message_countObject


115
116
117
# File 'app/models/user.rb', line 115

def unread_message_count
  ConversationVisibility.where(person_id: self.person_id).sum(:unread)
end

#unread_notificationsObject


111
112
113
# File 'app/models/user.rb', line 111

def unread_notifications
  notifications.where(:unread => true)
end

#update_post(post, post_hash = {}) ⇒ Object


253
254
255
256
257
258
# File 'app/models/user.rb', line 253

def update_post(post, post_hash={})
  if self.owns? post
    post.update_attributes(post_hash)
    self.dispatch_post(post)
  end
end

#update_post_default_aspects(post_default_aspect_ids) ⇒ Object


282
283
284
285
286
287
# File 'app/models/user.rb', line 282

def update_post_default_aspects(post_default_aspect_ids)
  aspects.each do |aspect|
    enable = post_default_aspect_ids.include?(aspect.id.to_s)
    aspect.update_attribute(:post_default, enable)
  end
end

#update_profile(params) ⇒ Object

Profile ######################


378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
# File 'app/models/user.rb', line 378

def update_profile(params)
  if photo = params.delete(:photo)
    photo.update_attributes(:pending => false) if photo.pending
    params[:image_url] = photo.url(:thumb_large)
    params[:image_url_medium] = photo.url(:thumb_medium)
    params[:image_url_small] = photo.url(:thumb_small)
  end

  params.stringify_keys!
  params.slice!(*(Profile.column_names+['tag_string', 'date']))
  if self.profile.update_attributes(params)
    deliver_profile_update
    true
  else
    false
  end
end

#update_profile_with_omniauth(user_info) ⇒ Object


396
397
398
# File 'app/models/user.rb', line 396

def update_profile_with_omniauth(  )
  update_profile( self.profile.from_omniauth_hash(  ) )
end

#update_user_preferences(pref_hash) ⇒ Object


184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'app/models/user.rb', line 184

def update_user_preferences(pref_hash)
  if self.disable_mail
    UserPreference::VALID_EMAIL_TYPES.each{|x| self.user_preferences.find_or_create_by(email_type: x)}
    self.disable_mail = false
    self.save
  end

  pref_hash.keys.each do |key|
    if pref_hash[key] == 'true'
      self.user_preferences.find_or_create_by(email_type: key)
    else
      block = user_preferences.find_by(email_type: key)
      if block
        block.destroy
      end
    end
  end
end