From 58f757b91d1d768b0980aba10509792af88bb10b Mon Sep 17 00:00:00 2001 From: "Mike Sofaer, Raphael Sofaer & Sarah Mei" Date: Sat, 18 Dec 2010 18:45:55 -0800 Subject: [PATCH] profile_spec is passing with mysql... baby steps. --- Gemfile | 5 +- Gemfile.lock | 2 + app/models/aspect.rb | 23 +- .../{contact.rb => aspect_membership.rb} | 19 +- app/models/comment.rb | 39 +- app/models/invitation.rb | 24 +- app/models/notification.rb | 34 +- app/models/person.rb | 54 +- app/models/profile.rb | 51 +- app/models/user.rb | 776 +++++++++--------- config/application.rb | 4 +- config/database.yml | 10 + config/routes.rb | 6 +- db/migrate/0000_create_schema.rb | 94 +++ db/schema.rb | 120 ++- lib/tasks/db.rake | 3 + spec/factories.rb | 3 +- spec/models/person_spec.rb | 8 +- spec/models/profile_spec.rb | 30 +- spec/spec_helper.rb | 7 +- 20 files changed, 714 insertions(+), 598 deletions(-) rename app/models/{contact.rb => aspect_membership.rb} (58%) create mode 100644 config/database.yml create mode 100644 db/migrate/0000_create_schema.rb diff --git a/Gemfile b/Gemfile index d17024072..34ac839f8 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ source 'http://rubygems.org' gem 'rails', '3.0.1' - +gem 'mysql2' gem 'bundler', '>= 1.0.0' gem "chef", :require => false @@ -56,13 +56,14 @@ gem 'resque' gem 'SystemTimer' unless RUBY_VERSION.include? "1.9" group :test, :development do - gem 'factory_girl_rails' + gem 'factory_girl_rails', :require => false gem 'ruby-debug19' if RUBY_VERSION.include? "1.9" gem 'ruby-debug' if RUBY_VERSION.include? "1.8" gem 'launchy' end group :test do + gem 'factory_girl_rails' gem 'capybara', '~> 0.3.9' gem 'cucumber-rails', '0.3.2' gem 'rspec', '>= 2.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index 577d91226..c00287981 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -231,6 +231,7 @@ GEM multi_json (0.0.5) multi_xml (0.2.0) multipart-post (1.0.1) + mysql2 (0.2.6) net-ldap (0.1.1) nokogiri (1.4.3.1) oa-basic (0.1.6) @@ -405,6 +406,7 @@ DEPENDENCIES mocha mongo_mapper! mongrel + mysql2 nokogiri (= 1.4.3.1) omniauth (= 0.1.6) pubsubhubbub diff --git a/app/models/aspect.rb b/app/models/aspect.rb index f59c77e3d..a7b09e5a0 100644 --- a/app/models/aspect.rb +++ b/app/models/aspect.rb @@ -2,36 +2,25 @@ # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. -class Aspect - include MongoMapper::Document +class Aspect < ActiveRecord::Base + belongs_to :user - key :name, String - key :post_ids, Array + has_many :aspect_memberships + has_many :members, :through => :aspect_memberships, :class_name => 'Person' - many :contacts, :foreign_key => 'aspect_ids', :class_name => 'Contact' - many :posts, :in => :post_ids, :class_name => 'Post' - - belongs_to :user, :class_name => 'User' + has_and_belongs_to_many :posts validates_presence_of :name validates_length_of :name, :maximum => 20 validates_uniqueness_of :name, :scope => :user_id - attr_accessible :name - + before_validation do name.strip! end - - timestamps! def to_s name end - - def person_objects - person_ids = people.map{|x| x.person_id} - Person.all(:id.in => person_ids) - end def as_json(opts = {}) { diff --git a/app/models/contact.rb b/app/models/aspect_membership.rb similarity index 58% rename from app/models/contact.rb rename to app/models/aspect_membership.rb index b330811e3..b4ac5fe7e 100644 --- a/app/models/contact.rb +++ b/app/models/aspect_membership.rb @@ -2,25 +2,16 @@ # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. -class Contact - include MongoMapper::Document +class AspectMembership < ActiveRecord::Base - key :pending, Boolean, :default => true - - key :user_id, ObjectId - belongs_to :user - validates_presence_of :user - - key :person_id, ObjectId + belongs_to :aspect belongs_to :person validates_presence_of :person - validates_uniqueness_of :person_id, :scope => :user_id + validates_presence_of :aspect + has_one :user, :through => :aspect validate :not_contact_for_self - key :aspect_ids, Array, :typecast => 'ObjectId' - many :aspects, :in => :aspect_ids, :class_name => 'Aspect' - def dispatch_request request = self.generate_request self.user.push_to_people(request, [self.person]) @@ -33,7 +24,7 @@ class Contact private def not_contact_for_self - if person.owner_id == user.id + if person.owner == user errors[:base] << 'Cannot create self-contact' end end diff --git a/app/models/comment.rb b/app/models/comment.rb index 39d43d19d..5d58709f9 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -2,19 +2,10 @@ # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. -class HandleValidator < ActiveModel::Validator - def validate(document) - unless document.diaspora_handle == document.person.diaspora_handle - document.errors[:base] << "Diaspora handle and person handle must match" - end - end -end - -class Comment +class Comment < ActiveRecord::Base require File.join(Rails.root, 'lib/diaspora/web_socket') require File.join(Rails.root, 'lib/youtube_titles') include YoutubeTitles - include MongoMapper::Document include ROXML include Diaspora::Webhooks include Encryptable @@ -22,26 +13,18 @@ class Comment xml_reader :text xml_reader :diaspora_handle - xml_reader :post_id - xml_reader :_id + xml_reader :post_guid + xml_reader :guid - key :text, String - key :post_id, ObjectId - key :person_id, ObjectId - key :diaspora_handle, String + belongs_to :post + belongs_to :person - belongs_to :post, :class_name => "Post" - belongs_to :person, :class_name => "Person" - - validates_presence_of :text, :diaspora_handle, :post - validates_with HandleValidator + validates_presence_of :text, :post before_save do get_youtube_title text end - timestamps! - def notification_type(user, person) if self.post.diaspora_handle == user.diaspora_handle return "comment_on_post" @@ -55,9 +38,6 @@ class Comment xml_reader :creator_signature xml_reader :post_creator_signature - key :creator_signature, String - key :post_creator_signature, String - def signable_accessors accessors = self.class.roxml_attrs.collect{|definition| definition.accessor} @@ -82,7 +62,7 @@ class Comment def self.hash_from_post_ids post_ids hash = {} - comments = self.on_posts(post_ids) + comments = where(:post_id.in => post_ids) post_ids.each do |id| hash[id] = [] end @@ -92,9 +72,4 @@ class Comment hash.each_value {|comments| comments.sort!{|c1, c2| c1.created_at <=> c2.created_at }} hash end - - - scope :on_posts, lambda { |post_ids| - where(:post_id.in => post_ids) - } end diff --git a/app/models/invitation.rb b/app/models/invitation.rb index dc98f9d39..7fed99ac3 100644 --- a/app/models/invitation.rb +++ b/app/models/invitation.rb @@ -2,15 +2,13 @@ # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. -class Invitation - include MongoMapper::Document +class Invitation < ActiveRecord::Base - belongs_to :from, :class => User - belongs_to :to, :class => User - belongs_to :into, :class => Aspect - key :message, String + belongs_to :sender, :class_name => 'User' + belongs_to :recipient, :class_name => 'User' + belongs_to :aspect - validates_presence_of :from, :to, :into + validates_presence_of :sender, :recipient, :aspect def self.invite(opts = {}) return false if opts[:email] == opts[:from].email @@ -21,7 +19,7 @@ class Invitation elsif not existing_user.invited? opts[:from].send_contact_request_to(existing_user.person, opts[:into]) return - elsif Invitation.first(:from_id => opts[:from].id, :to_id => existing_user.id) + elsif Invitation.first(:sender_id => opts[:from].id, :recipient_id => existing_user.id) raise "You already invited this person" end end @@ -54,9 +52,9 @@ class Invitation if opts[:from] invitee.save(:validate => false) - Invitation.create!(:from => opts[:from], - :to => invitee, - :into => opts[:into], + Invitation.create!(:sender => opts[:from], + :recipient => invitee, + :aspect => opts[:into], :message => opts[:message]) opts[:from].invites -= 1 unless opts[:from].invites == 0 @@ -64,13 +62,13 @@ class Invitation invitee.reload end - invitee.invite! + invitee.invite! Rails.logger.info("event=invitation_sent to=#{opts[:email]} #{"inviter=#{opts[:from].diaspora_handle}" if opts[:from]}") invitee end def to_request! - request = from.send_contact_request_to(to.person, into) + request = sender.send_contact_request_to(recipient.person, aspect) destroy if request request end diff --git a/app/models/notification.rb b/app/models/notification.rb index 4068da5dd..9f53278b5 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -2,31 +2,23 @@ # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. # -class Notification - include MongoMapper::Document +class Notification < ActiveRecord::Base - key :object_id, ObjectId - key :kind, String - key :unread, Boolean, :default => true + belongs_to :receiver, :class_name => 'User' + belongs_to :actor, :class_name => 'Person' + belongs_to :target, :polymorphic => true - belongs_to :user - belongs_to :person - - timestamps! - - attr_accessible :object_id, :kind, :user_id, :person_id, :unread - - def self.for(user, opts={}) - self.where(opts.merge!(:user_id => user.id)).order('created_at desc') + def self.for(receiver, opts={}) + self.where(opts.merge!(:receiver => receiver)).order('created_at desc') end - def self.notify(user, object, person) - if object.respond_to? :notification_type - if kind = object.notification_type(user, person) - Notification.create(:object_id => object.id, - :kind => kind, - :person_id => person.id, - :user_id => user.id) + def self.notify(receiver, target, actor) + if target.respond_to? :notification_type + if action = target.notification_type(receiver, actor) + create(:target => target, + :action => action, + :actor => actor, + :receiver => receiver) end end end diff --git a/app/models/person.rb b/app/models/person.rb index 50816bbeb..357c5b834 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -4,50 +4,35 @@ require File.join(Rails.root, 'lib/hcard') -class Person - include MongoMapper::Document +class Person < ActiveRecord::Base include ROXML include Encryptor::Public require File.join(Rails.root, 'lib/diaspora/web_socket') include Diaspora::Socketable - xml_accessor :_id - xml_accessor :diaspora_handle + xml_accessor :guid +# xml_accessor :diaspora_handle xml_accessor :url xml_accessor :profile, :as => Profile xml_reader :exported_key - key :url, String - key :diaspora_handle, String, :unique => true - key :serialized_public_key, String - - key :owner_id, ObjectId - - one :profile, :class_name => 'Profile' - validates_associated :profile + has_one :profile delegate :last_name, :to => :profile - before_save :downcase_diaspora_handle + before_save :downcase_diaspora_handle def downcase_diaspora_handle diaspora_handle.downcase! end belongs_to :owner, :class_name => 'User' - timestamps! - before_destroy :remove_all_traces before_validation :clean_url + validates_presence_of :url, :profile, :serialized_public_key validates_uniqueness_of :diaspora_handle, :case_sensitive => false - #validates_format_of :url, :with => - # /^(https?):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(\.[a-z]{2,5})?(:[0-9]{1,5})?(\/.*)?$/ix - ensure_index :diaspora_handle - - scope :searchable, where('profile.searchable' => true) - - attr_accessible :profile + scope :searchable, includes(:profile).where(:profile => {:searchable => true}) def self.search(query) return [] if query.to_s.empty? @@ -74,6 +59,7 @@ class Person "#{profile.first_name.to_s} #{profile.last_name.to_s}" end end + def first_name @first_name ||= if profile.first_name.nil? || profile.first_name.blank? self.diaspora_handle.split('@').first @@ -81,8 +67,9 @@ class Person profile.first_name.to_s end end + def owns?(post) - self.id == post.person.id + self == post.person end def receive_url @@ -93,7 +80,6 @@ class Person "#{self.url}public/#{self.owner.username}" end - def public_key_hash Base64.encode64 OpenSSL::Digest::SHA256.new(self.exported_key).to_s end @@ -126,21 +112,21 @@ class Person return nil if profile.nil? || !profile.valid_diaspora_profile? new_person = Person.new new_person.exported_key = profile.public_key - new_person.id = profile.guid + new_person.guid = profile.guid new_person.diaspora_handle = profile.account new_person.url = profile.seed_location #hcard_profile = HCard.find profile.hcard.first[:href] Rails.logger.info("event=webfinger_marshal valid=#{new_person.valid?} target=#{new_person.diaspora_handle}") new_person.url = hcard[:url] - new_person.profile = Profile.new( :first_name => hcard[:given_name], - :last_name => hcard[:family_name], - :image_url => hcard[:photo], - :image_url_medium => hcard[:photo_medium], - :image_url_small => hcard[:photo_small], - :searchable => hcard[:searchable]) - - new_person.save! ? new_person : nil + new_person.create_profile(:first_name => hcard[:given_name], + :last_name => hcard[:family_name], + :image_url => hcard[:photo], + :image_url_medium => hcard[:photo_medium], + :image_url_small => hcard[:photo_small], + :searchable => hcard[:searchable]) + new_person.save! + new_person end def remote? @@ -150,7 +136,7 @@ class Person def as_json(opts={}) { :person => { - :id => self.id, + :id => self.guid, :name => self.name, :url => self.url, :exported_key => exported_key, diff --git a/app/models/profile.rb b/app/models/profile.rb index 3fa9b84b8..54807f08a 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -2,51 +2,37 @@ # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. -class Profile - include MongoMapper::EmbeddedDocument +class Profile < ActiveRecord::Base require File.join(Rails.root, 'lib/diaspora/webhooks') include Diaspora::Webhooks include ROXML - xml_reader :diaspora_handle - xml_reader :first_name - xml_reader :last_name - xml_reader :image_url - xml_reader :image_url_small - xml_reader :image_url_medium - xml_reader :birthday - xml_reader :gender - xml_reader :bio - xml_reader :searchable - - key :diaspora_handle, String - key :first_name, String - key :last_name, String - key :image_url, String - key :image_url_small, String - key :image_url_medium, String - key :birthday, Date - key :gender, String - key :bio, String - key :searchable, Boolean, :default => true + xml_accessor :diaspora_handle + xml_accessor :first_name + xml_accessor :last_name + xml_accessor :image_url + xml_accessor :image_url_small + xml_accessor :image_url_medium + xml_accessor :birthday + xml_accessor :gender + xml_accessor :bio + xml_accessor :searchable + before_save :strip_names after_validation :strip_names + validates_length_of :first_name, :maximum => 32 validates_length_of :last_name, :maximum => 32 +# attr_accessible :first_name, :last_name, :image_url, :image_url_medium, +# :image_url_small, :birthday, :gender, :bio, :searchable, :date - before_save :strip_names - - attr_accessible :first_name, :last_name, :image_url, :image_url_medium, - :image_url_small, :birthday, :gender, :bio, :searchable, :date - - def person - self._parent_document - end + belongs_to :person + # TODO: this should always delegate to the person def diaspora_handle #get the parent diaspora handle, unless we want to access a profile without a person - (self._parent_document) ? self.person.diaspora_handle : self[:diaspora_handle] + (self.person) ? self.person.diaspora_handle : self[:diaspora_handle] end def image_url(size = :thumb_large) @@ -59,7 +45,6 @@ class Profile end end - def image_url= url return image_url if url == '' if url.nil? || url.match(/^https?:\/\//) diff --git a/app/models/user.rb b/app/models/user.rb index ffbbd09de..e7e1583cb 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -6,392 +6,392 @@ require File.join(Rails.root, 'lib/diaspora/user') require File.join(Rails.root, 'lib/salmon/salmon') require 'rest-client' -class User - include MongoMapper::Document - include Diaspora::UserModules - include Encryptor::Private - - plugin MongoMapper::Devise - - devise :invitable, :database_authenticatable, :registerable, - :recoverable, :rememberable, :trackable, :validatable, - :timeoutable - - key :username - key :serialized_private_key, String - key :invites, Integer, :default => 5 - key :invitation_token, String - key :invitation_sent_at, DateTime - key :visible_post_ids, Array, :typecast => 'ObjectId' - key :visible_person_ids, Array, :typecast => 'ObjectId' - - key :getting_started, Boolean, :default => true - key :disable_mail, Boolean, :default => false - - key :language, String - - before_validation :strip_and_downcase_username, :on => :create - before_validation :set_current_language, :on => :create - - validates_presence_of :username - validates_uniqueness_of :username, :case_sensitive => false - validates_format_of :username, :with => /\A[A-Za-z0-9_]+\z/ - validates_length_of :username, :maximum => 32 - validates_inclusion_of :language, :in => AVAILABLE_LANGUAGE_CODES - - validates_presence_of :person, :unless => proc {|user| user.invitation_token.present?} - validates_associated :person - - one :person, :class => Person, :foreign_key => :owner_id - - many :invitations_from_me, :class => Invitation, :foreign_key => :from_id - many :invitations_to_me, :class => Invitation, :foreign_key => :to_id - many :contacts, :class => Contact, :foreign_key => :user_id - many :visible_people, :in => :visible_person_ids, :class => Person # One of these needs to go - many :raw_visible_posts, :in => :visible_post_ids, :class => Post - many :aspects, :class => Aspect, :dependent => :destroy - - many :services, :class => Service - timestamps! - #after_create :seed_aspects - - before_destroy :disconnect_everyone, :remove_person - before_save do - person.save if person - end - - attr_accessible :getting_started, :password, :password_confirmation, :language, :disable_mail - - def strip_and_downcase_username - if username.present? - username.strip! - username.downcase! - end - end - - def set_current_language - self.language = I18n.locale.to_s if self.language.blank? - end - - def self.find_for_authentication(conditions={}) - conditions[:username] = conditions[:username].downcase - if conditions[:username] =~ /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i # email regex - conditions[:email] = conditions.delete(:username) - end - super - end - - ######## Making things work ######## - key :email, String - - def method_missing(method, *args) - self.person.send(method, *args) if self.person - end - - ######### Aspects ###################### - def drop_aspect(aspect) - if aspect.contacts.count == 0 - aspect.destroy - else - raise "Aspect not empty" - end - end - - def move_contact(person, to_aspect, from_aspect) - contact = contact_for(person) - if to_aspect == from_aspect - true - elsif add_contact_to_aspect(contact, to_aspect) - delete_person_from_aspect(person.id, from_aspect.id) - end - end - - def add_contact_to_aspect(contact, aspect) - return true if contact.aspect_ids.include?(aspect.id) - contact.aspects << aspect - contact.save! - end - - def delete_person_from_aspect(person_id, aspect_id, opts = {}) - aspect = Aspect.find(aspect_id) - raise "Can not delete a person from an aspect you do not own" unless aspect.user == self - contact = contact_for Person.find(person_id) - - if opts[:force] || contact.aspect_ids.count > 1 - contact.aspect_ids.delete aspect.id - contact.save! - aspect.save! - else - raise "Can not delete a person from last aspect" - end - end - - ######## Posting ######## - def build_post(class_name, opts = {}) - opts[:person] = self.person - opts[:diaspora_handle] = opts[:person].diaspora_handle - - model_class = class_name.to_s.camelize.constantize - model_class.instantiate(opts) - end - - def dispatch_post(post, opts = {}) - aspect_ids = opts.delete(:to) - - Rails.logger.info("event=dispatch user=#{diaspora_handle} post=#{post.id.to_s}") - push_to_aspects(post, aspects_from_ids(aspect_ids)) - Resque.enqueue(Jobs::PostToServices, self.id, post.id, opts[:url]) if post.public - end - - def post_to_services(post, url) - if post.respond_to?(:message) - self.services.each do |service| - service.post(post, url) - end - end - end - - def post_to_hub(post) - Rails.logger.debug("event=post_to_service type=pubsub sender_handle=#{self.diaspora_handle}") - EventMachine::PubSubHubbub.new(APP_CONFIG[:pubsub_server]).publish self.public_url - end - - def update_post(post, post_hash = {}) - if self.owns? post - post.update_attributes(post_hash) - aspects = aspects_with_post(post.id) - self.push_to_aspects(post, aspects) - end - end - - def add_to_streams(post, aspect_ids) - self.raw_visible_posts << post - self.save - - post.socket_to_uid(id, :aspect_ids => aspect_ids) if post.respond_to? :socket_to_uid - target_aspects = aspects_from_ids(aspect_ids) - target_aspects.each do |aspect| - aspect.posts << post - aspect.save - end - end - - def aspects_from_ids(aspect_ids) - if aspect_ids == "all" || aspect_ids == :all - self.aspects - else - if aspect_ids.respond_to? :to_id - aspect_ids = [aspect_ids] - end - aspect_ids.map!{ |x| x.to_id } - aspects.all(:id.in => aspect_ids) - end - end - - def push_to_aspects(post, aspects) - #send to the aspects - target_aspect_ids = aspects.map {|a| a.id} - - target_contacts = Contact.all(:aspect_ids.in => target_aspect_ids, :pending => false) - - post_to_hub(post) if post.respond_to?(:public) && post.public - push_to_people(post, self.person_objects(target_contacts)) - end - - def push_to_people(post, people) - salmon = salmon(post) - people.each do |person| - push_to_person(salmon, post, person) - end - end - - def push_to_person(salmon, post, person) - person.reload # Sadly, we need this for Ruby 1.9. - # person.owner will always return a ProxyObject. - # calling nil? performs a necessary evaluation. - if person.owner_id - Rails.logger.info("event=push_to_person route=local sender=#{self.diaspora_handle} recipient=#{person.diaspora_handle} payload_type=#{post.class}") - - if post.is_a?(Post) || post.is_a?(Comment) - Resque.enqueue(Jobs::ReceiveLocal, person.owner_id, self.person.id, post.class.to_s, post.id) - else - Resque.enqueue(Jobs::Receive, person.owner_id, post.to_diaspora_xml, self.person.id) - end - else - xml = salmon.xml_for person - Rails.logger.info("event=push_to_person route=remote sender=#{self.diaspora_handle} recipient=#{person.diaspora_handle} payload_type=#{post.class}") - MessageHandler.add_post_request(person.receive_url, xml) - end - end - - def salmon(post) - created_salmon = Salmon::SalmonSlap.create(self, post.to_diaspora_xml) - created_salmon - end - - ######## Commenting ######## - def build_comment(text, options = {}) - comment = Comment.new(:person_id => self.person.id, - :diaspora_handle => self.person.diaspora_handle, - :text => text, - :post => options[:on]) - - #sign comment as commenter - comment.creator_signature = comment.sign_with_key(self.encryption_key) - - if !comment.post_id.blank? && owns?(comment.post) - #sign comment as post owner - comment.post_creator_signature = comment.sign_with_key(self.encryption_key) - end - - comment - end - - def dispatch_comment(comment) - if owns? comment.post - #push DOWNSTREAM (to original audience) - Rails.logger.info "event=dispatch_comment direction=downstream user=#{self.diaspora_handle} comment=#{comment.id}" - aspects = aspects_with_post(comment.post_id) - - #just socket to local users, as the comment has already - #been associated and saved by post owner - # (we'll push to all of their aspects for now, the comment won't - # show up via js where corresponding posts are not present) - - people_in_aspects(aspects, :type => 'local').each do |person| - comment.socket_to_uid(person.owner_id, :aspect_ids => 'all') - end - - #push to remote people - push_to_people(comment, people_in_aspects(aspects, :type => 'remote')) - - elsif owns? comment - #push UPSTREAM (to poster) - Rails.logger.info "event=dispatch_comment direction=upstream user=#{self.diaspora_handle} comment=#{comment.id}" - push_to_people comment, [comment.post.person] - end - end - - ######### Mailer ####################### - def mail(job, *args) - unless self.disable_mail - Resque.enqueue(job, *args) - end - end - - ######### Posts and Such ############### - def retract(post) - aspect_ids = aspects_with_post(post.id) - aspect_ids.map! { |aspect| aspect.id.to_s } - - post.unsocket_from_uid(self.id, :aspect_ids => aspect_ids) if post.respond_to? :unsocket_from_uid - retraction = Retraction.for(post) - push_to_people retraction, people_in_aspects(aspects_with_post(post.id)) - retraction - end - - ########### Profile ###################### - def update_profile(params) - if params[:photo] - params[:photo].update_attributes(:pending => false) if params[:photo].pending - params[:image_url] = params[:photo].url(:thumb_large) - params[:image_url_medium] = params[:photo].url(:thumb_medium) - params[:image_url_small] = params[:photo].url(:thumb_small) - end - if self.person.profile.update_attributes(params) - push_to_people profile, self.person_objects(contacts(:pending => false)) - true - else - false - end - end - - ###Invitations############ - def invite_user(email, aspect_id, invite_message = "") - aspect_object = Aspect.first(:user_id => self.id, :id => aspect_id) - if aspect_object - Invitation.invite(:email => email, - :from => self, - :into => aspect_object, - :message => invite_message) - else - false - end - end - - def accept_invitation!(opts = {}) - if self.invited? - log_string = "event=invitation_accepted username=#{opts[:username]} " - log_string << "inviter=#{invitations_to_me.first.from.diaspora_handle}" if invitations_to_me.first - Rails.logger.info log_string - self.setup(opts) - self.invitation_token = nil - self.password = opts[:password] - self.password_confirmation = opts[:password_confirmation] - self.save! - invitations_to_me.each{|invitation| invitation.to_request!} - - self.reload # Because to_request adds a request and saves elsewhere - self - end - end - - ###Helpers############ - def self.build(opts = {}) - u = User.new(opts) - u.email = opts[:email] - u.setup(opts) - u - end - - def setup(opts) - self.username = opts[:username] - self.valid? - errors = self.errors - errors.delete :person - return if errors.size > 0 - - opts[:person] ||= {} - opts[:person][:profile] ||= Profile.new - - self.person = Person.new(opts[:person]) - self.person.diaspora_handle = "#{opts[:username]}@#{APP_CONFIG[:pod_uri].host}" - self.person.url = APP_CONFIG[:pod_url] - - - self.serialized_private_key ||= User.generate_key - self.person.serialized_public_key = OpenSSL::PKey::RSA.new(self.serialized_private_key).public_key - - self - end - - def seed_aspects - self.aspects.create(:name => I18n.t('aspects.seed.family')) - self.aspects.create(:name => I18n.t('aspects.seed.work')) - end - - def self.generate_key - key_size = (Rails.env == 'test' ? 512 : 4096) - OpenSSL::PKey::RSA::generate key_size - end - - def encryption_key - OpenSSL::PKey::RSA.new(serialized_private_key) - end - - protected - - def remove_person - self.person.destroy - end - - def disconnect_everyone - contacts.each { |contact| - if contact.person.owner? - contact.person.owner.disconnected_by self.person - else - self.disconnect contact - end - } - end +class User < ActiveRecord::Base +# include MongoMapper::Document +# include Diaspora::UserModules +# include Encryptor::Private +# +# plugin MongoMapper::Devise +# +# devise :invitable, :database_authenticatable, :registerable, +# :recoverable, :rememberable, :trackable, :validatable, +# :timeoutable +# +# key :username +# key :serialized_private_key, String +# key :invites, Integer, :default => 5 +# key :invitation_token, String +# key :invitation_sent_at, DateTime +# key :visible_post_ids, Array, :typecast => 'ObjectId' +# key :visible_person_ids, Array, :typecast => 'ObjectId' +# +# key :getting_started, Boolean, :default => true +# key :disable_mail, Boolean, :default => false +# +# key :language, String +# +# before_validation :strip_and_downcase_username, :on => :create +# before_validation :set_current_language, :on => :create +# +# validates_presence_of :username +# validates_uniqueness_of :username, :case_sensitive => false +# validates_format_of :username, :with => /\A[A-Za-z0-9_]+\z/ +# validates_length_of :username, :maximum => 32 +# validates_inclusion_of :language, :in => AVAILABLE_LANGUAGE_CODES +# +# validates_presence_of :person, :unless => proc {|user| user.invitation_token.present?} +# validates_associated :person +# +# one :person, :class => Person, :foreign_key => :owner_id +# +# many :invitations_from_me, :class => Invitation, :foreign_key => :from_id +# many :invitations_to_me, :class => Invitation, :foreign_key => :to_id +# has_many :aspects, :dependent => :destroy +# has_many :aspect_memberships, :through => :aspects +# many :visible_people, :in => :visible_person_ids, :class => Person # One of these needs to go +# many :raw_visible_posts, :in => :visible_post_ids, :class => Post +# +# many :services, :class => Service +# timestamps! +# #after_create :seed_aspects +# +# before_destroy :disconnect_everyone, :remove_person +# before_save do +# person.save if person +# end +# +# attr_accessible :getting_started, :password, :password_confirmation, :language, :disable_mail +# +# def strip_and_downcase_username +# if username.present? +# username.strip! +# username.downcase! +# end +# end +# +# def set_current_language +# self.language = I18n.locale.to_s if self.language.blank? +# end +# +# def self.find_for_authentication(conditions={}) +# conditions[:username] = conditions[:username].downcase +# if conditions[:username] =~ /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i # email regex +# conditions[:email] = conditions.delete(:username) +# end +# super +# end +# +# ######## Making things work ######## +# key :email, String +# +# def method_missing(method, *args) +# self.person.send(method, *args) if self.person +# end +# +# ######### Aspects ###################### +# def drop_aspect(aspect) +# if aspect.contacts.count == 0 +# aspect.destroy +# else +# raise "Aspect not empty" +# end +# end +# +# def move_contact(person, to_aspect, from_aspect) +# contact = contact_for(person) +# if to_aspect == from_aspect +# true +# elsif add_contact_to_aspect(contact, to_aspect) +# delete_person_from_aspect(person.id, from_aspect.id) +# end +# end +# +# def add_contact_to_aspect(contact, aspect) +# return true if contact.aspect_ids.include?(aspect.id) +# contact.aspects << aspect +# contact.save! +# end +# +# def delete_person_from_aspect(person_id, aspect_id, opts = {}) +# aspect = Aspect.find(aspect_id) +# raise "Can not delete a person from an aspect you do not own" unless aspect.user == self +# contact = contact_for Person.find(person_id) +# +# if opts[:force] || contact.aspect_ids.count > 1 +# contact.aspect_ids.delete aspect.id +# contact.save! +# aspect.save! +# else +# raise "Can not delete a person from last aspect" +# end +# end +# +# ######## Posting ######## +# def build_post(class_name, opts = {}) +# opts[:person] = self.person +# opts[:diaspora_handle] = opts[:person].diaspora_handle +# +# model_class = class_name.to_s.camelize.constantize +# model_class.instantiate(opts) +# end +# +# def dispatch_post(post, opts = {}) +# aspect_ids = opts.delete(:to) +# +# Rails.logger.info("event=dispatch user=#{diaspora_handle} post=#{post.id.to_s}") +# push_to_aspects(post, aspects_from_ids(aspect_ids)) +# Resque.enqueue(Jobs::PostToServices, self.id, post.id, opts[:url]) if post.public +# end +# +# def post_to_services(post, url) +# if post.respond_to?(:message) +# self.services.each do |service| +# service.post(post, url) +# end +# end +# end +# +# def post_to_hub(post) +# Rails.logger.debug("event=post_to_service type=pubsub sender_handle=#{self.diaspora_handle}") +# EventMachine::PubSubHubbub.new(APP_CONFIG[:pubsub_server]).publish self.public_url +# end +# +# def update_post(post, post_hash = {}) +# if self.owns? post +# post.update_attributes(post_hash) +# aspects = aspects_with_post(post.id) +# self.push_to_aspects(post, aspects) +# end +# end +# +# def add_to_streams(post, aspect_ids) +# self.raw_visible_posts << post +# self.save +# +# post.socket_to_uid(id, :aspect_ids => aspect_ids) if post.respond_to? :socket_to_uid +# target_aspects = aspects_from_ids(aspect_ids) +# target_aspects.each do |aspect| +# aspect.posts << post +# aspect.save +# end +# end +# +# def aspects_from_ids(aspect_ids) +# if aspect_ids == "all" || aspect_ids == :all +# self.aspects +# else +# if aspect_ids.respond_to? :to_id +# aspect_ids = [aspect_ids] +# end +# aspect_ids.map!{ |x| x.to_id } +# aspects.all(:id.in => aspect_ids) +# end +# end +# +# def push_to_aspects(post, aspects) +# #send to the aspects +# target_aspect_ids = aspects.map {|a| a.id} +# +# target_contacts = Contact.all(:aspect_ids.in => target_aspect_ids, :pending => false) +# +# post_to_hub(post) if post.respond_to?(:public) && post.public +# push_to_people(post, self.person_objects(target_contacts)) +# end +# +# def push_to_people(post, people) +# salmon = salmon(post) +# people.each do |person| +# push_to_person(salmon, post, person) +# end +# end +# +# def push_to_person(salmon, post, person) +# person.reload # Sadly, we need this for Ruby 1.9. +# # person.owner will always return a ProxyObject. +# # calling nil? performs a necessary evaluation. +# if person.owner_id +# Rails.logger.info("event=push_to_person route=local sender=#{self.diaspora_handle} recipient=#{person.diaspora_handle} payload_type=#{post.class}") +# +# if post.is_a?(Post) || post.is_a?(Comment) +# Resque.enqueue(Jobs::ReceiveLocal, person.owner_id, self.person.id, post.class.to_s, post.id) +# else +# Resque.enqueue(Jobs::Receive, person.owner_id, post.to_diaspora_xml, self.person.id) +# end +# else +# xml = salmon.xml_for person +# Rails.logger.info("event=push_to_person route=remote sender=#{self.diaspora_handle} recipient=#{person.diaspora_handle} payload_type=#{post.class}") +# MessageHandler.add_post_request(person.receive_url, xml) +# end +# end +# +# def salmon(post) +# created_salmon = Salmon::SalmonSlap.create(self, post.to_diaspora_xml) +# created_salmon +# end +# +# ######## Commenting ######## +# def build_comment(text, options = {}) +# comment = Comment.new(:person_id => self.person.id, +# :diaspora_handle => self.person.diaspora_handle, +# :text => text, +# :post => options[:on]) +# +# #sign comment as commenter +# comment.creator_signature = comment.sign_with_key(self.encryption_key) +# +# if !comment.post_id.blank? && owns?(comment.post) +# #sign comment as post owner +# comment.post_creator_signature = comment.sign_with_key(self.encryption_key) +# end +# +# comment +# end +# +# def dispatch_comment(comment) +# if owns? comment.post +# #push DOWNSTREAM (to original audience) +# Rails.logger.info "event=dispatch_comment direction=downstream user=#{self.diaspora_handle} comment=#{comment.id}" +# aspects = aspects_with_post(comment.post_id) +# +# #just socket to local users, as the comment has already +# #been associated and saved by post owner +# # (we'll push to all of their aspects for now, the comment won't +# # show up via js where corresponding posts are not present) +# +# people_in_aspects(aspects, :type => 'local').each do |person| +# comment.socket_to_uid(person.owner_id, :aspect_ids => 'all') +# end +# +# #push to remote people +# push_to_people(comment, people_in_aspects(aspects, :type => 'remote')) +# +# elsif owns? comment +# #push UPSTREAM (to poster) +# Rails.logger.info "event=dispatch_comment direction=upstream user=#{self.diaspora_handle} comment=#{comment.id}" +# push_to_people comment, [comment.post.person] +# end +# end +# +# ######### Mailer ####################### +# def mail(job, *args) +# unless self.disable_mail +# Resque.enqueue(job, *args) +# end +# end +# +# ######### Posts and Such ############### +# def retract(post) +# aspect_ids = aspects_with_post(post.id) +# aspect_ids.map! { |aspect| aspect.id.to_s } +# +# post.unsocket_from_uid(self.id, :aspect_ids => aspect_ids) if post.respond_to? :unsocket_from_uid +# retraction = Retraction.for(post) +# push_to_people retraction, people_in_aspects(aspects_with_post(post.id)) +# retraction +# end +# +# ########### Profile ###################### +# def update_profile(params) +# if params[:photo] +# params[:photo].update_attributes(:pending => false) if params[:photo].pending +# params[:image_url] = params[:photo].url(:thumb_large) +# params[:image_url_medium] = params[:photo].url(:thumb_medium) +# params[:image_url_small] = params[:photo].url(:thumb_small) +# end +# if self.person.profile.update_attributes(params) +# push_to_people profile, self.person_objects(contacts(:pending => false)) +# true +# else +# false +# end +# end +# +# ###Invitations############ +# def invite_user(email, aspect_id, invite_message = "") +# aspect_object = Aspect.first(:user_id => self.id, :id => aspect_id) +# if aspect_object +# Invitation.invite(:email => email, +# :from => self, +# :into => aspect_object, +# :message => invite_message) +# else +# false +# end +# end +# +# def accept_invitation!(opts = {}) +# if self.invited? +# log_string = "event=invitation_accepted username=#{opts[:username]} " +# log_string << "inviter=#{invitations_to_me.first.from.diaspora_handle}" if invitations_to_me.first +# Rails.logger.info log_string +# self.setup(opts) +# self.invitation_token = nil +# self.password = opts[:password] +# self.password_confirmation = opts[:password_confirmation] +# self.save! +# invitations_to_me.each{|invitation| invitation.to_request!} +# +# self.reload # Because to_request adds a request and saves elsewhere +# self +# end +# end +# +# ###Helpers############ +# def self.build(opts = {}) +# u = User.new(opts) +# u.email = opts[:email] +# u.setup(opts) +# u +# end +# +# def setup(opts) +# self.username = opts[:username] +# self.valid? +# errors = self.errors +# errors.delete :person +# return if errors.size > 0 +# +# opts[:person] ||= {} +# opts[:person][:profile] ||= Profile.new +# +# self.person = Person.new(opts[:person]) +# self.person.diaspora_handle = "#{opts[:username]}@#{APP_CONFIG[:pod_uri].host}" +# self.person.url = APP_CONFIG[:pod_url] +# +# +# self.serialized_private_key ||= User.generate_key +# self.person.serialized_public_key = OpenSSL::PKey::RSA.new(self.serialized_private_key).public_key +# +# self +# end +# +# def seed_aspects +# self.aspects.create(:name => I18n.t('aspects.seed.family')) +# self.aspects.create(:name => I18n.t('aspects.seed.work')) +# end +# +# def self.generate_key +# key_size = (Rails.env == 'test' ? 512 : 4096) +# OpenSSL::PKey::RSA::generate key_size +# end +# +# def encryption_key +# OpenSSL::PKey::RSA.new(serialized_private_key) +# end +# +# protected +# +# def remove_person +# self.person.destroy +# end +# +# def disconnect_everyone +# contacts.each { |contact| +# if contact.person.owner? +# contact.person.owner.disconnected_by self.person +# else +# self.disconnect contact +# end +# } +# end end diff --git a/config/application.rb b/config/application.rb index 3772825d5..e9fa4ad29 100644 --- a/config/application.rb +++ b/config/application.rb @@ -4,9 +4,7 @@ require File.expand_path('../boot', __FILE__) -require 'action_controller/railtie' -require 'action_mailer/railtie' -require 'active_resource/railtie' +require 'rails/all' # If you have a Gemfile, require the gems listed there, including any gems # you've limited to :test, :development, or :production. Bundler.require(:default, Rails.env) if defined?(Bundler) diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 000000000..30dcd4324 --- /dev/null +++ b/config/database.yml @@ -0,0 +1,10 @@ +test: + adapter: mysql2 + database: diaspora_test + user: root + password: password +development: + adapter: mysql2 + database: diaspora_development + user: root + password: password diff --git a/config/routes.rb b/config/routes.rb index e8b45c3ac..e9ed566c2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -26,9 +26,9 @@ Diaspora::Application.routes.draw do match 'photos/make_profile_photo' => 'photos#make_profile_photo' resources :photos, :except => [:index] - devise_for :users, :controllers => {:registrations => "registrations", - :password => "devise/passwords", - :invitations => "invitations"} +# devise_for :users, :controllers => {:registrations => "registrations", +# :password => "devise/passwords", +# :invitations => "invitations"} # added public route to user match 'public/:username', :to => 'users#public' match 'getting_started', :to => 'users#getting_started', :as => 'getting_started' diff --git a/db/migrate/0000_create_schema.rb b/db/migrate/0000_create_schema.rb new file mode 100644 index 000000000..ac17fc236 --- /dev/null +++ b/db/migrate/0000_create_schema.rb @@ -0,0 +1,94 @@ +class CreateSchema < ActiveRecord::Migration + def self.up + create_table :aspects do |t| + t.string :name + t.integer :user_id + t.timestamps + end + add_index :aspects, :user_id + + create_table :aspect_memberships do |t| + t.boolean :pending, :default => true + t.integer :aspect_id + t.integer :person_id + t.timestamps + end + add_index :aspect_memberships, :aspect_id + add_index :aspect_memberships, [:aspect_id, :person_id], :unique => true + + create_table :aspects_posts, :id => false do |t| + t.integer :aspect_id + t.integer :post_id + t.timestamps + end + add_index :aspects_posts, :aspect_id + add_index :aspects_posts, :post_id + + create_table :comments do |t| + t.text :text + t.integer :post_id + t.integer :person_id + t.string :guid + t.text :creator_signature + t.text :post_creator_signature + t.timestamps + end + add_index :comments, :guid, :unique => true + add_index :comments, :post_id + + create_table :invitations do |t| + t.text :message + t.integer :sender_id + t.integer :recipient_id + t.integer :aspect_id + t.timestamps + end + add_index :invitations, :sender_id + + create_table :notifications do |t| + t.string :target_type + t.integer :target_id + t.integer :receiver_id + t.integer :actor_id + t.string :action + t.boolean :unread, :default => true + t.timestamps + end + add_index :notifications, [:target_type, :target_id] + + create_table :people do |t| + t.string :guid + t.text :url + t.string :diaspora_handle + t.text :serialized_public_key + t.integer :owner_id + t.timestamps + end + add_index :people, :guid, :unique => true + add_index :people, :owner_id, :unique => true + add_index :people, :diaspora_handle, :unique => true + + create_table :profiles do |t| + t.string :diaspora_handle + t.string :first_name + t.string :last_name + t.string :image_url + t.string :image_url_small + t.string :image_url_medium + t.date :birthday + t.string :gender + t.text :bio + t.boolean :searchable, :default => true + t.integer :person_id + t.timestamps + end + add_index :profiles, [:first_name, :searchable] + add_index :profiles, [:last_name, :searchable] + add_index :profiles, [:first_name, :last_name, :searchable] + add_index :profiles, :person_id + end + + def self.down + raise "irreversable migration!" + end +end diff --git a/db/schema.rb b/db/schema.rb index a05d3a11c..6bf3a6d3b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1,18 +1,118 @@ -# Copyright (c) 2010, Diaspora Inc. This file is -# licensed under the Affero General Public License version 3 or later. See -# the COPYRIGHT file. - -# This file is auto-generated from the current state of the database. Instead of editing this file, -# please use the migrations feature of Active Record to incrementally modify your database, and -# then regenerate this schema definition. +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. # -# Note that this schema.rb definition is the authoritative source for your database schema. If you need -# to create the application database on another system, you should be using db:schema:load, not running -# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations # you'll amass, the slower it'll run and the greater likelihood for issues). # # It's strongly recommended to check this file into your version control system. ActiveRecord::Schema.define(:version => 0) do + create_table "aspect_memberships", :force => true do |t| + t.boolean "pending", :default => true + t.integer "aspect_id" + t.integer "person_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "aspect_memberships", ["aspect_id", "person_id"], :name => "index_aspect_memberships_on_aspect_id_and_person_id", :unique => true + add_index "aspect_memberships", ["aspect_id"], :name => "index_aspect_memberships_on_aspect_id" + + create_table "aspects", :force => true do |t| + t.string "name" + t.integer "user_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "aspects", ["user_id"], :name => "index_aspects_on_user_id" + + create_table "aspects_posts", :id => false, :force => true do |t| + t.integer "aspect_id" + t.integer "post_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "aspects_posts", ["aspect_id"], :name => "index_aspects_posts_on_aspect_id" + add_index "aspects_posts", ["post_id"], :name => "index_aspects_posts_on_post_id" + + create_table "comments", :force => true do |t| + t.text "text" + t.integer "post_id" + t.integer "person_id" + t.string "guid" + t.text "creator_signature" + t.text "post_creator_signature" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "comments", ["guid"], :name => "index_comments_on_guid", :unique => true + add_index "comments", ["post_id"], :name => "index_comments_on_post_id" + + create_table "invitations", :force => true do |t| + t.text "message" + t.integer "sender_id" + t.integer "recipient_id" + t.integer "aspect_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "invitations", ["sender_id"], :name => "index_invitations_on_sender_id" + + create_table "notifications", :force => true do |t| + t.string "target_type" + t.integer "target_id" + t.integer "receiver_id" + t.integer "actor_id" + t.string "action" + t.boolean "unread", :default => true + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "notifications", ["target_type", "target_id"], :name => "index_notifications_on_target_type_and_target_id" + + create_table "people", :force => true do |t| + t.string "guid" + t.text "url" + t.string "diaspora_handle" + t.text "serialized_public_key" + t.integer "owner_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "people", ["diaspora_handle"], :name => "index_people_on_diaspora_handle", :unique => true + add_index "people", ["guid"], :name => "index_people_on_guid", :unique => true + add_index "people", ["owner_id"], :name => "index_people_on_owner_id", :unique => true + + create_table "profiles", :force => true do |t| + t.string "diaspora_handle" + t.string "first_name" + t.string "last_name" + t.string "image_url" + t.string "image_url_small" + t.string "image_url_medium" + t.date "birthday" + t.string "gender" + t.text "bio" + t.boolean "searchable", :default => true + t.integer "person_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "profiles", ["first_name", "last_name", "searchable"], :name => "index_profiles_on_first_name_and_last_name_and_searchable" + add_index "profiles", ["first_name", "searchable"], :name => "index_profiles_on_first_name_and_searchable" + add_index "profiles", ["last_name", "searchable"], :name => "index_profiles_on_last_name_and_searchable" + add_index "profiles", ["person_id"], :name => "index_profiles_on_person_id" + end diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index a273559a9..050569910 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -3,6 +3,9 @@ # the COPYRIGHT file. namespace :db do + desc "rebuild and prepare test db" + task :rebuild => [:drop, :create, :migrate, 'db:test:prepare'] + desc 'Seed the current RAILS_ENV database from db/seeds.rb' namespace :seed do task :tom do diff --git a/spec/factories.rb b/spec/factories.rb index 048c0dfc3..c9a9d279b 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -20,8 +20,7 @@ end Factory.define :person do |p| p.sequence(:diaspora_handle) { |n| "bob-person-#{n}#{r_str}@aol.com" } p.sequence(:url) { |n| "http://google-#{n}#{r_str}.com/" } - p.profile Factory.create(:profile, :first_name => "eugene", :last_name => "weinstien") - + p.association :profile p.serialized_public_key OpenSSL::PKey::RSA.generate(1024).public_key.export end diff --git a/spec/models/person_spec.rb b/spec/models/person_spec.rb index dc71dfca3..0752444a0 100644 --- a/spec/models/person_spec.rb +++ b/spec/models/person_spec.rb @@ -6,8 +6,8 @@ require 'spec_helper' describe Person do before do - @user = make_user - @user2 = make_user + @user = Factory(:user) + @user2 = Factory(:user) @person = Factory.create(:person) @aspect = @user.aspects.create(:name => "Dudes") @aspect2 = @user2.aspects.create(:name => "Abscence of Babes") @@ -57,7 +57,7 @@ describe Person do end context '#name' do - let!(:user) { make_user } + let!(:user) { Factory(:user) } let!(:person) { user.person } let!(:profile) { person.profile } @@ -201,7 +201,7 @@ describe Person do end context 'people finders for webfinger' do - let(:user) {make_user} + let(:user) {Factory(:user)} let(:person) {Factory(:person)} describe '.by_account_identifier' do diff --git a/spec/models/profile_spec.rb b/spec/models/profile_spec.rb index 2a54945de..04b0ee427 100644 --- a/spec/models/profile_spec.rb +++ b/spec/models/profile_spec.rb @@ -10,6 +10,7 @@ describe Profile do it "strips leading and trailing whitespace" do profile = Factory.build(:profile, :first_name => " Shelly ") profile.should be_valid + pp profile profile.first_name.should == "Shelly" end @@ -44,10 +45,7 @@ describe Profile do describe '#image_url=' do before do - @user = make_user - @profile = @user.person.profile - fixture_name = File.dirname(__FILE__) + '/../fixtures/button.png' - @photo = @user.post(:photo, :user_file => File.open(fixture_name), :to => 'all') + @profile = Factory.build(:profile) @profile.image_url = "http://tom.joindiaspora.com/images/user/tom.jpg" @pod_url = (APP_CONFIG[:pod_url][-1,1] == '/' ? APP_CONFIG[:pod_url].chop : APP_CONFIG[:pod_url]) end @@ -55,27 +53,25 @@ describe Profile do lambda {@profile.image_url = ""}.should_not change(@profile, :image_url) end it 'makes relative urls absolute' do - @profile.image_url = @photo.url(:thumb_large) - @profile.image_url.should == "#{@pod_url}#{@photo.url(:thumb_large)}" + @profile.image_url = "/relative/url" + @profile.image_url.should == "#{@pod_url}/relative/url" end - it 'accepts absolute urls' do - @profile.image_url = "#{@pod_url}#{@photo.url(:thumb_large)}" - @profile.image_url.should == "#{@pod_url}#{@photo.url(:thumb_large)}" + it "doesn't change absolute urls" do + @profile.image_url = "http://not/a/relative/url" + @profile.image_url.should == "http://not/a/relative/url" end end - describe 'serialization' do - let(:person) {Factory.create(:person)} - - it 'should include persons diaspora handle' do - xml = person.profile.to_diaspora_xml - xml.should include person.diaspora_handle - xml.should_not include person.id.to_s + describe 'serialization' do + it "includes the person's diaspora handle if it doesn't have one" do + person = Factory(:person, :diaspora_handle => "foobar") + xml = person.profile.to_diaspora_xml + xml.should include "foobar" end end describe 'date=' do - let(:profile) { make_user.profile } + let(:profile) { Factory(:profile) } it 'accepts form data' do profile.birthday.should == nil diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2d9901dae..9a335ca0b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,13 +4,12 @@ # This file is copied to ~/spec when you run 'ruby script/generate rspec' # from the project root directory. - ENV["RAILS_ENV"] ||= 'test' require File.dirname(__FILE__) + "/../config/environment" unless defined?(Rails) require 'helper_methods' require 'rspec/rails' -require 'database_cleaner' require 'webmock/rspec' +require 'factory_girl' include Devise::TestHelpers include WebMock::API @@ -24,15 +23,13 @@ RSpec.configure do |config| config.mock_with :mocha config.mock_with :rspec - DatabaseCleaner.strategy = :truncation - DatabaseCleaner.orm = "mongo_mapper" + config.use_transactional_fixtures = true config.before(:each) do I18n.locale = :en EventMachine::HttpRequest.stub!(:new).and_return(FakeHttpRequest.new(:success)) RestClient.stub!(:post).and_return(FakeHttpRequest.new(:success)) - DatabaseCleaner.clean UserFixer.load_user_fixtures $process_queue = false end