diff --git a/.gitignore b/.gitignore index 8b309cc03..91e987e1c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ db/*.sqlite3 log/*.log tmp/**/* +Gemfile.lock gpg/diaspora-development/*.gpg gpg/diaspora-production/*.gpg diff --git a/Gemfile b/Gemfile index 4f2c736a1..7be06ae84 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ source 'http://rubygems.org' source 'http://gemcutter.org' -gem 'rails', '3.0.0.beta4' +gem 'rails', :git =>'http://github.com/rails/rails.git' gem 'bundler' gem 'mongo_mapper', :git => "http://github.com/BadMinus/mongomapper.git" gem 'devise', :git => "http://github.com/BadMinus/devise.git" diff --git a/app/controllers/dashboards_controller.rb b/app/controllers/dashboards_controller.rb index c5508d51c..11dbd939a 100644 --- a/app/controllers/dashboards_controller.rb +++ b/app/controllers/dashboards_controller.rb @@ -17,21 +17,21 @@ class DashboardsController < ApplicationController def warzombie render :nothing => true - if User.first.email == "tom@joindiaspora.com" && StatusMessage.where(:message => "There's a bomb in the lasagna!?").first == nil - StatusMessage.create(:message => "There's a bomb in the lasagna!?", :person => User.first) - Bookmark.create(:title => "xkcd", :link => "http://xkcd.com/743/", :person => User.first ) - StatusMessage.create(:message => "I switched to Motoroi today, a Motorola Android-based phone, in Korea. Now, I am using Android phones in both the U.S. and Korea", :person => User.first, :created_at => Time.now-930) - StatusMessage.create(:message => "I had 5 hours to study for it :-( GREs on Thursday. Wunderbar.", :person => User.first, :created_at => Time.now-43990) - StatusMessage.create(:message => "Spotted in toy story 3: google maps, OSX, and windows XP. Two out of three isn't bad.", :person => User.first, :created_at => Time.now-4390) - Bookmark.create( :title => "Reddit", :link => "http://reddit.com", :person => User.first, :created_at => Time.now-54390) - Blog.create(:title => "I Love Rock'N'Roll - Joan Jett & The Blackhearts", :body => "
The loudspeakers played this song as we walked into the city pool for the first time this summer. Those loudspeakers make every song sound fresh even if I have heard it a thousand times and their effect on this song was no different. Joan sounded young and strong and ready, and for a moment I forgot where or when I was.
also i can tell it won’t be long and also happy summer imaginary constructs -mumblelard
", :person => User.first, :created_at => Time.now-3090) - StatusMessage.create(:message => "Commercials for IE make me SO MAD and my friends just don't get why.", :person => User.first, :created_at => Time.now-30900) - Bookmark.create(:title => "Zombo.com", :link => "http://zombo.com", :person => User.first, :created_at => Time.now-9090) - StatusMessage.create(:message => "Why do I have \"No More Heroes\" by Westlife on repeat all day?", :person => User.first, :created_at => Time.now-590000) - StatusMessage.create(:message => "Mmm. Friday night. Acknowledged.", :person => User.first, :created_at => Time.now-503900) - StatusMessage.create(:message => "Getting a universal remote is the epitome of laziness, I do declare.", :person => User.first, :created_at => Time.now-4400) - StatusMessage.create(:message => "Does anyone know how to merge two Skype contact entries of the same person? (i.e. one Skype ID and one mobile number)", :person => User.first, :created_at => Time.now-400239) - StatusMessage.create(:message => "A cool, cool morning for once.", :person => User.first, :created_at => Time.now-150000) + if User.owner.email == "tom@joindiaspora.com" && StatusMessage.where(:message => "There's a bomb in the lasagna!?").first == nil + StatusMessage.create(:message => "There's a bomb in the lasagna!?", :person => User.owner) + Bookmark.create(:title => "xkcd", :link => "http://xkcd.com/743/", :person => User.owner ) + StatusMessage.create(:message => "I switched to Motoroi today, a Motorola Android-based phone, in Korea. Now, I am using Android phones in both the U.S. and Korea", :person => User.owner, :created_at => Time.now-930) + StatusMessage.create(:message => "I had 5 hours to study for it :-( GREs on Thursday. Wunderbar.", :person => User.owner, :created_at => Time.now-43990) + StatusMessage.create(:message => "Spotted in toy story 3: google maps, OSX, and windows XP. Two out of three isn't bad.", :person => User.owner, :created_at => Time.now-4390) + Bookmark.create( :title => "Reddit", :link => "http://reddit.com", :person => User.owner, :created_at => Time.now-54390) + Blog.create(:title => "I Love Rock'N'Roll - Joan Jett & The Blackhearts", :body => "The loudspeakers played this song as we walked into the city pool for the first time this summer. Those loudspeakers make every song sound fresh even if I have heard it a thousand times and their effect on this song was no different. Joan sounded young and strong and ready, and for a moment I forgot where or when I was.
also i can tell it won’t be long and also happy summer imaginary constructs -mumblelard
", :person => User.owner, :created_at => Time.now-3090) + StatusMessage.create(:message => "Commercials for IE make me SO MAD and my friends just don't get why.", :person => User.owner, :created_at => Time.now-30900) + Bookmark.create(:title => "Zombo.com", :link => "http://zombo.com", :person => User.owner, :created_at => Time.now-9090) + StatusMessage.create(:message => "Why do I have \"No More Heroes\" by Westlife on repeat all day?", :person => User.owner, :created_at => Time.now-590000) + StatusMessage.create(:message => "Mmm. Friday night. Acknowledged.", :person => User.owner, :created_at => Time.now-503900) + StatusMessage.create(:message => "Getting a universal remote is the epitome of laziness, I do declare.", :person => User.owner, :created_at => Time.now-4400) + StatusMessage.create(:message => "Does anyone know how to merge two Skype contact entries of the same person? (i.e. one Skype ID and one mobile number)", :person => User.owner, :created_at => Time.now-400239) + StatusMessage.create(:message => "A cool, cool morning for once.", :person => User.owner, :created_at => Time.now-150000) end end end diff --git a/app/controllers/people_controller.rb b/app/controllers/people_controller.rb index d8769d448..44bdaf63f 100644 --- a/app/controllers/people_controller.rb +++ b/app/controllers/people_controller.rb @@ -12,9 +12,8 @@ class PeopleController < ApplicationController end def destroy - @person = Person.where(:id => params[:id]).first - @person.destroy - flash[:notice] = "Successfully destroyed person." + current_user.unfriend(params[:id]) + flash[:notice] = "unfriended person." redirect_to people_url end diff --git a/app/controllers/requests_controller.rb b/app/controllers/requests_controller.rb index 4bafd6d54..c37a86ca7 100644 --- a/app/controllers/requests_controller.rb +++ b/app/controllers/requests_controller.rb @@ -8,13 +8,15 @@ class RequestsController < ApplicationController def destroy if params[:accept] - current_user.accept_friend_request params[:id] - flash[:notice] = "you are now friends with #{@request.person.real_name}" + @friend = current_user.accept_friend_request params[:id] + + flash[:notice] = "you are now friends" + redirect_to root_url else current_user.ignore_friend_request params[:id] flash[:notice] = "ignored friend request" + redirect_to requests_url end - redirect_to requests_url end @@ -24,11 +26,13 @@ class RequestsController < ApplicationController def create @request = current_user.send_friend_request_to(params[:request][:destination_url]) - if @request flash[:notice] = "a friend request was sent to #{@request.destination_url}" redirect_to requests_url else + + flash[:error] = "you have already friended this person" + @request = Request.new render :action => 'new' end end diff --git a/app/controllers/sockets_controller.rb b/app/controllers/sockets_controller.rb index daea6466a..67ffc7dc8 100644 --- a/app/controllers/sockets_controller.rb +++ b/app/controllers/sockets_controller.rb @@ -3,12 +3,6 @@ class SocketsController < ApplicationController include SocketsHelper include Rails.application.routes.url_helpers before_filter :authenticate_user! - - - - # def default_url_options() - # {:host=> 'example.com'} - # end def incoming(msg) puts "#{msg} connected!" @@ -20,12 +14,11 @@ class SocketsController < ApplicationController def outgoing(object) @_request = ActionDispatch::Request.new({}) + puts action_hash(object) WebSocket.push_to_clients(action_hash(object)) end def delete_subscriber(sid) WebSocket.unsubscribe(sid) end - - end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c476210ab..897c4826a 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -10,7 +10,7 @@ module ApplicationHelper end def mine?(post) - post.person == User.first + post.person == User.owner end def type_partial(post) @@ -39,9 +39,9 @@ module ApplicationHelper def owner_picture default = "/images/user/default.jpg" - image = "/images/user/#{User.first.profile.last_name.gsub(/ /,'').downcase}.jpg" + image = "/images/user/#{User.owner.profile.last_name.gsub(/ /,'').downcase}.jpg" - if File.exist?("public/images/user/#{User.first.profile.last_name.gsub(/ /,'').downcase}.jpg") + if File.exist?("public/images/user/#{User.owner.profile.last_name.gsub(/ /,'').downcase}.jpg") image_tag image, :id => "user_picture" else image_tag default, :id => "user_picture" diff --git a/app/models/comment.rb b/app/models/comment.rb index b8a682a94..b1cdc493b 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -29,7 +29,7 @@ class Comment protected def send_people_comments_on_my_posts - if User.first.mine?(self.post) && !(self.person.is_a? User) + if User.owner.mine?(self.post) && !(self.person.is_a? User) self.push_to(self.post.people_with_permissions) end end diff --git a/app/models/person.rb b/app/models/person.rb index 7ace2308d..d299b35fc 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -30,6 +30,7 @@ class Person scope :friends, where(:_type => "Person", :active => true) + def real_name "#{profile.first_name.to_s} #{profile.last_name.to_s}" diff --git a/app/models/post.rb b/app/models/post.rb index ae6d11af3..c29c9510b 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -36,7 +36,7 @@ class Post end def self.my_newest - self.newest(User.first) + self.newest(User.owner) end def self.newest_by_email(email) self.newest(Person.first(:email => email)) diff --git a/app/models/retraction.rb b/app/models/retraction.rb index a4d10bb59..c799df5fd 100644 --- a/app/models/retraction.rb +++ b/app/models/retraction.rb @@ -2,21 +2,44 @@ class Retraction include ROXML include Diaspora::Webhooks - def self.for(post) - result = self.new - result.post_id = post.id - result.person_id = post.person.id - result + def self.for(object) + retraction = self.new + retraction.post_id= object.id + retraction.person_id = person_id_from(object) + retraction.type = self.type_name(object) + retraction end xml_accessor :post_id xml_accessor :person_id + xml_accessor :type attr_accessor :post_id attr_accessor :person_id - + attr_accessor :type + def perform - Post.delete(self.post_id) + puts('GO GO GO') + self.type.constantize.destroy(self.post_id) + end + + def self.person_id_from(object) + if object.is_a? Person + object.id + else + object.person.id + end + end + + + def self.type_name(object) + if object.is_a? Post + object.class + elsif object.is_a? User + 'Person' + else + 'Clowntown' + end end end diff --git a/app/models/user.rb b/app/models/user.rb index 9c7393ecd..1e7aa4bd7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -8,7 +8,9 @@ class User < Person validates_presence_of :profile before_validation :do_bad_things - + + + ######## Commenting ######## def comment(text, options = {}) @@ -29,10 +31,11 @@ class User < Person def send_friend_request_to(friend_url) unless Person.where(:url => friend_url).first p = Request.instantiate(:to => friend_url, :from => self) + puts p.inspect if p.save p.push_to_url friend_url - p end + p end end @@ -46,7 +49,7 @@ class User < Person end def ignore_friend_request(friend_request_id) - request = Request.where(:id => friend_request_id).first + request = Request.first(:id => friend_request_id) person = request.person person.destroy unless person.active request.destroy @@ -62,6 +65,14 @@ class User < Person end end + def unfriend(friend_id) + bad_friend = Person.first(:id => friend_id, :active => true) + if bad_friend + Retraction.for(self).push_to_url(bad_friend.url) + bad_friend.destroy + end + end + ###Helpers############ def mine?(post) @@ -72,6 +83,9 @@ class User < Person self.password_confirmation = self.password end + def self.owner + User.first + end protected diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index 79a391314..96b9ca9c4 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -6,7 +6,7 @@ /= f.check_box :remember_me /= f.label :remember_me - = hidden_field_tag "user_email", "#{User.first.email}", :name => "user[email]" + = hidden_field_tag "user_email", "#{User.owner.email}", :name => "user[email]" = f.submit "Sign in" /= render :partial => "devise/shared/links" diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 09c7dff3b..79abadcdf 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -2,7 +2,7 @@ %html %head %title - = User.first.real_name if User.first + = current_user.real_name if current_user = " | diaspora" %meta{"http-equiv"=>"Content-Type", :content=>"text/html; charset=utf-8"}/ @@ -30,7 +30,7 @@ #session_action - if user_signed_in? - =User.first.real_name + = current_user.real_name | = link_to "requests (#{@request_count})", requests_path | @@ -50,9 +50,9 @@ .span-20 - if user_signed_in? %h1#user_name - = link_to User.first.real_name, root_url + = link_to current_user.real_name, root_url %span.description = my_latest_message = yield - .span-20 + .span-12 = render "posts/debug" diff --git a/app/views/layouts/session_wall.html.haml b/app/views/layouts/session_wall.html.haml index f4b13e524..19e9d2043 100644 --- a/app/views/layouts/session_wall.html.haml +++ b/app/views/layouts/session_wall.html.haml @@ -39,11 +39,11 @@ - flash.each do |name, msg| = content_tag :div, msg, :id => "flash_#{name}" - - if User.first + - if User.owner %div#huge_text welcome back, %span - = User.first.real_name.downcase + = User.owner.real_name.downcase = yield -else %div#huge_text diff --git a/app/views/people/show.html.haml b/app/views/people/show.html.haml index ccdabacd3..50050d2eb 100644 --- a/app/views/people/show.html.haml +++ b/app/views/people/show.html.haml @@ -1,5 +1,6 @@ .span-20.last %h1= "#{@person.real_name}" + = link_to 'remove friend', @person, :confirm => 'Are you sure?', :method => :delete - if @person_profile %p %b First Name diff --git a/app/views/requests/_request.html.haml b/app/views/requests/_request.html.haml index 84284151a..39a4114b3 100644 --- a/app/views/requests/_request.html.haml +++ b/app/views/requests/_request.html.haml @@ -4,6 +4,6 @@ = "#{request.destination_url}" .destroy_link - = link_to 'Accept', request_path(request, :accept => true), :confirm => 'Are you sure?', :method => :delete + = link_to 'Accept', request_path(request, :accept => true), :method => :delete | = link_to 'Ignore', request_path(request), :confirm => 'Are you sure?', :method => :delete diff --git a/config/environments/development.rb b/config/environments/development.rb index d03bf7d3a..12446d661 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -16,6 +16,6 @@ Diaspora::Application.configure do # Don't care if the mailer can't send config.action_mailer.raise_delivery_errors = false - + config.active_support.deprecation = :log #config.threadsafe! end diff --git a/lib/common.rb b/lib/common.rb index c0fd6947f..fcd9cd82b 100644 --- a/lib/common.rb +++ b/lib/common.rb @@ -33,7 +33,7 @@ module Diaspora if p.is_a? Retraction p.perform elsif p.is_a? Request - User.first.receive_friend_request(p) + User.owner.receive_friend_request(p) #This line checks if the sender was in the database, among other things? elsif p.respond_to?(:person) && !(p.person.nil?) && !(p.person.is_a? User) #WTF p.save @@ -47,10 +47,11 @@ module Diaspora def self.included(klass) klass.class_eval do include ROXML + require 'message_handler' @@queue = MessageHandler.new def notify_people - if self.person_id == User.first.id + if self.person_id == User.owner.id push_to(people_with_permissions) end end @@ -76,7 +77,7 @@ module Diaspora end def people_with_permissions - Person.where( :_type => "Person" ).all + Person.friends.all end def self.build_xml_for(posts) diff --git a/public/javascripts/jquery_form.js b/public/javascripts/jquery_form.js deleted file mode 100644 index be8c0b6bf..000000000 --- a/public/javascripts/jquery_form.js +++ /dev/null @@ -1,675 +0,0 @@ -/*! - * jQuery Form Plugin - * version: 2.43 (12-MAR-2010) - * @requires jQuery v1.3.2 or later - * - * Examples and documentation at: http://malsup.com/jquery/form/ - * Dual licensed under the MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - */ -;(function($) { - -/* - Usage Note: - ----------- - Do not use both ajaxSubmit and ajaxForm on the same form. These - functions are intended to be exclusive. Use ajaxSubmit if you want - to bind your own submit handler to the form. For example, - - $(document).ready(function() { - $('#myForm').bind('submit', function() { - $(this).ajaxSubmit({ - target: '#output' - }); - return false; // <-- important! - }); - }); - - Use ajaxForm when you want the plugin to manage all the event binding - for you. For example, - - $(document).ready(function() { - $('#myForm').ajaxForm({ - target: '#output' - }); - }); - - When using ajaxForm, the ajaxSubmit function will be invoked for you - at the appropriate time. -*/ - -/** - * ajaxSubmit() provides a mechanism for immediately submitting - * an HTML form using AJAX. - */ -$.fn.ajaxSubmit = function(options) { - // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) - if (!this.length) { - log('ajaxSubmit: skipping submit process - no element selected'); - return this; - } - - if (typeof options == 'function') - options = { success: options }; - - var url = $.trim(this.attr('action')); - if (url) { - // clean url (don't include hash vaue) - url = (url.match(/^([^#]+)/)||[])[1]; - } - url = url || window.location.href || ''; - - options = $.extend({ - url: url, - type: this.attr('method') || 'GET', - iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' - }, options || {}); - - // hook for manipulating the form data before it is extracted; - // convenient for use with rich editors like tinyMCE or FCKEditor - var veto = {}; - this.trigger('form-pre-serialize', [this, options, veto]); - if (veto.veto) { - log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); - return this; - } - - // provide opportunity to alter form data before it is serialized - if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { - log('ajaxSubmit: submit aborted via beforeSerialize callback'); - return this; - } - - var a = this.formToArray(options.semantic); - if (options.data) { - options.extraData = options.data; - for (var n in options.data) { - if(options.data[n] instanceof Array) { - for (var k in options.data[n]) - a.push( { name: n, value: options.data[n][k] } ); - } - else - a.push( { name: n, value: options.data[n] } ); - } - } - - // give pre-submit callback an opportunity to abort the submit - if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { - log('ajaxSubmit: submit aborted via beforeSubmit callback'); - return this; - } - - // fire vetoable 'validate' event - this.trigger('form-submit-validate', [a, this, options, veto]); - if (veto.veto) { - log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); - return this; - } - - var q = $.param(a); - - if (options.type.toUpperCase() == 'GET') { - options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; - options.data = null; // data is null for 'get' - } - else - options.data = q; // data is the query string for 'post' - - var $form = this, callbacks = []; - if (options.resetForm) callbacks.push(function() { $form.resetForm(); }); - if (options.clearForm) callbacks.push(function() { $form.clearForm(); }); - - // perform a load on the target only if dataType is not provided - if (!options.dataType && options.target) { - var oldSuccess = options.success || function(){}; - callbacks.push(function(data) { - var fn = options.replaceTarget ? 'replaceWith' : 'html'; - $(options.target)[fn](data).each(oldSuccess, arguments); - }); - } - else if (options.success) - callbacks.push(options.success); - - options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg - for (var i=0, max=callbacks.length; i < max; i++) - callbacks[i].apply(options, [data, status, xhr || $form, $form]); - }; - - // are there files to upload? - var files = $('input:file', this).fieldValue(); - var found = false; - for (var j=0; j < files.length; j++) - if (files[j]) - found = true; - - var multipart = false; -// var mp = 'multipart/form-data'; -// multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); - - // options.iframe allows user to force iframe mode - // 06-NOV-09: now defaulting to iframe mode if file input is detected - if ((files.length && options.iframe !== false) || options.iframe || found || multipart) { - // hack to fix Safari hang (thanks to Tim Molendijk for this) - // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d - if (options.closeKeepAlive) - $.get(options.closeKeepAlive, fileUpload); - else - fileUpload(); - } - else - $.ajax(options); - - // fire 'notify' event - this.trigger('form-submit-notify', [this, options]); - return this; - - - // private function for handling file uploads (hat tip to YAHOO!) - function fileUpload() { - var form = $form[0]; - - if ($(':input[name=submit]', form).length) { - alert('Error: Form elements must not be named "submit".'); - return; - } - - var opts = $.extend({}, $.ajaxSettings, options); - var s = $.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts); - - var id = 'jqFormIO' + (new Date().getTime()); - var $io = $(''); - var io = $io[0]; - - $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' }); - - var xhr = { // mock object - aborted: 0, - responseText: null, - responseXML: null, - status: 0, - statusText: 'n/a', - getAllResponseHeaders: function() {}, - getResponseHeader: function() {}, - setRequestHeader: function() {}, - abort: function() { - this.aborted = 1; - $io.attr('src', opts.iframeSrc); // abort op in progress - } - }; - - var g = opts.global; - // trigger ajax global events so that activity/block indicators work like normal - if (g && ! $.active++) $.event.trigger("ajaxStart"); - if (g) $.event.trigger("ajaxSend", [xhr, opts]); - - if (s.beforeSend && s.beforeSend(xhr, s) === false) { - s.global && $.active--; - return; - } - if (xhr.aborted) - return; - - var cbInvoked = false; - var timedOut = 0; - - // add submitting element to data if we know it - var sub = form.clk; - if (sub) { - var n = sub.name; - if (n && !sub.disabled) { - opts.extraData = opts.extraData || {}; - opts.extraData[n] = sub.value; - if (sub.type == "image") { - opts.extraData[n+'.x'] = form.clk_x; - opts.extraData[n+'.y'] = form.clk_y; - } - } - } - - // take a breath so that pending repaints get some cpu time before the upload starts - function doSubmit() { - // make sure form attrs are set - var t = $form.attr('target'), a = $form.attr('action'); - - // update form attrs in IE friendly way - form.setAttribute('target',id); - if (form.getAttribute('method') != 'POST') - form.setAttribute('method', 'POST'); - if (form.getAttribute('action') != opts.url) - form.setAttribute('action', opts.url); - - // ie borks in some cases when setting encoding - if (! opts.skipEncodingOverride) { - $form.attr({ - encoding: 'multipart/form-data', - enctype: 'multipart/form-data' - }); - } - - // support timout - if (opts.timeout) - setTimeout(function() { timedOut = true; cb(); }, opts.timeout); - - // add "extra" data to form if provided in options - var extraInputs = []; - try { - if (opts.extraData) - for (var n in opts.extraData) - extraInputs.push( - $('') - .appendTo(form)[0]); - - // add iframe to doc and submit the form - $io.appendTo('body'); - $io.data('form-plugin-onload', cb); - form.submit(); - } - finally { - // reset attrs and remove "extra" input elements - form.setAttribute('action',a); - t ? form.setAttribute('target', t) : $form.removeAttr('target'); - $(extraInputs).remove(); - } - }; - - if (opts.forceSync) - doSubmit(); - else - setTimeout(doSubmit, 10); // this lets dom updates render - - var domCheckCount = 100; - - function cb() { - if (cbInvoked) - return; - - var ok = true; - try { - if (timedOut) throw 'timeout'; - // extract the server response from the iframe - var data, doc; - - doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document; - - var isXml = opts.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc); - log('isXml='+isXml); - if (!isXml && (doc.body == null || doc.body.innerHTML == '')) { - if (--domCheckCount) { - // in some browsers (Opera) the iframe DOM is not always traversable when - // the onload callback fires, so we loop a bit to accommodate - log('requeing onLoad callback, DOM not available'); - setTimeout(cb, 250); - return; - } - log('Could not access iframe DOM after 100 tries.'); - return; - } - - log('response detected'); - cbInvoked = true; - xhr.responseText = doc.body ? doc.body.innerHTML : null; - xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc; - xhr.getResponseHeader = function(header){ - var headers = {'content-type': opts.dataType}; - return headers[header]; - }; - - if (opts.dataType == 'json' || opts.dataType == 'script') { - // see if user embedded response in textarea - var ta = doc.getElementsByTagName('textarea')[0]; - if (ta) - xhr.responseText = ta.value; - else { - // account for browsers injecting pre around json response - var pre = doc.getElementsByTagName('pre')[0]; - if (pre) - xhr.responseText = pre.innerHTML; - } - } - else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) { - xhr.responseXML = toXml(xhr.responseText); - } - data = $.httpData(xhr, opts.dataType); - } - catch(e){ - log('error caught:',e); - ok = false; - xhr.error = e; - $.handleError(opts, xhr, 'error', e); - } - - // ordering of these callbacks/triggers is odd, but that's how $.ajax does it - if (ok) { - opts.success(data, 'success'); - if (g) $.event.trigger("ajaxSuccess", [xhr, opts]); - } - if (g) $.event.trigger("ajaxComplete", [xhr, opts]); - if (g && ! --$.active) $.event.trigger("ajaxStop"); - if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error'); - - // clean up - setTimeout(function() { - $io.removeData('form-plugin-onload'); - $io.remove(); - xhr.responseXML = null; - }, 100); - }; - - function toXml(s, doc) { - if (window.ActiveXObject) { - doc = new ActiveXObject('Microsoft.XMLDOM'); - doc.async = 'false'; - doc.loadXML(s); - } - else - doc = (new DOMParser()).parseFromString(s, 'text/xml'); - return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null; - }; - }; -}; - -/** - * ajaxForm() provides a mechanism for fully automating form submission. - * - * The advantages of using this method instead of ajaxSubmit() are: - * - * 1: This method will include coordinates for elements (if the element - * is used to submit the form). - * 2. This method will include the submit element's name/value data (for the element that was - * used to submit the form). - * 3. This method binds the submit() method to the form for you. - * - * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely - * passes the options argument along after properly binding events for submit elements and - * the form itself. - */ -$.fn.ajaxForm = function(options) { - return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) { - e.preventDefault(); - $(this).ajaxSubmit(options); - }).bind('click.form-plugin', function(e) { - var target = e.target; - var $el = $(target); - if (!($el.is(":submit,input:image"))) { - // is this a child element of the submit el? (ex: a span within a button) - var t = $el.closest(':submit'); - if (t.length == 0) - return; - target = t[0]; - } - var form = this; - form.clk = target; - if (target.type == 'image') { - if (e.offsetX != undefined) { - form.clk_x = e.offsetX; - form.clk_y = e.offsetY; - } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin - var offset = $el.offset(); - form.clk_x = e.pageX - offset.left; - form.clk_y = e.pageY - offset.top; - } else { - form.clk_x = e.pageX - target.offsetLeft; - form.clk_y = e.pageY - target.offsetTop; - } - } - // clear form vars - setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100); - }); -}; - -// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm -$.fn.ajaxFormUnbind = function() { - return this.unbind('submit.form-plugin click.form-plugin'); -}; - -/** - * formToArray() gathers form element data into an array of objects that can - * be passed to any of the following ajax functions: $.get, $.post, or load. - * Each object in the array has both a 'name' and 'value' property. An example of - * an array for a simple login form might be: - * - * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ] - * - * It is this array that is passed to pre-submit callback functions provided to the - * ajaxSubmit() and ajaxForm() methods. - */ -$.fn.formToArray = function(semantic) { - var a = []; - if (this.length == 0) return a; - - var form = this[0]; - var els = semantic ? form.getElementsByTagName('*') : form.elements; - if (!els) return a; - for(var i=0, max=els.length; i < max; i++) { - var el = els[i]; - var n = el.name; - if (!n) continue; - - if (semantic && form.clk && el.type == "image") { - // handle image inputs on the fly when semantic == true - if(!el.disabled && form.clk == el) { - a.push({name: n, value: $(el).val()}); - a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); - } - continue; - } - - var v = $.fieldValue(el, true); - if (v && v.constructor == Array) { - for(var j=0, jmax=v.length; j < jmax; j++) - a.push({name: n, value: v[j]}); - } - else if (v !== null && typeof v != 'undefined') - a.push({name: n, value: v}); - } - - if (!semantic && form.clk) { - // input type=='image' are not found in elements array! handle it here - var $input = $(form.clk), input = $input[0], n = input.name; - if (n && !input.disabled && input.type == 'image') { - a.push({name: n, value: $input.val()}); - a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); - } - } - return a; -}; - -/** - * Serializes form data into a 'submittable' string. This method will return a string - * in the format: name1=value1&name2=value2 - */ -$.fn.formSerialize = function(semantic) { - //hand off to jQuery.param for proper encoding - return $.param(this.formToArray(semantic)); -}; - -/** - * Serializes all field elements in the jQuery object into a query string. - * This method will return a string in the format: name1=value1&name2=value2 - */ -$.fn.fieldSerialize = function(successful) { - var a = []; - this.each(function() { - var n = this.name; - if (!n) return; - var v = $.fieldValue(this, successful); - if (v && v.constructor == Array) { - for (var i=0,max=v.length; i < max; i++) - a.push({name: n, value: v[i]}); - } - else if (v !== null && typeof v != 'undefined') - a.push({name: this.name, value: v}); - }); - //hand off to jQuery.param for proper encoding - return $.param(a); -}; - -/** - * Returns the value(s) of the element in the matched set. For example, consider the following form: - * - * - * - * var v = $(':text').fieldValue(); - * // if no values are entered into the text inputs - * v == ['',''] - * // if values entered into the text inputs are 'foo' and 'bar' - * v == ['foo','bar'] - * - * var v = $(':checkbox').fieldValue(); - * // if neither checkbox is checked - * v === undefined - * // if both checkboxes are checked - * v == ['B1', 'B2'] - * - * var v = $(':radio').fieldValue(); - * // if neither radio is checked - * v === undefined - * // if first radio is checked - * v == ['C1'] - * - * The successful argument controls whether or not the field element must be 'successful' - * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls). - * The default value of the successful argument is true. If this value is false the value(s) - * for each element is returned. - * - * Note: This method *always* returns an array. If no valid value can be determined the - * array will be empty, otherwise it will contain one or more values. - */ -$.fn.fieldValue = function(successful) { - for (var val=[], i=0, max=this.length; i < max; i++) { - var el = this[i]; - var v = $.fieldValue(el, successful); - if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) - continue; - v.constructor == Array ? $.merge(val, v) : val.push(v); - } - return val; -}; - -/** - * Returns the value of the field element. - */ -$.fieldValue = function(el, successful) { - var n = el.name, t = el.type, tag = el.tagName.toLowerCase(); - if (typeof successful == 'undefined') successful = true; - - if (successful && (!n || el.disabled || t == 'reset' || t == 'button' || - (t == 'checkbox' || t == 'radio') && !el.checked || - (t == 'submit' || t == 'image') && el.form && el.form.clk != el || - tag == 'select' && el.selectedIndex == -1)) - return null; - - if (tag == 'select') { - var index = el.selectedIndex; - if (index < 0) return null; - var a = [], ops = el.options; - var one = (t == 'select-one'); - var max = (one ? index+1 : ops.length); - for(var i=(one ? index : 0); i < max; i++) { - var op = ops[i]; - if (op.selected) { - var v = op.value; - if (!v) // extra pain for IE... - v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value; - if (one) return v; - a.push(v); - } - } - return a; - } - return el.value; -}; - -/** - * Clears the form data. Takes the following actions on the form's input fields: - * - input text fields will have their 'value' property set to the empty string - * - select elements will have their 'selectedIndex' property set to -1 - * - checkbox and radio inputs will have their 'checked' property set to false - * - inputs of type submit, button, reset, and hidden will *not* be effected - * - button elements will *not* be effected - */ -$.fn.clearForm = function() { - return this.each(function() { - $('input,select,textarea', this).clearFields(); - }); -}; - -/** - * Clears the selected form elements. - */ -$.fn.clearFields = $.fn.clearInputs = function() { - return this.each(function() { - var t = this.type, tag = this.tagName.toLowerCase(); - if (t == 'text' || t == 'password' || tag == 'textarea') - this.value = ''; - else if (t == 'checkbox' || t == 'radio') - this.checked = false; - else if (tag == 'select') - this.selectedIndex = -1; - }); -}; - -/** - * Resets the form data. Causes all form elements to be reset to their original value. - */ -$.fn.resetForm = function() { - return this.each(function() { - // guard against an input with the name of 'reset' - // note that IE reports the reset function as an 'object' - if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) - this.reset(); - }); -}; - -/** - * Enables or disables any matching elements. - */ -$.fn.enable = function(b) { - if (b == undefined) b = true; - return this.each(function() { - this.disabled = !b; - }); -}; - -/** - * Checks/unchecks any matching checkboxes or radio buttons and - * selects/deselects and matching option elements. - */ -$.fn.selected = function(select) { - if (select == undefined) select = true; - return this.each(function() { - var t = this.type; - if (t == 'checkbox' || t == 'radio') - this.checked = select; - else if (this.tagName.toLowerCase() == 'option') { - var $sel = $(this).parent('select'); - if (select && $sel[0] && $sel[0].type == 'select-one') { - // deselect all other options - $sel.find('option').selected(false); - } - this.selected = select; - } - }); -}; - -// helper fn for console logging -// set $.fn.ajaxSubmit.debug to true to enable debug logging -function log() { - if ($.fn.ajaxSubmit.debug) { - var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); - if (window.console && window.console.log) - window.console.log(msg); - else if (window.opera && window.opera.postError) - window.opera.postError(msg); - } -}; - -})(jQuery); diff --git a/spec/factories.rb b/spec/factories.rb index 912cb7d90..240dfb017 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -13,6 +13,7 @@ end Factory.define :person do |p| p.email "bob-person@aol.com" + p.active true p.sequence(:url) {|n|"http://google-#{n}.com/"} p.key_fingerprint GPGME::list_keys("Aditi").first.subkeys.first.fingerprint p.profile Profile.new( :first_name => "Robert", :last_name => "Grimm" ) diff --git a/spec/models/person_spec.rb b/spec/models/person_spec.rb index 69b5ff29a..8c6dd30bf 100644 --- a/spec/models/person_spec.rb +++ b/spec/models/person_spec.rb @@ -26,9 +26,9 @@ describe Person do end it 'should only return active friends' do - Factory.create(:person, :active => true) - Factory.create(:person) Factory.create(:person) + Factory.create(:person, :active => false) + Factory.create(:person, :active => false) Person.friends.all.count.should == 1 end @@ -57,5 +57,16 @@ describe Person do s.comments.count.should == 1 end + it 'should let a user unfriend another user' do + u = Factory.create(:user) + + f = Factory.create(:person, :active => true) + + + Person.friends.all.count.should == 1 + u.unfriend(f.id) + Person.friends.all.count.should == 0 + + end end diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb index e2e068b6d..96b271861 100644 --- a/spec/models/post_spec.rb +++ b/spec/models/post_spec.rb @@ -12,7 +12,7 @@ describe Post do end it "should associate the owner if none is present" do - @post.person.should == User.first + @post.person.should == User.owner end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 201ec6318..8c0f1cf7b 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -9,7 +9,7 @@ describe User do it "should be able to accept a pending friend request" do @user = Factory.create(:user) - @friend = Factory.create(:person) + @friend = Factory.create(:person, :active => false) r = Request.instantiate(:to => @user.url, :from => @friend) r.save Person.all.count.should == 2 @@ -21,7 +21,7 @@ describe User do it 'should be able to ignore a pending friend request' do @user = Factory.create(:user) - @friend = Factory.create(:person) + @friend = Factory.create(:person, :active => false) r = Request.instantiate(:to => @user.url, :from => @friend) r.save @@ -36,7 +36,7 @@ describe User do it 'should not be able to friend request an existing friend' do @user = Factory.create(:user) - @friend = Factory.create(:person, :active => true) + @friend = Factory.create(:person) @user.send_friend_request_to( @friend.url ).should be nil end