conversations 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. data/.gitignore +8 -0
  2. data/CHANGELOG.md +7 -0
  3. data/Gemfile +17 -0
  4. data/Gemfile.lock +146 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +55 -0
  7. data/Rakefile +32 -0
  8. data/TODO.md +4 -0
  9. data/app/assets/javascripts/conversations.js +5 -0
  10. data/app/assets/javascripts/jquery.tokeninput.js +860 -0
  11. data/app/assets/stylesheets/conversations.css +4 -0
  12. data/app/assets/stylesheets/token-input-facebook.css +122 -0
  13. data/app/assets/stylesheets/token-input-mac.css +204 -0
  14. data/app/assets/stylesheets/token-input.css +113 -0
  15. data/app/controllers/conversations/conversations_controller.rb +26 -0
  16. data/app/controllers/conversations/messages_controller.rb +17 -0
  17. data/app/controllers/conversations/user_conversations_controller.rb +28 -0
  18. data/app/models/conversations/conversation.rb +19 -0
  19. data/app/models/conversations/message.rb +11 -0
  20. data/app/models/conversations/user_conversation.rb +22 -0
  21. data/app/views/conversations/conversations/new.html.erb +19 -0
  22. data/app/views/conversations/user_conversations/index.html.erb +17 -0
  23. data/app/views/conversations/user_conversations/show.html.erb +35 -0
  24. data/config/routes.rb +12 -0
  25. data/conversations.gemspec +33 -0
  26. data/lib/conversations.rb +19 -0
  27. data/lib/conversations/engine.rb +29 -0
  28. data/lib/conversations/models/conversationalist.rb +22 -0
  29. data/lib/conversations/version.rb +3 -0
  30. data/lib/generators/conversations/conversations_generator.rb +20 -0
  31. data/lib/generators/conversations/templates/20120105153739_create_conversations.rb +9 -0
  32. data/lib/generators/conversations/templates/20120105153800_create_user_conversations.rb +12 -0
  33. data/lib/generators/conversations/templates/20120105153812_create_messages.rb +11 -0
  34. data/lib/tasks/conversations_tasks.rake +4 -0
  35. data/spec/dummy/Rakefile +7 -0
  36. data/spec/dummy/app/assets/javascripts/application.js +10 -0
  37. data/spec/dummy/app/assets/stylesheets/application.css +24 -0
  38. data/spec/dummy/app/controllers/application_controller.rb +13 -0
  39. data/spec/dummy/app/controllers/users_controller.rb +44 -0
  40. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  41. data/spec/dummy/app/mailers/.gitkeep +0 -0
  42. data/spec/dummy/app/models/.gitkeep +0 -0
  43. data/spec/dummy/app/models/user.rb +7 -0
  44. data/spec/dummy/app/views/layouts/application.html.erb +15 -0
  45. data/spec/dummy/app/views/users/_form.html.erb +5 -0
  46. data/spec/dummy/app/views/users/edit.html.erb +3 -0
  47. data/spec/dummy/app/views/users/index.html.erb +7 -0
  48. data/spec/dummy/app/views/users/new.html.erb +3 -0
  49. data/spec/dummy/app/views/users/show.html.erb +13 -0
  50. data/spec/dummy/config.ru +4 -0
  51. data/spec/dummy/config/application.rb +45 -0
  52. data/spec/dummy/config/boot.rb +10 -0
  53. data/spec/dummy/config/database.yml +25 -0
  54. data/spec/dummy/config/environment.rb +5 -0
  55. data/spec/dummy/config/environments/development.rb +37 -0
  56. data/spec/dummy/config/environments/production.rb +60 -0
  57. data/spec/dummy/config/environments/test.rb +39 -0
  58. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  59. data/spec/dummy/config/initializers/inflections.rb +10 -0
  60. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  61. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  62. data/spec/dummy/config/initializers/session_store.rb +8 -0
  63. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  64. data/spec/dummy/config/locales/en.yml +5 -0
  65. data/spec/dummy/config/routes.rb +69 -0
  66. data/spec/dummy/db/migrate/20120105152859_create_users.rb +9 -0
  67. data/spec/dummy/db/migrate/20120105153739_create_conversations.rb +9 -0
  68. data/spec/dummy/db/migrate/20120105153800_create_user_conversations.rb +12 -0
  69. data/spec/dummy/db/migrate/20120105153812_create_messages.rb +11 -0
  70. data/spec/dummy/db/schema.rb +45 -0
  71. data/spec/dummy/db/seeds.rb +12 -0
  72. data/spec/dummy/lib/assets/.gitkeep +0 -0
  73. data/spec/dummy/log/.gitkeep +0 -0
  74. data/spec/dummy/public/404.html +26 -0
  75. data/spec/dummy/public/422.html +26 -0
  76. data/spec/dummy/public/500.html +26 -0
  77. data/spec/dummy/public/favicon.ico +0 -0
  78. data/spec/dummy/script/rails +6 -0
  79. data/spec/factories.rb +29 -0
  80. data/spec/integration/conversations_controller_spec.rb +54 -0
  81. data/spec/integration/messages_controller_spec.rb +37 -0
  82. data/spec/integration/user_conversations_controller_spec.rb +51 -0
  83. data/spec/models/conversation_spec.rb +28 -0
  84. data/spec/models/message_spec.rb +23 -0
  85. data/spec/models/user_conversation_spec.rb +18 -0
  86. data/spec/spec_helper.rb +42 -0
  87. metadata +300 -0
