Class: Panda::Core::User

Inherits:
ApplicationRecord show all
Includes:
HasUUID
Defined in:
app/models/panda/core/user.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.admin_columnObject

Determine which column stores admin flag (supports legacy ‘admin` and new `is_admin`)



23
24
25
26
# File 'app/models/panda/core/user.rb', line 23

def self.admin_column
  # Prefer canonical `admin` if available, otherwise fall back to legacy `is_admin`
  @admin_column ||= column_names.include?("admin") ? "admin" : "is_admin"
end

.find_or_create_from_auth_hash(auth_hash) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'app/models/panda/core/user.rb', line 33

def self.find_or_create_from_auth_hash(auth_hash)
  user = find_by(email: auth_hash.info.email.downcase)

  # Handle avatar for both new and existing users
  avatar_url = auth_hash.info.image
  if user
    # Update avatar if URL has changed or no avatar is attached
    if avatar_url.present? && (avatar_url != user.oauth_avatar_url || !user.avatar.attached?)
      AttachAvatarService.call(user: user, avatar_url: avatar_url)
    end
    return user
  end

  attributes = {
    email: auth_hash.info.email.downcase,
    name: auth_hash.info.name || "Unknown User",
    image_url: auth_hash.info.image,
    admin_column => User.count.zero? # First user is admin
  }

  user = create!(attributes)

  # Attach avatar for new user
  if avatar_url.present?
    AttachAvatarService.call(user: user, avatar_url: avatar_url)
  end

  user
end

Instance Method Details

#active_for_authentication?Boolean

Returns:

  • (Boolean)


79
80
81
# File 'app/models/panda/core/user.rb', line 79

def active_for_authentication?
  true
end

#adminObject Also known as: is_admin

Support both legacy ‘admin` and new `is_admin` columns



69
70
71
# File 'app/models/panda/core/user.rb', line 69

def admin
  self[self.class.admin_column]
end

#admin=(value) ⇒ Object Also known as: is_admin=



73
74
75
# File 'app/models/panda/core/user.rb', line 73

def admin=(value)
  self[self.class.admin_column] = ActiveRecord::Type::Boolean.new.cast(value)
end

#admin?Boolean

Admin status check

Returns:

  • (Boolean)


64
65
66
# File 'app/models/panda/core/user.rb', line 64

def admin?
  ActiveRecord::Type::Boolean.new.cast(admin)
end

#avatar_url(size: nil) ⇒ String?

Returns the URL for the user’s avatar Prefers Active Storage attachment over OAuth provider URL

Parameters:

  • size (Symbol) (defaults to: nil)

    The variant size (:thumb, :small, :medium, :large, or nil for original)

Returns:

  • (String, nil)

    The avatar URL or nil if no avatar available



87
88
89
90
91
92
93
94
95
96
97
98
# File 'app/models/panda/core/user.rb', line 87

def avatar_url(size: nil)
  if avatar.attached?
    if size && [:thumb, :small, :medium, :large].include?(size)
      Rails.application.routes.url_helpers.rails_blob_path(avatar.variant(size), only_path: true)
    else
      Rails.application.routes.url_helpers.rails_blob_path(avatar, only_path: true)
    end
  elsif self[:image_url].present?
    # Fallback to OAuth provider URL if no avatar is attached yet
    self[:image_url]
  end
end