Skip to Content Skip to Search
Methods
A
B
C
D
E
F
G
H
I
L
M
P
R
S
T
W
Included Modules

Constants

ACTIVE_STATUSES = %w[approved approved_manually].freeze
 
PROFILE_ATTRIBUTES = %w[first_name last_name email profile_image_data].freeze
 
STATUSES = (ACTIVE_STATUSES + %w[awaiting_approval denied imported invited removed]).freeze
 

Attributes

[RW] after_signup_plan_id
[W] previous_email
[RW] validate_after_signup_fields

Instance Public methods

active_plan()

# File app/models/db/member.rb, line 224
def active_plan
  active_subscription&.plan
end

active_plan?()

# File app/models/db/member.rb, line 220
def active_plan?
  active_subscription.present?
end

active_plans()

# File app/models/db/member.rb, line 228
def active_plans
  plans.select { |plan| plannings.find_by!(plan:).good_standing? }
end

active_sites()

# File app/models/db/member.rb, line 495
def active_sites
  if of_memberspace?
    becomes(SiteOwner).active_sites
  else
    []
  end
end

active_subscription()

# File app/models/db/member.rb, line 212
def active_subscription
  subscriptions.recurring.active.last
end

after_session_created(ip:)

# File app/models/db/member.rb, line 410
def after_session_created(ip:)
  limit_concurrent_sessions!(ip)
end

agency?()

# File app/models/db/member.rb, line 418
def agency?
  becomes(Agency).organization.present? ||
    becomes(SiteOwner).can_create_organization?
end

all_free_plans_expired?()

# File app/models/db/member.rb, line 406
def all_free_plans_expired?
  free_plans.any? && expired_free_plans.count == free_plans.count
end

any_unexpired_free_plans?()

# File app/models/db/member.rb, line 402
def any_unexpired_free_plans?
  free_plans.any? && !all_free_plans_expired?
end

approved?()

# File app/models/db/member.rb, line 204
def approved?
  approved_status? || approved_manually_status?
end

as_json(_options = {})

# File app/models/db/member.rb, line 255
def as_json(_options = {})
  ActiveModelSerializers::SerializableResource.new(
    self,
    serializer: RestApi::V1::MemberSerializer
  ).as_json
end

available_plans()

# File app/models/db/member.rb, line 236
def available_plans
  site.plans.reject(&:specific_time_expired?) -
    expired_plans.select(&:free_plan_type?)
end

billing_history?()

# File app/models/db/member.rb, line 385
def billing_history?
  paid_subscriptions.any? || paid_plans.any? || charges.any? || invoices.any?
end

broadcasts_subscribe!()

# File app/models/db/member.rb, line 507
def broadcasts_subscribe!
  update!(broadcasts_unsubscribed_at: nil)
end

broadcasts_unsubscribe!()

# File app/models/db/member.rb, line 503
def broadcasts_unsubscribe!
  update!(broadcasts_unsubscribed_at: Time.current)
end

can_resend_invitation()

can_resend_invitation?()

Also aliased as: can_resend_invitation
# File app/models/db/member.rb, line 397
def can_resend_invitation?
  !email_inactive?
end

card_recently_updated?()

# File app/models/db/member.rb, line 359
def card_recently_updated?
  event = events.card_updated.or(events.dunning_conversion).most_recent
  return false unless event

  event.created_at.after? last_failed_payment.updated_at
end

client?()

# File app/models/db/member.rb, line 423
def client?
  becomes(SiteOwner).billing_invites.present?
end

custom_field_value(field)

# File app/models/db/member.rb, line 432
def custom_field_value(field)
  custom_fields[field.id.to_s]
end

custom_fields=(fields)

# File app/models/db/member.rb, line 427
def custom_fields=(fields)
  fields = sanitize_custom_fields(fields)
  super
end

disable_new_content_notifications!()

# File app/models/db/member.rb, line 148
def disable_new_content_notifications!
  update!(send_new_content_notifications: false)
end

email=(email)

# File app/models/db/member.rb, line 152
def email=(email)
  super(sanitize_email(email))
end

email_confirmation=(email)

# File app/models/db/member.rb, line 156
def email_confirmation=(email)
  @email_confirmation = sanitize_email(email)
end

enable_new_content_notifications!()

