Merge branch 'master' of github.com:diaspora/diaspora into import

Conflicts:
	app/controllers/users_controller.rb
This commit is contained in:
maxwell 2010-10-13 23:09:48 -07:00
commit e218ab6780
18 changed files with 236 additions and 105 deletions

24
.gitignore vendored
View file

@ -1,4 +1,17 @@
# Configuration files
config/app_config.yml
config/fb_config.yml
config/initializers/secret_token.rb
.bundle .bundle
# Uploded files and local files
log/*
public/uploads/*
public/source.tar
tmp/**/*
db/*.sqlite3
# Temporary files of every sort
.DS_Store .DS_Store
.idea .idea
.rvmrc .rvmrc
@ -8,17 +21,6 @@
*.swp *.swp
*~ *~
bin/* bin/*
config/app_config.yml
config/fb_config.yml
config/initializers/secret_token.rb
db/*.sqlite3
log/*
nbproject nbproject
gpg/diaspora-development/*.gpg
gpg/diaspora-production/*.gpg
gpg/*/random_seed
patches-* patches-*
public/uploads/*
public/source.tar
tmp/**/*
capybara-*.html capybara-*.html

View file

@ -9,6 +9,7 @@ class ApplicationController < ActionController::Base
before_filter :set_friends_and_status, :except => [:create, :update] before_filter :set_friends_and_status, :except => [:create, :update]
before_filter :count_requests before_filter :count_requests
before_filter :fb_user_info before_filter :fb_user_info
before_filter :set_invites
layout :layout_by_resource layout :layout_by_resource
@ -37,6 +38,12 @@ class ApplicationController < ActionController::Base
@request_count = Request.for_user(current_user).size if current_user @request_count = Request.for_user(current_user).size if current_user
end end
def set_invites
if current_user
@invites = current_user.invites
end
end
def fb_user_info def fb_user_info
if current_user if current_user
@access_token = warden.session[:access_token] @access_token = warden.session[:access_token]

View file

@ -3,6 +3,22 @@
# the COPYRIGHT file. # the COPYRIGHT file.
class InvitationsController < Devise::InvitationsController class InvitationsController < Devise::InvitationsController
def create
begin
self.resource = current_user.invite_user(params[resource_name])
flash[:notice] = I18n.t 'invitations.create.sent'
rescue RuntimeError => e
if e.message == "You have no invites"
flash[:error] = I18n.t 'invitations.create.no_more'
elsif e.message == "You already invited this person"
flash[:error] = I18n.t 'invitations.create.already_sent'
else
raise e
end
end
redirect_to after_sign_in_path_for(resource_name)
end
def update def update
begin begin
user = User.find_by_invitation_token(params["user"]["invitation_token"]) user = User.find_by_invitation_token(params["user"]["invitation_token"])

View file

@ -104,7 +104,6 @@ class UsersController < ApplicationController
end end
private private
def prep_image_url(params) def prep_image_url(params)
url = APP_CONFIG[:pod_url].chop if APP_CONFIG[:pod_url][-1,1] == '/' url = APP_CONFIG[:pod_url].chop if APP_CONFIG[:pod_url][-1,1] == '/'

View file