@@ -0,0 +1,17 @@
1
+ module Conversations
2
+ class MessagesController < ::ApplicationController
3
+ include ApplicationHelper
4
+
5
+ def create
6
+ @user = User.find(params[:user_id])
7
+ @conversation = UserConversation.find params[:conversation_id]
8
+ @message = @conversation.conversation.messages.build params[:conversations_message]
9
+ @message.user = @user
10
+ if @message.save
11
+ redirect_to user_conversation_path(@user, @conversation)
12
+ else
13
+ render template: 'conversations/user_conversations/show'
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,28 @@
1
+ module Conversations
2
+ class UserConversationsController < ::ApplicationController
3
+ include ApplicationHelper
4
+
5
+ def index
6
+ @user = User.find params[:user_id]
7
+ @conversations = @user.user_conversations
8
+ end
9
+
10
+ def show
11
+ @user = User.find params[:user_id]
12
+ @conversation = UserConversation.find params[:id]
13
+ @message = @conversation.conversation.messages.build
14
+ end
15
+
16
+ def mark_as_read
17
+ @conversation = UserConversation.find params[:id]
18
+ @conversation.update_attributes :read => true
19
+ redirect_to user_conversation_path(current_user, @conversation)
20
+ end
21
+
22
+ def mark_as_unread
23
+ @conversation = UserConversation.find params[:id]
24
+ @conversation.update_attributes :read => false
25
+ redirect_to user_conversation_path(current_user, @conversation)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,19 @@
1
+ module Conversations
2
+ class Conversation < ActiveRecord::Base
3
+ attr_accessible :subject, :to_tokens
4
+ attr_accessor :to_tokens
5
+
6
+ has_many :user_conversations
7
+ has_many :users, :through => :user_conversations
8
+ has_many :messages
9
+
10
+ accepts_nested_attributes_for :messages
11
+
12
+ validates :subject, :presence => :true
13
+
14
+ def to_tokens=(ids)
15
+ self.user_ids = ids.split(",")
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ module Conversations
2
+ class Message < ActiveRecord::Base
3
+ attr_accessible :user_id, :conversation_id, :body
4
+
5
+ belongs_to :user
6
+ belongs_to :conversation
7
+
8
+ validates :user_id, :presence => true
9
+ validates :body, :presence => true
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ module Conversations
2
+ class UserConversation < ActiveRecord::Base
3
+ attr_accessible :user_id, :conversation_id, :deleted, :read
4
+
5
+ belongs_to :user
6
+ belongs_to :conversation
7
+ has_many :messages, :through => :conversation
8
+
9
+ accepts_nested_attributes_for :conversation
10
+
11
+ delegate :subject, :to => :conversation
12
+ delegate :users, :to => :conversation
13
+
14
+ validates :user_id, :presence => true
15
+
16
+ # TODO: Add more attributes like :username, :first_name, :last_name
17
+ def participants
18
+ self.users.collect { |u| u.name }.join(', ')
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ <h1>New Conversation</h1>
2
+
3
+ <%= form_for(@conversation, :url => user_conversations_path) do |f| %>
4
+ <div>
5
+ <%= f.label :to_tokens %>
6
+ <%= f.text_field :to_tokens %>
7
+ </div>
8
+ <div>
9
+ <%= f.label :subject %>
10
+ <%= f.text_field :subject %>
11
+ </div>
12
+ <%= f.fields_for :messages do |m| %>
13
+ <div>
14
+ <%= m.label :body %><br />
15
+ <%= m.text_area :body %>
16
+ </div>
17
+ <% end %>
18
+ <%= f.submit %>
19
+ <% end %>
@@ -0,0 +1,17 @@
1
+ <h1><%= @user.name %>'s Conversations</h1>
2
+
3
+ <ul>
4
+ <% for conversation in @conversations do %>
5
+ <li class="<%= conversation.read? ? 'read' : 'unread' %>">
6
+ <%= conversation.participants %>
7
+ -
8
+ <%= link_to conversation.subject, user_conversation_path(conversation.user, conversation) %>
9
+ -
10
+ <%=l conversation.created_at, :format => :short %>
11
+ </li>
12
+ <% end %>
13
+ </ul>
14
+
15
+ <%= link_to "Create a New Conversation", new_user_conversation_path(@user) %>
16
+ <br>
17
+ <%= link_to "Back to User", user_path(@user) %>
@@ -0,0 +1,35 @@
1
+ <h1><%= @conversation.subject %></h1>
2
+
3
+ <div>
4
+ <h4>From: <%= @user.name %></h4>
5
+ <h4>To:</h4>
6
+ <ul>
7
+ <%# TODO: move method into model %>
8
+ <% for user in @conversation.users.reject! { |u| u == @user } do %>
9
+ <li><%= link_to user.name, user %></li>
10
+ <% end %>
11
+ </ul>
12
+ </div>
13
+
14
+ <% for message in @conversation.messages do %>
15
+ <div class="message"><%= time_ago_in_words(message.created_at) %> ago, <%= message.user.name %> wrote:
16
+ <div class="message_body"><%= message.body %></div>
17
+ </div>
18
+ <% end %>
19
+
20
+ <%= form_for(@message, :url => user_conversation_messages_path(@conversation.user, @conversation)) do |f| %>
21
+ <div>
22
+ <%= f.label :body %><br />
23
+ <%= f.text_area :body %>
24
+ </div>
25
+ <%= f.submit %>
26
+ <% end %>
27
+
28
+ <% if current_user == @conversation.user && !@conversation.read? %>
29
+ <%= link_to "Mark as read", mark_as_read_user_conversation_path(@conversation.user, @conversation), :method => :post %>
30
+ <% elsif current_user == @conversation.user && @conversation.read? %>
31
+ <%= link_to "Mark as unread", mark_as_unread_user_conversation_path(@conversation.user, @conversation), :method => :post %>
32
+ <% end %>
33
+ <br />
34
+
35
+ <%= link_to "Back to conversations", user_conversations_path(@user) %>
@@ -0,0 +1,12 @@
1
+ Rails.application.routes.draw do
2
+ resources :users do
3
+ resources :conversations, :controller => "conversations/conversations", :only => [:new, :create]
4
+ resources :conversations, :controller => "conversations/user_conversations", :except => [:new, :create] do
5
+ resources :messages, :controller => "conversations/messages"
6
+ member do
7
+ post :mark_as_read
8
+ post :mark_as_unread
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ # Maintain your gem's version:
5
+ require "conversations/version"
6
+
7
+ # Describe your gem and declare its dependencies:
8
+ Gem::Specification.new do |s|
9
+ s.name = "conversations"
10
+ s.version = Conversations::VERSION
11
+ s.platform = Gem::Platform::RUBY
12
+ s.authors = ["Patrick Bartels"]
13
+ s.email = ["patrick@bartels.ug"]
14
+ s.homepage = %q{https://github.com/roughneck/conversations}
15
+ s.summary = "Summary of Conversations."
16
+ s.description = "Description of Conversations."
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+
23
+ s.rubyforge_project = "conversations"
24
+
25
+ s.add_dependency "rails", "~> 3.1.3"
26
+ s.add_dependency "jquery-rails", "~> 1.0.19"
27
+
28
+ s.add_development_dependency "sqlite3", "~> 1.3"
29
+ s.add_development_dependency "rspec-rails", "~> 2.8"
30
+ s.add_development_dependency "capybara", "~> 1.1"
31
+ s.add_development_dependency "factory_girl_rails", "~> 1.4"
32
+ s.add_development_dependency "simplecov", "~> 0.5"
33
+ end
@@ -0,0 +1,19 @@
1
+ module Conversations
2
+ module Models
3
+ autoload :Conversationalist, 'conversations/models/conversationalist'
4
+ end
5
+
6
+ # Our host application root path
7
+ # We set this when the engine is initialized
8
+ mattr_accessor :app_root
9
+
10
+ # Yield self on setup for nice config blocks
11
+ class << self
12
+ def setup
13
+ yield self
14
+ end
15
+ end
16
+ end
17
+
18
+ # Require engine
19
+ require "conversations/engine"
@@ -0,0 +1,29 @@
1
+ module Conversations
2
+
3
+ class Engine < Rails::Engine
4
+
5
+ initializer "conversations.load_app_instance_data" do |app|
6
+ Conversations.setup do |config|
7
+ config.app_root = app.root
8
+ end
9
+ end
10
+
11
+ initializer "conversations.load_static_assets" do |app|
12
+ app.middleware.use ::ActionDispatch::Static, "#{root}/public"
13
+ end
14
+
15
+ initializer "conversations.models.conversationalist" do
16
+ ActiveSupport.on_load(:active_record) do
17
+ include Conversations::Models::Conversationalist
18
+ end
19
+ end
20
+
21
+ initializer 'conversations.controller' do
22
+ ActiveSupport.on_load(:action_controller) do
23
+ # include Conversations::ConversationsController::InstanceMethods
24
+ # extend Conversations::ConversationsController::ClassMethods
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ module Conversations
2
+ module Models
3
+ module Conversationalist
4
+ def self.included(mod)
5
+ mod.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def has_conversations
10
+ has_many :user_conversations, :class_name => "Conversations::UserConversation"
11
+ has_many :conversations, :through => :user_conversations
12
+ has_many :messages, :through => :conversations
13
+
14
+ include InstanceMethods
15
+ end
16
+ end
17
+
18
+ module InstanceMethods
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module Conversations
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,20 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ class ConversationsGenerator < Rails::Generators::Base
5
+ include Rails::Generators::Migration
6
+ def self.source_root
7
+ @source_root ||= File.join(File.dirname(__FILE__), 'templates')
8
+ end
9
+
10
+ def self.next_migration_number(dirname)
11
+ next_migration_number = current_migration_number(dirname) + 1
12
+ ActiveRecord::Migration.next_migration_number(next_migration_number)
13
+ end
14
+
15
+ def create_migration_file
16
+ migration_template '20120105153739_create_conversations.rb', 'db/migrate/create_conversations.rb'
17
+ migration_template '20120105153800_create_user_conversations.rb', 'db/migrate/create_user_conversations.rb'
18
+ migration_template '20120105153812_create_messages.rb', 'db/migrate/create_messages.rb'
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ class CreateConversations < ActiveRecord::Migration
2
+ def change
3
+ create_table :conversations do |t|
4
+ t.string :subject
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ class CreateUserConversations < ActiveRecord::Migration
2
+ def change
3
+ create_table :user_conversations do |t|
4
+ t.integer :user_id
5
+ t.integer :conversation_id
6
+ t.boolean :deleted
7
+ t.boolean :read
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ class CreateMessages < ActiveRecord::Migration
2
+ def change
3
+ create_table :messages do |t|
4
+ t.integer :user_id
5
+ t.integer :conversation_id
6
+ t.text :body
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :conversations do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
3
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4
+
5
+ require File.expand_path('../config/application', __FILE__)
6
+
7
+ Dummy::Application.load_tasks
@@ -0,0 +1,10 @@
1
+ // This is a manifest file that'll be compiled into including all the files listed below.
2
+ // Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
3
+ // be included in the compiled file accessible from http://example.com/assets/application.js
4
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
5
+ // the compiled file.
6
+ //
7
+ //= require jquery
8
+ //= require jquery_ujs
9
+ //= require conversations
10
+ //= require_tree .
@@ -0,0 +1,24 @@
1
+ /*
2
+ * This is a manifest file that'll automatically include all the stylesheets available in this directory
3
+ * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
4
+ * the top of the compiled file, but it's generally better to create a new file per style scope.
5
+ *= require_self
6
+ *= require conversations
7
+ *= require_tree .
8
+ */
9
+
10
+ .read {
11
+ font-style: italic;
12
+ }
13
+
14
+ .unread {
15
+ font-weight: bold;
16
+ }
17
+
18
+ .message {
19
+ border-bottom: 1px dotted gray;
20
+ }
21
+
22
+ .message_body {
23
+ margin: 10px 20px;
24
+ }
@@ -0,0 +1,13 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery
3
+
4
+ helper_method :current_user
5
+
6
+ def current_user
7
+ begin
8
+ session[:current_user_id] ? User.find(session[:current_user_id]) : nil
9
+ rescue ActiveRecord::RecordNotFound
10
+ nil
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,44 @@
1
+ class UsersController < ApplicationController
2
+ def index
3
+ @users = User.all
4
+
5
+ respond_to do |format|
6
+ format.html
7
+ format.json { render :json => User.where("name like ?", "%#{params[:q]}%").map(&:attributes) }
8
+ end
9
+ end
10
+
11
+ def show
12
+ @user = User.find params[:id]
13
+ end
14
+
15
+ def edit
16
+ @user = User.find params[:id]
17
+ end
18
+
19
+ def update
20
+ @user = User.find params[:id]
21
+ @user.update_attributes params[:user]
22
+ redirect_to @user
23
+ end
24
+
25
+ def new
26
+ @user = User.new
27
+ end
28
+
29
+ def create
30
+ @user = User.create params[:user]
31
+ redirect_to @user
32
+ end
33
+
34
+ def signin
35
+ @user = User.find params[:id]
36
+ session[:current_user_id] = @user.id if @user
37
+ redirect_to @user
38
+ end
39
+
40
+ def signout
41
+ session.delete(:current_user_id)
42
+ redirect_to users_path
43
+ end
44
+ end