Skip to content
Extraits de code Groupes Projets
user.rb 8,31 ko
Newer Older
  • Learn to ignore specific revisions
  • Raphael's avatar
    Raphael a validé
    #   Copyright (c) 2010, Diaspora Inc.  This file is
    
    Raphael's avatar
    Raphael a validé
    #   licensed under the Affero General Public License version 3.  See
    #   the COPYRIGHT file.
    
    require File.expand_path('../../../lib/diaspora/user/friending', __FILE__)
    require File.expand_path('../../../lib/diaspora/user/querying', __FILE__)
    
    Raphael's avatar
    Raphael a validé
    require File.expand_path('../../../lib/diaspora/user/receiving', __FILE__)
    
    require File.expand_path('../../../lib/salmon/salmon', __FILE__)
    
    class User
      include MongoMapper::Document
    
      include Diaspora::UserModules::Friending
    
      include Diaspora::UserModules::Receiving
    
    Raphael's avatar
    Raphael a validé
      include Encryptor::Private
    
    Raphael's avatar
    Raphael a validé
    
    
      devise :database_authenticatable, :registerable,
             :recoverable, :rememberable, :trackable, :validatable
    
      key :username, :unique => true
    
      key :serialized_private_key, String
    
    Daniel Grippi's avatar
    Daniel Grippi a validé
      key :friend_ids,          Array
    
    maxwell's avatar
    maxwell a validé
      key :pending_request_ids, Array
    
    Daniel Grippi's avatar
    Daniel Grippi a validé
      key :visible_post_ids,    Array
      key :visible_person_ids,  Array
    
      one :person, :class_name => 'Person', :foreign_key => :owner_id
    
    Daniel Grippi's avatar
    Daniel Grippi a validé
      many :friends,           :in => :friend_ids,          :class_name => 'Person'
      many :visible_people,    :in => :visible_person_ids,  :class_name => 'Person' # One of these needs to go
      many :pending_requests,  :in => :pending_request_ids, :class_name => 'Request'
      many :raw_visible_posts, :in => :visible_post_ids,    :class_name => 'Post'
    
    Raphael's avatar
    Raphael a validé
      many :aspects, :class_name => 'Aspect'
    
      after_create :seed_aspects
    
      before_validation :downcase_username, :on => :create
    
       def self.find_for_authentication(conditions={})
        if conditions[:username] =~ /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i # email regex
          conditions[:email] = conditions.delete(:username)
    
    Raphael's avatar
    Raphael a validé
        else
          conditions[:username].downcase!
    
      end
    
      ######## Making things work ########
    
      def method_missing(method, *args)
        self.person.send(method, *args)
      end
    
      def real_name
        "#{person.profile.first_name.to_s} #{person.profile.last_name.to_s}"
    
    Raphael's avatar
    Raphael a validé
      ######### Aspects ######################
      def aspect( opts = {} )
    
    Raphael's avatar
    Raphael a validé
        Aspect.create(opts)
    
    danielvincent's avatar
    danielvincent a validé
      def drop_aspect( aspect )
        if aspect.people.size == 0
          aspect.destroy
    
    danielvincent's avatar
    danielvincent a validé
          raise "Aspect not empty"
        end
      end
    
    
      def move_friend( opts = {})
        return true if opts[:to] == opts[:from]
        friend = Person.first(:_id => opts[:friend_id])
        if self.friend_ids.include?(friend.id)
    
          from_aspect = self.aspect_by_id(opts[:from])
    
    Raphael's avatar
    Raphael a validé
          to_aspect = self.aspect_by_id(opts[:to])
          if from_aspect && to_aspect
            posts_to_move = from_aspect.posts.find_all_by_person_id(friend.id)
            to_aspect.people << friend
            to_aspect.posts << posts_to_move
            from_aspect.person_ids.delete(friend.id.to_id)
            posts_to_move.each{ |x| from_aspect.post_ids.delete(x.id)}
            from_aspect.save
            to_aspect.save
    
            return true
          end
        end
        false
      end
    
      ######## Posting ########
    
      def post(class_name, options = {})
    
    Raphael's avatar
    Raphael a validé
          raise ArgumentError.new("No album_id given") unless options[:album_id]
    
    Raphael's avatar
    Raphael a validé
          aspect_ids = aspects_with_post( options[:album_id] )
          aspect_ids.map!{ |aspect| aspect.id }
    
    Raphael's avatar
    Raphael a validé
          aspect_ids = options.delete(:to)
    
        aspect_ids = validate_aspect_permissions(aspect_ids)
    
        intitial_post(class_name, aspect_ids, options)
      end
    
      def intitial_post(class_name, aspect_ids, options = {})
    
        post = build_post(class_name, options)
    
    Raphael's avatar
    Raphael a validé
        post.socket_to_uid(id, :aspect_ids => aspect_ids) if post.respond_to?(:socket_to_uid)
        push_to_aspects(post, aspect_ids)
    
    danielvincent's avatar
    danielvincent a validé
      def update_post( post, post_hash = {} )
    
    danielvincent's avatar
    danielvincent a validé
        if self.owns? post
    
    danielvincent's avatar
    danielvincent a validé
          post.update_attributes(post_hash)
    
      def validate_aspect_permissions(aspect_ids)
    
    Raphael's avatar
    Raphael a validé
        if aspect_ids == "all"
          return aspect_ids
        end
    
        aspect_ids = [aspect_ids.to_s] unless aspect_ids.is_a? Array
    
    
        if aspect_ids.nil? || aspect_ids.empty?
          raise ArgumentError.new("You must post to someone.")
        end
    
        aspect_ids.each do |aspect_id|
    
          unless self.aspects.find(aspect_id)
    
            raise ArgumentError.new("Cannot post to an aspect you do not own.")
    
      def build_post( class_name, options = {})
        options[:person] = self.person
        model_class = class_name.to_s.camelize.constantize
        post = model_class.instantiate(options)
        post.save
    
        self.raw_visible_posts << post
        self.save
        post
      end
    
    Raphael's avatar
    Raphael a validé
      def push_to_aspects( post, aspect_ids )
        if aspect_ids == :all || aspect_ids == "all"
          aspects = self.aspects
        elsif aspect_ids.is_a?(Array) && aspect_ids.first.class == Aspect
          aspects = aspect_ids
    
    Raphael's avatar
    Raphael a validé
          aspects = self.aspects.find_all_by_id( aspect_ids )
    
    Raphael's avatar
    Raphael a validé
        #send to the aspects
    
        target_people = []
    
    Raphael's avatar
    Raphael a validé
    
    
    Raphael's avatar
    Raphael a validé
        aspects.each{ |aspect|
          aspect.posts << post
          aspect.save
          target_people = target_people | aspect.people
    
    Raphael's avatar
    Raphael a validé
        }
    
    danielvincent's avatar
    danielvincent a validé
        push_to_hub(post) if post.respond_to?(:public) && post.public
    
    
        push_to_people(post, target_people)
      end
    
      def push_to_people(post, people)
    
        salmon = salmon(post)
    
          xml = salmon.xml_for person
          push_to_person( person, xml)
    
    danielvincent's avatar
    danielvincent a validé
        Rails.logger.debug("Adding xml for #{self} to message queue to #{self.url}")
        QUEUE.add_post_request( person.receive_url, xml )
        QUEUE.process
      end
    
    danielvincent's avatar
    danielvincent a validé
      def push_to_hub(post)
    
    danielvincent's avatar
    danielvincent a validé
        Rails.logger.debug("Pushing update to pubsub server #{APP_CONFIG[:pubsub_server]} with url #{self.public_url}")
    
    danielvincent's avatar
    danielvincent a validé
        QUEUE.add_hub_notification(APP_CONFIG[:pubsub_server], self.public_url)
    
      def salmon( post )
    
        created_salmon = Salmon::SalmonSlap.create(self, post.to_diaspora_xml)
        created_salmon
    
    Raphael's avatar
    Raphael a validé
      end
    
    
      ######## Commenting  ########
      def comment(text, options = {})
    
        comment = build_comment(text, options)
        if comment
          dispatch_comment comment
          comment.socket_to_uid id
        end
        comment
      end
    
        raise "must comment on something!" unless options[:on]
    
        comment = Comment.new(:person_id => self.person.id, :text => text, :post => options[:on])
        comment.creator_signature = comment.sign_with_key(encryption_key)
        if comment.save
          comment
    
          Rails.logger.warn "this failed to save: #{comment.inspect}"
    
      def dispatch_comment( comment )
        if owns? comment.post
          comment.post_creator_signature = comment.sign_with_key(encryption_key)
          comment.save
    
    Raphael's avatar
    Raphael a validé
          push_to_people comment, people_in_aspects(aspects_with_post(comment.post.id))
    
        elsif owns? comment
          comment.save
    
          push_to_people comment, [comment.post.person]
    
      ######### Posts and Such ###############
    
    Raphael's avatar
    Raphael a validé
        aspect_ids = aspects_with_post( post.id )
        aspect_ids.map!{|aspect| aspect.id.to_s}
    
    Raphael's avatar
    Raphael a validé
        post.unsocket_from_uid(self.id, :aspect_ids => aspect_ids) if post.respond_to? :unsocket_from_uid
    
    Raphael's avatar
    Raphael a validé
        push_to_people retraction, people_in_aspects(aspects_with_post(post.id))
    
      ########### Profile ######################
      def update_profile(params)
        if self.person.update_attributes(params)
    
    Raphael's avatar
    Raphael a validé
          push_to_aspects profile, :all
    
      def self.instantiate!( opts = {} )
    
        opts[:person][:diaspora_handle] = "#{opts[:username]}@#{APP_CONFIG[:terse_pod_url]}"
    
    ilya's avatar
    ilya a validé
        opts[:person][:url] = APP_CONFIG[:pod_url]
    
        
        opts[:serialized_private_key] = generate_key
        opts[:person][:serialized_public_key] = opts[:serialized_private_key].public_key
    
        User.create(opts)
    
    
      def seed_aspects
        aspect(:name => "Family")
        aspect(:name => "Work")
    
    Raphael's avatar
    Raphael a validé
        "#{self.username}@#{APP_CONFIG[:terse_pod_url]}"
    
    Raphael's avatar
    Raphael a validé
      def downcase_username
    
        username.downcase! if username
    
    Raphael's avatar
    Raphael a validé
      end
    
      def as_json(opts={})
        {
          :user => {
            :posts            => self.raw_visible_posts.each{|post| post.as_json},
            :friends          => self.friends.each {|friend| friend.as_json},
    
    Raphael's avatar
    Raphael a validé
            :aspects           => self.aspects.each  {|aspect|  aspect.as_json},
    
            :pending_requests => self.pending_requests.each{|request| request.as_json},
          }
        }
      end
    
    
    
      def self.generate_key
        OpenSSL::PKey::RSA::generate 4096
      end
      
      def encryption_key
        OpenSSL::PKey::RSA.new( serialized_private_key )
      end