@ -2,9 +2,7 @@
# licensed under the Affero General Public License version 3 or later. See # licensed under the Affero General Public License version 3 or later. See
# the COPYRIGHT file. # the COPYRIGHT file.
require File.join(Rails.root, 'lib/diaspora/user/friending') require File.join(Rails.root, 'lib/diaspora/user')
require File.join(Rails.root, 'lib/diaspora/user/querying')
require File.join(Rails.root, 'lib/diaspora/user/receiving')
require File.join(Rails.root, 'lib/salmon/salmon') require File.join(Rails.root, 'lib/salmon/salmon')
class InvitedUserValidator < ActiveModel::Validator class InvitedUserValidator < ActiveModel::Validator
@ -20,9 +18,7 @@ end
class User class User
include MongoMapper::Document include MongoMapper::Document
plugin MongoMapper::Devise plugin MongoMapper::Devise
include Diaspora::UserModules::Friending include Diaspora::UserModules
include Diaspora::UserModules::Querying
include Diaspora::UserModules::Receiving
include Encryptor::Private include Encryptor::Private
QUEUE = MessageHandler.new QUEUE = MessageHandler.new
@ -31,8 +27,10 @@ class User
key :username, :unique => true key :username, :unique => true
key :serialized_private_key, String key :serialized_private_key, String
key :invites, Integer, :default => 5
key :invitation_token, String key :invitation_token, String
key :invitation_sent_at, DateTime key :invitation_sent_at, DateTime
key :inviter_ids, Array
key :friend_ids, Array key :friend_ids, Array
key :pending_request_ids, Array key :pending_request_ids, Array
key :visible_post_ids, Array key :visible_post_ids, Array
@ -40,6 +38,7 @@ class User
one :person, :class_name => 'Person', :foreign_key => :owner_id one :person, :class_name => 'Person', :foreign_key => :owner_id
many :inviters, :in => :inviter_ids, :class_name => 'User'
many :friends, :in => :friend_ids, :class_name => 'Person' many :friends, :in => :friend_ids, :class_name => 'Person'
many :visible_people, :in => :visible_person_ids, :class_name => 'Person' # One of these needs to go many :visible_people, :in => :visible_person_ids, :class_name => 'Person' # One of these needs to go
many :pending_requests, :in => :pending_request_ids, :class_name => 'Request' many :pending_requests, :in => :pending_request_ids, :class_name => 'Request'
@ -266,7 +265,37 @@ class User
end end
end end
###Helpers############ ###Invitations############
def invite_user( opts = {} )
if self.invites > 0
invited_user = User.invite!(:email => opts[:email], :inviter => self)
self.invites = self.invites - 1
self.save!
invited_user
else
raise "You have no invites"
end
end
def self.invite!(attributes={})
inviter = attributes.delete(:inviter)
invitable = find_or_initialize_with_error_by(:email, attributes.delete(:email))
invitable.attributes = attributes
if invitable.inviters.include?(inviter)
raise "You already invited this person"
else
invitable.inviters << inviter
end
if invitable.new_record?
invitable.errors.clear if invitable.email.try(:match, Devise.email_regexp)
else
invitable.errors.add(:email, :taken) unless invitable.invited?
end
invitable.invite! if invitable.errors.empty?
invitable
end
def accept_invitation!( opts = {} ) def accept_invitation!( opts = {} )
if self.invited? if self.invited?
@ -283,11 +312,13 @@ class User
person_hash = opts.delete(:person) person_hash = opts.delete(:person)
self.person = Person.create(person_hash) self.person = Person.create(person_hash)
self.person.save self.person.save
self.invitation_token = nil
self.save self.save
self self
end end
end end
###Helpers############
def self.instantiate!( opts = {} ) def self.instantiate!( opts = {} )
opts[:person][:diaspora_handle] = "#{opts[:username]}@#{APP_CONFIG[:terse_pod_url]}" opts[:person][:diaspora_handle] = "#{opts[:username]}@#{APP_CONFIG[:terse_pod_url]}"
opts[:person][:url] = APP_CONFIG[:pod_url] opts[:person][:url] = APP_CONFIG[:pod_url]

View file

@ -26,6 +26,7 @@
%li.grey Drag to ignore/remove %li.grey Drag to ignore/remove
%h3= link_to "Invite a friend!", "#invite_user_pane", :id => "invite_user_button", :class => "invite_user_button", :title => "Invite a friend" %h3= link_to "Invite a friend!", "#invite_user_pane", :id => "invite_user_button", :class => "invite_user_button", :title => "Invite a friend"
%h3= "You have #{@invites} invites."
.yo{ :style => "display:none;"} .yo{ :style => "display:none;"}
#invite_user_pane #invite_user_pane

