Skip to content
Extraits de code Groupes Projets
person.rb 8,58 ko
Newer Older
danielgrippi's avatar
danielgrippi a validé
#   Copyright (c) 2010-2011, Diaspora Inc.  This file is
Raphael's avatar
Raphael a validé
#   licensed under the Affero General Public License version 3 or later.  See
Raphael's avatar
Raphael a validé
#   the COPYRIGHT file.
Raphael's avatar
Raphael a validé
  include Encryptor::Public
Raphael's avatar
Raphael a validé
  include Diaspora::Guid
  # NOTE API V1 to be extracted
  acts_as_api
  api_accessible :backbone do |t|
    t.add :guid
    t.add lambda { |person|
      person.diaspora_handle
    }, :as => :diaspora_id
      {:small => person.profile.image_url(:thumb_small),
       :medium => person.profile.image_url(:thumb_medium),
       :large => person.profile.image_url(:thumb_large) }
Raphael's avatar
Raphael a validé
  xml_attr :diaspora_handle
  xml_attr :url
  xml_attr :profile, :as => Profile
  xml_attr :exported_key
  has_one :profile, dependent: :destroy
  delegate :last_name, :image_url, :tag_string, :bio, :location,
           :gender, :birthday, :formatted_birthday, :tags, :searchable,
  before_validation :downcase_diaspora_handle
  def downcase_diaspora_handle
    diaspora_handle.downcase! unless diaspora_handle.blank?
  has_many :contacts, :dependent => :destroy # Other people's contacts for this person
  has_many :posts, :foreign_key => :author_id, :dependent => :destroy # This person's own posts
  has_many :photos, :foreign_key => :author_id, :dependent => :destroy # This person's own photos
  has_many :comments, :foreign_key => :author_id, :dependent => :destroy # This person's own comments
  has_many :participations, :foreign_key => :author_id, :dependent => :destroy
  has_many :conversation_visibilities
Daniel Grippi's avatar
Daniel Grippi a validé
  belongs_to :owner, :class_name => 'User'
  belongs_to :pod
zhitomirskiyi's avatar
zhitomirskiyi a validé
  has_many :notification_actors
zhitomirskiyi's avatar
zhitomirskiyi a validé
  has_many :notifications, :through => :notification_actors

