diff --git a/.gitignore b/.gitignore index 8482dc230..999b067f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,17 @@ +# Configuration files +config/app_config.yml +config/fb_config.yml +config/initializers/secret_token.rb .bundle + +# Uploded files and local files +log/* +public/uploads/* +public/source.tar +tmp/**/* +db/*.sqlite3 + +# Temporary files of every sort .DS_Store .idea .rvmrc @@ -8,17 +21,6 @@ *.swp *~ bin/* -config/app_config.yml -config/fb_config.yml -config/initializers/secret_token.rb -db/*.sqlite3 -log/* nbproject -gpg/diaspora-development/*.gpg -gpg/diaspora-production/*.gpg -gpg/*/random_seed patches-* -public/uploads/* -public/source.tar -tmp/**/* capybara-*.html diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 82a8f7cd1..65b57b252 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -9,6 +9,7 @@ class ApplicationController < ActionController::Base before_filter :set_friends_and_status, :except => [:create, :update] before_filter :count_requests before_filter :fb_user_info + before_filter :set_invites layout :layout_by_resource @@ -37,6 +38,12 @@ class ApplicationController < ActionController::Base @request_count = Request.for_user(current_user).size if current_user end + def set_invites + if current_user + @invites = current_user.invites + end + end + def fb_user_info if current_user @access_token = warden.session[:access_token] diff --git a/app/controllers/invitations_controller.rb b/app/controllers/invitations_controller.rb index 852904458..92da135d8 100644 --- a/app/controllers/invitations_controller.rb +++ b/app/controllers/invitations_controller.rb @@ -3,6 +3,22 @@ # the COPYRIGHT file. 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 begin user = User.find_by_invitation_token(params["user"]["invitation_token"]) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 6a12c1842..d9492546d 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -104,7 +104,6 @@ class UsersController < ApplicationController end - private def prep_image_url(params) url = APP_CONFIG[:pod_url].chop if APP_CONFIG[:pod_url][-1,1] == '/' diff --git a/app/models/user.rb b/app/models/user.rb index f4937788d..b179378a1 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2,9 +2,7 @@ # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. -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') +require File.join(Rails.root, 'lib/diaspora/user') require File.join(Rails.root, 'lib/salmon/salmon') class InvitedUserValidator < ActiveModel::Validator @@ -20,9 +18,7 @@ end class User include MongoMapper::Document plugin MongoMapper::Devise - include Diaspora::UserModules::Friending - include Diaspora::UserModules::Querying - include Diaspora::UserModules::Receiving + include Diaspora::UserModules include Encryptor::Private QUEUE = MessageHandler.new @@ -31,8 +27,10 @@ class User key :username, :unique => true key :serialized_private_key, String + key :invites, Integer, :default => 5 key :invitation_token, String key :invitation_sent_at, DateTime + key :inviter_ids, Array key :friend_ids, Array key :pending_request_ids, Array key :visible_post_ids, Array @@ -40,6 +38,7 @@ class User 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 :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' @@ -266,7 +265,37 @@ class User 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 = {} ) if self.invited? @@ -283,11 +312,13 @@ class User person_hash = opts.delete(:person) self.person = Person.create(person_hash) self.person.save + self.invitation_token = nil self.save self end end + ###Helpers############ def self.instantiate!( opts = {} ) opts[:person][:diaspora_handle] = "#{opts[:username]}@#{APP_CONFIG[:terse_pod_url]}" opts[:person][:url] = APP_CONFIG[:pod_url] diff --git a/app/views/aspects/manage.html.haml b/app/views/aspects/manage.html.haml index 85296669f..472d8241f 100644 --- a/app/views/aspects/manage.html.haml +++ b/app/views/aspects/manage.html.haml @@ -26,6 +26,7 @@ %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= "You have #{@invites} invites." .yo{ :style => "display:none;"} #invite_user_pane diff --git a/app/views/users/mailer/invitation.html.haml b/app/views/devise/mailer/invitation.html.haml similarity index 55% rename from app/views/users/mailer/invitation.html.haml rename to app/views/devise/mailer/invitation.html.haml index 884a8fc27..86b01d97a 100644 --- a/app/views/users/mailer/invitation.html.haml +++ b/app/views/devise/mailer/invitation.html.haml @@ -1,9 +1,9 @@ %p Hello #{@resource.email}! %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 If you don't want to accept the invitation, please ignore this email. %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. diff --git a/app/views/shared/_aspect_friends.haml b/app/views/shared/_aspect_friends.haml index 343272dff..a37068577 100644 --- a/app/views/shared/_aspect_friends.haml +++ b/app/views/shared/_aspect_friends.haml @@ -24,6 +24,8 @@ %br = 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;"} #invite_user_pane = render "invitations/new" diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml deleted file mode 100644 index 07a2611d0..000000000 --- a/config/locales/devise.en.yml +++ /dev/null @@ -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!' - diff --git a/config/locales/devise/devise.en.yml b/config/locales/devise/devise.en.yml index 06308488b..07a2611d0 100644 --- a/config/locales/devise/devise.en.yml +++ b/config/locales/devise/devise.en.yml @@ -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: errors: messages: @@ -11,30 +7,40 @@ en: 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." + 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." + 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." + 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." + 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." + 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." + 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: "Confirmation instructions" - reset_password_instructions: "Reset password instructions" - unlock_instructions: "Unlock Instructions" + 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!' + diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index 554f8bcb8..1dd33bb3f 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -154,6 +154,14 @@ en: sign_up: "Sign up" create: 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: new_status_message: tell_me_something_good: "tell me something good" diff --git a/lib/diaspora/user.rb b/lib/diaspora/user.rb new file mode 100644 index 000000000..94da947f8 --- /dev/null +++ b/lib/diaspora/user.rb @@ -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 diff --git a/pkg/fedora/README.md b/pkg/fedora/README.md index c0b29d3d2..346730a3a 100644 --- a/pkg/fedora/README.md +++ b/pkg/fedora/README.md @@ -1,5 +1,9 @@ ## 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 An alternative to the capistrano system, providing classic, binary RPM diff --git a/pkg/ubuntu/README.md b/pkg/ubuntu/README.md index f50897b24..b676ebf0c 100644 --- a/pkg/ubuntu/README.md +++ b/pkg/ubuntu/README.md @@ -1,5 +1,10 @@ ## 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 work as a first step towards packaging, but should be usable as is. diff --git a/script/server b/script/server index 130b61220..2649ed677 100755 --- a/script/server +++ b/script/server @@ -3,13 +3,23 @@ # Start diaspora websocket and main services # -# Is someone listening on 3000 already? (ipv4 only test ?) -services=$( netstat -nl | grep '[^:]:3000[ \t]') -test -n "$services" && { - echo "Warning: something is already using port 3000" - echo " $services" -} +# Is someone listening on the port already? (ipv4 only test ?) +PORT=3000 +while getopts ":p:" OPTION +do + 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 diff --git a/spec/models/user/attack_vectors_spec.rb b/spec/models/user/attack_vectors_spec.rb index 2918cf1ca..625969bef 100644 --- a/spec/models/user/attack_vectors_spec.rb +++ b/spec/models/user/attack_vectors_spec.rb @@ -21,7 +21,7 @@ describe User do end 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 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!" 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 user.receive_salmon(user2.salmon(original_message).xml_for(user.person)) user.raw_visible_posts.count.should be 1 @@ -47,7 +47,7 @@ describe User do user.raw_visible_posts.first.message.should == "store this!" end - it 'overites another persons profile' do + it 'should not overwrite another persons profile profile' do profile = user2.profile.clone profile.first_name = "Not BOB" @@ -57,6 +57,29 @@ describe User do user2.reload user2.profile.first_name.should == "Robert" 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 diff --git a/spec/models/user/invite_spec.rb b/spec/models/user/invite_spec.rb index 1bb2bf0f6..117bb5b37 100644 --- a/spec/models/user/invite_spec.rb +++ b/spec/models/user/invite_spec.rb @@ -5,18 +5,55 @@ require 'spec_helper' 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 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", :username => "user", :password => "secret", :password_confirmation => "secret", :person => {:profile => {:first_name => "Bob", :last_name => "Smith"}} ) - Person.count.should be 1 + Person.count.should be person_count + 1 u.person.profile.first_name.should == "Bob" end end @@ -25,11 +62,12 @@ describe User do end def create_user_with_invitation(invitation_token, attributes={}) + inviter = attributes.delete(:inviter) user = User.new({:password => nil, :password_confirmation => nil}.update(attributes)) - #puts user.inspect #user.skip_confirmation! user.invitation_token = invitation_token user.invitation_sent_at = Time.now.utc + user.inviters << inviter user.save(:validate => false) user end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index dfb0f685c..8da51bc4a 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -22,6 +22,20 @@ describe User do user.valid? user.username.should == "someuppercase" 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 describe '#diaspora_handle' do