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

This commit is contained in:
Raphael 2010-10-14 13:15:38 -07:00
commit be8cacdc79
22 changed files with 152 additions and 85 deletions

View file

@ -47,8 +47,8 @@ end
group :test do group :test do
gem 'capybara', '~> 0.3.9' gem 'capybara', '~> 0.3.9'
gem 'cucumber-rails', '0.3.2' gem 'cucumber-rails', '0.3.2'
gem 'rspec', '>= 2.0.0.beta.17' gem 'rspec', '>= 2.0.0'
gem 'rspec-rails', '2.0.0.beta.17' gem 'rspec-rails', '>= 2.0.0'
gem 'mocha' gem 'mocha'
gem 'database_cleaner' gem 'database_cleaner'
gem 'webmock' gem 'webmock'

View file

@ -223,9 +223,8 @@ GEM
rspec-mocks (2.0.0) rspec-mocks (2.0.0)
rspec-core (= 2.0.0) rspec-core (= 2.0.0)
rspec-expectations (= 2.0.0) rspec-expectations (= 2.0.0)
rspec-rails (2.0.0.beta.17) rspec-rails (2.0.0)
rspec (>= 2.0.0.beta.14) rspec (= 2.0.0)
webrat (>= 0.7.0)
ruby-debug (0.10.3) ruby-debug (0.10.3)
columnize (>= 0.1) columnize (>= 0.1)
ruby-debug-base (~> 0.10.3.0) ruby-debug-base (~> 0.10.3.0)
@ -253,10 +252,6 @@ GEM
webmock (1.3.5) webmock (1.3.5)
addressable (>= 2.1.1) addressable (>= 2.1.1)
crack (>= 0.1.7) crack (>= 0.1.7)
webrat (0.7.1)
nokogiri (>= 1.2.0)
rack (>= 1.0)
rack-test (>= 0.5.3)
will_paginate (3.0.pre2) will_paginate (3.0.pre2)
xml-simple (1.0.12) xml-simple (1.0.12)
@ -290,8 +285,8 @@ DEPENDENCIES
rails (= 3.0.0) rails (= 3.0.0)
redfinger! redfinger!
roxml! roxml!
rspec (>= 2.0.0.beta.17) rspec (>= 2.0.0)
rspec-rails (= 2.0.0.beta.17) rspec-rails (>= 2.0.0)
ruby-debug ruby-debug
sprinkle! sprinkle!
thin thin

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

@ -4,15 +4,20 @@
class InvitationsController < Devise::InvitationsController class InvitationsController < Devise::InvitationsController
def create def create
begin
self.resource = current_user.invite_user(params[resource_name]) self.resource = current_user.invite_user(params[resource_name])
flash[:notice] = I18n.t 'invitations.create.sent'
if resource.errors.empty? rescue RuntimeError => e
set_flash_message :notice, :send_instructions#, :email => self.resource.email if e.message == "You have no invites"
redirect_to after_sign_in_path_for(resource_name) 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 else
render_with_scope :new raise e
end end
end end
redirect_to after_sign_in_path_for(resource_name)
end
def update def update
begin begin

View file

@ -12,7 +12,6 @@ class PeopleController < ApplicationController
@aspects_dropdown_array = current_user.aspects.collect{|x| [x.to_s, x.id]} @aspects_dropdown_array = current_user.aspects.collect{|x| [x.to_s, x.id]}
@aspect = :all @aspect = :all
@people = Person.search(params[:q]).paginate :page => params[:page], :per_page => 25, :order => 'created_at DESC' @people = Person.search(params[:q]).paginate :page => params[:page], :per_page => 25, :order => 'created_at DESC'
respond_with @people respond_with @people
end end

View file

@ -78,10 +78,6 @@ class UsersController < ApplicationController
send_data( File.open(tar_path).read, :filename => "#{current_user.id}.tar" ) send_data( File.open(tar_path).read, :filename => "#{current_user.id}.tar" )
end end
def invite
User.invite!(:email => params[:email])
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