Raphael Sofaer's avatar
Raphael Sofaer a validé
  has_many :mentions, :dependent => :destroy

  validate :owner_xor_pod
  validates :profile, :presence => true
  validates :serialized_public_key, :presence => true
  validates :diaspora_handle, :uniqueness => true
  scope :searchable, -> { joins(:profile).where(:profiles => {:searchable => true}) }
  scope :remote, -> { where('people.owner_id IS NULL') }
  scope :local, -> { where('people.owner_id IS NOT NULL') }
  scope :for_json, -> {
    select('DISTINCT people.id, people.guid, people.diaspora_handle')
      .includes(:profile)
  }
  # @note user is passed in here defensively
  scope :all_from_aspects, ->(aspect_ids, user) {
    joins(:contacts => :aspect_memberships).
         where(:contacts => {:user_id => user.id}).
         where(:aspect_memberships => {:aspect_id => aspect_ids})
  scope :unique_from_aspects, ->(aspect_ids, user) {
    all_from_aspects(aspect_ids, user).select('DISTINCT people.*')
  }

  #not defensive
  scope :in_aspects, ->(aspect_ids) {
        where(:aspect_memberships => {:aspect_id => aspect_ids})
  scope :profile_tagged_with, ->(tag_name) {
    joins(:profile => :tags)
      .where(:tags => {:name => tag_name})
      .where('profiles.searchable IS TRUE')
  }
Maxwell Salzberg's avatar
Maxwell Salzberg a validé

  scope :who_have_reshared_a_users_posts, ->(user) {
    joins(:posts)
      .where(:posts => {:root_guid => StatusMessage.guids_for_author(user.person), :type => 'Reshare'} )
  def self.community_spotlight
    Person.joins(:roles).where(:roles => {:name => 'spotlight'})
  # Set a default of an empty profile when a new Person record is instantiated.
  # Passing :profile => nil to Person.new will instantiate a person with no profile.
  # Calling Person.new with a block:
  #   Person.new do |p|
  #     p.profile = nil
  #   end
  # will not work!  The nil profile will be overriden with an empty one.
  def initialize(params={})
    profile_set = params.has_key?(:profile) || params.has_key?("profile")
    params[:profile_attributes] = params.delete(:profile) if params.has_key?(:profile) && params[:profile].is_a?(Hash)
    super
    self.profile ||= Profile.new unless profile_set
  end
  def self.find_from_guid_or_username(params)
          Person.where(:guid => params[:id]).first
        elsif params[:username].present? && u = User.find_by_username(params[:username])
          u.person
        else
          nil
        end
    raise ActiveRecord::RecordNotFound unless p.present?
    p
  end

  def to_param
    self.guid
  end

maxwell's avatar
maxwell a validé
  def self.search_query_string(query)
    query = query.downcase
Jonne Haß's avatar
Jonne Haß a validé
    like_operator = AppConfig.postgres? ? "ILIKE" : "LIKE"
danielgrippi's avatar
danielgrippi a validé
    where_clause = <<-SQL
      profiles.full_name #{like_operator} ? OR
      people.diaspora_handle #{like_operator} ?
    SQL
Raphael Sofaer's avatar
Raphael Sofaer a validé

    q_tokens = []
    q_tokens[0] = query.to_s.strip.gsub(/(\s|$|^)/) { "%#{$1}" }
    q_tokens[1] = q_tokens[0].gsub(/\s/,'').gsub('%','')
    q_tokens[1] << "%"

    [where_clause, q_tokens]
maxwell's avatar
maxwell a validé
  end
Raphael Sofaer's avatar
Raphael Sofaer a validé

maxwell's avatar
maxwell a validé
  def self.search(query, user)
    return self.where("1 = 0") if query.to_s.blank? || query.to_s.length < 2
maxwell's avatar
maxwell a validé

    sql, tokens = self.search_query_string(query)
danielgrippi's avatar
danielgrippi a validé

    Person.searchable.where(sql, *tokens).joins(
      "LEFT OUTER JOIN contacts ON contacts.user_id = #{user.id} AND contacts.person_id = people.id"
    ).includes(:profile
  # @return [Array<String>] postgreSQL and mysql deal with null values in orders differently, it seems.
  def self.search_order
    @search_order ||= Proc.new {
Jonne Haß's avatar
Jonne Haß a validé
      order = if AppConfig.postgres?
        "ASC"
      else
        "DESC"
      end
      ["contacts.user_id #{order}", "profiles.last_name ASC", "profiles.first_name ASC"]
    }.call
  end

  def name(opts = {})
    @name ||= Person.name_from_attrs(self.profile.first_name, self.profile.last_name, self.diaspora_handle)
  end

  def self.name_from_attrs(first_name, last_name, diaspora_handle)
    first_name.blank? && last_name.blank? ? diaspora_handle : "#{first_name.to_s.strip} #{last_name.to_s.strip}".strip
    @first_name ||= if profile.nil? || profile.first_name.nil? || profile.first_name.blank?
                self.diaspora_handle.split('@').first
              else
                names = profile.first_name.to_s.split(/\s/)
danielgrippi's avatar
danielgrippi a validé
                str = names[0...-1].join(' ')
                str = names[0] if str.blank?
                str
  def username
    @username ||= owner ? owner.username : diaspora_handle.split("@")[0]
  end

danielvincent's avatar
danielvincent a validé
  def owns?(obj)
Raphael's avatar
Raphael a validé
  end
Benjamin Neff's avatar
Benjamin Neff a validé
    url_to "/"
Raphael's avatar
Raphael a validé

Benjamin Neff's avatar
Benjamin Neff a validé
    url_to "/u/#{username}"
Raphael's avatar
Raphael a validé
  end
Benjamin Neff's avatar
Benjamin Neff a validé
    url_to "/public/#{username}.atom"
Benjamin Neff's avatar
Benjamin Neff a validé
    url_to "/receive/users/#{guid}"
danielvincent's avatar
danielvincent a validé
  end

    Base64.encode64(OpenSSL::Digest::SHA256.new(serialized_public_key).to_s)
Raphael's avatar
Raphael a validé
  def public_key
Raphael's avatar
Raphael a validé
  end

    raise "Don't change a key" if serialized_public_key
zhitomirskiyi's avatar
zhitomirskiyi a validé
    serialized_public_key = new_key
  # discovery (webfinger)
  def self.find_or_fetch_by_identifier(diaspora_id)
    # exiting person?
    person = by_account_identifier(diaspora_id)
    return person if person.present? && person.profile.present?

    # create or update person from webfinger
    logger.info "webfingering #{diaspora_id}, it is not known or needs updating"
    DiasporaFederation::Discovery::Discovery.new(diaspora_id).fetch_and_save
    by_account_identifier(diaspora_id)
  def self.by_account_identifier(diaspora_id)
    find_by(diaspora_handle: diaspora_id.strip.downcase)
Raphael's avatar
Raphael a validé
  def remote?
Jakob Kramer's avatar
Jakob Kramer a validé
  def has_photos?
    self.photos.exists?
Jakob Kramer's avatar
Jakob Kramer a validé
  end

  def as_json( opts = {} )
    opts ||= {}
    json = {
      :id => self.id,
      :guid => self.guid,
Raphael Sofaer's avatar
Raphael Sofaer a validé
      :name => self.name,
danielgrippi's avatar
danielgrippi a validé
      :avatar => self.profile.image_url(:thumb_medium),
Raphael Sofaer's avatar
Raphael Sofaer a validé
      :handle => self.diaspora_handle,
      :url => Rails.application.routes.url_helpers.person_path(self),
    json.merge!(:tags => self.profile.tags.map{|t| "##{t.name}"}) if opts[:includes] == "tags"
    json
    self.closed_account = true
    self.save
  private
Benjamin Neff's avatar
Benjamin Neff a validé
  # @param path [String]
  # @return [String]
  def url_to(path)
    local? ? AppConfig.url_to(path) : pod.url_to(path)
Benjamin Neff's avatar
Benjamin Neff a validé
  end

    logger.info "fix profile for account: #{diaspora_handle}"
    DiasporaFederation::Discovery::Discovery.new(diaspora_handle).fetch_and_save
    reload

  def owner_xor_pod
    errors.add(:base, "Specify an owner or a pod, not both") unless owner.blank? ^ pod.blank?
  end
Daniel Grippi's avatar
Daniel Grippi a validé
end