profile_spec is passing with mysql... baby steps.

This commit is contained in:
Mike Sofaer, Raphael Sofaer & Sarah Mei 2010-12-18 18:45:55 -08:00
parent c43cd7bf7a
commit 58f757b91d
20 changed files with 714 additions and 598 deletions

View file

@ -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'

View file

@ -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

View file

@ -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 = {})
{

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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?:\/\//)

View file

@ -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

View file

@ -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)

10
config/database.yml Normal file
View file

@ -0,0 +1,10 @@
test:
adapter: mysql2
database: diaspora_test
user: root
password: password
development:
adapter: mysql2
database: diaspora_development
user: root
password: password

View file

@ -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'

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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