View file

@ -1,9 +1,9 @@
%p %p
Hello #{@resource.email}! Hello #{@resource.email}!
%p %p
Someone has invited you to #{root_url}, you can accept it through the link below. #{(@resource.inviters.count == 1)? ( @resource.inviters.first.real_name + " has") : (@resource.inviters.map{|inv| inv.real_name}.join(",") + " have")} invited you to #{root_url}, you can accept it through the link below.
%p= link_to 'Accept invitation', accept_invitation_url(@resource, :invitation_token => @resource.invitation_token) %p= link_to 'Accept invitation', accept_invitation_url(@resource, :invitation_token => @resource.invitation_token)
%p %p
If you don't want to accept the invitation, please ignore this email. If you don't want to accept the invitation, please ignore this email.
%br/ %br/
Your account won't be created until you access the link above and set your password. Your account won't be created until you access the link above and sign up.

View file

@ -24,6 +24,8 @@
%br %br
= link_to "Invite a friend!", "#invite_user_pane", :id => "invite_user_button", :class => "invite_user_button", :title => "Invite a friend" = link_to "Invite a friend!", "#invite_user_pane", :id => "invite_user_button", :class => "invite_user_button", :title => "Invite a friend"
%br
= "You have #{@invites} invites."
.yo{ :style => "display:none;"} .yo{ :style => "display:none;"}
#invite_user_pane #invite_user_pane
= render "invitations/new" = render "invitations/new"

View file

@ -1,46 +0,0 @@
en:
errors:
messages:
not_found: "not found"
already_confirmed: "was already confirmed"
not_locked: "was not locked"
devise:
failure:
unauthenticated: 'You need to sign in or sign up before continuing.'
unconfirmed: 'You have to confirm your account before continuing.'
locked: 'Your account is locked.'
invalid: 'Invalid email or password.'
invalid_token: 'Invalid authentication token.'
timeout: 'Your session expired, please sign in again to continue.'
inactive: 'Your account was not activated yet.'
sessions:
signed_in: 'Signed in successfully.'
signed_out: 'Signed out successfully.'
passwords:
send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
updated: 'Your password was changed successfully. You are now signed in.'
confirmations:
send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
confirmed: 'Your account was successfully confirmed. You are now signed in.'
registrations:
signed_up: 'You have signed up successfully. If enabled, a confirmation was sent to your e-mail.'
updated: 'You updated your account successfully.'
destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
unlocks:
send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
unlocked: 'Your account was successfully unlocked. You are now signed in.'
invitations:
send_instructions: 'Your invitation has been sent.'
invitation_token_invalid: 'The invitation token provided is not valid!'
updated: 'Your password was set successfully. You are now signed in.'
mailer:
confirmation_instructions:
subject: 'Confirmation instructions'
reset_password_instructions:
subject: 'Reset password instructions'
unlock_instructions:
subject: 'Unlock Instructions'
invitation:
subject: 'A friend wants you to join Diaspora!'

View file