# File app/models/db/member.rb, line 144
def enable_new_content_notifications!
  update!(send_new_content_notifications: true)
end

event_activity()

# File app/models/db/member.rb, line 196
def event_activity
  events.order(created_at: :desc)
end

expired_plans()

# File app/models/db/member.rb, line 232
def expired_plans
  plannings.includes(:plan).select(&:expired?).map(&:plan)
end

facebook_referral()

# File app/models/db/member.rb, line 192
def facebook_referral
  find_referral_metadata(:facebook)[:data]
end

failed_card?()

# File app/models/db/member.rb, line 366
def failed_card?
  # Check for failed payment records with status in_recovery or churned.
  failed_payment = failed_payments.where({
    status: %w[in_recovery churned]
  }).exists?

  # If none exists, then there's no failing card.
  return false unless failed_payment

  # If there's a failed payment, check if there's a subscription with status
  # other than active or trialing (e.g: past_due)
  # if that's the case, then we know we have a failing card
  subscriptions.where.not(status: %w[active trialing]).exists?
end

first_name=(name)

# File app/models/db/member.rb, line 160
def first_name=(name)
  super(sanitize(name))
end

formatted_custom_fields()

# File app/models/db/member.rb, line 436
def formatted_custom_fields
  field_ids = custom_fields.keys
  fields = requested_fields.where(id: field_ids)

  fields.map { |field|
    [field.id.to_s, field.format_value(custom_field_value(field))]
  }.to_h
end

full_name()

# File app/models/db/member.rb, line 208
def full_name
  "#{first_name} #{last_name}"
end

global_role()

# File app/models/db/member.rb, line 483
def global_role
  if super_admin?
    :super_admin
  elsif agency?
    :agency_owner
  elsif site_owner?
    :site_owner
  else
    :member
  end
end

handle_outstanding_invoices(conversion_method)

# File app/models/db/member.rb, line 473
def handle_outstanding_invoices(conversion_method)
  past_due_failed_payment_ids.each do |failed_payment_id|
    OutstandingInvoiceCollectorJob.perform_later(
      failed_payment_id:,
      event: "card updated",
      conversion_method:
    )
  end
end

has_active_trial?()

# File app/models/db/member.rb, line 216
def has_active_trial?
  active_subscription&.trialing_status?
end

has_plan_from_field?(field)

# File app/models/db/member.rb, line 299
def has_plan_from_field?(field)
  return true if field.allow_all_plans
  active_plans.intersection(field.plans).any?
end

incomplete_subscription()

# File app/models/db/member.rb, line 308
def incomplete_subscription
  subscriptions
    .where.not(pending_intent_id: nil)
    .where(status: %w[incomplete past_due])
    .last
end

incomplete_subscription?()

# File app/models/db/member.rb, line 304
def incomplete_subscription?
  incomplete_subscription.present?
end

last_failed_payment()

# File app/models/db/member.rb, line 381
def last_failed_payment
  @last_failed_payment ||= failed_payments.order(:updated_at).last
end

last_name=(name)

# File app/models/db/member.rb, line 164
def last_name=(name)
  super(sanitize(name))
end

latest_pending_intent_id()

# File app/models/db/member.rb, line 393
def latest_pending_intent_id
  incomplete_subscription.pending_intent_id
end

metadata()

# File app/models/db/member.rb, line 172
def metadata
  super.with_indifferent_access
end

metadata=(input)

# File app/models/db/member.rb, line 168
def metadata=(input)
  super(safe_modify_metadata(input))
end

pending_intent(client_secret:)

# File app/models/db/member.rb, line 454
def pending_intent(client_secret:)
  case client_secret
  when /^pi_/
    pending_payment_intent
  when /^seti_/
    pending_setup_intent
  end
end

plan_removed(subscription, reason, performed_by = full_name)

# File app/models/db/member.rb, line 315
def plan_removed(subscription, reason, performed_by = full_name)
  Dispatch.track(
    model: self,
    action: :plan_removed,
    title: "Unsubscribed from #{subscription.plan.name}",
    details: {
      plan_type: DB::Plan.plan_types[subscription.plan.plan_type], # FIXME: legacy support for older magic strings
      plan_id: subscription.plan.id,
      reason: reason,
      performed_by: performed_by
    }
  )
