user_private_messages 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/Gemfile +11 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +31 -0
  6. data/Rakefile +16 -0
  7. data/lib/generators/simple_private_messages/model/USAGE +11 -0
  8. data/lib/generators/simple_private_messages/model/model_generator.rb +51 -0
  9. data/lib/generators/simple_private_messages/model/templates/migration.rb +16 -0
  10. data/lib/generators/simple_private_messages/model/templates/model.rb +9 -0
  11. data/lib/generators/simple_private_messages/scaffold/USAGE +11 -0
  12. data/lib/generators/simple_private_messages/scaffold/scaffold_generator.rb +50 -0
  13. data/lib/generators/simple_private_messages/scaffold/templates/controller.rb +60 -0
  14. data/lib/generators/simple_private_messages/scaffold/templates/view_index.html.erb +7 -0
  15. data/lib/generators/simple_private_messages/scaffold/templates/view_index_inbox.html.erb +38 -0
  16. data/lib/generators/simple_private_messages/scaffold/templates/view_index_sent.html.erb +31 -0
  17. data/lib/generators/simple_private_messages/scaffold/templates/view_new.html.erb +20 -0
  18. data/lib/generators/simple_private_messages/scaffold/templates/view_show.html.erb +13 -0
  19. data/lib/has_private_messages_extensions.rb +61 -0
  20. data/lib/private_message_extensions.rb +70 -0
  21. data/lib/private_messages/matchers/be_private_message_matcher.rb +39 -0
  22. data/lib/private_messages/matchers/have_private_messages_matcher.rb +39 -0
  23. data/lib/private_messages/matchers.rb +9 -0
  24. data/lib/private_messages/version.rb +3 -0
  25. data/lib/private_messages.rb +8 -0
  26. data/lib/tasks/simple_private_messages_tasks.rake +4 -0
  27. data/private_messages.gemspec +23 -0
  28. data/test/database.yml +3 -0
  29. data/test/fixtures/message.rb +5 -0
  30. data/test/fixtures/user.rb +5 -0
  31. data/test/schema.rb +21 -0
  32. data/test/test_helper.rb +31 -0
  33. data/test/unit/message_model.rb +54 -0
  34. data/test/unit/user_model.rb +17 -0
  35. metadata +112 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5250815c308b9a9ac4fb88e2a3b1fead2c40f22f
