rs-rails-base 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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rubocop.yml +75 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +9 -0
- data/LICENSE.md +9 -0
- data/README.md +61 -0
- data/Rakefile +7 -0
- data/bin/bundle +3 -0
- data/bin/rails +7 -0
- data/bin/rake +16 -0
- data/bin/rs_rails_base +37 -0
- data/bin/setup +8 -0
- data/circle.yml +12 -0
- data/config.reek +109 -0
- data/docs/chat.md +14 -0
- data/docs/facebook.md +10 -0
- data/docs/twilio.md +21 -0
- data/images/chat_flow.png +0 -0
- data/images/chat_struct.png +0 -0
- data/lib/rs-rails-base/cli_actions.rb +16 -0
- data/lib/rs-rails-base/commands.rb +81 -0
- data/lib/rs-rails-base/constants.rb +7 -0
- data/lib/rs-rails-base/features.rb +16 -0
- data/lib/rs-rails-base/features/chat.rb +91 -0
- data/lib/rs-rails-base/features/facebook.rb +41 -0
- data/lib/rs-rails-base/features/twilio.rb +18 -0
- data/lib/rs-rails-base/file_manipulation.rb +55 -0
- data/lib/rs-rails-base/git_actions.rb +13 -0
- data/lib/rs-rails-base/rails_actions.rb +27 -0
- data/lib/rs_rails_base.rb +10 -0
- data/lib/templates/chat/channel.rb +4 -0
- data/lib/templates/chat/chat_channel.rb +15 -0
- data/lib/templates/chat/chat_service.rb +28 -0
- data/lib/templates/chat/chats_controller.rb +56 -0
- data/lib/templates/chat/connection.rb +24 -0
- data/lib/templates/chat/jbuilder/_info.json.jbuilder +2 -0
- data/lib/templates/chat/jbuilder/_message.json.jbuilder +2 -0
- data/lib/templates/chat/jbuilder/index.json.jbuilder +3 -0
- data/lib/templates/chat/jbuilder/messages_create.json.jbuilder +3 -0
- data/lib/templates/chat/jbuilder/messages_create_info.json.jbuilder +7 -0
- data/lib/templates/chat/jbuilder/show.json.jbuilder +3 -0
- data/lib/templates/chat/messages_controller.rb +23 -0
- data/lib/templates/chat/migration-models/add_chat.rb +9 -0
- data/lib/templates/chat/migration-models/add_message.rb +15 -0
- data/lib/templates/chat/migration-models/add_participant.rb +12 -0
- data/lib/templates/chat/migration-models/chat.rb +30 -0
- data/lib/templates/chat/migration-models/message.rb +43 -0
- data/lib/templates/chat/migration-models/participant.rb +28 -0
- data/lib/templates/chat/migration-models/user.rb +3 -0
- data/lib/templates/chat/routes.rb +6 -0
- data/lib/templates/chat/routes_2.rb +1 -0
- data/lib/templates/chat/sessions_controller.rb +7 -0
- data/lib/templates/chat/specs/chat_channel_spec.rb +25 -0
- data/lib/templates/chat/specs/chat_factory.rb +20 -0
- data/lib/templates/chat/specs/chat_service_spec.rb +19 -0
- data/lib/templates/chat/specs/chat_spec.rb +27 -0
- data/lib/templates/chat/specs/connection_spec.rb +10 -0
- data/lib/templates/chat/specs/message_factory.rb +7 -0
- data/lib/templates/chat/specs/message_spec.rb +40 -0
- data/lib/templates/chat/specs/participant_factory.rb +7 -0
- data/lib/templates/chat/specs/participant_spec.rb +21 -0
- data/lib/templates/chat/specs/rails_helper.rb +1 -0
- data/lib/templates/facebook/apiary.apib +28 -0
- data/lib/templates/facebook/en.yml +4 -0
- data/lib/templates/facebook/facebook_service.rb +13 -0
- data/lib/templates/facebook/facebook_spec.rb +146 -0
- data/lib/templates/facebook/factories_user.rb +6 -0
- data/lib/templates/facebook/routes.rb +3 -0
- data/lib/templates/facebook/sessions_controller.rb +9 -0
- data/lib/templates/facebook/sessions_controller_2.rb +7 -0
- data/lib/templates/facebook/sessions_routing_spec.rb +4 -0
- data/lib/templates/facebook/user_spec.rb +5 -0
- data/lib/templates/twilio/twilio.rb +4 -0
- data/lib/templates/twilio/twilio_service.rb +21 -0
- data/rs-rails-base.gemspec +29 -0
- data/tasks/code_analysis.rake +4 -0
- metadata +206 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
class ChatChannel < ApplicationCable::Channel
|
2
|
+
def subscribed
|
3
|
+
chat = Chat.find(params[:chat_id])
|
4
|
+
stream_for(chat)
|
5
|
+
end
|
6
|
+
|
7
|
+
def unsubscribed; end
|
8
|
+
|
9
|
+
def send_message(data)
|
10
|
+
content = data['message']
|
11
|
+
chat_id = data['chat_id']
|
12
|
+
chat = Chat.find(chat_id)
|
13
|
+
ChatService.create_message(chat, content, current_user)
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ChatService
|
2
|
+
extend self
|
3
|
+
def create_message(chat, content, user)
|
4
|
+
message = user.messages.create!(chat: chat, content: content)
|
5
|
+
chat.messages << message
|
6
|
+
chat.save!
|
7
|
+
broadcast_message(chat, message)
|
8
|
+
message
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def broadcast_message(chat, message)
|
14
|
+
message_data = form_message_data(message)
|
15
|
+
ChatChannel.broadcast_to(chat, message_data)
|
16
|
+
end
|
17
|
+
|
18
|
+
def form_message_data(message)
|
19
|
+
user = message.user
|
20
|
+
{
|
21
|
+
action: 'new_message',
|
22
|
+
content: message.content,
|
23
|
+
user: user.username,
|
24
|
+
user_id: user.id,
|
25
|
+
date: Time.zone.now.iso8601
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Api
|
2
|
+
module V1
|
3
|
+
class ChatsController < Api::V1::ApiController
|
4
|
+
def index
|
5
|
+
@chats = Chat.joins(:participants).where('participants.user' => current_user)
|
6
|
+
end
|
7
|
+
|
8
|
+
def show
|
9
|
+
chat = Chat.find(params[:id])
|
10
|
+
if !chat || chat.messages.empty?
|
11
|
+
return render json: { messages: {} }, status: :ok
|
12
|
+
end
|
13
|
+
chat.mark_user_seen(current_user)
|
14
|
+
get_messages(chat, params[:page])
|
15
|
+
end
|
16
|
+
|
17
|
+
def create
|
18
|
+
chat = Chat.new(name: chat_name)
|
19
|
+
chat.users << params[:users].each { |user| User.find(user) }
|
20
|
+
chat.save!
|
21
|
+
end
|
22
|
+
|
23
|
+
def visit
|
24
|
+
chat = Chat.find(params[:chat_id])
|
25
|
+
participant = Participant.find_by(user: current_user, chat: chat)
|
26
|
+
participant.touch(:last_connection)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def get_messages(chat, page)
|
32
|
+
@messages = chat.messages.order_by_date.page(page)
|
33
|
+
@messages = @messages.sort_by(&:created_at)
|
34
|
+
end
|
35
|
+
|
36
|
+
def chat_name
|
37
|
+
Chat.find_or_create_by_name(infer_chat_type)
|
38
|
+
end
|
39
|
+
|
40
|
+
def infer_chat_type
|
41
|
+
room = params[:room]
|
42
|
+
room.present ? room : personal_chat
|
43
|
+
end
|
44
|
+
|
45
|
+
def personal_chat
|
46
|
+
username = params[:user]
|
47
|
+
current_user_name = current_user.username
|
48
|
+
if (current_user_name <=> username).negative?
|
49
|
+
"#{current_user_name}_#{username}"
|
50
|
+
else
|
51
|
+
"#{username}_#{current_user_name}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ApplicationCable
|
2
|
+
class Connection < ActionCable::Connection::Base
|
3
|
+
identified_by :current_user
|
4
|
+
|
5
|
+
def connect
|
6
|
+
self.current_user = find_verified_user
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def find_verified_user
|
12
|
+
if (current_user = find_user)
|
13
|
+
current_user
|
14
|
+
else
|
15
|
+
reject_unauthorized_connection
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def find_user
|
20
|
+
user_id = request.headers['HTTP_AUTHORIZATION'] || request.query_parameters['user'].to_i
|
21
|
+
User.find_by(id: user_id)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Api
|
2
|
+
module V1
|
3
|
+
class MessagesController < Api::V1::ApiController
|
4
|
+
include Concerns::ActAsApiRequest
|
5
|
+
protect_from_forgery with: :null_session
|
6
|
+
before_action :chat, only: :create
|
7
|
+
|
8
|
+
def create
|
9
|
+
@message = ChatService.create_message(chat, message_params[:content], current_user)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def message_params
|
15
|
+
params.require(:message).permit(:content)
|
16
|
+
end
|
17
|
+
|
18
|
+
def chat
|
19
|
+
@chat ||= current_user.chats.find(params[:chat_id])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class AddMessage < ActiveRecord::Migration[5.0]
|
2
|
+
def change
|
3
|
+
create_table :messages do |t|
|
4
|
+
t.belongs_to :user
|
5
|
+
t.belongs_to :chat
|
6
|
+
t.string :content
|
7
|
+
t.string :image
|
8
|
+
t.integer :image_orientation
|
9
|
+
t.string :message_type
|
10
|
+
t.boolean :sent
|
11
|
+
t.boolean :read
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class AddParticipant < ActiveRecord::Migration[5.0]
|
2
|
+
def change
|
3
|
+
create_table :participants do |t|
|
4
|
+
t.belongs_to :user
|
5
|
+
t.belongs_to :chat
|
6
|
+
t.datetime :last_connection
|
7
|
+
t.string :last_message_user
|
8
|
+
t.boolean :seen_data
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# == Schema Information
|
2
|
+
#
|
3
|
+
# Table name: chats
|
4
|
+
#
|
5
|
+
# id :integer not null, primary key
|
6
|
+
# name :string
|
7
|
+
# last_message :string
|
8
|
+
# created_at :datetime not null
|
9
|
+
# updated_at :datetime not null
|
10
|
+
#
|
11
|
+
|
12
|
+
class Chat < ApplicationRecord
|
13
|
+
has_many :participants
|
14
|
+
has_many :messages
|
15
|
+
has_many :users, through: :participants
|
16
|
+
has_many :authors_messages, through: :messages, source: :users
|
17
|
+
|
18
|
+
validates :name, presence: true
|
19
|
+
validate :users?
|
20
|
+
|
21
|
+
def mark_user_seen(user)
|
22
|
+
participants.find_by(user: user).update_column(:seen_data, true)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def users?
|
28
|
+
errors.add(:base, 'A chat must have at least two users') if users.length < 2
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# == Schema Information
|
2
|
+
#
|
3
|
+
# Table name: messages
|
4
|
+
#
|
5
|
+
# id :integer not null, primary key
|
6
|
+
# user_id :integer
|
7
|
+
# chat_id :integer
|
8
|
+
# content :string
|
9
|
+
# image :string
|
10
|
+
# image_orientation :integer
|
11
|
+
# message_type :string
|
12
|
+
# sent :boolean
|
13
|
+
# read :boolean
|
14
|
+
# created_at :datetime not null
|
15
|
+
# updated_at :datetime not null
|
16
|
+
#
|
17
|
+
# Indexes
|
18
|
+
#
|
19
|
+
# index_messages_on_chat_id (chat_id)
|
20
|
+
# index_messages_on_user_id (user_id)
|
21
|
+
#
|
22
|
+
|
23
|
+
class Message < ApplicationRecord
|
24
|
+
belongs_to :chat
|
25
|
+
belongs_to :user
|
26
|
+
|
27
|
+
validates :content, presence: true
|
28
|
+
validate :user_in_chat
|
29
|
+
|
30
|
+
scope :order_by_date, -> { order(created_at: :desc) }
|
31
|
+
|
32
|
+
after_save :update_chat_generic_data
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def update_chat_generic_data
|
37
|
+
chat.update_column(:last_message, content)
|
38
|
+
end
|
39
|
+
|
40
|
+
def user_in_chat
|
41
|
+
chat.users.includes(user)
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# == Schema Information
|
2
|
+
#
|
3
|
+
# Table name: participants
|
4
|
+
#
|
5
|
+
# id :integer not null, primary key
|
6
|
+
# user_id :integer
|
7
|
+
# chat_id :integer
|
8
|
+
# last_connection :datetime
|
9
|
+
# last_message_user :string
|
10
|
+
# seen_data :boolean
|
11
|
+
# created_at :datetime not null
|
12
|
+
# updated_at :datetime not null
|
13
|
+
#
|
14
|
+
# Indexes
|
15
|
+
#
|
16
|
+
# index_participants_on_chat_id (chat_id)
|
17
|
+
# index_participants_on_user_id (user_id)
|
18
|
+
#
|
19
|
+
|
20
|
+
class Participant < ApplicationRecord
|
21
|
+
belongs_to :chat
|
22
|
+
belongs_to :user
|
23
|
+
|
24
|
+
validates :user, uniqueness: { scope: :chat }
|
25
|
+
|
26
|
+
# Please add conversation statistics or useful data here,
|
27
|
+
# instead of fetching all the messages and re process eveytime
|
28
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
mount ActionCable.server => '/cable'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
RSpec.describe ChatChannel, type: :channel do
|
4
|
+
let!(:user) { create(:user) }
|
5
|
+
|
6
|
+
describe '.send_message' do
|
7
|
+
let!(:chat) do
|
8
|
+
create(:chat, :with_messages, user_ids: [user.id])
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'successfully subscribes' do
|
12
|
+
subscribe(chat_id: chat.id)
|
13
|
+
expect(subscription).to be_confirmed
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'on a private chat' do
|
17
|
+
it 'broadcasts to both users' do
|
18
|
+
expect { ChatService.create_message(chat, 'some content', user) }
|
19
|
+
.to have_broadcasted_to(chat)
|
20
|
+
.from_channel(ChatChannel)
|
21
|
+
.with(a_hash_including(content: 'some content'))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
FactoryBot.define do
|
2
|
+
factory :chat do
|
3
|
+
name { Faker::Name.unique.name }
|
4
|
+
|
5
|
+
after(:build) do |chat|
|
6
|
+
chat.users << create(:user)
|
7
|
+
chat.users << create(:user)
|
8
|
+
end
|
9
|
+
|
10
|
+
trait :with_messages do
|
11
|
+
transient do
|
12
|
+
end
|
13
|
+
|
14
|
+
after(:create) do |chat, _evaluator|
|
15
|
+
chat.messages.create!(user_id: chat.users.first,
|
16
|
+
content: Faker::ChuckNorris.fact)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe ChatService do
|
4
|
+
let!(:user) { create(:user) }
|
5
|
+
let!(:chat) { create(:chat) }
|
6
|
+
let!(:participant) { create(:participant, user: user, chat: chat) }
|
7
|
+
|
8
|
+
describe '.create_message' do
|
9
|
+
it 'creates a message' do
|
10
|
+
expect do
|
11
|
+
ChatService.create_message(chat, 'hello', user)
|
12
|
+
end.to change(Message, :count).by(1)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'returns a message' do
|
16
|
+
expect(ChatService.create_message(chat, 'hello', user)).to be_a(Message)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Chat do
|
4
|
+
describe 'chat validations' do
|
5
|
+
it 'have a name' do
|
6
|
+
subject build :chat
|
7
|
+
it { should validate_presence_of(:name) }
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'have no user and fail' do
|
11
|
+
subject build :chat
|
12
|
+
subject.users = nil
|
13
|
+
it { should_not be_valid }
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'have 1 user and fail' do
|
17
|
+
subject build :chat
|
18
|
+
subject.users.pop
|
19
|
+
it { should_not be_valid }
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'have 2 user and be created' do
|
23
|
+
subject build :chat
|
24
|
+
it { should be_valid }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|