diff --git a/app/controllers/conversation_visibilities_controller.rb b/app/controllers/conversation_visibilities_controller.rb new file mode 100644 index 000000000..b136e38be --- /dev/null +++ b/app/controllers/conversation_visibilities_controller.rb @@ -0,0 +1,19 @@ +# Copyright (c) 2010, Diaspora Inc. This file is +# licensed under the Affero General Public License version 3 or later. See +# the COPYRIGHT file. +# + +class ConversationVisibilitiesController < ApplicationController + before_filter :authenticate_user! + + def destroy + @vis = ConversationVisibility.where(:person_id => current_user.person.id, + :conversation_id => params[:conversation_id]).first + if @vis + if @vis.destroy + flash[:notice] = "Conversation successfully removed" + end + end + redirect_to conversations_path + end +end diff --git a/app/controllers/conversations_controller.rb b/app/controllers/conversations_controller.rb new file mode 100644 index 000000000..72825017a --- /dev/null +++ b/app/controllers/conversations_controller.rb @@ -0,0 +1,41 @@ +class ConversationsController < ApplicationController + before_filter :authenticate_user! + + respond_to :html + + def index + @conversations = Conversation.joins(:conversation_visibilities).where( + :conversation_visibilities => {:person_id => current_user.person.id}).all + end + + def create + person_ids = Contact.where(:id => params[:conversation][:contact_ids]).map! do |contact| + contact.person_id + end + + person_ids = person_ids | [current_user.person.id] + + @conversation = Conversation.new(:subject => params[:conversation][:subject], :participant_ids => person_ids) + + if @conversation.save + @message = Message.new(:text => params[:message][:text], :author => current_user.person, :conversation_id => @conversation.id ) + unless @message.save + @conversation.destroy + end + end + + respond_with @conversation + end + + def show + @conversation = Conversation.joins(:conversation_visibilities).where(:id => params[:id], + :conversation_visibilities => {:person_id => current_user.person.id}).first + + if @conversation + respond_with @conversation + else + redirect_to conversations_path + end + end + +end diff --git a/app/controllers/private_message_visibilities_controller.rb b/app/controllers/private_message_visibilities_controller.rb deleted file mode 100644 index 706f7a866..000000000 --- a/app/controllers/private_message_visibilities_controller.rb +++ /dev/null @@ -1,19 +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. -# - -class PrivateMessageVisibilitiesController < ApplicationController - before_filter :authenticate_user! - - def destroy - @vis = PrivateMessageVisibility.where(:person_id => current_user.person.id, - :private_message_id => params[:private_message_id]).first - if @vis - if @vis.destroy - flash[:notice] = "Message successfully removed" - end - end - redirect_to private_messages_path - end -end diff --git a/app/controllers/private_messages_controller.rb b/app/controllers/private_messages_controller.rb deleted file mode 100644 index 4128faa14..000000000 --- a/app/controllers/private_messages_controller.rb +++ /dev/null @@ -1,38 +0,0 @@ -class PrivateMessagesController < ApplicationController - before_filter :authenticate_user! - - respond_to :html - - def index - @messages = PrivateMessage.joins(:private_message_visibilities).where( - :private_message_visibilities => {:person_id => current_user.person.id}).all - end - - def create - person_ids = Contact.where(:id => params[:private_message][:contact_ids]).map! do |contact| - contact.person_id - end - - person_ids = person_ids | [current_user.person.id] - - @message = PrivateMessage.new( :author => current_user.person, :participant_ids => person_ids, :message => params[:private_message][:message] ) - - if @message.save - Rails.logger.info("event=create type=private_message chars=#{params[:private_message][:message].length}") - end - - respond_with @message - end - - def show - @message = PrivateMessage.joins(:private_message_visibilities).where(:id => params[:id], - :private_message_visibilities => {:person_id => current_user.person.id}).first - - if @message - respond_with @message - else - redirect_to private_messages_path - end - end - -end diff --git a/app/models/conversation.rb b/app/models/conversation.rb new file mode 100644 index 000000000..58ab2ab2f --- /dev/null +++ b/app/models/conversation.rb @@ -0,0 +1,22 @@ +class Conversation < ActiveRecord::Base + include ROXML + include Diaspora::Guid + include Diaspora::Webhooks + + xml_attr :subject + xml_attr :messages, :as => [Message] + xml_attr :created_at + xml_reader :participant_handles + + has_many :conversation_visibilities + has_many :participants, :class_name => 'Person', :through => :conversation_visibilities, :source => :person + has_many :messages, :order => 'created_at ASC' + + def recipients + self.participants - [self.author] + end + + def participant_handles + self.participants.map{|p| p.diaspora_handle}.join(";") + end +end diff --git a/app/models/conversation_visibility.rb b/app/models/conversation_visibility.rb new file mode 100644 index 000000000..da398c724 --- /dev/null +++ b/app/models/conversation_visibility.rb @@ -0,0 +1,6 @@ +class ConversationVisibility < ActiveRecord::Base + + belongs_to :conversation + belongs_to :person + +end diff --git a/app/models/message.rb b/app/models/message.rb new file mode 100644 index 000000000..53dff9305 --- /dev/null +++ b/app/models/message.rb @@ -0,0 +1,12 @@ +class Message < ActiveRecord::Base + include ROXML + include Diaspora::Guid + include Diaspora::Webhooks + + xml_attr :text + xml_attr :created_at + + belongs_to :author, :class_name => 'Person' + belongs_to :conversation + +end diff --git a/app/models/private_message.rb b/app/models/private_message.rb deleted file mode 100644 index 899e55784..000000000 --- a/app/models/private_message.rb +++ /dev/null @@ -1,12 +0,0 @@ -class PrivateMessage < ActiveRecord::Base - include ROXML - include Diaspora::Guid - - belongs_to :author, :class_name => 'Person' - has_many :private_message_visibilities - has_many :participants, :class_name => 'Person', :through => :private_message_visibilities, :source => :person - - def recipients - self.participants - [self.author] - end -end diff --git a/app/models/private_message_visibility.rb b/app/models/private_message_visibility.rb deleted file mode 100644 index e4ba8f53b..000000000 --- a/app/models/private_message_visibility.rb +++ /dev/null @@ -1,6 +0,0 @@ -class PrivateMessageVisibility < ActiveRecord::Base - - belongs_to :private_message - belongs_to :person - -end diff --git a/app/views/conversations/index.haml b/app/views/conversations/index.haml new file mode 100644 index 000000000..71a8167be --- /dev/null +++ b/app/views/conversations/index.haml @@ -0,0 +1,30 @@ +-# Copyright (c) 2010, Diaspora Inc. This file is +-# licensed under the Affero General Public License version 3 or later. See +-# the COPYRIGHT file. + + +.span-12.last + + %h2 + .right + = link_to 'new message', new_conversation_path, :class => 'button' + Inbox + + + - if @conversations.count > 0 + .stream + - for conversation in @conversations + .stream_element + .right + = link_to image_tag('deletelabel.png'), conversation_conversation_visibility_path(conversation), :method => 'delete', :confirm => t('are_you_sure') + + .from + = conversation.messages.last.author.name + %p + = link_to conversation.subject, conversation + %p + = link_to conversation.messages.last, conversation + + - else + %i + You have no messages diff --git a/app/views/conversations/new.haml b/app/views/conversations/new.haml new file mode 100644 index 000000000..5d13de323 --- /dev/null +++ b/app/views/conversations/new.haml @@ -0,0 +1,24 @@ +-# Copyright (c) 2010, Diaspora Inc. This file is +-# licensed under the Affero General Public License version 3 or later. See +-# the COPYRIGHT file. + + +%h2 + New Message + += form_for Conversation.new do |conversation| + %h4 + to + = text_field_tag "private_message[contact_ids]" + + %h4 + subject + = conversation.text_field :subject + + = fields_for :message do |message| + %h4 + message + = message.text_area :text, :rows => 5 + + = conversation.submit :send + = link_to 'cancel', conversations_path diff --git a/app/views/conversations/show.haml b/app/views/conversations/show.haml new file mode 100644 index 000000000..99a8989fa --- /dev/null +++ b/app/views/conversations/show.haml @@ -0,0 +1,32 @@ +-# Copyright (c) 2010, Diaspora Inc. This file is +-# licensed under the Affero General Public License version 3 or later. See +-# the COPYRIGHT file. + += link_to 'back', conversations_path + +%br +%br +%br +%br + + +- for participant in @conversation.participants + = participant.name + +- for message in @conversation.messages + %h4 + from + = message.author.name + + %br + %br + + %h4 + message + = message.text + + %hr + += link_to t('delete'), conversation_conversation_visibility_path(@conversation), :method => 'delete', :confirm => t('are_you_sure') + + diff --git a/app/views/private_messages/index.haml b/app/views/private_messages/index.haml deleted file mode 100644 index a2e91d8c1..000000000 --- a/app/views/private_messages/index.haml +++ /dev/null @@ -1,28 +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. - - -.span-12.last - - %h2 - .right - = link_to 'new message', new_private_message_path, :class => 'button' - Message Inbox - - - - if @messages.count > 0 - .stream - - for message in @messages - .stream_element - .right - = link_to image_tag('deletelabel.png'), private_message_private_message_visibility_path(message), :method => 'delete', :confirm => t('are_you_sure') - - .from - = message.author.name - %p - = link_to message.message, message - - - else - %i - You have no messages diff --git a/app/views/private_messages/new.haml b/app/views/private_messages/new.haml deleted file mode 100644 index 8bff8af7a..000000000 --- a/app/views/private_messages/new.haml +++ /dev/null @@ -1,19 +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. - - -%h2 - New Message - -= form_for PrivateMessage.new do |private_message| - %h4 - to - = text_field_tag "private_message[contact_ids]" - - %h4 - message - = private_message.text_area :message, :rows => 5 - - = private_message.submit :send - = link_to 'cancel', private_messages_path diff --git a/app/views/private_messages/show.haml b/app/views/private_messages/show.haml deleted file mode 100644 index 43d5baecd..000000000 --- a/app/views/private_messages/show.haml +++ /dev/null @@ -1,38 +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. - -= link_to 'back', private_messages_path - -%br -%br -%br -%br - -%h4 - from -= @message.author.name - -%br -%br - -%h4 - to -- for recipient in @message.recipients - = recipient.name - -%br -%br - -%h4 - message -= @message.message - -%br -%br -%br -%br - -= link_to t('delete'), private_message_private_message_visibility_path(@message), :method => 'delete', :confirm => t('are_you_sure') - - diff --git a/config/routes.rb b/config/routes.rb index 881ebec5e..6d8298244 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -26,8 +26,8 @@ Diaspora::Application.routes.draw do resources :contacts resources :aspect_memberships, :only => [:destroy, :create] - resources :private_messages do - resource :private_message_visibility, :only => [:destroy], :path => '/visibility/' + resources :conversations do + resource :conversation_visibility, :only => [:destroy], :path => '/visibility/' end resources :people, :except => [:edit, :update] do diff --git a/db/migrate/20110225190919_create_conversations_and_messages_and_visibilities.rb b/db/migrate/20110225190919_create_conversations_and_messages_and_visibilities.rb new file mode 100644 index 000000000..397ded1f3 --- /dev/null +++ b/db/migrate/20110225190919_create_conversations_and_messages_and_visibilities.rb @@ -0,0 +1,38 @@ +class CreateConversationsAndMessagesAndVisibilities < ActiveRecord::Migration + def self.up + create_table :messages do |t| + t.integer :conversation_id, :null => false + t.integer :author_id, :null => false + t.string :guid, :null => false + t.text :text, :null => false + + t.timestamps + end + + create_table :conversation_visibilities do |t| + t.integer :conversation_id, :null => false + t.integer :person_id, :null => false + t.integer :unread, :null => false, :default => 0 + + t.timestamps + end + + create_table :conversations do |t| + t.string :subject + t.string :guid, :null => false + + t.timestamps + end + + add_index :conversation_visibilities, :person_id + add_index :conversation_visibilities, :conversation_id + add_index :conversation_visibilities, [:conversation_id, :person_id], :unique => true + add_index :messages, :author_id + end + + def self.down + drop_table :messages + drop_table :conversations + drop_table :conversation_visibilities + end +end diff --git a/db/migrate/20110225190919_create_private_messages_and_visibilities.rb b/db/migrate/20110225190919_create_private_messages_and_visibilities.rb deleted file mode 100644 index f5fce46f3..000000000 --- a/db/migrate/20110225190919_create_private_messages_and_visibilities.rb +++ /dev/null @@ -1,30 +0,0 @@ -class CreatePrivateMessagesAndVisibilities < ActiveRecord::Migration - def self.up - create_table :private_messages do |t| - t.integer :author_id, :null => false - t.string :guid, :null => false - t.text :message, :null => false - - t.timestamps - end - - - create_table :private_message_visibilities do |t| - t.integer :private_message_id - t.integer :person_id - t.boolean :unread, :null => false, :default => true - - t.timestamps - end - - add_index :private_message_visibilities, :person_id - add_index :private_message_visibilities, :private_message_id - add_index :private_message_visibilities, [:private_message_id, :person_id], :name => 'pm_visibilities_on_pm_id_and_person_id', :unique => true - add_index :private_messages, :author_id - end - - def self.down - drop_table :private_messages - drop_table :private_message_visibilities - end -end diff --git a/db/schema.rb b/db/schema.rb index bc959b945..adea1e3a4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -70,6 +70,25 @@ ActiveRecord::Schema.define(:version => 20110228201109) do add_index "contacts", ["user_id", "pending"], :name => "index_contacts_on_user_id_and_pending" add_index "contacts", ["user_id", "person_id"], :name => "index_contacts_on_user_id_and_person_id", :unique => true + create_table "conversation_visibilities", :force => true do |t| + t.integer "conversation_id", :null => false + t.integer "person_id", :null => false + t.integer "unread", :default => 0, :null => false + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "conversation_visibilities", ["conversation_id", "person_id"], :name => "index_conversation_visibilities_on_conversation_id_and_person_id", :unique => true + add_index "conversation_visibilities", ["conversation_id"], :name => "index_conversation_visibilities_on_conversation_id" + add_index "conversation_visibilities", ["person_id"], :name => "index_conversation_visibilities_on_person_id" + + create_table "conversations", :force => true do |t| + t.string "subject" + t.string "guid", :null => false + t.datetime "created_at" + t.datetime "updated_at" + end + create_table "data_points", :force => true do |t| t.string "key", :null => false t.integer "value", :null => false @@ -104,6 +123,17 @@ ActiveRecord::Schema.define(:version => 20110228201109) do add_index "mentions", ["person_id"], :name => "index_mentions_on_person_id" add_index "mentions", ["post_id"], :name => "index_mentions_on_post_id" + create_table "messages", :force => true do |t| + t.integer "conversation_id", :null => false + t.integer "author_id", :null => false + t.string "guid", :null => false + t.text "text", :null => false + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "messages", ["author_id"], :name => "index_messages_on_author_id" + create_table "mongo_aspect_memberships", :force => true do |t| t.string "aspect_mongo_id" t.string "contact_mongo_id" @@ -383,28 +413,6 @@ ActiveRecord::Schema.define(:version => 20110228201109) do add_index "posts", ["type", "pending", "id"], :name => "index_posts_on_type_and_pending_and_id" add_index "posts", ["type"], :name => "index_posts_on_type" - create_table "private_message_visibilities", :force => true do |t| - t.integer "private_message_id" - t.integer "person_id" - t.boolean "unread", :default => true, :null => false - t.datetime "created_at" - t.datetime "updated_at" - end - - add_index "private_message_visibilities", ["person_id"], :name => "index_private_message_visibilities_on_person_id" - add_index "private_message_visibilities", ["private_message_id", "person_id"], :name => "pm_visibilities_on_pm_id_and_person_id", :unique => true - add_index "private_message_visibilities", ["private_message_id"], :name => "index_private_message_visibilities_on_private_message_id" - - create_table "private_messages", :force => true do |t| - t.integer "author_id", :null => false - t.string "guid", :null => false - t.text "message", :null => false - t.datetime "created_at" - t.datetime "updated_at" - end - - add_index "private_messages", ["author_id"], :name => "index_private_messages_on_author_id" - create_table "profiles", :force => true do |t| t.string "diaspora_handle" t.string "first_name", :limit => 127 diff --git a/spec/controllers/private_message_visibilities_controller_spec.rb b/spec/controllers/conversation_visibilities_controller_spec.rb similarity index 59% rename from spec/controllers/private_message_visibilities_controller_spec.rb rename to spec/controllers/conversation_visibilities_controller_spec.rb index 2dc6c21da..c2458ec05 100644 --- a/spec/controllers/private_message_visibilities_controller_spec.rb +++ b/spec/controllers/conversation_visibilities_controller_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' -describe PrivateMessageVisibilitiesController do +describe ConversationVisibilitiesController do render_views before do @@ -12,15 +12,15 @@ describe PrivateMessageVisibilitiesController do sign_in :user, @user1 @create_hash = { :participant_ids => [@user1.contacts.first.person.id, @user1.person.id], - :author => @user1.person, :message => "cool stuff" } - @message = PrivateMessage.create(@create_hash) + :subject => "cool stuff" } + @conversation = Conversation.create(@create_hash) end describe '#destroy' do it 'deletes the visibility' do lambda { - delete :destroy, :private_message_id => @message.id - }.should change(PrivateMessageVisibility, :count).by(-1) + delete :destroy, :conversation_id => @conversation.id + }.should change(ConversationVisibility, :count).by(-1) end it 'does not let a user destroy a visibility that is not theirs' do @@ -28,8 +28,8 @@ describe PrivateMessageVisibilitiesController do sign_in :user, user2 lambda { - delete :destroy, :private_message_id => @message.id - }.should_not change(PrivateMessageVisibility, :count) + delete :destroy, :conversation_id => @conversation.id + }.should_not change(ConversationVisibility, :count) end end end diff --git a/spec/controllers/conversations_controller_spec.rb b/spec/controllers/conversations_controller_spec.rb new file mode 100644 index 000000000..0dce62b9d --- /dev/null +++ b/spec/controllers/conversations_controller_spec.rb @@ -0,0 +1,85 @@ +require 'spec_helper' + +describe ConversationsController do + render_views + + before do + @user1 = alice + sign_in :user, @user1 + end + + describe '#new' do + it 'succeeds' do + get :new + response.should be_success + end + end + + describe '#index' do + it 'succeeds' do + get :index + response.should be_success + end + + it 'retrieves all messages for a user' do + @conversation_hash = { :participant_ids => [@user1.contacts.first.person.id, @user1.person.id], + :subject => 'not spam' } + @message_hash = {:author => @user1.person, :text => 'cool stuff'} + + 3.times do + cnv = Conversation.create(@conversation_hash) + Message.create(@message_hash.merge({:conversation_id => cnv.id})) + end + + get :index + assigns[:conversations].count.should == 3 + end + end + + describe '#create' do + before do + @message_hash = {:conversation => { + :contact_ids => [@user1.contacts.first.id], + :subject => "secret stuff"}, + :message => {:text => "text"} + } + end + + it 'creates a conversation' do + lambda { + post :create, @message_hash + }.should change(Conversation, :count).by(1) + end + + it 'creates a message' do + lambda { + post :create, @message_hash + }.should change(Message, :count).by(1) + end + end + + describe '#show' do + before do + conversation_hash = { :participant_ids => [@user1.contacts.first.person.id, @user1.person.id], + :subject => 'not spam' } + message_hash = {:author => @user1.person, :text => 'cool stuff'} + + @conversation = Conversation.create(conversation_hash) + @message = Message.create(message_hash.merge({:conversation_id => @conversation.id})) + end + + it 'succeeds' do + get :show, :id => @conversation.id + response.should be_success + assigns[:conversation].should == @conversation + end + + it 'does not let you access conversations where you are not a recipient' do + user2 = eve + sign_in :user, user2 + + get :show, :id => @conversation.id + response.code.should == '302' + end + end +end diff --git a/spec/controllers/private_messages_controller_spec.rb b/spec/controllers/private_messages_controller_spec.rb deleted file mode 100644 index 4c30bc1ad..000000000 --- a/spec/controllers/private_messages_controller_spec.rb +++ /dev/null @@ -1,70 +0,0 @@ -require 'spec_helper' - -describe PrivateMessagesController do - render_views - - before do - @user1 = alice - sign_in :user, @user1 - end - - describe '#new' do - it 'succeeds' do - get :new - response.should be_success - end - end - - describe '#index' do - it 'succeeds' do - get :index - response.should be_success - end - - it 'retrieves all messages for a user' do - @create_hash = { :participant_ids => [@user1.contacts.first.person.id, @user1.person.id], - :author => @user1.person, :message => "cool stuff" } - 3.times do - PrivateMessage.create(@create_hash) - end - - get :index - assigns[:messages].count.should == 3 - end - end - - describe '#create' do - it 'creates a private message' do - message_hash = {:private_message => { - :contact_ids => [@user1.contacts.first.id], - :message => "secret stuff"}} - - - lambda { - post :create, message_hash - }.should change(PrivateMessage, :count).by(1) - end - end - - describe '#show' do - before do - @create_hash = { :participant_ids => [@user1.contacts.first.person.id, @user1.person.id], - :author => @user1.person, :message => "cool stuff" } - @message = PrivateMessage.create(@create_hash) - end - - it 'succeeds' do - get :show, :id => @message.id - response.should be_success - assigns[:message].should == @message - end - - it 'does not let you access messages where you are not a recipient' do - user2 = eve - sign_in :user, user2 - - get :show, :id => @message.id - response.code.should == '302' - end - end -end diff --git a/spec/models/conversation_spec.rb b/spec/models/conversation_spec.rb new file mode 100644 index 000000000..f595adf8d --- /dev/null +++ b/spec/models/conversation_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe Conversation do + before do + @user1 = alice + end + + describe 'serialization' do + before do + @create_hash = { :participant_ids => [@user1.contacts.first.person.id, @user1.person.id], + :subject => "cool stuff" } + @cnv = Conversation.new(@create_hash) + @message = Message.new(:author => @user1.person, :text => "stuff") + @cnv.messages << @message + @xml = @cnv.to_diaspora_xml + end + + it 'serializes the message' do + @xml.gsub(/\s/, '').should include(@message.to_xml.to_s.gsub(/\s/, '')) + end + + it 'serializes the participants' do + @create_hash[:participant_ids].each{|id| + @xml.should include(Person.find(id).diaspora_handle) + } + end + + it 'serializes the created_at time' do + @xml.should include(@message.created_at.to_s) + end + end + + describe "#subscribers?" do + it 'returns the recipients for the post owner' do + + end + + it 'returns the author for any other user' do + + end + end +end diff --git a/spec/models/conversation_visibility_spec.rb b/spec/models/conversation_visibility_spec.rb new file mode 100644 index 000000000..691b61b0e --- /dev/null +++ b/spec/models/conversation_visibility_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe ConversationVisibility do + before do + @user = alice + @aspect = @user.aspects.create(:name => 'Boozers') + + @person = Factory(:person) + @post = Factory(:status_message, :person => @person) + end + it 'has an aspect' do + pv = PostVisibility.new(:aspect => @aspect) + pv.aspect.should == @aspect + end + it 'has a post' do + pv = PostVisibility.new(:post => @post) + pv.post.should == @post + end +end diff --git a/spec/models/private_message_spec.rb b/spec/models/private_message_spec.rb deleted file mode 100644 index b37a57fbe..000000000 --- a/spec/models/private_message_spec.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'spec_helper' - -describe PrivateMessage do -end