@ -1,7 +1,3 @@
# Copyright (c) 2010, Diaspora Inc. This file is
# licensed under the Affero General Public License version 3 or later. See
# the COPYRIGHT file.
en: en:
errors: errors:
messages: messages:
@ -11,30 +7,40 @@ en:
devise: devise:
failure: failure:
unauthenticated: "You need to sign in or sign up before continuing." unauthenticated: 'You need to sign in or sign up before continuing.'
unconfirmed: "You have to confirm your account before continuing." unconfirmed: 'You have to confirm your account before continuing.'
locked: "Your account is locked." locked: 'Your account is locked.'
invalid: "Invalid email or password." invalid: 'Invalid email or password.'
invalid_token: "Invalid authentication token." invalid_token: 'Invalid authentication token.'
timeout: "Your session expired, please sign in again to continue." timeout: 'Your session expired, please sign in again to continue.'
inactive: "Your account was not activated yet." inactive: 'Your account was not activated yet.'
sessions: sessions:
signed_in: "Signed in successfully." signed_in: 'Signed in successfully.'
signed_out: "Signed out successfully." signed_out: 'Signed out successfully.'
passwords: passwords:
send_instructions: "You will receive an email with instructions about how to reset your password in a few minutes." send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
updated: "Your password was changed successfully. You are now signed in." updated: 'Your password was changed successfully. You are now signed in.'
confirmations: confirmations:
send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes." send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
confirmed: "Your account was successfully confirmed. You are now signed in." confirmed: 'Your account was successfully confirmed. You are now signed in.'
registrations: registrations:
signed_up: "You have signed up successfully. If enabled, a confirmation was sent to your e-mail." signed_up: 'You have signed up successfully. If enabled, a confirmation was sent to your e-mail.'
updated: "You updated your account successfully." updated: 'You updated your account successfully.'
destroyed: "Bye! Your account was successfully cancelled. We hope to see you again soon." destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
unlocks: unlocks:
send_instructions: "You will receive an email with instructions about how to unlock your account in a few minutes." send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
unlocked: "Your account was successfully unlocked. You are now signed in." unlocked: 'Your account was successfully unlocked. You are now signed in.'
invitations:
send_instructions: 'Your invitation has been sent.'
invitation_token_invalid: 'The invitation token provided is not valid!'
updated: 'Your password was set successfully. You are now signed in.'
mailer: mailer:
confirmation_instructions: "Confirmation instructions" confirmation_instructions:
reset_password_instructions: "Reset password instructions" subject: 'Confirmation instructions'
unlock_instructions: "Unlock Instructions" reset_password_instructions:
subject: 'Reset password instructions'
unlock_instructions:
subject: 'Unlock Instructions'
invitation:
subject: 'A friend wants you to join Diaspora!'

View file

@ -154,6 +154,14 @@ en:
sign_up: "Sign up" sign_up: "Sign up"
create: create:
success: "You've joined Diaspora!" success: "You've joined Diaspora!"
invitations:
create:
sent: 'Your invitation has been sent.'
no_more: 'You have no more invitations.'
already_sent: 'You already invited this person.'
invitation_token_invalid: 'The invitation token provided is not valid!'
updated: 'Your password was set successfully. You are now signed in.'
status_messages: status_messages:
new_status_message: new_status_message:
tell_me_something_good: "tell me something good" tell_me_something_good: "tell me something good"

11
lib/diaspora/user.rb Normal file
View file

@ -0,0 +1,11 @@
require File.join(Rails.root, 'lib/diaspora/user/friending')
require File.join(Rails.root, 'lib/diaspora/user/querying')
require File.join(Rails.root, 'lib/diaspora/user/receiving')
module Diaspora
module UserModules
include Friending
include Querying
include Receiving
end
end

View file

@ -1,5 +1,9 @@
## Diaspora RPM tools ## Diaspora RPM tools
NOTE: This does not work ATM, see discussions on Gemfile.lock in
attached to a commit 12/10 (yea, I know, you calll it 10/12, but you
are wrong ;)
Creates diaspora source tarballs and RPM packages Creates diaspora source tarballs and RPM packages
An alternative to the capistrano system, providing classic, binary RPM An alternative to the capistrano system, providing classic, binary RPM

View file

@ -1,5 +1,10 @@
## Package-oriented install for ubuntu. ## Package-oriented install for ubuntu.
NOTE: This does not work ATM, see discussions on Gemfile.lock in
attached to a commit 12/10 (yea, I know, you calll it 10/12, but you
are wrong ;)
Here are somediaspora-installdiaspora-install scripts to install diaspora on Ubuntu. They are designed to Here are somediaspora-installdiaspora-install scripts to install diaspora on Ubuntu. They are designed to
work as a first step towards packaging, but should be usable as is. work as a first step towards packaging, but should be usable as is.

