user_private_messages 1.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +16 -0
- data/lib/generators/simple_private_messages/model/USAGE +11 -0
- data/lib/generators/simple_private_messages/model/model_generator.rb +51 -0
- data/lib/generators/simple_private_messages/model/templates/migration.rb +16 -0
- data/lib/generators/simple_private_messages/model/templates/model.rb +9 -0
- data/lib/generators/simple_private_messages/scaffold/USAGE +11 -0
- data/lib/generators/simple_private_messages/scaffold/scaffold_generator.rb +50 -0
- data/lib/generators/simple_private_messages/scaffold/templates/controller.rb +60 -0
- data/lib/generators/simple_private_messages/scaffold/templates/view_index.html.erb +7 -0
- data/lib/generators/simple_private_messages/scaffold/templates/view_index_inbox.html.erb +38 -0
- data/lib/generators/simple_private_messages/scaffold/templates/view_index_sent.html.erb +31 -0
- data/lib/generators/simple_private_messages/scaffold/templates/view_new.html.erb +20 -0
- data/lib/generators/simple_private_messages/scaffold/templates/view_show.html.erb +13 -0
- data/lib/has_private_messages_extensions.rb +61 -0
- data/lib/private_message_extensions.rb +70 -0
- data/lib/private_messages/matchers/be_private_message_matcher.rb +39 -0
- data/lib/private_messages/matchers/have_private_messages_matcher.rb +39 -0
- data/lib/private_messages/matchers.rb +9 -0
- data/lib/private_messages/version.rb +3 -0
- data/lib/private_messages.rb +8 -0
- data/lib/tasks/simple_private_messages_tasks.rake +4 -0
- data/private_messages.gemspec +23 -0
- data/test/database.yml +3 -0
- data/test/fixtures/message.rb +5 -0
- data/test/fixtures/user.rb +5 -0
- data/test/schema.rb +21 -0
- data/test/test_helper.rb +31 -0
- data/test/unit/message_model.rb +54 -0
- data/test/unit/user_model.rb +17 -0
- 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
data/Gemfile
ADDED
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,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
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
|
data/test/test_helper.rb
ADDED
@@ -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
|