inboxes 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|