profile_spec is passing with mysql... baby steps.
This commit is contained in:
parent
c43cd7bf7a
commit
58f757b91d
20 changed files with 714 additions and 598 deletions
5
Gemfile
5
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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = {})
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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?:\/\//)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
10
config/database.yml
Normal 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
|
||||
|
|
@ -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'
|
||||
|
|
|
|||
94
db/migrate/0000_create_schema.rb
Normal file
94
db/migrate/0000_create_schema.rb
Normal 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
|
||||
120
db/schema.rb
120
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue