rs-rails-base 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +75 -0
  5. data/.travis.yml +5 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +9 -0
  8. data/LICENSE.md +9 -0
  9. data/README.md +61 -0
  10. data/Rakefile +7 -0
  11. data/bin/bundle +3 -0
  12. data/bin/rails +7 -0
  13. data/bin/rake +16 -0
  14. data/bin/rs_rails_base +37 -0
  15. data/bin/setup +8 -0
  16. data/circle.yml +12 -0
  17. data/config.reek +109 -0
  18. data/docs/chat.md +14 -0
  19. data/docs/facebook.md +10 -0
  20. data/docs/twilio.md +21 -0
  21. data/images/chat_flow.png +0 -0
  22. data/images/chat_struct.png +0 -0
  23. data/lib/rs-rails-base/cli_actions.rb +16 -0
  24. data/lib/rs-rails-base/commands.rb +81 -0
  25. data/lib/rs-rails-base/constants.rb +7 -0
  26. data/lib/rs-rails-base/features.rb +16 -0
  27. data/lib/rs-rails-base/features/chat.rb +91 -0
  28. data/lib/rs-rails-base/features/facebook.rb +41 -0
  29. data/lib/rs-rails-base/features/twilio.rb +18 -0
  30. data/lib/rs-rails-base/file_manipulation.rb +55 -0
  31. data/lib/rs-rails-base/git_actions.rb +13 -0
  32. data/lib/rs-rails-base/rails_actions.rb +27 -0
  33. data/lib/rs_rails_base.rb +10 -0
  34. data/lib/templates/chat/channel.rb +4 -0
  35. data/lib/templates/chat/chat_channel.rb +15 -0
  36. data/lib/templates/chat/chat_service.rb +28 -0
  37. data/lib/templates/chat/chats_controller.rb +56 -0
  38. data/lib/templates/chat/connection.rb +24 -0
  39. data/lib/templates/chat/jbuilder/_info.json.jbuilder +2 -0
  40. data/lib/templates/chat/jbuilder/_message.json.jbuilder +2 -0
  41. data/lib/templates/chat/jbuilder/index.json.jbuilder +3 -0
  42. data/lib/templates/chat/jbuilder/messages_create.json.jbuilder +3 -0
  43. data/lib/templates/chat/jbuilder/messages_create_info.json.jbuilder +7 -0
  44. data/lib/templates/chat/jbuilder/show.json.jbuilder +3 -0
  45. data/lib/templates/chat/messages_controller.rb +23 -0
  46. data/lib/templates/chat/migration-models/add_chat.rb +9 -0
  47. data/lib/templates/chat/migration-models/add_message.rb +15 -0
  48. data/lib/templates/chat/migration-models/add_participant.rb +12 -0
  49. data/lib/templates/chat/migration-models/chat.rb +30 -0
  50. data/lib/templates/chat/migration-models/message.rb +43 -0
  51. data/lib/templates/chat/migration-models/participant.rb +28 -0
  52. data/lib/templates/chat/migration-models/user.rb +3 -0
  53. data/lib/templates/chat/routes.rb +6 -0
  54. data/lib/templates/chat/routes_2.rb +1 -0
  55. data/lib/templates/chat/sessions_controller.rb +7 -0
  56. data/lib/templates/chat/specs/chat_channel_spec.rb +25 -0
  57. data/lib/templates/chat/specs/chat_factory.rb +20 -0
  58. data/lib/templates/chat/specs/chat_service_spec.rb +19 -0
  59. data/lib/templates/chat/specs/chat_spec.rb +27 -0
  60. data/lib/templates/chat/specs/connection_spec.rb +10 -0
  61. data/lib/templates/chat/specs/message_factory.rb +7 -0
  62. data/lib/templates/chat/specs/message_spec.rb +40 -0
  63. data/lib/templates/chat/specs/participant_factory.rb +7 -0
  64. data/lib/templates/chat/specs/participant_spec.rb +21 -0
  65. data/lib/templates/chat/specs/rails_helper.rb +1 -0
  66. data/lib/templates/facebook/apiary.apib +28 -0
  67. data/lib/templates/facebook/en.yml +4 -0
  68. data/lib/templates/facebook/facebook_service.rb +13 -0
  69. data/lib/templates/facebook/facebook_spec.rb +146 -0
  70. data/lib/templates/facebook/factories_user.rb +6 -0
  71. data/lib/templates/facebook/routes.rb +3 -0
  72. data/lib/templates/facebook/sessions_controller.rb +9 -0
  73. data/lib/templates/facebook/sessions_controller_2.rb +7 -0
  74. data/lib/templates/facebook/sessions_routing_spec.rb +4 -0
  75. data/lib/templates/facebook/user_spec.rb +5 -0
  76. data/lib/templates/twilio/twilio.rb +4 -0
  77. data/lib/templates/twilio/twilio_service.rb +21 -0
  78. data/rs-rails-base.gemspec +29 -0
  79. data/tasks/code_analysis.rake +4 -0
  80. metadata +206 -0
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Channel < ActionCable::Channel::Base
3
+ end
4
+ end
@@ -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,2 @@
1
+ json.id chat.id
2
+ json.name chat.name
@@ -0,0 +1,2 @@
1
+ json.id message.id
2
+ json.content message.content
@@ -0,0 +1,3 @@
1
+ json.chats do
2
+ json.array! @chats, partial: 'info', as: :chat
3
+ end
@@ -0,0 +1,3 @@
1
+ json.message do
2
+ json.partial! 'info', message: @message
3
+ end
@@ -0,0 +1,7 @@
1
+ json.id message.id
2
+ json.content message.content
3
+ json.created_at message.created_at
4
+ json.chat_id message.chat_id
5
+ json.sender do
6
+ json.partial! 'api/v1/users/info', user: message.user
7
+ end
@@ -0,0 +1,3 @@
1
+ json.messages do
2
+ json.array! @messages, partial: 'message', as: :message
3
+ 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,9 @@
1
+ class AddChat < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :chats do |t|
4
+ t.string :name
5
+ t.string :last_message
6
+ t.timestamps
7
+ end
8
+ end
9
+ 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,3 @@
1
+ has_many :participants
2
+ has_many :chats, through: :participants
3
+ has_many :messages
@@ -0,0 +1,6 @@
1
+ resources :chats, only: %i[index show create] do
2
+ resources :messages, only: :create
3
+ member do
4
+ post :visit
5
+ end
6
+ end
@@ -0,0 +1 @@
1
+ mount ActionCable.server => '/cable'
@@ -0,0 +1,7 @@
1
+ def create
2
+ super
3
+ end
4
+
5
+ def destroy
6
+ super
7
+ end
@@ -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