View file

@ -3,13 +3,23 @@
# Start diaspora websocket and main services # Start diaspora websocket and main services
# #
# Is someone listening on 3000 already? (ipv4 only test ?) # Is someone listening on the port already? (ipv4 only test ?)
services=$( netstat -nl | grep '[^:]:3000[ \t]') PORT=3000
test -n "$services" && { while getopts ":p:" OPTION
echo "Warning: something is already using port 3000" do
echo " $services" if [ $OPTION == 'p' ]
} then
PORT=$OPTARG
fi
done
services=$( netstat -nl | grep ":$PORT[ \t]")
test -n "$services" && {
echo "Warning: something is already using port "$PORT
echo " $services"
exit
}
# Check if Mongo is running # Check if Mongo is running

View file

@ -21,7 +21,7 @@ describe User do
end end
context 'malicious friend attack vector' do context 'malicious friend attack vector' do
it 'ovewrites messages with a different user' do it 'overwrites messages with a different user' do
original_message = user2.post :status_message, :message => 'store this!', :to => aspect2.id original_message = user2.post :status_message, :message => 'store this!', :to => aspect2.id
user.receive_salmon(user2.salmon(original_message).xml_for(user.person)) user.receive_salmon(user2.salmon(original_message).xml_for(user.person))
@ -34,7 +34,7 @@ describe User do
user.raw_visible_posts.first.message.should == "store this!" user.raw_visible_posts.first.message.should == "store this!"
end end
it 'ovewrites messages which apear to be from the same user' do it 'overwrites messages which apear to be from the same user' do
original_message = user2.post :status_message, :message => 'store this!', :to => aspect2.id original_message = user2.post :status_message, :message => 'store this!', :to => aspect2.id
user.receive_salmon(user2.salmon(original_message).xml_for(user.person)) user.receive_salmon(user2.salmon(original_message).xml_for(user.person))
user.raw_visible_posts.count.should be 1 user.raw_visible_posts.count.should be 1
@ -47,7 +47,7 @@ describe User do
user.raw_visible_posts.first.message.should == "store this!" user.raw_visible_posts.first.message.should == "store this!"
end end
it 'overites another persons profile' do it 'should not overwrite another persons profile profile' do
profile = user2.profile.clone profile = user2.profile.clone
profile.first_name = "Not BOB" profile.first_name = "Not BOB"
@ -57,6 +57,29 @@ describe User do
user2.reload user2.reload
user2.profile.first_name.should == "Robert" user2.profile.first_name.should == "Robert"
end end
it 'should not overwrite another persons profile through comment' do
pending
user_status = user.post(:status_message, :message => "hi", :to => 'all')
comment = Comment.new(:person_id => user3.person.id, :text => "hey", :post => user_status)
comment.creator_signature = comment.sign_with_key(user3.encryption_key)
comment.post_creator_signature = comment.sign_with_key(user.encryption_key)
person = user3.person
original_url = person.url
original_id = person.id
puts original_url
comment.person.url = "http://bad.com/"
user3.delete
person.delete
comment.to_diaspora_xml.include?("bad.com").should be true
user2.receive_salmon(user.salmon(comment).xml_for(user2.person))
comment.person.url.should == original_url
Person.first(:id => original_id).url.should == original_url
end
end end
end end

View file