@ -35,19 +35,17 @@ class Person
def self.search(query) def self.search(query)
return Person.all if query.to_s.empty? return Person.all if query.to_s.empty?
qTokens = query.to_s.strip.split(" ") query_tokens = query.to_s.strip.split(" ")
fullQueryText = Regexp.escape( query.to_s.strip ) full_query_text = Regexp.escape( query.to_s.strip )
p = [] p = []
qTokens.each { query_tokens.each do |token|
|token|
q = Regexp.escape( token.to_s.strip ) q = Regexp.escape( token.to_s.strip )
p = Person.all('profile.first_name' => /^#{q}/i) \ p = Person.all('profile.first_name' => /^#{q}/i) \
| Person.all('profile.last_name' => /^#{q}/i) \ | Person.all('profile.last_name' => /^#{q}/i) \
| p | p
end
}
return p return p
end end

View file

@ -27,6 +27,7 @@ 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 :inviter_ids, Array
@ -266,17 +267,25 @@ class User
###Invitations############ ###Invitations############
def invite_user( opts = {} ) def invite_user( opts = {} )
if self.invites > 0
invited_user = User.invite!(:email => opts[:email], :inviter => self) invited_user = User.invite!(:email => opts[:email], :inviter => self)
#invited_user.inviters << self self.invites = self.invites - 1
#invited_user.save! self.save!
invited_user invited_user
else
raise "You have no invites"
end
end end
def self.invite!(attributes={}) def self.invite!(attributes={})
inviter = attributes.delete(:inviter) inviter = attributes.delete(:inviter)
invitable = find_or_initialize_with_error_by(:email, attributes.delete(:email)) invitable = find_or_initialize_with_error_by(:email, attributes.delete(:email))
invitable.attributes = attributes invitable.attributes = attributes
if invitable.inviters.include?(inviter)
raise "You already invited this person"
else
invitable.inviters << inviter invitable.inviters << inviter
end
if invitable.new_record? if invitable.new_record?
invitable.errors.clear if invitable.email.try(:match, Devise.email_regexp) invitable.errors.clear if invitable.email.try(:match, Devise.email_regexp)

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
#{(@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. #{(@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

@ -11,6 +11,8 @@
%meta{"http-equiv"=>"Content-Type", :content=>"text/html; charset=utf-8"}/ %meta{"http-equiv"=>"Content-Type", :content=>"text/html; charset=utf-8"}/
= stylesheet_link_tag "blueprint/screen", :media => 'screen' = stylesheet_link_tag "blueprint/screen", :media => 'screen'
= stylesheet_link_tag "blueprint/print", :media => 'print'
= stylesheet_link_tag "application", "ui" = stylesheet_link_tag "application", "ui"
= stylesheet_link_tag "/../javascripts/fancybox/jquery.fancybox-1.3.1" = stylesheet_link_tag "/../javascripts/fancybox/jquery.fancybox-1.3.1"

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

@ -5,8 +5,13 @@
%h2 Account %h2 Account
%h3 Change Password = link_to "invite friends", new_user_invitation_path(current_user)
%br
%br
%br
%h3 Change Password
= form_for @user do |f| = form_for @user do |f|
= f.error_messages = f.error_messages
@ -23,12 +28,14 @@
= f.submit 'Change password' = f.submit 'Change password'
%h3 Export Data %h3 Export Data
= link_to "download my xml", users_export_path, :class => "button" = link_to "download my xml", users_export_path, :class => "button"
= link_to "download my photos", users_export_photos_path, :class => "button" = link_to "download my photos", users_export_photos_path, :class => "button"
%h3 Close Account %br
%br
%br
%h3 Close Account
= link_to "Close Account", current_user, = link_to "Close Account", current_user,
:confirm => "Are you sure?", :method => :delete, :confirm => "Are you sure?", :method => :delete,
:class => "button" :class => "button"

View file

@ -4,8 +4,6 @@
%h2 Profile %h2 Profile
= link_to new_user_invitation_path(current_user)
= form_for @user do |f| = form_for @user do |f|
= f.error_messages = f.error_messages

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"

View file

@ -195,8 +195,8 @@ li.message {
li.message .content .from a { li.message .content .from a {
font-weight: bold; } font-weight: bold; }
li.message .content div.info { li.message .content div.info {
color: #444444; color: #999999;
font-size: 13px; } font-size: smaller; }
li.message .content div.info a { li.message .content div.info a {
color: #cccccc; } color: #cccccc; }
li.message .content div.info .time { li.message .content div.info .time {

View file

@ -266,8 +266,8 @@ li.message
:size 14px :size 14px
div.info div.info
:color #444 :color #999
:font-size 13px :font-size smaller
a a
:color #ccc :color #ccc
.time .time

View file

@ -1,25 +0,0 @@
# Copyright (c) 2010, Diaspora Inc. This file is
# licensed under the Affero General Public License version 3 or later. See
# the COPYRIGHT file.
require 'spec_helper'
describe InvitationsController do
render_views
let(:user) {Factory.create :user}
before do
sign_in :user, user
end
context 'inviting another user' do
it 'should create an invited user and add keep track of an invitor' do
debugger
params = {"user" => {"email" => "test@example.com"}}
post :create, params
#invitee = inviter.invite_user(:email => "test@example.com")
#invitee.inviters.includes?(inviter).should be true
end
end
end

View file

@ -14,9 +14,10 @@ describe PeopleController do
end end
it "index should yield search results for substring of person name" do it "index should yield search results for substring of person name" do
pending "wait, what???"
Person.should_receive(:search) eugene = Factory.create(:person, :profile => {:first_name => "Eugene", :last_name => "w"})
get :index, :q => "Eu" get :index, :q => "Eu"
assigns[:people].should include eugene
end end
it 'should go to the current_user show page' do it 'should go to the current_user show page' do

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"
@ -58,5 +58,28 @@ describe User do
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

@ -6,20 +6,51 @@ require 'spec_helper'
describe User do describe User do
let(:inviter) {Factory.create :user} 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_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 context "creating invites" do
it 'should invite the user' do before do
pending "weird wrong number of arguments error (0 for 2), which changes if you put in two args" deliverable = Object.new
#User.should_receive(:invite!).and_return(invited_user) deliverable.stub!(:deliver)
inviter.invite_user(:email => "email@example.com") ::Devise.mailer.stub!(:invitation).and_return(deliverable)
end end
it 'should add the inviter to the invited_user' do it 'creates a user' do
User.should_receive(:invite!).and_return(invited_user) lambda {
invited_user = inviter.invite_user(:email => "email@example.com") inviter.invite_user(:email => "joe@example.com")
}.should change(User, :count).by(1)
end
it 'sends email to the invited user' do
::Devise.mailer.should_receive(:invitation).once
inviter.invite_user(:email => "ian@example.com")
end
it 'adds the inviter to the invited_user' do
invited_user = inviter.invite_user(:email => "marcy@example.com")
invited_user.reload invited_user.reload
invited_user.inviters.include?(inviter).should be true 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
end end

View file

@ -87,6 +87,16 @@ describe User do
user.destroy user.destroy
end end
it 'should remove all aspects' do
pending "this should use :dependant => :destroy on the many assoc...but that screws this test suite..."
aspects = user.aspects
user.destroy
proc{ aspects.reload }.should raise_error /does not exist/
end
describe '#remove_person' do describe '#remove_person' do
it 'should remove the person object' do it 'should remove the person object' do
person = user.person person = user.person