4
+ data.tar.gz: 4f2969c3f2ddac7e1bf1d300fa6decbf43958928
5
+ SHA512:
6
+ metadata.gz: 633af6ba7234d912012a302d36b9d7eda258a815da96d9bbfd986c6d246c0d47b7f2af9825148e62aa7a0879bc737a1868587c5e049ff12193d20352b0c6edc5
7
+ data.tar.gz: 567c3d071d768520f70e4974f937c54e8b61ba49ccb15366d92f7ed0bc949177c03dbf8e0f8f94f2e24a4a204390545e6d522dd8d9dd6013e86edc76247adc9d
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ /vendor
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in private_messages.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'activerecord'
8
+ gem 'sqlite3'
9
+ gem 'activesupport'
10
+ gem 'byebug'
11
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Aleksandar Zoric
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # PrivateMessages
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'private_messages'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install private_messages
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/[my-github-username]/private_messages/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+
6
+ desc 'Default: run unit tests.'
7
+ task :default => :test
8
+
9
+ desc 'Test the private_messages gem.'
10
+ Rake::TestTask.new(:test) do |t|
11
+ t.libs << 'lib'
12
+ t.pattern = 'test/**/*_model.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+
@@ -0,0 +1,11 @@
1
+ Description:
2
+ Creates the private message model and migration for use with
3
+ the simple_private_messages plugin.
4
+
5
+ Run the migration, passing the name of the model to be created.
6
+
7
+ Example:
8
+
9
+ ./script/generate private_message_model Message
10
+
11
+ Further steps are involved after this, see the README for full details.
@@ -0,0 +1,51 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ module PrivateMessages
5
+ module Generators
6
+ class ModelGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+
9
+ desc "Creates the private message model."
10
+
11
+ argument :user_model_name, :required => false, :default => "User", :desc => "The user model name"
12
+ argument :message_model_name, :required => false, :default => "Message", :desc => "The message model name"
13
+
14
+ attr_reader :singular_camel_case_name, :plural_camel_case_name, :singular_lower_case_name, :plural_lower_case_name
15
+ attr_reader :singular_camel_case_parent, :plural_camel_case_parent, :singular_lower_case_parent, :plural_lower_case_parent
16
+
17
+ def self.source_root
18
+ File.join(File.dirname(__FILE__), 'templates')
19
+ end
20
+
21
+ # Implement the required interface for Rails::Generators::Migration.
22
+ # taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
23
+ def self.next_migration_number(dirname) #:nodoc:
24
+ if ActiveRecord::Base.timestamped_migrations
25
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
26
+ else
27
+ "%.3d" % (current_migration_number(dirname) + 1)
28
+ end
29
+ end
30
+
31
+ def go
32
+ @singular_camel_case_name = message_model_name.singularize.camelize
33
+ @plural_camel_case_name = message_model_name.pluralize.camelize
34
+ @singular_lower_case_name = message_model_name.singularize.underscore
35
+ @plural_lower_case_name = message_model_name.pluralize.underscore
36
+
37
+ @singular_camel_case_parent = user_model_name.singularize.camelize
38
+ @plural_camel_case_parent = user_model_name.pluralize.camelize
39
+ @singular_lower_case_parent = user_model_name.singularize.underscore
40
+ @plural_lower_case_parent = user_model_name.pluralize.underscore
41
+
42
+ #directory "app/models"
43
+ template "model.rb", "app/models/#{singular_lower_case_name}.rb"
44
+
45
+ migration_template "migration.rb", "db/migrate/create_#{plural_lower_case_name}", :assigns => {
46
+ :migration_name => "Create#{plural_camel_case_name}"
47
+ }
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,16 @@
1
+ class <%= "Create#{plural_camel_case_name}" %> < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :<%= plural_lower_case_name %> do |t|
4
+ t.integer :sender_id, :recipient_id
5
+ t.boolean :sender_deleted, :recipient_deleted, :default => false
6
+ t.string :subject
7
+ t.text :body
8
+ t.datetime :read_at
9
+ t.timestamps
10
+ end
11
+ end
12
+
13
+ def self.down
14
+ drop_table :<%= plural_lower_case_name %>
15
+ end
16
+ end
@@ -0,0 +1,9 @@
1
+ class <%= singular_camel_case_name %> < ActiveRecord::Base
2
+
3
+ is_private_message<% unless singular_camel_case_parent == "User" %> :class_name => "<%= "#{singular_camel_case_parent}" %>"<% end %>
4
+
5
+ # The :to accessor is used by the scaffolding,
6
+ # uncomment it if using it or you can remove it if not
7
+ #attr_accessor :to
8
+
9
+ end
@@ -0,0 +1,11 @@
1
+ Description:
2
+ Creates a basic but working controller and set of views for private
3
+ messages.
4
+
5
+ Run the following generator, passing the name of the model you created.
6
+
7
+ Example:
8
+
9
+ ./script/generate private_message_scaffold Message
10
+
11
+ Further steps are involved after this, see the README for full details.
@@ -0,0 +1,50 @@
1
+ require 'rails/generators'
2
+
3
+ module PrivateMessages
4
+ module Generators
5
+ class ScaffoldGenerator < Rails::Generators::Base
6
+ desc "Creates a basic controller and a set of views."
7
+
8
+ argument :user_model_name, :required => false, :default => "User", :desc => "The user model name"
9
+ argument :message_model_name, :required => false, :default => "Message", :desc => "The message model name"
10
+
11
+ attr_reader :singular_camel_case_name, :plural_camel_case_name, :singular_lower_case_name, :plural_lower_case_name
12
+ attr_reader :singular_camel_case_parent, :plural_camel_case_parent, :singular_lower_case_parent, :plural_lower_case_parent
13
+
14
+ def self.source_root
15
+ File.join(File.dirname(__FILE__), 'templates')
16
+ end
17
+
18
+ def go
19
+ @singular_camel_case_name = message_model_name.singularize.camelize
20
+ @plural_camel_case_name = message_model_name.pluralize.camelize
21
+ @singular_lower_case_name = message_model_name.singularize.underscore
22
+ @plural_lower_case_name = message_model_name.pluralize.underscore
23
+
24
+ @singular_camel_case_parent = user_model_name.singularize.camelize
25
+ @plural_camel_case_parent = user_model_name.pluralize.camelize
26
+ @singular_lower_case_parent = user_model_name.singularize.underscore
27
+ @plural_lower_case_parent = user_model_name.pluralize.underscore
28
+
29
+ route("resources :#{@plural_lower_case_parent} do
30
+ resources :#{@plural_lower_case_name} do
31
+ collection do
32
+ post :delete_selected
33
+ end
34
+ end
35
+ end")
36
+
37
+ #directory "app/controllers"
38
+ template "controller.rb", "app/controllers/#{@plural_lower_case_name}_controller.rb"
39
+
40
+ #directory "app/views"
41
+ #directory "app/views/#{@plural_lower_case_name}"
42
+ template "view_index.html.erb", "app/views/#{@plural_lower_case_name}/index.html.erb"
43
+ template "view_index_inbox.html.erb", "app/views/#{@plural_lower_case_name}/_inbox.html.erb"
44
+ template "view_index_sent.html.erb", "app/views/#{@plural_lower_case_name}/_sent.html.erb"
45
+ template "view_show.html.erb", "app/views/#{@plural_lower_case_name}/show.html.erb"
46
+ template "view_new.html.erb", "app/views/#{@plural_lower_case_name}/new.html.erb"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,60 @@
1
+ class <%= plural_camel_case_name %>Controller < ApplicationController
2
+
3
+ before_filter :set_user
4
+
5
+ def index
6
+ if params[:mailbox] == "sent"
7
+ @<%= plural_lower_case_name %> = @<%= singular_lower_case_parent %>.sent_messages
8
+ else
9
+ @<%= plural_lower_case_name %> = @<%= singular_lower_case_parent %>.received_messages
10
+ end
11
+ end
12
+
13
+ def show
14
+ @<%= singular_lower_case_name %> = <%= singular_camel_case_name %>.read_message(params[:id], current_user)
15
+ end
16
+
17
+ def new
18
+ @<%= singular_lower_case_name %> = <%= singular_camel_case_name %>.new
19
+
20
+ if params[:reply_to]
21
+ @reply_to = @<%= singular_lower_case_parent %>.received_messages.find(params[:reply_to])
22
+ unless @reply_to.nil?
23
+ @<%= singular_lower_case_name %>.to = @reply_to.sender.login
24
+ @<%= singular_lower_case_name %>.subject = "Re: #{@reply_to.subject}"
25
+ @<%= singular_lower_case_name %>.body = "\n\n*Original message*\n\n #{@reply_to.body}"
26
+ end
27
+ end
28
+ end
29
+
30
+ def create
31
+ @<%= singular_lower_case_name %> = <%= singular_camel_case_name %>.new(params[:<%= singular_lower_case_name %>])
32
+ @<%= singular_lower_case_name %>.sender = @<%= singular_lower_case_parent %>
33
+ @<%= singular_lower_case_name %>.recipient = <%= singular_camel_case_parent %>.find_by_login(params[:<%= singular_lower_case_name %>][:to])
34
+
35
+ if @<%= singular_lower_case_name %>.save
36
+ flash[:notice] = "Message sent"
37
+ redirect_to user_<%= plural_lower_case_name %>_path(@<%= singular_lower_case_parent %>)
38
+ else
39
+ render :action => :new
40
+ end
41
+ end
42
+
43
+ def delete_selected
44
+ if request.post?
45
+ if params[:delete]
46
+ params[:delete].each { |id|
47
+ @<%= singular_lower_case_name %> = <%= singular_camel_case_name %>.find(:first, :conditions => ["<%= plural_lower_case_name %>.id = ? AND (sender_id = ? OR recipient_id = ?)", id, @<%= singular_lower_case_parent %>, @<%= singular_lower_case_parent %>])
48
+ @<%= singular_lower_case_name %>.mark_deleted(@<%= singular_lower_case_parent %>) unless @<%= singular_lower_case_name %>.nil?
49
+ }
50
+ flash[:notice] = "Messages deleted"
51
+ end
52
+ redirect_to :back
53
+ end
54
+ end
55
+
56
+ private
57
+ def set_user
58
+ @<%= singular_lower_case_parent %> = User.find(params[:<%= singular_lower_case_parent %>_id])
59
+ end
60
+ end
@@ -0,0 +1,7 @@
1
+ <%% form_tag delete_selected_user_<%= plural_lower_case_name %>_path(@<%= singular_lower_case_parent %>, :method => :post) do %>
2
+ <%% if params[:mailbox] == "sent" %>
3
+ <%%= render :partial => "sent" %>
4
+ <%% else %>
5
+ <%%= render :partial => "inbox" %>
6
+ <%% end %>
7
+ <%% end %>
@@ -0,0 +1,38 @@
1
+ <h2>Inbox</h2>
2
+ <table>
3
+ <tr>
4
+ <th>Del?</th>
5
+ <th>Sent</th>
6
+ <th>Sender</th>
7
+ <th>Sent</th>
8
+ </tr>
9
+ <%% if @<%= plural_lower_case_name %>.size == 0 %>
10
+ <tr>
11
+ <td colspan="4">
12
+ No messages
13
+ </td>
14
+ </tr>
15
+ <%% else %>
16
+ <%% for <%= singular_lower_case_name %> in @<%= plural_lower_case_name %> %>
17
+ <tr>
18
+ <td><%%= check_box_tag "delete[]", <%= singular_lower_case_name %>.id %></td>
19
+ <td>
20
+ <%% if <%= singular_lower_case_name %>.message_read? %>
21
+ <%%= link_to h(<%= singular_lower_case_name %>.subject), user_<%= singular_lower_case_name %>_path(@<%= singular_lower_case_parent %>, <%= singular_lower_case_name %>) %>
22
+ <%% else %>
23
+ <%%= link_to "#{h(<%= singular_lower_case_name %>.subject)} (unread)", user_<%= singular_lower_case_name %>_path(@<%= singular_lower_case_parent %>, <%= singular_lower_case_name %>) %>
24
+ <%% end %>
25
+ </td>
26
+ <td><%%= link_to h(<%= singular_lower_case_name %>.sender.login), user_path(<%= singular_lower_case_name %>.sender) %></td>
27
+ <td><%%=h <%= singular_lower_case_name %>.created_at.to_s(:long) %></td>
28
+ </tr>
29
+ <%% end %>
30
+ <tr>
31
+ <td colspan="4">
32
+ <%%= submit_tag "Delete" %>
33
+ </td>
34
+ </tr>
35
+ <%% end %>
36
+ </table>
37
+ <%%= link_to "Sent", user_<%= plural_lower_case_name %>_path(@<%= singular_lower_case_parent %>, :mailbox => :sent)%> |
38
+ <%%= link_to "Compose", new_user_<%= singular_lower_case_name %>_path(@<%= singular_lower_case_parent %>)%>
@@ -0,0 +1,31 @@
1
+ <h2>Sent</h2>
2
+ <table>
3
+ <tr>
4
+ <th>Del?</th>
5
+ <th>Subject</th>
6
+ <th>To</th>
7
+ <th>Sent</th>
8
+ </tr>
9
+ <%% if @<%= plural_lower_case_name %>.size == 0 %>
10
+ <tr>
11
+ <td colspan="4">
12
+ No messages
13
+ </td>
14
+ </tr>
15
+ <%% else %>
16
+ <%% for <%= singular_lower_case_name %> in @<%= plural_lower_case_name %> %>
17
+ <tr>
18
+ <td><%%= check_box_tag "delete[]", <%= singular_lower_case_name %>.id %></td>
19
+ <td><%%= link_to h(<%= singular_lower_case_name %>.subject), user_<%= singular_lower_case_name %>_path(@<%= singular_lower_case_parent %>, <%= singular_lower_case_name %>) %></td>
20
+ <td><%%= link_to h(<%= singular_lower_case_name %>.recipient.login), user_path(<%= singular_lower_case_name %>.recipient) %></td>
21
+ <td><%%=h <%= singular_lower_case_name %>.created_at.to_s(:long) %></td>
22
+ </tr>
23
+ <%% end %>
24
+ <tr>
25
+ <td colspan="4">
26
+ <%%= submit_tag "Delete" %>
27
+ </td>
28
+ </tr>
29
+ <%% end %>
30
+ </table>
31
+ <%%= link_to "Inbox", user_<%= plural_lower_case_name %>_path(@<%= singular_lower_case_parent %>)%>
@@ -0,0 +1,20 @@
1
+ <%% form_for @<%= singular_lower_case_name %>, :url => user_<%= plural_lower_case_name %>_path(@user) do |f| %>
2
+ <p>
3
+ To:<br />
4
+ <%%= f.text_field :to %>
5
+ <%%= error_message_on @<%= singular_lower_case_name %>, :to %>
6
+ </p>
7
+ <p>
8
+ Subject:<br />
9
+ <%%= f.text_field :subject %>
10
+ <%%= error_message_on @<%= singular_lower_case_name %>, :subject %>
11
+ </p>
12
+ <p>
13
+ Message<br />
14
+ <%%= f.text_area :body %>
15
+ <%%= error_message_on @<%= singular_lower_case_name %>, :body %>
16
+ </p>
17
+ <p>
18
+ <%%= submit_tag "Send" %>
19
+ </p>
20
+ <%% end %>
@@ -0,0 +1,13 @@
1
+ <p><strong>From:</strong> <%%= @<%= singular_lower_case_name %>.sender == @user ? link_to("You", user_path(@user)) : link_to(h(@<%= singular_lower_case_name %>.sender.login), user_path(@<%= singular_lower_case_name%>.sender)) %></p>
2
+ <p><strong>Received:</strong> <%%= @<%= singular_lower_case_name %>.created_at.to_s(:long) %></p>
3
+ <p><strong>To:</strong> <%%= @<%= singular_lower_case_name %>.recipient == @user ? link_to("You", user_path(@user)) : link_to(h(@<%= singular_lower_case_name %>.recipient.login), user_path(@<%= singular_lower_case_name %>.recipient)) %></p>
4
+ <p>
5
+ <strong>Message</strong><br />
6
+ <%%=h @<%= singular_lower_case_name %>.body %>
7
+ </p>
8
+ <p>
9
+ <%% if @<%= singular_lower_case_name %>.recipient == @user %>
10
+ <%%= link_to "Reply", new_user_<%= singular_lower_case_name %>_path(@user, :reply_to => @<%= singular_lower_case_name %>) %> |
11
+ <%% end %>
12
+ <%%= link_to "Inbox", user_<%= plural_lower_case_name %>_path(@user)%>
13
+ </p>
@@ -0,0 +1,61 @@
1
+ module PrivateExtension #:nodoc:
2
+ module PrivateMessages #:nodoc:
3
+ module HasPrivateMessagesExtensions #:nodoc:
4
+ def self.included(base) #:nodoc:
5
+ base.extend ActMethods
6
+ end
7
+
8
+ module ActMethods
9
+ # Sets up a model have private messages, defining the child class as specified in :class_name (typically "Messages").
10
+ # Provided the following instance messages:
11
+ # * <tt>sent_messages</tt> - returns a collection of messages for which this object is the sender.
12
+ # * <tt>received_messages</tt> - returns a collection of messages for which this object is the recipient.
13
+ def has_private_messages(options = {})
14
+ options[:class_name] ||= 'Message'
15
+
16
+ unless included_modules.include? InstanceMethods
17
+ class_attribute :options
18
+ table_name = options[:class_name].constantize.table_name
19
+
20
+ has_many :sent_messages, -> { where("#{table_name}.sender_deleted = ?", false).order("#{table_name}.created_at DESC") },
21
+ :class_name => options[:class_name],
22
+ :foreign_key => 'sender_id',
23
+ :as => :recipient
24
+
25
+ has_many :received_messages, -> { where("#{table_name}.recipient_deleted = ?", false).order("#{table_name}.created_at DESC") },
26
+ :class_name => options[:class_name],
27
+ :foreign_key => 'recipient_id',
28
+ :as => :sender
29
+
30
+
31
+ extend ClassMethods
32
+ include InstanceMethods
33
+ end
34
+ self.options = options
35
+ end
36
+ end
37
+
38
+ module ClassMethods #:nodoc:
39
+ # None yet...
40
+ end
41
+
42
+ module InstanceMethods
43
+ # Returns true or false based on if this user has any unread messages
44
+ def unread_messages?
45
+ unread_message_count > 0 ? true : false
46
+ end
47
+
48
+ # Returns the number of unread messages for this user
49
+ def unread_message_count
50
+ options[:class_name].constantize.where("recipient_id = ? AND read_at IS NULL and recipient_deleted = ?", self, false).count
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ if defined? ActiveRecord
58
+ ActiveRecord::Base.class_eval do
59
+ include PrivateExtension::PrivateMessages::HasPrivateMessagesExtensions
60
+ end
61
+ end
@@ -0,0 +1,70 @@
1
+ module PrivateExtension # :nodoc:
2
+ module PrivateMessages # :nodoc:
3
+ module PrivateMessageExtensions
4
+ def self.included(base) # :nodoc:
5
+ base.extend ActMethods
6
+ end
7
+
8
+ module ActMethods
9
+ # Sets up a model to be a private message model, defining the parent class as specified in :class_name (typically "User")
10
+ # Provides the following instance methods:
11
+ # * <tt>sender</tt> - the sender of the message.
12
+ # * <tt>recipient</tt> - the recipient of the message.
13
+ #
14
+ # Also adds a named scopes of :read and :unread, to get, well, read and unread messages.
15
+ def is_private_message(options = {})
16
+ options[:class_name] ||= 'User'
17
+
18
+ unless included_modules.include? InstanceMethods
19
+ belongs_to :sender,
20
+ :class_name => options[:class_name],
21
+ :foreign_key => 'sender_id'
22
+ belongs_to :recipient,
23
+ :class_name => options[:class_name],
24
+ :foreign_key => 'recipient_id'
25
+
26
+ extend ClassMethods
27
+ include InstanceMethods
28
+ end
29
+
30
+ scope :already_read, -> { where("read_at IS NOT NULL") }
31
+ scope :unread, -> { where("read_at IS NULL") }
32
+ end
33
+ end
34
+
35
+ module ClassMethods
36
+ # Ensures the passed user is either the sender or the recipient then returns the message.
37
+ # If the reader is the recipient and the message has yet not been read, it marks the read_at timestamp.
38
+ def read_message(id, reader)
39
+ message = where("sender_id = ? OR recipient_id = ?", reader, reader).first
40
+ if message.read_at.nil? && reader == message.recipient
41
+ message.read_at = Time.now
42
+ message.save!
43
+ end
44
+ message
45
+ end
46
+ end
47
+
48
+ module InstanceMethods
49
+ # Returns true or false value based on whether the a message has been read by it's recipient.
50
+ def message_read?
51
+ self.read_at.nil? ? false : true
52
+ end
53
+
54
+ # Marks a message as deleted by either the sender or the recipient, which ever the user that was passed is.
55
+ # Once both have marked it deleted, it is destroyed.
56
+ def mark_deleted(user)
57
+ self.sender_deleted = true if self.sender == user
58
+ self.recipient_deleted = true if self.recipient == user
59
+ self.sender_deleted && self.recipient_deleted ? self.destroy : save!
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ if defined? ActiveRecord
67
+ ActiveRecord::Base.class_eval do
68
+ include PrivateExtension::PrivateMessages::PrivateMessageExtensions
69
+ end
70
+ end
@@ -0,0 +1,39 @@
1
+ module PrivateExtension # :nodoc:
2
+ module PrivateMessages # :nodoc:
3
+ module Shoulda # :nodoc:
4
+ module Matchers # :nodoc:
5
+
6
+ def be_private_message
7
+ BePrivateMessage.new
8
+ end
9
+
10
+ class BePrivateMessage
11
+ def matches? subject
12
+ @subject = subject
13
+ @subject = @subject.class unless Class === @subject
14
+ included?
15
+ end
16
+
17
+ def failure_message
18
+ "Should be private message"
19
+ end
20
+
21
+ def negative_failure_message
22
+ "Should not be private message"
23
+ end
24
+
25
+ def description
26
+ "is private message"
27
+ end
28
+
29
+ protected
30
+
31
+ def included?
32
+ @subject.ancestors.include?(PrivateExtension::PrivateMessages::PrivateMessageExtensions::InstanceMethods)
33
+ end
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,39 @@
1
+ module PrivateExtension # :nodoc:
2
+ module PrivateMessages # :nodoc:
3
+ module Shoulda # :nodoc:
4
+ module Matchers # :nodoc:
5
+
6
+ def have_private_messages
7
+ HavePrivateMessagesMatcher.new
8
+ end
9
+
10
+ class HavePrivateMessagesMatcher # :nodoc:
11
+
12
+ def matches? subject
13
+ @subject = subject
14
+ @subject = @subject.class unless Class === @subject
15
+ included?
16
+ end
17
+
18
+ def failure_message
19
+ "Should have 'has_private_messages' method"
20
+ end
21
+
22
+ def negative_failure_message
23
+ "Should not have 'has_private_messages' method"
24
+ end
25
+
26
+ def description
27
+ "have private messages"
28
+ end
29
+
30
+ protected
31
+
32
+ def included?
33
+ @subject.ancestors.include?(PrivateExtension::PrivateMessages::HasPrivateMessagesExtensions::InstanceMethods)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,9 @@
1
+ require 'private_messages/matchers/have_private_messages_matcher'
2
+ require 'private_messages/matchers/be_private_message_matcher'
3
+
4
+ module PrivateMessages
5
+ module Shoulda
6
+ module Matchers
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module PrivateMessages
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,8 @@
1
+ require "private_messages/version"
2
+
3
+ require 'has_private_messages_extensions'
4
+ require 'private_message_extensions'
5
+
6
+ module PrivateMessages
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :simple_private_messages do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'private_messages/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "user_private_messages"
8
+ spec.version = PrivateMessages::VERSION
9
+ spec.authors = ["Aleksandar Zoric"]
10
+ spec.email = ["aleksandroz.mail@gmail.com"]
11
+ spec.summary = %q{Private messaging system}
12
+ spec.description = %q{Basic private messaging system between users on a site}
13
+ spec.homepage = "https://github.com/Aleksandaar/user-private-messages"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ end
data/test/database.yml ADDED
@@ -0,0 +1,3 @@
1
+ sqlite3:
2
+ :adapter: sqlite3
3
+ :database: ':memory:'
@@ -0,0 +1,5 @@
1
+ require 'active_record'
2
+
3
+ class Message < ActiveRecord::Base
4
+ is_private_message
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'active_record'
2
+
3
+ class User < ActiveRecord::Base
4
+ has_private_messages
5
+ end
data/test/schema.rb ADDED
@@ -0,0 +1,21 @@
1
+ ActiveRecord::Schema.define(:version => 2) do
2
+
3
+ create_table "messages", :force => true do |t|
4
+ t.integer "sender_id"
5
+ t.integer "recipient_id"
6
+ t.boolean "sender_deleted", :default => false
7
+ t.boolean "recipient_deleted", :default => false
8
+ t.string "subject"
9
+ t.text "body"
10
+ t.datetime "read_at"
11
+ t.datetime "created_at"
12
+ t.datetime "updated_at"
13
+ end
14
+
15
+ create_table "users", :force => true do |t|
16
+ t.string "login"
17
+ t.datetime "created_at"
18
+ t.datetime "updated_at"
19
+ end
20
+
21
+ end
@@ -0,0 +1,31 @@
1
+ require 'active_record'
2
+ require File.dirname(__FILE__) + '/../lib/has_private_messages_extensions'
3
+ require File.dirname(__FILE__) + '/../lib/private_message_extensions'
4
+ require File.dirname(__FILE__) + '/../lib/private_messages'
5
+
6
+ require 'byebug'
7
+ require 'thread'
8
+ require 'minitest/autorun'
9
+ begin require 'redgreen'; rescue LoadError; end
10
+
11
+ #ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + '/debug.log')
12
+ ActiveRecord::Base.configurations = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
13
+ ActiveRecord::Base.establish_connection(:sqlite3)
14
+ fixture_path = File.dirname(__FILE__) + '/fixtures/'
15
+ ActiveSupport::Dependencies.autoload_paths << fixture_path
16
+ load(File.dirname(__FILE__) + '/schema.rb')
17
+
18
+ class Minitest::Test
19
+
20
+ def create_user(options = {})
21
+ return User.create({:login => "Aleksandar"}.merge(options))
22
+ end
23
+
24
+ def create_message(options = {})
25
+ return Message.create({:sender => @john,
26
+ :recipient => @aleks,
27
+ :subject => "Hi, Aleks!",
28
+ :body => "Hello, Aleks! Long time no see."}.merge(options))
29
+ end
30
+
31
+ end
@@ -0,0 +1,54 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class MessageModelTest < Minitest::Test
4
+
5
+ def setup
6
+ @aleks = create_user(:login => "aleks")
7
+ @john = create_user(:login => "john")
8
+ @message = create_message
9
+ end
10
+
11
+ def test_create_message
12
+ @message = create_message
13
+
14
+ assert_equal @message.sender, @john
15
+ assert_equal @message.recipient, @aleks
16
+ assert_equal @message.subject, "Hi, Aleks!"
17
+ assert_equal @message.body, "Hello, Aleks! Long time no see."
18
+ assert @message.read_at.nil?
19
+ end
20
+
21
+ def test_read_returns_message
22
+ assert_equal @message, Message.read_message(@message, @john)
23
+ end
24
+
25
+ def test_read_records_timestamp
26
+ assert !@message.nil?
27
+ end
28
+
29
+ def test_read?
30
+ Message.read_message(@message, @aleks)
31
+ @message.reload
32
+ assert @message.message_read?
33
+ end
34
+
35
+ def test_mark_deleted_sender
36
+ @message.mark_deleted(@john)
37
+ @message.reload
38
+ assert @message.sender_deleted
39
+ end
40
+
41
+ def test_mark_deleted_recipient
42
+ @message.mark_deleted(@aleks)
43
+ @message.reload
44
+ assert @message.recipient_deleted
45
+ end
46
+
47
+ def test_mark_deleted_both
48
+ id = @message.id
49
+ @message.mark_deleted(@aleks)
50
+ @message.mark_deleted(@john)
51
+ assert !Message.exists?(id)
52
+ end
53
+
54
+ end
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class UserModelTest < Minitest::Test
4
+
5
+ def setup
6
+ @aleks = create_user(:login => "aleks")
7
+ @message = create_message
8
+ end
9
+
10
+ def test_unread_messages?
11
+ assert @aleks.unread_messages?
12
+ end
13
+
14
+ def test_unread_message_count
15
+ assert_equal @aleks.unread_message_count, 1
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: user_private_messages
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Aleksandar Zoric
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: Basic private messaging system between users on a site
42
+ email:
43
+ - aleksandroz.mail@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - Gemfile
50
+ - LICENSE.txt
51
+ - README.md
52
+ - Rakefile
53
+ - lib/generators/simple_private_messages/model/USAGE
54
+ - lib/generators/simple_private_messages/model/model_generator.rb
55
+ - lib/generators/simple_private_messages/model/templates/migration.rb
56
+ - lib/generators/simple_private_messages/model/templates/model.rb
57
+ - lib/generators/simple_private_messages/scaffold/USAGE
58
+ - lib/generators/simple_private_messages/scaffold/scaffold_generator.rb
59
+ - lib/generators/simple_private_messages/scaffold/templates/controller.rb
60
+ - lib/generators/simple_private_messages/scaffold/templates/view_index.html.erb
61
+ - lib/generators/simple_private_messages/scaffold/templates/view_index_inbox.html.erb
62
+ - lib/generators/simple_private_messages/scaffold/templates/view_index_sent.html.erb
63
+ - lib/generators/simple_private_messages/scaffold/templates/view_new.html.erb
64
+ - lib/generators/simple_private_messages/scaffold/templates/view_show.html.erb
65
+ - lib/has_private_messages_extensions.rb
66
+ - lib/private_message_extensions.rb
67
+ - lib/private_messages.rb
68
+ - lib/private_messages/matchers.rb
69
+ - lib/private_messages/matchers/be_private_message_matcher.rb
70
+ - lib/private_messages/matchers/have_private_messages_matcher.rb
71
+ - lib/private_messages/version.rb
72
+ - lib/tasks/simple_private_messages_tasks.rake
73
+ - private_messages.gemspec
74
+ - test/database.yml
75
+ - test/fixtures/message.rb
76
+ - test/fixtures/user.rb
77
+ - test/schema.rb
78
+ - test/test_helper.rb
79
+ - test/unit/message_model.rb
80
+ - test/unit/user_model.rb
81
+ homepage: https://github.com/Aleksandaar/user-private-messages
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 2.2.2
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: Private messaging system
105
+ test_files:
106
+ - test/database.yml
107
+ - test/fixtures/message.rb
108
+ - test/fixtures/user.rb
109
+ - test/schema.rb
110
+ - test/test_helper.rb
111
+ - test/unit/message_model.rb
112
+ - test/unit/user_model.rb