mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-05-17 05:00:09 -04:00
267 lines
7.5 KiB
Ruby
267 lines
7.5 KiB
Ruby
class Member < ActiveRecord::Base
|
|
extend FriendlyId
|
|
friendly_id :login_name, use: :slugged
|
|
|
|
has_many :posts, :foreign_key => 'author_id'
|
|
has_many :comments, :foreign_key => 'author_id'
|
|
has_many :forums, :foreign_key => 'owner_id'
|
|
|
|
has_many :gardens, :foreign_key => 'owner_id'
|
|
has_many :plantings, :foreign_key => 'owner_id'
|
|
|
|
has_many :seeds, :foreign_key => 'owner_id'
|
|
|
|
has_and_belongs_to_many :roles
|
|
|
|
has_many :notifications, :foreign_key => 'recipient_id'
|
|
has_many :sent_notifications, :foreign_key => 'sender_id'
|
|
|
|
has_many :authentications
|
|
|
|
has_many :orders
|
|
has_one :account
|
|
has_one :account_type, :through => :account
|
|
|
|
has_many :photos
|
|
|
|
default_scope order("lower(login_name) asc")
|
|
scope :confirmed, where('confirmed_at IS NOT NULL')
|
|
scope :located, where("location <> '' and latitude IS NOT NULL and longitude IS NOT NULL")
|
|
scope :recently_signed_in, reorder('updated_at DESC')
|
|
scope :wants_newsletter, where(:newsletter => true)
|
|
|
|
# Include default devise modules. Others available are:
|
|
# :token_authenticatable, :confirmable,
|
|
# :lockable, :timeoutable and :omniauthable
|
|
devise :database_authenticatable, :registerable,
|
|
:recoverable, :rememberable, :trackable, :validatable,
|
|
:confirmable, :lockable, :timeoutable
|
|
|
|
# Setup accessible (or protected) attributes for your model
|
|
attr_accessible :login_name, :email, :password, :password_confirmation,
|
|
:remember_me, :login, :tos_agreement, :show_email, :newsletter,
|
|
:location, :latitude, :longitude, :send_notification_email, :bio
|
|
|
|
# set up geocoding
|
|
geocoded_by :location
|
|
after_validation :geocode
|
|
after_validation :empty_unwanted_geocodes
|
|
|
|
# Virtual attribute for authenticating by either username or email
|
|
# This is in addition to a real persisted field like 'username'
|
|
attr_accessor :login
|
|
|
|
# Requires acceptance of the Terms of Service
|
|
validates_acceptance_of :tos_agreement, :allow_nil => false,
|
|
:accept => true
|
|
|
|
validates :login_name,
|
|
:length => {
|
|
:minimum => 2,
|
|
:maximum => 25,
|
|
:message => "should be between 2 and 25 characters long"
|
|
},
|
|
:exclusion => {
|
|
:in => %w(growstuff admin moderator staff nearby),
|
|
:message => "name is reserved"
|
|
},
|
|
:format => {
|
|
:with => /^\w+$/,
|
|
:message => "may only include letters, numbers, or underscores"
|
|
},
|
|
:uniqueness => {
|
|
:case_sensitive => false
|
|
}
|
|
|
|
# Give each new member a default garden
|
|
after_create {|member| Garden.create(:name => "Garden", :owner_id => member.id) }
|
|
|
|
# and an account record (for paid accounts etc)
|
|
# we use find_or_create to avoid accidentally creating a second one,
|
|
# which can happen sometimes especially with FactoryGirl associations
|
|
after_create {|member| Account.find_or_create_by_member_id(:member_id => member.id) }
|
|
|
|
after_save :update_newsletter_subscription
|
|
|
|
# allow login via either login_name or email address
|
|
def self.find_first_by_auth_conditions(warden_conditions)
|
|
conditions = warden_conditions.dup
|
|
if login = conditions.delete(:login)
|
|
where(conditions).where(["lower(login_name) = :value OR lower(email) = :value", { :value => login.downcase }]).first
|
|
else
|
|
where(conditions).first
|
|
end
|
|
end
|
|
|
|
def to_s
|
|
return login_name
|
|
end
|
|
|
|
def has_role?(role_sym)
|
|
roles.any? { |r| r.name.gsub(/\s+/, "_").underscore.to_sym == role_sym }
|
|
end
|
|
|
|
def current_order
|
|
orders.where(:completed_at => nil).first
|
|
end
|
|
|
|
# when purchasing a product that gives you a paid account, this method
|
|
# does all the messing around to actually make sure the account is
|
|
# updated correctly -- account type, paid until, etc. Usually this is
|
|
# called by order.update_account, which loops through all order items
|
|
# and does this for each one.
|
|
def update_account_after_purchase(product)
|
|
if product.account_type
|
|
account.account_type = product.account_type
|
|
end
|
|
if product.paid_months
|
|
start_date = account.paid_until || Time.zone.now
|
|
account.paid_until = start_date + product.paid_months.months
|
|
end
|
|
account.save
|
|
end
|
|
|
|
def is_paid?
|
|
if account.account_type.is_permanent_paid
|
|
return true
|
|
elsif account.account_type.is_paid and account.paid_until >= Time.zone.now
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
def auth(provider)
|
|
return authentications.find_by_provider(provider)
|
|
end
|
|
|
|
# Authenticates against Flickr and returns an object we can use for subsequent api calls
|
|
def flickr
|
|
if @flickr.nil?
|
|
flickr_auth = auth('flickr')
|
|
if flickr_auth
|
|
FlickRaw.api_key = ENV['FLICKR_KEY']
|
|
FlickRaw.shared_secret = ENV['FLICKR_SECRET']
|
|
@flickr = FlickRaw::Flickr.new
|
|
@flickr.access_token = flickr_auth.token
|
|
@flickr.access_secret = flickr_auth.secret
|
|
end
|
|
end
|
|
return @flickr
|
|
end
|
|
|
|
# Fetches a collection of photos from Flickr
|
|
# Returns a [[page of photos], total] pair.
|
|
# Total is needed for pagination.
|
|
def flickr_photos(page_num=1, set=nil)
|
|
result = false
|
|
if set
|
|
result = flickr.photosets.getPhotos(
|
|
:photoset_id => set,
|
|
:page => page_num,
|
|
:per_page => 30
|
|
)
|
|
else
|
|
result = flickr.people.getPhotos(
|
|
:user_id => 'me',
|
|
:page => page_num,
|
|
:per_page => 30
|
|
)
|
|
end
|
|
if result
|
|
return [result.photo, result.total]
|
|
else
|
|
return [[], 0]
|
|
end
|
|
end
|
|
|
|
# Returns a hash of Flickr photosets' ids and titles
|
|
def flickr_sets
|
|
sets = Hash.new
|
|
flickr.photosets.getList.each do |p|
|
|
sets[p.title] = p.id
|
|
end
|
|
return sets
|
|
end
|
|
|
|
def interesting?
|
|
# we assume we're being passed something from
|
|
# Member.confirmed.located as those are required for
|
|
# interestingness, as well.
|
|
return true if plantings.present?
|
|
return false
|
|
end
|
|
|
|
def Member.interesting
|
|
howmany = 12 # max number to find
|
|
interesting_members = Array.new
|
|
Member.confirmed.located.recently_signed_in.each do |m|
|
|
break if interesting_members.length == howmany
|
|
if m.interesting?
|
|
interesting_members.push(m)
|
|
end
|
|
end
|
|
return interesting_members
|
|
end
|
|
|
|
def Member.nearest_to(place)
|
|
nearby_members = []
|
|
if place
|
|
latitude, longitude = Geocoder.coordinates(place, params: {limit: 1})
|
|
if latitude && longitude
|
|
nearby_members = Member.located.sort_by { |x| x.distance_from([latitude, longitude]) }
|
|
end
|
|
end
|
|
return nearby_members
|
|
end
|
|
|
|
private
|
|
|
|
def geocode
|
|
unless self.location.blank?
|
|
self.latitude, self.longitude =
|
|
Geocoder.coordinates(location, params: {limit: 1})
|
|
end
|
|
end
|
|
|
|
def empty_unwanted_geocodes
|
|
if self.location.blank?
|
|
self.latitude = nil
|
|
self.longitude = nil
|
|
end
|
|
end
|
|
|
|
def update_newsletter_subscription
|
|
if confirmed_at_changed? and newsletter # just signed up
|
|
newsletter_subscribe
|
|
elsif confirmed_at # i.e. after member's confirmed their account
|
|
if newsletter_changed? # edited member settings
|
|
if newsletter
|
|
newsletter_subscribe
|
|
else
|
|
newsletter_unsubscribe
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def newsletter_subscribe
|
|
gb = Gibbon::API.new
|
|
res = gb.lists.subscribe({
|
|
:id => ENV['MAILCHIMP_NEWSLETTER_ID'],
|
|
:email => { :email => email },
|
|
:merge_vars => { :login_name => login_name },
|
|
:double_optin => false # they alredy confirmed their email with us
|
|
})
|
|
end
|
|
|
|
def newsletter_unsubscribe
|
|
gb = Gibbon::API.new
|
|
res = gb.lists.unsubscribe({
|
|
:id => ENV['MAILCHIMP_NEWSLETTER_ID'],
|
|
:email => { :email => email }
|
|
})
|
|
end
|
|
|
|
end
|