inboxes 0.1.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.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.md +60 -0
- data/Rakefile +1 -0
- data/app/controllers/inboxes/base_controller.rb +3 -0
- data/app/controllers/inboxes/discussions_controller.rb +67 -0
- data/app/controllers/inboxes/messages_controller.rb +18 -0
- data/app/controllers/inboxes/speakers_controller.rb +26 -0
- data/app/helpers/inboxes_helper.rb +9 -0
- data/app/models/discussion.rb +116 -0
- data/app/models/message.rb +22 -0
- data/app/models/speaker.rb +16 -0
- data/app/views/inboxes/discussions/_form.html.haml +12 -0
- data/app/views/inboxes/discussions/index.html.haml +19 -0
- data/app/views/inboxes/discussions/new.html.haml +5 -0
- data/app/views/inboxes/discussions/show.html.haml +31 -0
- data/app/views/inboxes/messages/_form.html.haml +7 -0
- data/app/views/inboxes/messages/_message.html.haml +8 -0
- data/config/locales/en.yml +15 -0
- data/config/locales/ru.yml +17 -0
- data/config/routes.rb +11 -0
- data/inboxes.gemspec +33 -0
- data/lib/generators/inboxes/install_generator.rb +40 -0
- data/lib/generators/inboxes/templates/install.rb +29 -0
- data/lib/generators/inboxes/views_generator.rb +24 -0
- data/lib/inboxes.rb +33 -0
- data/lib/inboxes/active_record_extension.rb +11 -0
- data/lib/inboxes/engine.rb +4 -0
- data/lib/inboxes/railtie.rb +18 -0
- data/lib/inboxes/version.rb +3 -0
- data/vendor/assets/javascripts/inboxes/faye.js +3 -0
- data/vendor/assets/javascripts/inboxes/faye/init.js.coffee +9 -0
- metadata +152 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#Inboxes
|
2
|
+
|
3
|
+
Inboxes is a young messaging system for Rails app. It:
|
4
|
+
|
5
|
+
- provides 3 models for developers: Discussion, Message and Speaker
|
6
|
+
- read/unread discussions counter
|
7
|
+
- any user can be invited to discussion by the member of this discussion, so you can chat with unlimited number of users
|
8
|
+
|
9
|
+
##Requirements and recommendations
|
10
|
+
|
11
|
+
Inboxes requires Rails 3.x and [Devise](https://github.com/plataformatec/devise) for user identification (surely, messaging system is not possible without users). Now the gem is tested only with Ruby 1.8.7 and REE.
|
12
|
+
|
13
|
+
We recommend to use Inboxes with [Faye](https://github.com/jcoglan/faye), because it's really sexy with it.
|
14
|
+
|
15
|
+
Remember that unfortunately, Inboxes reserve 3 resources names: Discussion, Message and Speaker.
|
16
|
+
|
17
|
+
##Installation
|
18
|
+
|
19
|
+
*Make sure that Devise is already installed and configured!*
|
20
|
+
|
21
|
+
1. Add `gem "inboxes"` to your `Gemfile` and run `bundle install`
|
22
|
+
2. Execute `rails generate inboxes:install`. This command will generate migration for messaging system. Don't forget to run migrations: `rake db:migrate`
|
23
|
+
3. Add `inboxes` to your User model like [here](https://gist.github.com/1330080)
|
24
|
+
4. Now Inboxes is ready to use. Open `http://yoursite.dev/discussions` to see the list of discussions. You can start new one.
|
25
|
+
|
26
|
+
Default Inboxes views are ugly, so you can copy into your app and make anything with them: `rails generate inboxes:views`
|
27
|
+
If you have problems with installation, you can check [code of demo app](https://github.com/kirs/inboxes-app)
|
28
|
+
|
29
|
+
## I18n
|
30
|
+
|
31
|
+
By default, the gem provides localized phrases for Russian and English languages. You can easily override any of them. [Here is](https://github.com/kirs/inboxes/blob/master/config/locales/en.yml) list of all I18n phrases.
|
32
|
+
|
33
|
+
#Integration with Faye
|
34
|
+
|
35
|
+
1. Add `gem "faye"` to your Gemfile and run `bundle install`. Install Faye by [the screencast](http://railscasts.com/episodes/260-messaging-with-faye)
|
36
|
+
2. Create `messaging.js` in `app/assets/javascripts/` with these lines:
|
37
|
+
|
38
|
+
/*
|
39
|
+
= require inboxes/faye
|
40
|
+
*/
|
41
|
+
|
42
|
+
3. Copy or replace 2 views from Inboxes example app to your application: [app/views/inboxes/messages/_form](https://github.com/kirs/inboxes-app/blob/master/app/views/inboxes/messages/_form.html.haml) and [app/views/inboxes/messages/create](https://github.com/kirs/inboxes-app/blob/master/app/views/inboxes/messages/create.js.erb)
|
43
|
+
|
44
|
+
4. Add config parameters to your application config (last 2 are not necessary):
|
45
|
+
|
46
|
+
config.inboxes.faye_enabled = true
|
47
|
+
config.inboxes.faye_host = "inboxes-app.dev" # localhost by default
|
48
|
+
config.inboxes.faye_port = 9292 # 9292 by default
|
49
|
+
|
50
|
+
5. Faye installation is finished. If you have any troubles, check the [example app](https://github.com/kirs/inboxes-app/)
|
51
|
+
|
52
|
+
##Todo
|
53
|
+
|
54
|
+
- Add RSpec tests
|
55
|
+
|
56
|
+
##Authors
|
57
|
+
|
58
|
+
- [Kir Shatrov](https://github.com/kirs/) (Evrone Company)
|
59
|
+
|
60
|
+
##Feel free for pull requests!
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class Inboxes::DiscussionsController < Inboxes::BaseController
|
2
|
+
before_filter :authenticate_user!
|
3
|
+
before_filter :init_and_check_permissions, :only => :show
|
4
|
+
before_filter :load_and_check_discussion_recipient, :only => [:create, :new]
|
5
|
+
|
6
|
+
def index
|
7
|
+
@discussions = current_user.discussions
|
8
|
+
end
|
9
|
+
|
10
|
+
# GET /discussions/1
|
11
|
+
# GET /discussions/1.json
|
12
|
+
def show
|
13
|
+
@discussion.mark_as_read_for(current_user)
|
14
|
+
end
|
15
|
+
|
16
|
+
# GET /discussions/new
|
17
|
+
# GET /discussions/new.json
|
18
|
+
def new
|
19
|
+
# @discussion = Discussion.new
|
20
|
+
@discussion.messages.build
|
21
|
+
end
|
22
|
+
|
23
|
+
# POST /discussions
|
24
|
+
# POST /discussions.json
|
25
|
+
def create
|
26
|
+
# @discussion = Discussion.new(params[:discussion])
|
27
|
+
@discussion.add_recipient_token current_user.id
|
28
|
+
|
29
|
+
@discussion.messages.each do |m|
|
30
|
+
m.discussion = @discussion
|
31
|
+
m.user = current_user
|
32
|
+
end
|
33
|
+
|
34
|
+
if @discussion.save
|
35
|
+
redirect_to @discussion, :notice => t("inboxes.discussions.started")
|
36
|
+
else
|
37
|
+
render :action => "new"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def init_and_check_permissions
|
44
|
+
@discussion = Discussion.includes(:messages, :speakers).find(params[:id])
|
45
|
+
redirect_to discussions_url, :notice => t("inboxes.discussions.can_not_participate") unless @discussion.can_participate?(current_user)
|
46
|
+
end
|
47
|
+
|
48
|
+
def load_and_check_discussion_recipient
|
49
|
+
# initializing model fir new and create actions
|
50
|
+
@discussion = Discussion.new((params[:discussion] ? params[:discussion] : {}))
|
51
|
+
# @discussion.recipient_tokens = params[:recipients] if params[:recipients] # pre-population
|
52
|
+
|
53
|
+
# checking if discussion with this user already exists
|
54
|
+
if @discussion.recipient_ids && @discussion.recipient_ids.size == 1
|
55
|
+
user = User.find(@discussion.recipient_ids.first)
|
56
|
+
discussion = Discussion.find_between_users(current_user, user)
|
57
|
+
if discussion
|
58
|
+
# it exists, let's add message and redirect current user
|
59
|
+
@discussion.messages.each do |message|
|
60
|
+
Message.create(:discussion => discussion, :user => current_user, :body => message.body) if message.body
|
61
|
+
end
|
62
|
+
# перекидываем на нее
|
63
|
+
redirect_to discussion_url(discussion), :notice => t("inboxes.discussions.exists", :user => user[Inboxes::config.user_name])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Inboxes::MessagesController < Inboxes::BaseController
|
2
|
+
|
3
|
+
def create
|
4
|
+
@discussion = Discussion.find(params[:discussion_id])
|
5
|
+
redirect_to root_url, :notice => t("inboxes.discussions.can_not_participate") unless @discussion.can_participate?(current_user)
|
6
|
+
|
7
|
+
@message = Message.new(params[:message])
|
8
|
+
@message.user = current_user
|
9
|
+
@message.discussion = @discussion
|
10
|
+
@message.save
|
11
|
+
|
12
|
+
respond_to do |format|
|
13
|
+
format.html { redirect_to @message.discussion }
|
14
|
+
format.js
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Inboxes::SpeakersController < Inboxes::BaseController
|
2
|
+
before_filter :init_and_check_permissions
|
3
|
+
|
4
|
+
def create
|
5
|
+
# check permissions
|
6
|
+
raise ActiveRecord::RecordNotFound unless params[:speaker] && params[:speaker][:user_id]
|
7
|
+
@user = User.find(params[:speaker][:user_id])
|
8
|
+
|
9
|
+
flash[:notice] = t("views.speakers.added") if @discussion.add_speaker(@user)
|
10
|
+
redirect_to @discussion
|
11
|
+
end
|
12
|
+
|
13
|
+
def destroy
|
14
|
+
@speaker = Speaker.find(params[:id])
|
15
|
+
@speaker.destroy
|
16
|
+
flash[:notice] = @speaker.user == current_user ? t("inboxes.discussions.leaved") : t("inboxes.speakers.removed")
|
17
|
+
redirect_to @discussion.speakers.any? && @discussion.can_participate?(current_user) ? @discussion : discussions_url
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def init_and_check_permissions
|
23
|
+
@discussion = Discussion.find(params[:discussion_id])
|
24
|
+
redirect_to discussions_url, :notice => t("inboxes.discussions.can_not_participate") unless @discussion.can_participate?(current_user)
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
module InboxesHelper
|
3
|
+
def inboxes_faye_broadcast(channel, &block)
|
4
|
+
message = {:channel => channel, :data => capture(&block), :ext => {:auth_token => defined?(FAYE_TOKEN) ? FAYE_TOKEN : ""}}
|
5
|
+
uri = URI.parse("http://#{Inboxes::config.faye_host}:#{Inboxes::config.faye_port}/faye")
|
6
|
+
# Rails.logger.info "Faye URL: #{uri}"
|
7
|
+
res = Net::HTTP.post_form(uri, :message => message.to_json)
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
|
2
|
+
class Discussion < ActiveRecord::Base
|
3
|
+
attr_accessor :recipient_tokens, :recipient_ids
|
4
|
+
attr_reader :recipient_ids
|
5
|
+
|
6
|
+
# paginates_per 10
|
7
|
+
|
8
|
+
# создатель
|
9
|
+
has_many :messages, :dependent => :destroy
|
10
|
+
|
11
|
+
# участники
|
12
|
+
has_many :speakers, :dependent => :destroy
|
13
|
+
has_many :users, :through => :speakers
|
14
|
+
|
15
|
+
# отметки о прочтении юзеров
|
16
|
+
|
17
|
+
scope :unread_for, (lambda do |user_or_user_id|
|
18
|
+
user = user_or_user_id.is_a?(User) ? user_or_user_id.id : user_or_user_id
|
19
|
+
joins(:speakers).where("discussions.updated_at >= speakers.updated_at AND speakers.user_id = ?", user)
|
20
|
+
end)
|
21
|
+
|
22
|
+
accepts_nested_attributes_for :messages
|
23
|
+
|
24
|
+
validate :check_that_has_at_least_two_users # не даем создать дискуссию, у которой нет получателей
|
25
|
+
|
26
|
+
# добавляем записи об указанных собеседников
|
27
|
+
after_save(:on => :create) do
|
28
|
+
# Rails.logger.info("Repicients ids: #{recipient_ids.inspect}")
|
29
|
+
|
30
|
+
if recipient_ids.kind_of?(Array)
|
31
|
+
recipient_ids.uniq!
|
32
|
+
recipient_ids.each do |id|
|
33
|
+
recipient = User.find(id)
|
34
|
+
add_speaker(recipient) if recipient
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def recipient_tokens=(ids)
|
40
|
+
self.recipient_ids = ids
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_recipient_token id
|
44
|
+
self.recipient_ids << id if self.recipient_ids
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_speaker(user)
|
48
|
+
raise ArgumentError, "You can add speaker only to existing Discussion. Save your the Discussion object firstly" if new_record?
|
49
|
+
Speaker.create(:discussion => self, :user => user)
|
50
|
+
end
|
51
|
+
|
52
|
+
def remove_speaker(user)
|
53
|
+
speaker = find_speaker_by_user(user)
|
54
|
+
speaker.destroy if speaker
|
55
|
+
end
|
56
|
+
|
57
|
+
def user_invited_at(user)
|
58
|
+
speaker = find_speaker_by_user(user)
|
59
|
+
speaker.created_at
|
60
|
+
end
|
61
|
+
|
62
|
+
def can_participate?(user)
|
63
|
+
speaker = find_speaker_by_user(user)
|
64
|
+
speaker ? true : false
|
65
|
+
end
|
66
|
+
|
67
|
+
# проверяет, есть ли уже беседа между пользователями
|
68
|
+
# TODO вынести в отдельный метод а в этом возращать true/false, а то неправославно как-то
|
69
|
+
def self.find_between_users(user, user2)
|
70
|
+
dialog = nil
|
71
|
+
discussions = self.joins(:speakers).includes(:users).where("speakers.user_id = ?", user.id)
|
72
|
+
Rails.logger.info "Searching for ids: #{user.id}, #{user2.id}"
|
73
|
+
discussions.each do |discussion|
|
74
|
+
dialog = discussion if discussion.private? && ((discussion.users.first == user && discussion.users.last == user2) || (discussion.users.first == user2 && discussion.users.last == user))
|
75
|
+
end
|
76
|
+
dialog
|
77
|
+
end
|
78
|
+
|
79
|
+
# приватная/групповая
|
80
|
+
def private?
|
81
|
+
self.users.size <= 2
|
82
|
+
end
|
83
|
+
|
84
|
+
# дата последнего сообщения в дискуссии
|
85
|
+
# def last_message_at
|
86
|
+
# self.messages.last ? self.messages.last.created_at : nil
|
87
|
+
# end
|
88
|
+
|
89
|
+
# проверка, является ли дискуссия непрочитанной для пользователя
|
90
|
+
def unread_for?(user)
|
91
|
+
speaker = find_speaker_by_user(user)
|
92
|
+
if speaker
|
93
|
+
self.updated_at >= speaker.updated_at
|
94
|
+
else
|
95
|
+
true
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# пометить как прочитанная
|
100
|
+
def mark_as_read_for(user)
|
101
|
+
speaker = Speaker.find_or_create_by_user_id_and_discussion_id(user.id, self.id)
|
102
|
+
# flag.update_attributes(:updat => Time.zone.now)
|
103
|
+
speaker.touch
|
104
|
+
end
|
105
|
+
|
106
|
+
def find_speaker_by_user user
|
107
|
+
Speaker.find_by_discussion_id_and_user_id(self.id, user.id)
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def check_that_has_at_least_two_users
|
113
|
+
errors.add :recipient_tokens, t("inboxes.discussions.choose_at_least_one_recipient") if !self.recipient_ids || self.recipient_ids.size < 2
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Message < ActiveRecord::Base
|
2
|
+
|
3
|
+
default_scope order(:created_at)
|
4
|
+
|
5
|
+
belongs_to :discussion, :counter_cache => true
|
6
|
+
belongs_to :user
|
7
|
+
|
8
|
+
validates :user, :discussion, :body, :presence => true
|
9
|
+
|
10
|
+
after_save :touch_discussion_and_mark_as_read
|
11
|
+
|
12
|
+
def visible_for? user
|
13
|
+
self.created_at.to_i >= self.discussion.user_invited_at(user).to_i
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def touch_discussion_and_mark_as_read
|
19
|
+
self.discussion.touch
|
20
|
+
self.discussion.mark_as_read_for(self.user)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Speaker < ActiveRecord::Base
|
2
|
+
belongs_to :user
|
3
|
+
belongs_to :discussion
|
4
|
+
|
5
|
+
validates_uniqueness_of :user_id, :scope => :discussion_id
|
6
|
+
validates :user, :discussion, :presence => true
|
7
|
+
|
8
|
+
after_destroy :destroy_discussion
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def destroy_discussion
|
13
|
+
self.discussion.destroy unless self.discussion.speakers.any?
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
= form_for @discussion do |f|
|
2
|
+
%p
|
3
|
+
= f.label :recipient_tokens
|
4
|
+
%br
|
5
|
+
= select_tag "discussion[recipient_tokens]", options_from_collection_for_select(User.all, :id, Inboxes::config.user_name), :multiple => true, :size => "4"
|
6
|
+
%p
|
7
|
+
= f.fields_for :messages do |j|
|
8
|
+
= j.label :body
|
9
|
+
%br
|
10
|
+
= j.text_area :body
|
11
|
+
|
12
|
+
%p= f.submit
|
@@ -0,0 +1,19 @@
|
|
1
|
+
%h1 Discussions list
|
2
|
+
%p
|
3
|
+
Unread messages:
|
4
|
+
%table
|
5
|
+
%tr
|
6
|
+
%th Last message
|
7
|
+
%th Members
|
8
|
+
%th Unread
|
9
|
+
- @discussions.each do |discussion|
|
10
|
+
%tr
|
11
|
+
%td
|
12
|
+
= discussion.updated_at
|
13
|
+
%td
|
14
|
+
= link_to discussion.users.collect{|u| u[Inboxes::config.user_name]}.join(', '), discussion
|
15
|
+
%td
|
16
|
+
= discussion.unread_for?(current_user) ? "Yes" : "No"
|
17
|
+
|
18
|
+
%p
|
19
|
+
= link_to "Create new", new_discussion_path
|
@@ -0,0 +1,31 @@
|
|
1
|
+
- if Inboxes::config.faye_enabled
|
2
|
+
= javascript_include_tag "messaging"
|
3
|
+
|
4
|
+
%h1 Discussion
|
5
|
+
|
6
|
+
%h3
|
7
|
+
Members
|
8
|
+
- @discussion.speakers.each do |speaker|
|
9
|
+
%div
|
10
|
+
= speaker.user[Inboxes::config.user_name]
|
11
|
+
= link_to '(remove)', discussion_speaker_path(@discussion, speaker), :method => :delete
|
12
|
+
|
13
|
+
- available_users = User.all.map { |u| u unless @discussion.users.include?(u) }.delete_if { |w| w.nil? }
|
14
|
+
- if available_users.any?
|
15
|
+
= form_for Speaker.new, :url => discussion_speakers_path(@discussion) do |f|
|
16
|
+
= f.label :user_id, "Add speaker"
|
17
|
+
= f.collection_select :user_id, available_users, :id, :name
|
18
|
+
= f.submit "Add"
|
19
|
+
|
20
|
+
|
21
|
+
%h3 Messages
|
22
|
+
|
23
|
+
#messages_box
|
24
|
+
= render @discussion.messages, :as => :message
|
25
|
+
|
26
|
+
%h3 Add message
|
27
|
+
= render "inboxes/messages/form"
|
28
|
+
|
29
|
+
%p
|
30
|
+
= link_to "Leave discussion", discussion_speaker_path(@discussion, @discussion.find_speaker_by_user(current_user)), :method => :delete unless @discussion.private?
|
31
|
+
= link_to "All discussions", discussions_path
|
@@ -0,0 +1,15 @@
|
|
1
|
+
en:
|
2
|
+
activerecord:
|
3
|
+
attributes:
|
4
|
+
discussion:
|
5
|
+
recipient_tokens: "Recipients"
|
6
|
+
inboxes:
|
7
|
+
speakers:
|
8
|
+
added: "Speaker was added to discussion"
|
9
|
+
removed: "Speaker was removed from discussion"
|
10
|
+
discussions:
|
11
|
+
started: "Discussion started"
|
12
|
+
leaved: "You leaved the discussion"
|
13
|
+
exists: "Discussion between you and %{user} already exists"
|
14
|
+
can_not_participate: "You are not listed in this discussion"
|
15
|
+
choose_at_least_one_recipient: "You should choose at least one recipient of discussion"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
ru:
|
2
|
+
activerecord:
|
3
|
+
attributes:
|
4
|
+
discussion:
|
5
|
+
recipient_tokens: "Получатели"
|
6
|
+
message:
|
7
|
+
body: "Сообщение"
|
8
|
+
inboxes:
|
9
|
+
discussions:
|
10
|
+
started: "Чат начат"
|
11
|
+
leaved: "Вы покинули дискуссию"
|
12
|
+
exists: "Дискуссия между вами и %{user} уже существует"
|
13
|
+
can_not_participate: "Вы не состоите в этой дискуссии"
|
14
|
+
choose_at_least_one_recipient: "Укажите хотя бы одного получателя"
|
15
|
+
speakers:
|
16
|
+
added: "Участник дискуссии добавлен"
|
17
|
+
removed: "Участник дискуссии удален"
|
data/config/routes.rb
ADDED
data/inboxes.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "inboxes/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "inboxes"
|
7
|
+
s.version = Inboxes::VERSION
|
8
|
+
s.authors = ["Kir Shatrov"]
|
9
|
+
s.email = ["razor.psp@gmail.com"]
|
10
|
+
s.homepage = "http://evrone.com/"
|
11
|
+
s.summary = %q{Messaging system for Rails 3 app}
|
12
|
+
s.description = %q{Messaging system for Rails 3 app}
|
13
|
+
|
14
|
+
s.rubyforge_project = "inboxes"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "ruby-debug"
|
23
|
+
s.add_runtime_dependency "haml-rails"
|
24
|
+
# s.add_runtime_dependency "inherited_resources"
|
25
|
+
|
26
|
+
# s.add_development_dependency 'dm-sqlite-adapter', ['>= 1.1.0']
|
27
|
+
s.add_development_dependency 'rspec', ['>= 0']
|
28
|
+
s.add_development_dependency 'rspec-rails', ['>= 0']
|
29
|
+
# s.add_development_dependency 'rr', ['>= 0']
|
30
|
+
# s.add_development_dependency 'steak', ['>= 0']
|
31
|
+
# s.add_development_dependency 'capybara', ['>= 0']
|
32
|
+
s.add_development_dependency 'database_cleaner', ['>= 0']
|
33
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
|
4
|
+
module Inboxes
|
5
|
+
module Generators
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
7
|
+
include Rails::Generators::Migration
|
8
|
+
|
9
|
+
source_root File.expand_path("../templates", __FILE__)
|
10
|
+
|
11
|
+
# desc "Generates migration for Discussion, Message, Speaker and DiscussionView models"
|
12
|
+
|
13
|
+
def self.orm
|
14
|
+
Rails::Generators.options[:rails][:orm]
|
15
|
+
end
|
16
|
+
|
17
|
+
# def self.source_root
|
18
|
+
# File.join(File.dirname(__FILE__), 'templates', (orm.to_s unless orm.class.eql?(String)) )
|
19
|
+
# end
|
20
|
+
|
21
|
+
def self.orm_has_migration?
|
22
|
+
[:active_record].include? orm
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.next_migration_number(dirname)
|
26
|
+
if ActiveRecord::Base.timestamped_migrations
|
27
|
+
migration_number = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
28
|
+
migration_number += 1
|
29
|
+
migration_number.to_s
|
30
|
+
else
|
31
|
+
"%.3d" % (current_migration_number(dirname) + 1)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def copy_migration
|
36
|
+
migration_template 'install.rb', 'db/migrate/install_inboxes.rb'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class InstallInboxes < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :discussions do |t|
|
4
|
+
t.integer :messages_count, :default => 0 # counter cache
|
5
|
+
t.timestamps
|
6
|
+
end
|
7
|
+
|
8
|
+
create_table :messages do |t|
|
9
|
+
t.references :user
|
10
|
+
t.references :discussion
|
11
|
+
t.text :body
|
12
|
+
|
13
|
+
t.timestamps
|
14
|
+
end
|
15
|
+
|
16
|
+
create_table :speakers do |t|
|
17
|
+
t.references :user
|
18
|
+
t.references :discussion
|
19
|
+
|
20
|
+
t.timestamps
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.down
|
25
|
+
drop_table :speakers
|
26
|
+
drop_table :discussions
|
27
|
+
drop_table :messages
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Inboxes
|
4
|
+
module Generators
|
5
|
+
class ViewsGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path('../../../../app/views', __FILE__)
|
7
|
+
#class_option :template_engine, :type => :string, :aliases => '-e', :desc => 'Template engine for the views. Available options are "erb" and "haml".'
|
8
|
+
|
9
|
+
# TODO support of both haml and erb
|
10
|
+
def copy_or_fetch
|
11
|
+
filename_pattern = File.join self.class.source_root, "*" #/*.html.#{template_engine}"
|
12
|
+
Dir.glob(filename_pattern).map {|f| File.basename f}.each do |f|
|
13
|
+
directory f.to_s, "app/views/#{f}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# private
|
18
|
+
|
19
|
+
# def template_engine
|
20
|
+
# # options[:template_engine].try(:to_s).try(:downcase) || 'erb'
|
21
|
+
# end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/inboxes.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require "inboxes/version"
|
2
|
+
require "inboxes/railtie"
|
3
|
+
require "inboxes/engine"
|
4
|
+
require "inboxes/active_record_extension"
|
5
|
+
|
6
|
+
module Inboxes
|
7
|
+
|
8
|
+
def self.configure(&block)
|
9
|
+
yield @config ||= Inboxes::Configuration.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# Global settings for Inboxes
|
13
|
+
def self.config
|
14
|
+
@config
|
15
|
+
end
|
16
|
+
|
17
|
+
# need a Class for 3.0
|
18
|
+
class Configuration #:nodoc:
|
19
|
+
include ActiveSupport::Configurable
|
20
|
+
config_accessor :user_name
|
21
|
+
config_accessor :faye_host
|
22
|
+
config_accessor :faye_port
|
23
|
+
config_accessor :faye_enabled
|
24
|
+
|
25
|
+
def param_name
|
26
|
+
config.param_name.respond_to?(:call) ? config.param_name.call() : config.param_name
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# adding method inboxes for models
|
31
|
+
ActiveRecord::Base.extend(Inboxes::ActiveRecordExtension)
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Inboxes
|
2
|
+
module ActiveRecordExtension
|
3
|
+
def inboxes(options = {})
|
4
|
+
# field = options[:as] || name
|
5
|
+
# prefix = options[:prefix] || "with"
|
6
|
+
|
7
|
+
has_many :speakers, :dependent => :destroy
|
8
|
+
has_many :discussions, :through => :speakers
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rails'
|
2
|
+
|
3
|
+
module Inboxes
|
4
|
+
class Railtie < ::Rails::Railtie
|
5
|
+
config.inboxes = ActiveSupport::OrderedOptions.new
|
6
|
+
|
7
|
+
initializer "inboxes.configure" do |app|
|
8
|
+
Inboxes.configure do |config|
|
9
|
+
config.user_name = app.config.inboxes[:user_name] || "email"
|
10
|
+
config.faye_enabled = app.config.inboxes[:faye_enabled] || false
|
11
|
+
config.faye_host = app.config.inboxes[:faye_host] || "localhost"
|
12
|
+
config.faye_port = app.config.inboxes[:faye_port] || "9292"
|
13
|
+
end
|
14
|
+
|
15
|
+
# app.config.middleware.insert_before "::Rails::Rack::Logger", "Inboxes::Middleware"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: inboxes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Kir Shatrov
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-11-16 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: haml-rails
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: rspec
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: rspec-rails
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
type: :development
|
61
|
+
version_requirements: *id003
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: database_cleaner
|
64
|
+
prerelease: false
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
type: :development
|
75
|
+
version_requirements: *id004
|
76
|
+
description: Messaging system for Rails 3 app
|
77
|
+
email:
|
78
|
+
- razor.psp@gmail.com
|
79
|
+
executables: []
|
80
|
+
|
81
|
+
extensions: []
|
82
|
+
|
83
|
+
extra_rdoc_files: []
|
84
|
+
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- Gemfile
|
88
|
+
- README.md
|
89
|
+
- Rakefile
|
90
|
+
- app/controllers/inboxes/base_controller.rb
|
91
|
+
- app/controllers/inboxes/discussions_controller.rb
|
92
|
+
- app/controllers/inboxes/messages_controller.rb
|
93
|
+
- app/controllers/inboxes/speakers_controller.rb
|
94
|
+
- app/helpers/inboxes_helper.rb
|
95
|
+
- app/models/discussion.rb
|
96
|
+
- app/models/message.rb
|
97
|
+
- app/models/speaker.rb
|
98
|
+
- app/views/inboxes/discussions/_form.html.haml
|
99
|
+
- app/views/inboxes/discussions/index.html.haml
|
100
|
+
- app/views/inboxes/discussions/new.html.haml
|
101
|
+
- app/views/inboxes/discussions/show.html.haml
|
102
|
+
- app/views/inboxes/messages/_form.html.haml
|
103
|
+
- app/views/inboxes/messages/_message.html.haml
|
104
|
+
- config/locales/en.yml
|
105
|
+
- config/locales/ru.yml
|
106
|
+
- config/routes.rb
|
107
|
+
- inboxes.gemspec
|
108
|
+
- lib/generators/inboxes/install_generator.rb
|
109
|
+
- lib/generators/inboxes/templates/install.rb
|
110
|
+
- lib/generators/inboxes/views_generator.rb
|
111
|
+
- lib/inboxes.rb
|
112
|
+
- lib/inboxes/active_record_extension.rb
|
113
|
+
- lib/inboxes/engine.rb
|
114
|
+
- lib/inboxes/railtie.rb
|
115
|
+
- lib/inboxes/version.rb
|
116
|
+
- vendor/assets/javascripts/inboxes/faye.js
|
117
|
+
- vendor/assets/javascripts/inboxes/faye/init.js.coffee
|
118
|
+
homepage: http://evrone.com/
|
119
|
+
licenses: []
|
120
|
+
|
121
|
+
post_install_message:
|
122
|
+
rdoc_options: []
|
123
|
+
|
124
|
+
require_paths:
|
125
|
+
- lib
|
126
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
hash: 3
|
132
|
+
segments:
|
133
|
+
- 0
|
134
|
+
version: "0"
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
none: false
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
hash: 3
|
141
|
+
segments:
|
142
|
+
- 0
|
143
|
+
version: "0"
|
144
|
+
requirements: []
|
145
|
+
|
146
|
+
rubyforge_project: inboxes
|
147
|
+
rubygems_version: 1.8.11
|
148
|
+
signing_key:
|
149
|
+
specification_version: 3
|
150
|
+
summary: Messaging system for Rails 3 app
|
151
|
+
test_files: []
|
152
|
+
|