@ -5,18 +5,55 @@
require 'spec_helper' require 'spec_helper'
describe User do describe User do
let!(:invited_user) { create_user_with_invitation("abc")} let(:inviter) {Factory.create :user}
let(:inviter_with_3_invites) {Factory.create :user, :invites => 3}
let!(:invited_user) { create_user_with_invitation("abc", :email => "email@example.com", :inviter => inviter)}
let(:invited_user1) { create_user_with_invitation("abc", :email => "email@example.com", :inviter => inviter_with_3_invites)}
let(:invited_user2) { create_user_with_invitation("abc", :email => "email@example.com", :inviter => inviter_with_3_invites)}
let(:invited_user3) { create_user_with_invitation("abc", :email => "email@example.com", :inviter => inviter_with_3_invites)}
context "creating invites" do
it 'should invite the user' do
pending "weird wrong number of arguments error (0 for 2), which changes if you put in two args"
#User.should_receive(:invite!).and_return(invited_user)
inviter.invite_user(:email => "email@example.com")
end
it 'should add the inviter to the invited_user' do
User.should_receive(:invite!).and_return(invited_user)
invited_user = inviter.invite_user(:email => "email@example.com")
invited_user.reload
invited_user.inviters.include?(inviter).should be true
end
end
context "limit on invites" do
it 'does not invite users after 3 invites' do
User.stub!(:invite!).and_return(invited_user1,invited_user2,invited_user3)
inviter_with_3_invites.invite_user(:email => "email1@example.com")
inviter_with_3_invites.invite_user(:email => "email2@example.com")
inviter_with_3_invites.invite_user(:email => "email3@example.com")
proc{inviter_with_3_invites.invite_user(:email => "email4@example.com")}.should raise_error /You have no invites/
end
it 'does not invite people I already invited' do
pending "this is really weird to test without the actual method working"
User.stub!(:invite!).and_return(invited_user1,invited_user1)
inviter_with_3_invites.invite_user(:email => "email1@example.com")
proc{inviter_with_3_invites.invite_user(:email => "email1@example.com")}.should raise_error /You already invited that person/
end
end
context "the acceptance of an invitation" do context "the acceptance of an invitation" do
it "should create the person with the passed in params" do it "should create the person with the passed in params" do
Person.count.should be 0 person_count = Person.count
u = invited_user.accept_invitation!(:invitation_token => "abc", u = invited_user.accept_invitation!(:invitation_token => "abc",
:username => "user", :username => "user",
:password => "secret", :password => "secret",
:password_confirmation => "secret", :password_confirmation => "secret",
:person => {:profile => {:first_name => "Bob", :person => {:profile => {:first_name => "Bob",
:last_name => "Smith"}} ) :last_name => "Smith"}} )
Person.count.should be 1 Person.count.should be person_count + 1
u.person.profile.first_name.should == "Bob" u.person.profile.first_name.should == "Bob"
end end
end end
@ -25,11 +62,12 @@ describe User do
end end
def create_user_with_invitation(invitation_token, attributes={}) def create_user_with_invitation(invitation_token, attributes={})
inviter = attributes.delete(:inviter)
user = User.new({:password => nil, :password_confirmation => nil}.update(attributes)) user = User.new({:password => nil, :password_confirmation => nil}.update(attributes))
#puts user.inspect
#user.skip_confirmation! #user.skip_confirmation!
user.invitation_token = invitation_token user.invitation_token = invitation_token
user.invitation_sent_at = Time.now.utc user.invitation_sent_at = Time.now.utc
user.inviters << inviter
user.save(:validate => false) user.save(:validate => false)
user user
end end

View file

@ -22,6 +22,20 @@ describe User do
user.valid? user.valid?
user.username.should == "someuppercase" user.username.should == "someuppercase"
end end
it "confirms the password" do
pending "I cannot figure out why this doesn't work. --Raphael"
user = User.instantiate!(
:email => "tom@tom.joindiaspora.com",
:username => "tom",
:password => "evankorth",
:password_confirmation => "potatoes",
:person => Person.new(
:profile => Profile.new( :first_name => "Alexander", :last_name => "Hamiltom" ))
)
user.created_at.should be_nil
user.valid?.should be_false
end
end end
describe '#diaspora_handle' do describe '#diaspora_handle' do