end

previous_email()

# File app/models/db/member.rb, line 389
def previous_email
  @previous_email ||= (previous_changes[:email]&.first || email)
end

profile_attributes_changed?()

Profile attributes changed before save?

# File app/models/db/member.rb, line 246
def profile_attributes_changed?
  PROFILE_ATTRIBUTES.intersection(changed_attributes.keys).any?
end

profile_attributes_previously_changed?()

Profile attributes changed after save?

# File app/models/db/member.rb, line 251
def profile_attributes_previously_changed?
  PROFILE_ATTRIBUTES.intersection(previous_changes.keys).any?
end

profile_image_url(is_public = false)

# File app/models/db/member.rb, line 262
def profile_image_url(is_public = false)
  if profile_image.present?
    (profile_image(:processed) || profile_image).url(public: is_public)
  else
    default = "https://admin.memberspace.com/images/gravatar-default-v3.png"
    Service::GravatarService.new(email, {default: default, size: 200}).gravatar_url
  end
end

recovered!()

# File app/models/db/member.rb, line 180
def recovered!
  update!(metadata: {recovered_by: nil})
end

recovered_by()

# File app/models/db/member.rb, line 176
def recovered_by
  metadata[:recovered_by]
end

referrals()

# File app/models/db/member.rb, line 184
def referrals
  (metadata[:referrals] || [])
end

remote_customer()

# File app/models/db/member.rb, line 445
def remote_customer
  @remote_customer ||= StripeCustomer.new(member: self)
end

remote_customer_url()

# File app/models/db/member.rb, line 449
def remote_customer_url
  return unless payment_gateway_id
  "https://dashboard.stripe.com/#{site_payment_gateway_id}/customers/#{payment_gateway_id}"
end

remove_default_subscription_payments()

# File app/models/db/member.rb, line 463
def remove_default_subscription_payments
  updatable_subscription_remote_ids.each do |payment_gateway_id|
    StripeSubscriptionUpdatorJob.perform_later(
      site_id:,
      payment_gateway_id:,
      attributes: {default_payment_method: nil}
    )
  end
end

reset_password_by_token!(new_password)

# File app/models/db/member.rb, line 329
def reset_password_by_token!(new_password)
  update!(
    password: new_password.presence,
    reset_password_digest: nil,
    reset_password_sent_at: nil
  )
end

rewardful_referral()

# File app/models/db/member.rb, line 188
def rewardful_referral
  find_referral_metadata(:rewardful)[:data]
end

set_magic_login_token!()

# File app/models/db/member.rb, line 348
def set_magic_login_token!
  service = Service::SecureToken.new.generate

  update_columns(
    magic_login_digest: service.token_digest,
    magic_login_sent_at: service.timestamp
  )

  service.token
end

set_reset_password_token!()

# File app/models/db/member.rb, line 337
def set_reset_password_token!
  service = Service::SecureToken.new.generate

  update_columns(
    reset_password_digest: service.token_digest,
    reset_password_sent_at: service.timestamp
  )

  service.token
end

should_upgrade?()

# File app/models/db/member.rb, line 284
def should_upgrade?
  return false unless should_upgrade_event

  period = should_upgrade_event.details["period"]
  true if period && period.days.ago < should_upgrade_event.created_at
end

should_upgrade_event()

# File app/models/db/member.rb, line 291
def should_upgrade_event
  events
    .should_upgrade
    .where("(details->>'snoozed') IS ?", nil)
    .order(created_at: :desc)
    .first
end

site_owner?()

# File app/models/db/member.rb, line 414
def site_owner?
  site == DB::Site.memberspace
end

super_admin?()

# File app/models/db/member.rb, line 200
def super_admin?
  Rails.application.config.super_admin_emails.include?(email)
end

to_liquid()

# File app/models/db/member.rb, line 241
def to_liquid
  EmailDrops::MemberDrop.new(self)
end

websitetoolbox_username()

# File app/models/db/member.rb, line 271
def websitetoolbox_username
  integration = site.integrations.website_toolbox.first
  return unless integration

  version = integration.configuration.try(:[], "version").to_i
  case version
  when 0
    "#{first_name}_#{last_name}_#{Digest::MD5.hexdigest(email)[0..3]}".parameterize
  when 1
    email
  end
end